diff -uNrp linux-2.6.6-ia64/Documentation/adeos.txt linux-2.6.6-ia64-adeos/Documentation/adeos.txt
--- linux-2.6.6-ia64/Documentation/adeos.txt	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.6-ia64-adeos/Documentation/adeos.txt	2004-06-17 11:46:40.000000000 +0200
@@ -0,0 +1,176 @@
+
+The Adeos nanokernel is based on research and publications made in the
+early '90s on the subject of nanokernels. Our basic method was to
+reverse the approach described in most of the papers on the subject.
+Instead of first building the nanokernel and then building the client
+OSes, we started from a live and known-to-be-functional OS, Linux, and
+inserted a nanokernel beneath it. Starting from Adeos, other client
+OSes can now be put side-by-side with the Linux kernel.
+
+To this end, Adeos enables multiple domains to exist simultaneously on
+the same hardware. None of these domains see each other, but all of
+them see Adeos. A domain is most probably a complete OS, but there is
+no assumption being made regarding the sophistication of what's in
+a domain.
+
+To share the hardware among the different OSes, Adeos implements an
+interrupt pipeline (ipipe). Every OS domain has an entry in the ipipe.
+Each interrupt that comes in the ipipe is passed on to every domain
+in the ipipe. Instead of disabling/enabling interrupts, each domain
+in the pipeline only needs to stall/unstall his pipeline stage. If
+an ipipe stage is stalled, then the interrupts do not progress in the
+ipipe until that stage has been unstalled. Each stage of the ipipe
+can, of course, decide to do a number of things with an interrupt.
+Among other things, it can decide that it's the last recipient of the
+interrupt. In that case, the ipipe does not propagate the interrupt
+to the rest of the domains in the ipipe.
+
+Regardless of the operations being done in the ipipe, the Adeos code
+does __not__ play with the interrupt masks. The only case where the
+hardware masks are altered is during the addition/removal of a domain
+from the ipipe. This also means that no OS is allowed to use the real
+hardware cli/sti. But this is OK, since the stall/unstall calls
+achieve the same functionality.
+
+Our approach is based on the following papers (links to these
+papers are provided at the bottom of this message):
+[1] D. Probert, J. Bruno, and M. Karzaorman. "Space: a new approach to
+operating system abstraction." In: International Workshop on Object
+Orientation in Operating Systems, pages 133-137, October 1991.
+[2] D. Probert, J. Bruno. "Building fundamentally extensible application-
+specific operating systems in Space", March 1995.
+[3] D. Cheriton, K. Duda. "A caching model of operating system kernel
+functionality". In: Proc. Symp. on Operating Systems Design and
+Implementation, pages 179-194, Monterey CA (USA), 1994.
+[4] D. Engler, M. Kaashoek, and J. O'Toole Jr. "Exokernel: an operating
+system architecture for application-specific resource management",
+December 1995.
+
+If you don't want to go fetch the complete papers, here's a summary.
+The first 2 discuss the Space nanokernel, the 3rd discussed the cache
+nanokernel, and the last discusses exokernel.
+
+The complete Adeos approach has been thoroughly documented in a whitepaper
+published more than a year ago entitled "Adaptive Domain Environment
+for Operating Systems" and available here: http://www.opersys.com/adeos
+The current implementation is slightly different. Mainly, we do not
+implement the functionality to move Linux out of ring 0. Although of
+interest, this approach is not very portable.
+
+Instead, our patch taps right into Linux's main source of control
+over the hardware, the interrupt dispatching code, and inserts an
+interrupt pipeline which can then serve all the nanokernel's clients,
+including Linux.
+
+This is not a novelty in itself. Other OSes have been modified in such
+a way for a wide range of purposes. One of the most interesting
+examples is described by Stodolsky, Chen, and Bershad in a paper
+entitled "Fast Interrupt Priority Management in Operating System
+Kernels" published in 1993 as part of the Usenix Microkernels and
+Other Kernel Architectures Symposium. In that case, cli/sti were
+replaced by virtual cli/sti which did not modify the real interrupt
+mask in any way. Instead, interrupts were defered and delivered to
+the OS upon a call to the virtualized sti.
+
+Mainly, this resulted in increased performance for the OS. Although
+we haven't done any measurements on Linux's interrupt handling
+performance with Adeos, our nanokernel includes by definition the
+code implementing the technique described in the abovementioned
+Stodolsky paper, which we use to redirect the hardware interrupt flow
+to the pipeline.
+
+i386 and armnommu are currently supported. Most of the
+architecture-dependent code is easily portable to other architectures.
+
+Aside of adding the Adeos module (driver/adeos), we also modified some
+files to tap into Linux interrupt and system event dispatching (all
+the modifications are encapsulated in #ifdef CONFIG_ADEOS_*/#endif).
+
+We modified the idle task so it gives control back to Adeos in order for
+the ipipe to continue propagation.
+
+We modified init/main.c to initialize Adeos very early in the startup.
+
+Of course, we also added the appropriate makefile modifications and
+config options so that you can choose to enable/disable Adeos as
+part of the kernel build configuration.
+
+Adeos' public API is fully documented here:
+http://www.freesoftware.fsf.org/adeos/doc/api/index.html.
+
+In Linux's case, adeos_register_domain() is called very early during
+system startup.
+
+To add your domain to the ipipe, you need to:
+1) Register your domain with Adeos using adeos_register_domain()
+2) Call adeos_virtualize_irq() for all the IRQs you wish to be
+notified about in the ipipe.
+
+That's it. Provided you gave Adeos appropriate handlers in step
+#2, your interrupts will be delivered via the ipipe.
+
+During runtime, you may change your position in the ipipe using
+adeos_renice_domain(). You may also stall/unstall the pipeline
+and change the ipipe's handling of the interrupts according to your
+needs.
+
+Adeos supports SMP, and APIC support on UP.
+
+Here are some of the possible uses for Adeos (this list is far
+from complete):
+1) Much like User-Mode Linux, it should now be possible to have 2
+Linux kernels living side-by-side on the same hardware. In contrast
+to UML, this would not be 2 kernels one ontop of the other, but
+really side-by-side. Since Linux can be told at boot time to use
+only one portion of the available RAM, on a 128MB machine this
+would mean that the first could be made to use the 0-64MB space and
+the second would use the 64-128MB space. We realize that many
+modifications are required. Among other things, one of the 2 kernels
+will not need to conduct hardware initialization. Nevertheless, this
+possibility should be studied closer.
+
+2) It follows from #1 that adding other kernels beside Linux should
+be feasible. BSD is a prime candidate, but it would also be nice to
+see what virtualizers such as VMWare and Plex86 could do with Adeos.
+Proprietary operating systems could potentially also be accomodated.
+
+3) All the previous work that has been done on nanokernels should now
+be easily ported to Linux. Mainly, we would be very interested to
+hear about extensions to Adeos. Primarily, we have no mechanisms
+currently enabling multiple domains to share information. The papers
+mentioned earlier provide such mechanisms, but we'd like to see
+actual practical examples.
+
+4) Kernel debuggers' main problem (tapping into the kernel's
+interrupts) is solved and it should then be possible to provide
+patchless kernel debuggers. They would then become loadable kernel
+modules.
+
+5) Drivers who require absolute priority and dislike other kernel
+portions who use cli/sti can now create a domain of their own
+and place themselves before Linux in the ipipe. This provides a
+mechanism for the implementation of systems that can provide guaranteed
+realtime response.
+
+Philippe Gerum <rpm@xenomai.org>
+Karim Yaghmour <karim@opersys.com>
+
+----------------------------------------------------------------------
+Links to papers:
+1-
+http://citeseer.nj.nec.com/probert91space.html
+ftp://ftp.cs.ucsb.edu/pub/papers/space/iwooos91.ps.gz (not working)
+http://www4.informatik.uni-erlangen.de/~tsthiel/Papers/Space-iwooos91.ps.gz
+
+2-
+http://www.cs.ucsb.edu/research/trcs/abstracts/1995-06.shtml
+http://www4.informatik.uni-erlangen.de/~tsthiel/Papers/Space-trcs95-06.ps.gz
+
+3-
+http://citeseer.nj.nec.com/kenneth94caching.html
+http://guir.cs.berkeley.edu/projects/osprelims/papers/cachmodel-OSkernel.ps.gz
+
+4-
+http://citeseer.nj.nec.com/engler95exokernel.html
+ftp://ftp.cag.lcs.mit.edu/multiscale/exokernel.ps.Z
+----------------------------------------------------------------------
diff -uNrp linux-2.6.6-ia64/Makefile linux-2.6.6-ia64-adeos/Makefile
--- linux-2.6.6-ia64/Makefile	2004-06-13 12:55:47.000000000 +0200
+++ linux-2.6.6-ia64-adeos/Makefile	2004-06-17 12:23:06.000000000 +0200
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 6
-EXTRAVERSION =
+EXTRAVERSION = -adeos
 NAME=Zonked Quokka
 
 # *DOCUMENTATION*
@@ -486,6 +486,8 @@ export MODLIB
 ifeq ($(KBUILD_EXTMOD),)
 core-y		+= kernel/ mm/ fs/ ipc/ security/ crypto/
 
+core-$(CONFIG_ADEOS) += adeos/
+
 vmlinux-dirs	:= $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
 		     $(core-y) $(core-m) $(drivers-y) $(drivers-m) \
 		     $(net-y) $(net-m) $(libs-y) $(libs-m)))
diff -uNrp linux-2.6.6-ia64/adeos/Kconfig linux-2.6.6-ia64-adeos/adeos/Kconfig
--- linux-2.6.6-ia64/adeos/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.6-ia64-adeos/adeos/Kconfig	2004-06-17 11:46:40.000000000 +0200
@@ -0,0 +1,15 @@
+menu "Adeos support"
+
+config ADEOS
+	tristate "Adeos support"
+	default y
+	---help---
+	  Activate this option if you want the Adeos nanokernel to be
+	  compiled in.
+
+config ADEOS_CORE
+	bool
+	depends on ADEOS
+	default y
+
+endmenu
diff -uNrp linux-2.6.6-ia64/adeos/Makefile linux-2.6.6-ia64-adeos/adeos/Makefile
--- linux-2.6.6-ia64/adeos/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.6-ia64-adeos/adeos/Makefile	2004-06-17 11:46:40.000000000 +0200
@@ -0,0 +1,11 @@
+#
+# Makefile for the Adeos layer.
+#
+
+obj-$(CONFIG_ADEOS)	+= adeos.o
+
+adeos-objs		:= generic.o
+
+adeos-$(CONFIG_X86)	+= x86.o
+
+adeos-$(CONFIG_IA64)	+= ia64.o
diff -uNrp linux-2.6.6-ia64/adeos/generic.c linux-2.6.6-ia64-adeos/adeos/generic.c
--- linux-2.6.6-ia64/adeos/generic.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.6-ia64-adeos/adeos/generic.c	2004-06-17 11:46:40.000000000 +0200
@@ -0,0 +1,790 @@
+/*
+ *   linux/adeos/generic.c
+ *
+ *   Copyright (C) 2002 Philippe Gerum.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ *   USA; either version 2 of the License, or (at your option) any later
+ *   version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *   Architecture-independent ADEOS services.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/irq.h>
+
+MODULE_DESCRIPTION("Adeos nanokernel");
+MODULE_AUTHOR("Philippe Gerum");
+MODULE_LICENSE("GPL");
+
+extern spinlock_t __adeos_pipelock;
+
+extern struct list_head __adeos_pipeline;
+
+/* adeos_register_domain() -- Add a new domain to the system. All
+   client domains must call this routine to register themselves to
+   ADEOS before using its services. */
+
+int adeos_register_domain (adomain_t *adp, adattr_t *attr)
+
+{
+    struct list_head *pos;
+    unsigned long flags;
+    int n;
+
+    if (adp_current != adp_root)
+	{
+	printk(KERN_WARNING "Adeos: Only the root domain may register a new domain.\n");
+	return -EPERM;
+	}
+
+    flags = adeos_critical_enter(NULL);
+
+    list_for_each(pos,&__adeos_pipeline) {
+    	adomain_t *_adp = list_entry(pos,adomain_t,p_link);
+	if (_adp->domid == attr->domid)
+            break;
+    }
+
+    adeos_critical_exit(flags);
+
+    if (pos != &__adeos_pipeline)
+	/* A domain with the given id already exists -- fail. */
+	return -EBUSY;
+
+    for (n = 0; n < ADEOS_NR_CPUS; n++)
+	adp->cpudata[n].status = 0;
+
+    /* A special case for domains who won't process events (i.e. no
+       entry). We have to mark them as suspended so that
+       adeos_suspend_domain() won't consider them, unless they
+       _actually_ receive events, which would lead to a panic
+       situation since they have no stack context... :o> */
+
+    for (n = 0; n < ADEOS_NR_CPUS; n++)
+	{
+	set_bit(IPIPE_SLEEP_FLAG,&adp->cpudata[n].status);
+
+	if (attr->entry == NULL)
+	    adp->estackbase[n] = 0;
+	}
+
+    adp->name = attr->name;
+    adp->priority = attr->priority;
+    adp->domid = attr->domid;
+    adp->dswitch = attr->dswitch;
+    adp->flags = 0;
+    adp->ptd_setfun = attr->ptdset;
+    adp->ptd_getfun = attr->ptdget;
+    adp->ptd_keymap = 0;
+    adp->ptd_keycount = 0;
+    adp->ptd_keymax = attr->nptdkeys;
+
+    for (n = 0; n < ADEOS_NR_EVENTS; n++)
+	/* Event handlers must be cleared before the i-pipe stage is
+	   inserted since an exception may occur on behalf of the new
+	   emerging domain. */
+	adp->events[n].handler = NULL;
+
+    if (attr->entry != NULL)
+	__adeos_init_domain(adp,attr);
+
+    /* Insert the domain in the interrupt pipeline last, so it won't
+       be resumed for processing interrupts until it has a valid stack
+       context. */
+
+    __adeos_init_stage(adp);
+
+    INIT_LIST_HEAD(&adp->p_link);
+
+    flags = adeos_critical_enter(NULL);
+
+    list_for_each(pos,&__adeos_pipeline) {
+    	adomain_t *_adp = list_entry(pos,adomain_t,p_link);
+	if (adp->priority > _adp->priority)
+            break;
+    }
+
+    list_add_tail(&adp->p_link,pos);
+
+    adeos_critical_exit(flags);
+
+    printk(KERN_WARNING "Adeos: Domain %s registered.\n",adp->name);
+
+    /* Finally, allow the new domain to perform its initialization
+       chores on behalf of its own stack context. */
+
+    if (attr->entry != NULL)
+	{
+	adeos_declare_cpuid;
+
+	adeos_get_cpu(flags);
+
+	__adeos_switch_to(adp,cpuid);
+
+	adeos_load_cpuid();	/* Processor might have changed. */
+
+	if (!test_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status) &&
+	    adp_root->cpudata[cpuid].irq_pending_hi != 0)
+	    __adeos_sync_stage(IPIPE_IRQMASK_ANY);
+
+	adeos_put_cpu(flags);
+	}
+
+    return 0;
+}
+
+/* adeos_unregister_domain() -- Remove a domain from the system. All
+   client domains must call this routine to unregister themselves from
+   the ADEOS layer. */
+
+int adeos_unregister_domain (adomain_t *adp)
+
+{
+    unsigned long flags;
+    unsigned event;
+
+    if (adp_current != adp_root)
+	{
+	printk(KERN_WARNING "Adeos: Only the root domain may unregister a domain.\n");
+	return -EPERM;
+	}
+
+    if (adp == adp_root)
+	{
+	printk(KERN_WARNING "Adeos: Cannot unregister the root domain.\n");
+	return -EPERM;
+	}
+
+    for (event = 0; event < ADEOS_NR_EVENTS; event++)
+	/* Need this to update the monitor count. */
+	adeos_catch_event(event,NULL);
+
+#ifdef CONFIG_SMP
+    {
+    int nr_cpus = num_online_cpus(), _cpuid;
+    unsigned irq;
+
+    /* In the SMP case, wait for the logged events to drain on other
+       processors before eventually removing the domain from the
+       pipeline. */
+
+    adeos_unstall_pipeline_from(adp);
+
+    flags = adeos_critical_enter(NULL);
+
+    for (irq = 0; irq < IPIPE_NR_IRQS; irq++)
+	{
+	clear_bit(IPIPE_HANDLE_FLAG,&adp->irqs[irq].control);
+	clear_bit(IPIPE_STICKY_FLAG,&adp->irqs[irq].control);
+	set_bit(IPIPE_PASS_FLAG,&adp->irqs[irq].control);
+	}
+
+    adeos_critical_exit(flags);
+
+    for (_cpuid = 0; _cpuid < nr_cpus; _cpuid++)
+	{
+	for (irq = 0; irq < IPIPE_NR_IRQS; irq++)
+	    while (adp->cpudata[_cpuid].irq_hits[irq] > 0)
+		cpu_relax();
+
+	while (test_bit(IPIPE_XPEND_FLAG,&adp->cpudata[_cpuid].status))
+	    cpu_relax();
+
+	while (!test_bit(IPIPE_SLEEP_FLAG,&adp->cpudata[_cpuid].status))
+	     cpu_relax();
+	}
+    }
+#endif /* CONFIG_SMP */
+
+    /* Simply remove the domain from the pipeline and we are almost
+       done. */
+
+    flags = adeos_critical_enter(NULL);
+    list_del_init(&adp->p_link);
+    adeos_critical_exit(flags);
+
+    __adeos_cleanup_domain(adp);
+
+    printk(KERN_WARNING "Adeos: Domain %s unregistered.\n",adp->name);
+
+    return 0;
+}
+
+/* adeos_renice_domain() -- Change the priority of the current
+   domain. This affects the position of the domain in the interrupt
+   pipeline. The greater the priority value, the earlier the domain is
+   informed of incoming events when the pipeline is processed. This
+   routine causes a round-robin effect if newpri == oldpri. */
+
+void adeos_renice_domain (int newpri)
+
+{
+    adomain_t *adp, *nadp = NULL;
+    unsigned long lflags, xflags;
+    struct list_head *pos;
+    adeos_declare_cpuid;
+
+    /* We do want adeos_critical_exit() to leave the IRQs masked, so
+       we first clear the interrupt bit before calling
+       adeos_critical_enter(). */
+ 
+    adeos_lock_cpu(lflags);
+
+    adp = adp_cpu_current[cpuid];
+
+    xflags = adeos_critical_enter(NULL);
+
+    list_del_init(&adp->p_link);
+
+    list_for_each(pos,&__adeos_pipeline) {
+    	adomain_t *_adp = list_entry(pos,adomain_t,p_link);
+
+	if (newpri > _adp->priority)
+            break;
+
+	/* While scanning the pipeline from its head to the current
+	   domain's new position, pick the first domain which is
+	   entitled to preempt us. Such domain must be either:
+	   o in a preempted state (i.e. !sleeping),
+	   o or sleeping and unstalled with events to process. */
+
+	if (nadp == NULL &&
+	    (!test_bit(IPIPE_SLEEP_FLAG,&_adp->cpudata[cpuid].status) ||
+	     (!test_bit(IPIPE_STALL_FLAG,&_adp->cpudata[cpuid].status) &&
+	      _adp->cpudata[cpuid].irq_pending_hi != 0) ||
+	     test_bit(IPIPE_XPEND_FLAG,&_adp->cpudata[cpuid].status)))
+	    nadp = _adp;
+    }
+
+    list_add_tail(&adp->p_link,pos);
+    adp->priority = newpri;
+    
+    /* On SMP systems, we release the other CPUs but we still keep the
+       local IRQs masked so that we can't jump to a stale domain. */
+
+    adeos_critical_exit(xflags);
+
+    if (nadp == NULL)
+	goto release_cpu_and_exit;
+
+    __adeos_switch_to(nadp,cpuid);
+
+    adeos_load_cpuid(); /* Processor might have changed. */
+
+    /* Try sync'ing pending interrupts on return from our preemption
+       point. */
+
+    if (!test_bit(IPIPE_STALL_FLAG,&adp_cpu_current[cpuid]->cpudata[cpuid].status) &&
+	adp_cpu_current[cpuid]->cpudata[cpuid].irq_pending_hi != 0)
+	__adeos_sync_stage(IPIPE_IRQMASK_ANY);
+
+    /* Note that we only need to sync interrupts here, since other
+       kind of events (i.e. synchronous ones) cannot flow across the
+       domain which triggers them down the pipeline. Since a more
+       prioritary domain was running up to now, there is no chance for
+       us to have such event pending. */
+
+release_cpu_and_exit:
+
+    adeos_unlock_cpu(lflags);
+}
+
+int __adeos_schedule_irq (unsigned irq, struct list_head *head)
+
+{
+    struct list_head *ln;
+    unsigned long flags;
+    adeos_declare_cpuid;
+
+    if (irq >= IPIPE_NR_IRQS ||
+	(adeos_virtual_irq_p(irq) && !test_bit(irq - IPIPE_VIRQ_BASE,&__adeos_virtual_irq_map)))
+	return -EINVAL;
+
+    adeos_lock_cpu(flags);
+
+    ln = head;
+
+    while (ln != &__adeos_pipeline)
+	{
+	adomain_t *adp = list_entry(ln,adomain_t,p_link);
+
+	if (test_bit(IPIPE_HANDLE_FLAG,&adp->irqs[irq].control))
+	    {
+	    adp->cpudata[cpuid].irq_hits[irq]++;
+	    __adeos_set_irq_bit(adp,cpuid,irq);
+	    adeos_unlock_cpu(flags);
+	    return 1;
+	    }
+
+	ln = adp->p_link.next;
+	}
+
+    adeos_unlock_cpu(flags);
+
+    return 0;
+}
+
+/* adeos_propagate_irq() -- Force a given IRQ propagation on behalf of
+   a running interrupt handler to the next domain down the pipeline.
+   Returns non-zero if a domain has received the interrupt
+   notification, zero otherwise.
+   This call is useful for handling shared interrupts among domains.
+   e.g. pipeline = [domain-A]---[domain-B]...
+   Both domains share IRQ #X.
+   - domain-A handles IRQ #X but does not pass it down (i.e. Terminate
+   or Dynamic interrupt control mode)
+   - domain-B handles IRQ #X (i.e. Terminate or Accept interrupt
+   control modes).
+   When IRQ #X is raised, domain-A's handler determines whether it
+   should process the interrupt by identifying its source. If not,
+   adeos_propagate_irq() is called so that the next domain down the
+   pipeline which handles IRQ #X is given a chance to process it. This
+   process can be repeated until the end of the pipeline is
+   reached. */
+
+int fastcall adeos_propagate_irq (unsigned irq) {
+
+    return __adeos_schedule_irq(irq,adp_current->p_link.next);
+}
+
+/* adeos_schedule_irq() -- Almost the same as adeos_propagate_irq(),
+   but attempts to pend the interrupt for the current domain first. */
+
+int fastcall adeos_schedule_irq (unsigned irq) {
+
+    return __adeos_schedule_irq(irq,&adp_current->p_link);
+}
+
+/* adeos_free_irq() -- Return a previously allocated virtual/soft
+   pipelined interrupt to the pool of allocatable interrupts. */
+
+int adeos_free_irq (unsigned irq)
+
+{
+    if (irq >= IPIPE_NR_IRQS)
+	return -EINVAL;
+
+    clear_bit(irq - IPIPE_VIRQ_BASE,&__adeos_virtual_irq_map);
+
+    return 0;
+}
+
+unsigned long adeos_set_irq_affinity (unsigned irq, unsigned long cpumask)
+
+{
+#ifdef CONFIG_SMP
+     if (irq >= IPIPE_NR_XIRQS)
+	 /* Allow changing affinity of external IRQs only. */
+	 return 0;
+
+     if (num_online_cpus() > 1)
+	 /* Allow changing affinity of external IRQs only. */
+	 return __adeos_set_irq_affinity(irq,cpumask);
+#endif /* CONFIG_SMP */
+
+    return 0;
+}
+
+/* adeos_unstall_pipeline_from() -- Unstall the interrupt pipeline and
+   synchronize pending events from a given domain. */
+
+void fastcall adeos_unstall_pipeline_from (adomain_t *adp)
+
+{
+    struct list_head *pos;
+    unsigned long flags;
+    adeos_declare_cpuid;
+
+    adeos_get_cpu(flags);
+
+    clear_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status);
+
+    if (adp == adp_cpu_current[cpuid])
+	{
+	if (adp->cpudata[cpuid].irq_pending_hi != 0)
+	    __adeos_sync_stage(IPIPE_IRQMASK_ANY);
+
+	goto release_cpu_and_exit;
+	}
+
+    /* Attempt to flush all events that might be pending at the
+       unstalled domain level. This code is roughly lifted from
+       arch/i386/kernel/adeos.c:__adeos_walk_pipeline(). */
+
+    list_for_each(pos,&__adeos_pipeline) {
+
+    	adomain_t *_adp = list_entry(pos,adomain_t,p_link);
+
+	if (test_bit(IPIPE_STALL_FLAG,&_adp->cpudata[cpuid].status))
+	    break; /* Stalled stage -- do not go further. */
+
+	if (_adp->cpudata[cpuid].irq_pending_hi != 0)
+	    {
+	    /* Since the critical IPI might be triggered by the
+	       following actions, the current domain might not be
+	       linked to the pipeline anymore after its handler
+	       returns on SMP boxen, even if the domain remains valid
+	       (see adeos_unregister_domain()), so don't make any
+	       hazardous assumptions here. */
+
+	    if (_adp == adp_cpu_current[cpuid])
+		__adeos_sync_stage(IPIPE_IRQMASK_ANY);
+	    else
+		{
+		__adeos_switch_to(_adp,cpuid);
+
+		adeos_load_cpuid(); /* Processor might have changed. */
+
+		if (!test_bit(IPIPE_STALL_FLAG,&adp_cpu_current[cpuid]->cpudata[cpuid].status) &&
+		    adp_cpu_current[cpuid]->cpudata[cpuid].irq_pending_hi != 0)
+		    __adeos_sync_stage(IPIPE_IRQMASK_ANY);
+		}
+	    
+	    break;
+	    }
+	else if (_adp == adp_cpu_current[cpuid])
+	    break;
+    }
+
+release_cpu_and_exit:
+
+    adeos_put_cpu(flags);
+}
+
+/* adeos_catch_event_from() -- Interpose an event handler starting
+   from a given domain. */
+
+int adeos_catch_event_from (adomain_t *adp, unsigned event, void (*handler)(adevinfo_t *))
+
+{
+    if (event >= ADEOS_NR_EVENTS)
+	return -EINVAL;
+
+    if (!xchg(&adp->events[event].handler,handler))
+	{
+	if (handler)
+	    __adeos_event_monitors[event]++;
+	}
+    else if (!handler)
+	__adeos_event_monitors[event]--;
+
+    return 0;
+}
+
+void (*adeos_hook_dswitch(void (*handler)(void))) (void) {
+
+    return (void (*)(void))xchg(&adp_current->dswitch,handler);
+}
+
+void adeos_init_attr (adattr_t *attr)
+
+{
+    attr->name = "Anonymous";
+    attr->domid = 1;
+    attr->entry = NULL;
+    attr->estacksz = 0;	/* Let ADEOS choose a reasonable stack size */
+    attr->priority = ADEOS_ROOT_PRI;
+    attr->dswitch = NULL;
+    attr->nptdkeys = 0;
+    attr->ptdset = NULL;
+    attr->ptdget = NULL;
+}
+
+int adeos_alloc_ptdkey (void)
+
+{
+    unsigned long flags;
+    int key = -1;
+
+    adeos_spin_lock_irqsave(&__adeos_pipelock,flags);
+
+    if (adp_current->ptd_keycount < adp_current->ptd_keymax)
+	{
+	key = ffz(adp_current->ptd_keymap);
+	set_bit(key,&adp_current->ptd_keymap);
+	adp_current->ptd_keycount++;
+	}
+
+    adeos_spin_unlock_irqrestore(&__adeos_pipelock,flags);
+
+    return key;
+}
+
+int adeos_free_ptdkey (int key)
+
+{
+    unsigned long flags; 
+
+    if (key < 0 || key >= adp_current->ptd_keymax)
+	return -EINVAL;
+
+    adeos_spin_lock_irqsave(&__adeos_pipelock,flags);
+
+    if (test_and_clear_bit(key,&adp_current->ptd_keymap))
+	adp_current->ptd_keycount--;
+
+    adeos_spin_unlock_irqrestore(&__adeos_pipelock,flags);
+
+    return 0;
+}
+
+int adeos_set_ptd (int key, void *value)
+
+{
+    if (key < 0 || key >= adp_current->ptd_keymax)
+	return -EINVAL;
+
+    if (!adp_current->ptd_setfun)
+	{
+	printk(KERN_WARNING "Adeos: No ptdset hook for %s\n",adp_current->name);
+	return -EINVAL;
+	}
+
+    adp_current->ptd_setfun(key,value);
+
+    return 0;
+}
+
+void *adeos_get_ptd (int key)
+
+{
+    if (key < 0 || key >= adp_current->ptd_keymax)
+	return NULL;
+
+    if (!adp_current->ptd_getfun)
+	{
+	printk(KERN_WARNING "Adeos: No ptdget hook for %s\n",adp_current->name);
+	return NULL;
+	}
+
+    return adp_current->ptd_getfun(key);
+}
+
+int adeos_init_mutex (admutex_t *mutex)
+
+{
+    admutex_t initm = ADEOS_MUTEX_UNLOCKED;
+    *mutex = initm;
+    return 0;
+}
+
+int adeos_destroy_mutex (admutex_t *mutex)
+
+{
+    if (!adeos_spin_trylock(&mutex->lock) &&
+	adp_current != adp_root &&
+	mutex->owner != adp_current)
+	return -EBUSY;
+
+    return 0;
+}
+
+static inline void __adeos_sleepon_mutex (admutex_t *mutex, adomain_t *sleeper, int cpuid)
+
+{
+    adomain_t *owner = mutex->owner;
+
+    /* Make the current domain (== sleeper) wait for the mutex to be
+       released. Adeos' pipelined scheme guarantees that the new
+       sleeper _is_ more prioritary than any aslept domain since we
+       have stalled each sleeper's stage. Must be called with local hw
+       interrupts off. */
+
+    sleeper->m_link = mutex->sleepq;
+    mutex->sleepq = sleeper;
+    __adeos_switch_to(owner,cpuid);
+    mutex->owner = sleeper;
+    adeos_spin_unlock(&mutex->lock);
+}
+
+static inline void __adeos_signal_mutex (admutex_t *mutex, int cpuid)
+
+{
+    adomain_t *sleeper;
+
+    /* Wake up first most prioritary sleeper. Must be called with
+       local hw interrupts off. */
+
+    sleeper = mutex->sleepq;
+    mutex->sleepq = sleeper->m_link;
+    __adeos_switch_to(sleeper,cpuid);
+}
+
+unsigned long fastcall adeos_lock_mutex (admutex_t *mutex)
+
+{
+    unsigned long flags, hwflags;
+    adeos_declare_cpuid;
+    adomain_t *adp;
+
+    if (unlikely(!adp_pipelined))
+	{
+	adeos_hw_local_irq_save(hwflags);
+	flags = !adeos_hw_test_iflag(hwflags);
+	adeos_spin_lock(&mutex->lock);
+	return flags;
+	}
+
+    adeos_lock_cpu(hwflags);
+
+    adp = adp_cpu_current[cpuid];
+
+    flags = test_and_set_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status);
+
+    /* Two cases to handle here on SMP systems, only one for UP:
+       1) in case of a conflicting access from a prioritary domain
+       running on the same cpu, make this domain sleep on the mutex,
+       and resume the current owner so it can release the lock asap.
+       2) in case of a conflicting access from any domain on a
+       different cpu than the current owner's, simply enter a spinning
+       loop. Note that testing mutex->owncpu is safe since it is only
+       changed by the current owner, and set to -1 when the mutex is
+       unlocked. */
+
+#ifdef CONFIG_SMP
+    while (!adeos_spin_trylock(&mutex->lock))
+	{
+	if (mutex->owncpu == cpuid)
+	    {
+	    __adeos_sleepon_mutex(mutex,adp,cpuid);
+	    adeos_load_cpuid();
+	    }
+	}
+
+    mutex->owncpu = cpuid;
+#else  /* !CONFIG_SMP */
+    while (mutex->owner != NULL && mutex->owner != adp)
+	__adeos_sleepon_mutex(mutex,adp,cpuid);
+#endif /* CONFIG_SMP */
+
+    mutex->owner = adp;
+
+    adeos_unlock_cpu(hwflags);
+
+    return flags;
+}
+
+void fastcall adeos_unlock_mutex (admutex_t *mutex, unsigned long flags)
+
+{
+    unsigned long hwflags;
+    adeos_declare_cpuid;
+    adomain_t *adp;
+
+    if (unlikely(!adp_pipelined))
+	{
+	adeos_spin_unlock(&mutex->lock);
+
+	if (flags)
+	    adeos_hw_cli();
+	else
+	    adeos_hw_sti();
+
+	return;
+	}
+
+#ifdef CONFIG_SMP
+    mutex->owncpu = -1;
+#endif /* CONFIG_SMP */
+
+    if (!flags)
+	adeos_hw_sti();	/* Absolutely needed. */
+	
+    adeos_lock_cpu(hwflags);
+
+    if (unlikely(mutex->sleepq != NULL))
+	{
+	__adeos_signal_mutex(mutex,cpuid); /* Wake up one sleeper. */
+	adeos_load_cpuid();
+	}
+    else
+	{
+	mutex->owner = NULL;
+	adeos_spin_unlock(&mutex->lock);
+	}
+
+    adp = adp_cpu_current[cpuid];
+
+    if (flags)
+	set_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status);
+    else
+	{
+	clear_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status);
+	
+	if (adp->cpudata[cpuid].irq_pending_hi != 0)
+	    __adeos_sync_stage(IPIPE_IRQMASK_ANY);
+	}
+
+    adeos_unlock_cpu(hwflags);
+}
+
+void __adeos_takeover (void)
+
+{
+    __adeos_enable_pipeline();
+    printk(KERN_WARNING "Adeos: Pipelining started.\n");
+}
+
+#ifdef MODULE
+
+static int __init adeos_init_module (void)
+
+{
+    __adeos_takeover();
+    return 0;
+}
+
+static void __exit adeos_exit_module (void)
+
+{
+    __adeos_disable_pipeline();
+    printk(KERN_WARNING "Adeos: Pipelining stopped.\n");
+}
+
+module_init(adeos_init_module);
+module_exit(adeos_exit_module);
+
+#endif /* MODULE */
+
+EXPORT_SYMBOL(adeos_register_domain);
+EXPORT_SYMBOL(adeos_unregister_domain);
+EXPORT_SYMBOL(adeos_renice_domain);
+EXPORT_SYMBOL(adeos_virtualize_irq_from);
+EXPORT_SYMBOL(adeos_control_irq);
+EXPORT_SYMBOL(adeos_propagate_irq);
+EXPORT_SYMBOL(adeos_schedule_irq);
+EXPORT_SYMBOL(adeos_free_irq);
+EXPORT_SYMBOL(adeos_trigger_ipi);
+EXPORT_SYMBOL(adeos_stall_pipeline);
+EXPORT_SYMBOL(adeos_unstall_pipeline);
+EXPORT_SYMBOL(adeos_unstall_pipeline_from);
+EXPORT_SYMBOL(adeos_catch_event_from);
+EXPORT_SYMBOL(adeos_hook_dswitch);
+EXPORT_SYMBOL(adeos_init_attr);
+EXPORT_SYMBOL(adeos_get_sysinfo);
+EXPORT_SYMBOL(adeos_tune_timer);
+EXPORT_SYMBOL(adeos_alloc_ptdkey);
+EXPORT_SYMBOL(adeos_free_ptdkey);
+EXPORT_SYMBOL(adeos_set_ptd);
+EXPORT_SYMBOL(adeos_get_ptd);
+EXPORT_SYMBOL(adeos_set_irq_affinity);
+EXPORT_SYMBOL(adeos_init_mutex);
+EXPORT_SYMBOL(adeos_destroy_mutex);
+EXPORT_SYMBOL(adeos_lock_mutex);
+EXPORT_SYMBOL(adeos_unlock_mutex);
diff -uNrp linux-2.6.6-ia64/adeos/ia64.c linux-2.6.6-ia64-adeos/adeos/ia64.c
--- linux-2.6.6-ia64/adeos/ia64.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.6-ia64-adeos/adeos/ia64.c	2004-06-17 12:07:57.000000000 +0200
@@ -0,0 +1,602 @@
+/*
+ *   linux/adeos/ia64.c
+ *
+ *   Copyright (C) 2003,2004 Philippe Gerum.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ *   USA; either version 2 of the License, or (at your option) any later
+ *   version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *   Architecture-dependent ADEOS support for ia64.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/signal.h>
+#include <linux/module.h>
+#include <asm/io.h>
+#include <asm/delay.h>
+#include <asm/iosapic.h>
+#include <asm/bitops.h>
+#include <asm/ptrace.h>
+
+#define alloc_domain_stack()	((unsigned long)__get_free_pages(GFP_KERNEL,KERNEL_STACK_SIZE_ORDER))
+#define free_domain_stack(stk)	free_pages((unsigned long)stk,KERNEL_STACK_SIZE_ORDER)
+
+extern spinlock_t __adeos_pipelock;
+
+unsigned int do_IRQ(unsigned long irq,
+		    struct pt_regs *regs);
+
+int __adeos_acknowledge_irq(unsigned irq);
+
+static struct hw_interrupt_type __adeos_std_irq_dtype[NR_IRQS];
+
+static unsigned __adeos_override_irq_startup (unsigned irq)
+
+{
+    unsigned long adflags, hwflags;
+    adeos_declare_cpuid;
+    unsigned s;
+
+    adeos_lock_cpu(hwflags);
+    adflags = adeos_test_and_stall_pipeline();
+#ifdef CONFIG_PREEMPT
+    preempt_disable();
+#endif /* CONFIG_PREEMPT */
+    __adeos_unlock_irq(adp_cpu_current[cpuid],irq);
+    s = __adeos_std_irq_dtype[irq].startup(irq);
+#ifdef CONFIG_PREEMPT
+    preempt_enable_no_resched();
+#endif /* CONFIG_PREEMPT */
+    adeos_restore_pipeline_nosync(adp_cpu_current[cpuid],adflags,cpuid);
+    adeos_unlock_cpu(hwflags);
+
+    return s;
+}
+
+static void __adeos_override_irq_shutdown (unsigned irq)
+
+{
+    unsigned long adflags, hwflags;
+    adeos_declare_cpuid;
+
+    adeos_lock_cpu(hwflags);
+    adflags = adeos_test_and_stall_pipeline();
+#ifdef CONFIG_PREEMPT
+    preempt_disable();
+#endif /* CONFIG_PREEMPT */
+    __adeos_std_irq_dtype[irq].shutdown(irq);
+    __adeos_clear_irq(adp_cpu_current[cpuid],irq);
+#ifdef CONFIG_PREEMPT
+    preempt_enable_no_resched();
+#endif /* CONFIG_PREEMPT */
+    adeos_restore_pipeline_nosync(adp_cpu_current[cpuid],adflags,cpuid);
+    adeos_unlock_cpu(hwflags);
+}
+
+static void __adeos_override_irq_enable (unsigned irq)
+
+{
+    unsigned long adflags, hwflags;
+    adeos_declare_cpuid;
+
+    adeos_lock_cpu(hwflags);
+    adflags = adeos_test_and_stall_pipeline();
+#ifdef CONFIG_PREEMPT
+    preempt_disable();
+#endif /* CONFIG_PREEMPT */
+    __adeos_unlock_irq(adp_cpu_current[cpuid],irq);
+    __adeos_std_irq_dtype[irq].enable(irq);
+#ifdef CONFIG_PREEMPT
+    preempt_enable_no_resched();
+#endif /* CONFIG_PREEMPT */
+    adeos_restore_pipeline_nosync(adp_cpu_current[cpuid],adflags,cpuid);
+    adeos_unlock_cpu(hwflags);
+}
+
+static void __adeos_override_irq_disable (unsigned irq)
+
+{
+    unsigned long adflags, hwflags;
+    adeos_declare_cpuid;
+
+    adeos_lock_cpu(hwflags);
+    adflags = adeos_test_and_stall_pipeline();
+#ifdef CONFIG_PREEMPT
+    preempt_disable();
+#endif /* CONFIG_PREEMPT */
+    __adeos_std_irq_dtype[irq].disable(irq);
+    __adeos_lock_irq(adp_cpu_current[cpuid],cpuid,irq);
+#ifdef CONFIG_PREEMPT
+    preempt_enable_no_resched();
+#endif /* CONFIG_PREEMPT */
+    adeos_restore_pipeline_nosync(adp_cpu_current[cpuid],adflags,cpuid);
+    adeos_unlock_cpu(hwflags);
+}
+
+static void __adeos_override_irq_end (unsigned irq)
+
+{
+    unsigned long adflags, hwflags;
+    adeos_declare_cpuid;
+
+    adeos_lock_cpu(hwflags);
+    adflags = adeos_test_and_stall_pipeline();
+#ifdef CONFIG_PREEMPT
+    preempt_disable();
+#endif /* CONFIG_PREEMPT */
+
+    if (!(irq_descp(irq)->status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+	__adeos_unlock_irq(adp_cpu_current[cpuid],irq);
+
+    __adeos_std_irq_dtype[irq].end(irq);
+
+#ifdef CONFIG_PREEMPT
+    preempt_enable_no_resched();
+#endif /* CONFIG_PREEMPT */
+    adeos_restore_pipeline_nosync(adp_cpu_current[cpuid],adflags,cpuid);
+    adeos_unlock_cpu(hwflags);
+}
+
+static void __adeos_override_irq_affinity (unsigned irq, unsigned long mask)
+
+{
+    unsigned long adflags, hwflags;
+    adeos_declare_cpuid;
+
+    adeos_lock_cpu(hwflags);
+    adflags = adeos_test_and_stall_pipeline();
+#ifdef CONFIG_PREEMPT
+    preempt_disable();
+#endif /* CONFIG_PREEMPT */
+    __adeos_std_irq_dtype[irq].set_affinity(irq,mask);
+#ifdef CONFIG_PREEMPT
+    preempt_enable_no_resched();
+#endif /* CONFIG_PREEMPT */
+    adeos_restore_pipeline_nosync(adp_cpu_current[cpuid],adflags,cpuid);
+    adeos_unlock_cpu(hwflags);
+}
+
+static void  __adeos_enable_sync (void)
+
+{
+    __adeos_itm_next[adeos_processor_id()] = local_cpu_data->itm_next;
+    __adeos_itm_delta[adeos_processor_id()] = local_cpu_data->itm_delta;
+
+}
+
+/* __adeos_enable_pipeline() -- Take over the interrupt control from
+   the root domain (i.e. Linux). After this routine has returned, all
+   interrupts go through the pipeline. */
+
+void __adeos_enable_pipeline (void)
+
+{
+    unsigned long flags;
+    unsigned irq;
+	
+    flags = adeos_critical_enter(&__adeos_enable_sync);
+
+    /* First, grab the external interrupts. */
+
+    for (irq = IA64_MIN_VECTORED_IRQ; irq <= IA64_MAX_VECTORED_IRQ; irq++)
+	/* Fails for ADEOS_CRITICAL_IPI but that's ok. */
+	adeos_virtualize_irq(irq,
+			     (void (*)(unsigned))&do_IRQ,
+			     &__adeos_acknowledge_irq,
+			     IPIPE_HANDLE_MASK|IPIPE_PASS_MASK);
+
+    /* Interpose on the IRQ control routines so we can make them
+       atomic using hw masking and prevent the interrupt log from
+       being untimely flushed. Since we don't want to be too smart
+       about what's going on into irq.c and we want to change only
+       some of the controller members, let's be dumb and interpose the
+       rough way. */
+
+    for (irq = 0; irq < NR_IRQS; irq++)
+	__adeos_std_irq_dtype[irq] = *irq_descp(irq)->handler;
+
+    /* The original controller structs are often shared, so we first
+       save them all before changing any of them. Notice that we don't
+       redirect the ack handler since the relevant IOSAPIC management
+       code is already Adeos-aware. */
+
+    for (irq = 0; irq < NR_IRQS; irq++)
+	{
+	irq_descp(irq)->handler->startup = &__adeos_override_irq_startup;
+	irq_descp(irq)->handler->shutdown = &__adeos_override_irq_shutdown;
+	irq_descp(irq)->handler->enable = &__adeos_override_irq_enable;
+	irq_descp(irq)->handler->disable = &__adeos_override_irq_disable;
+	irq_descp(irq)->handler->end = &__adeos_override_irq_end;
+
+	if (irq_descp(irq)->handler->set_affinity != NULL)
+	    irq_descp(irq)->handler->set_affinity = &__adeos_override_irq_affinity;
+	}
+    
+    __adeos_tick_irq = __ia64_local_vector_to_irq(IA64_TIMER_VECTOR);
+    
+    __adeos_itm_next[adeos_processor_id()] = local_cpu_data->itm_next;
+    __adeos_itm_delta[adeos_processor_id()] = local_cpu_data->itm_delta;
+
+    adp_pipelined = 1;
+
+    adeos_critical_exit(flags);
+}
+
+/* __adeos_disable_pipeline() -- Disengage the pipeline. */
+
+void __adeos_disable_pipeline (void)
+
+{
+    unsigned long flags;
+    unsigned irq;
+
+    flags = adeos_critical_enter(NULL);
+
+    /* Restore interrupt controllers. */
+    for (irq = 0; irq < NR_IRQS; irq++)
+	*irq_descp(irq)->handler = __adeos_std_irq_dtype[irq];
+    
+    adp_pipelined = 0;
+
+    adeos_critical_exit(flags);
+}
+
+/* adeos_virtualize_irq_from() -- Attach a handler (and optionally a
+   hw acknowledge routine) to an interrupt for the given domain. */
+
+int adeos_virtualize_irq_from (adomain_t *adp,
+			       unsigned irq,
+			       void (*handler)(unsigned irq),
+			       int (*acknowledge)(unsigned irq),
+			       unsigned modemask)
+{
+    unsigned long flags;
+    int err;
+
+    if (irq >= IPIPE_NR_IRQS)
+	return -EINVAL;
+
+    if (adp->irqs[irq].control & IPIPE_SYSTEM_MASK)
+	return -EPERM;
+	
+    adeos_spin_lock_irqsave(&__adeos_pipelock,flags);
+
+    if (handler != NULL)
+	{
+	/* A bit of hack here: if we are re-virtualizing an IRQ just
+	   to change the acknowledge routine by passing the special
+	   ADEOS_SAME_HANDLER value, then allow to recycle the current
+	   handler for the IRQ. This allows Linux device drivers
+	   managing shared IRQ lines to call adeos_virtualize_irq() in
+	   addition to request_irq() just for the purpose of
+	   interposing their own shared acknowledge routine. */
+
+	if (handler == ADEOS_SAME_HANDLER)
+	    {
+	    handler = adp->irqs[irq].handler;
+
+	    if (handler == NULL)
+		{
+		err = -EINVAL;
+		goto unlock_and_exit;
+		}
+	    }
+	else if ((modemask & IPIPE_EXCLUSIVE_MASK) != 0 &&
+		 adp->irqs[irq].handler != NULL)
+	    {
+	    err = -EBUSY;
+	    goto unlock_and_exit;
+	    }
+	
+	if ((modemask & (IPIPE_SHARED_MASK|IPIPE_PASS_MASK)) == IPIPE_SHARED_MASK)
+	    {
+	    err = -EINVAL;
+	    goto unlock_and_exit;
+	    }
+
+	if ((modemask & IPIPE_STICKY_MASK) != 0)
+	    modemask |= IPIPE_HANDLE_MASK;
+	}
+    else
+	modemask &= ~(IPIPE_HANDLE_MASK|IPIPE_STICKY_MASK|IPIPE_SHARED_MASK);
+
+    if (acknowledge == NULL)
+	{
+	if ((modemask & IPIPE_SHARED_MASK) == 0)
+	    /* Acknowledge handler unspecified -- this is ok in
+	       non-shared management mode, but we will force the use
+	       of the Linux-defined handler instead. */
+	    acknowledge = adp_root->irqs[irq].acknowledge;
+	else
+	    {
+	    /* A valid acknowledge handler to be called in shared mode
+	       is required when declaring a shared IRQ. */
+	    err = -EINVAL;
+	    goto unlock_and_exit;
+	    }
+	}
+
+    adp->irqs[irq].handler = handler;
+    adp->irqs[irq].acknowledge = acknowledge;
+    adp->irqs[irq].control = modemask;
+
+    if (irq < NR_IRQS &&
+	handler != NULL &&
+	!adeos_virtual_irq_p(irq) &&
+	(modemask & IPIPE_ENABLE_MASK) != 0)
+	{
+	if (adp != adp_current)
+	    {
+	    /* IRQ enable/disable state is domain-sensitive, so we may
+	       not change it for another domain. What is allowed
+	       however is forcing some domain to handle an interrupt
+	       source, by passing the proper 'adp' descriptor which
+	       thus may be different from adp_current. */
+	    err = -EPERM;
+	    goto unlock_and_exit;
+	    }
+
+	irq_descp(irq)->handler->enable(irq);
+	}
+
+    err = 0;
+
+unlock_and_exit:
+
+    adeos_spin_unlock_irqrestore(&__adeos_pipelock,flags);
+
+    return err;
+}
+
+/* adeos_control_irq() -- Change an interrupt mode. This affects the
+   way a given interrupt is handled by ADEOS for the current
+   domain. setmask is a bitmask telling whether:
+   - the interrupt should be passed to the domain (IPIPE_HANDLE_MASK),
+     and/or
+   - the interrupt should be passed down to the lower priority domain(s)
+     in the pipeline (IPIPE_PASS_MASK).
+   This leads to four possibilities:
+   - PASS only => Ignore the interrupt
+   - HANDLE only => Terminate the interrupt (process but don't pass down)
+   - PASS + HANDLE => Accept the interrupt (process and pass down)
+   - <none> => Discard the interrupt
+   - DYNAMIC is currently an alias of HANDLE since it marks an interrupt
+   which is processed by the current domain but not implicitely passed
+   down to the pipeline, letting the domain's handler choose on a case-
+   by-case basis whether the interrupt propagation should be forced
+   using adeos_propagate_irq().
+   clrmask clears the corresponding bits from the control field before
+   setmask is applied.
+*/
+
+int adeos_control_irq (unsigned irq,
+		       unsigned clrmask,
+		       unsigned setmask)
+{
+    unsigned long flags;
+    irq_desc_t *desc;
+
+    if (irq >= IPIPE_NR_IRQS)
+	return -EINVAL;
+
+    if (adp_current->irqs[irq].control & IPIPE_SYSTEM_MASK)
+	return -EPERM;
+	
+    if (((setmask|clrmask) & IPIPE_SHARED_MASK) != 0)
+	return -EINVAL;
+	
+    desc = __ia64_irq_desc(irq);
+
+    if (adp_current->irqs[irq].handler == NULL)
+	setmask &= ~(IPIPE_HANDLE_MASK|IPIPE_STICKY_MASK);
+
+    if ((setmask & IPIPE_STICKY_MASK) != 0)
+	setmask |= IPIPE_HANDLE_MASK;
+
+    if ((clrmask & (IPIPE_HANDLE_MASK|IPIPE_STICKY_MASK)) != 0)	/* If one goes, both go. */
+	clrmask |= (IPIPE_HANDLE_MASK|IPIPE_STICKY_MASK);
+
+    adeos_spin_lock_irqsave(&__adeos_pipelock,flags);
+
+    adp_current->irqs[irq].control &= ~clrmask;
+    adp_current->irqs[irq].control |= setmask;
+
+    if ((setmask & IPIPE_ENABLE_MASK) != 0)
+	desc->handler->enable(irq);
+    else if ((clrmask & IPIPE_ENABLE_MASK) != 0)
+	desc->handler->disable(irq);
+
+    adeos_spin_unlock_irqrestore(&__adeos_pipelock,flags);
+
+    return 0;
+}
+
+void __adeos_init_domain (adomain_t *adp, adattr_t *attr)
+
+{
+    unsigned long rbs, bspstore, child_stack, child_rbs, rbs_size;
+    int _cpuid, nr_cpus = num_online_cpus();
+    void (*entry)(int) = attr->entry; /* keep this in a saved reg */
+    struct switch_stack *swstack;
+    adeos_declare_cpuid;
+
+    adeos_load_cpuid();
+
+    /* Make sure the new domain stack is congruent to that of the
+       current Linux task, modulo 512, so that NaT bits are properly
+       spilled/filled to/from ar.unat. Given the strict page alignment
+       constraint we have for domain stacks, the user-provided hint
+       for stack size (attr->estacksz) is not even considered, i.e. on
+       ia64, domain stacks have a fixed size of KERNEL_STACK_SIZE
+       bytes. */
+
+    for (_cpuid = 0; _cpuid < nr_cpus; _cpuid++)
+	{
+	adp->estackbase[_cpuid] = alloc_domain_stack();
+
+	if (adp->estackbase[_cpuid] == 0)
+	    panic("Adeos: no memory for domain stack on CPU #%d",_cpuid);
+
+	/* Build a switch stack frame at the bottom of the new domain
+	   stack as a clone of the parent context. */
+
+	__adeos_fork_domain(adp->estackbase[_cpuid] + KERNEL_STACK_SIZE);
+
+	if (adp_current != adp_root)
+	    {
+	    /* Child return path (upon initial switch in). */
+	    clear_bit(IPIPE_SLEEP_FLAG,&adp->cpudata[_cpuid].status);
+	    adeos_hw_sti();
+
+	    /* Here we don't care if a CPU migration has occured since
+	       we do not use the cpuid for accessing per-CPU data, but
+	       we don't want more than one CPU to be passed iflag ==
+	       1. */
+
+	    entry(_cpuid == cpuid);
+	    panic("Adeos: spurious return from domain %s\n",adp_current->name);
+	    }
+
+	/* Parent return path. */
+
+	child_stack = adp->estackbase[_cpuid] + KERNEL_STACK_SIZE - IA64_SWITCH_STACK_SIZE;
+	adp->esp[_cpuid] = child_stack;
+	swstack = (struct switch_stack *)child_stack;
+	bspstore = swstack->ar_bspstore;
+
+	/* Copy the parent's register backing store to the new
+	   domain's stack.  Since __adeos_init_domain() must be called
+	   on behalf of the root domain (i.e. Linux), referring to
+	   "current" is always valid here. The register backing store
+	   grows upward from the stack base. */
+
+        rbs = (unsigned long)current + IA64_RBS_OFFSET;
+        child_rbs = adp->estackbase[_cpuid] + IA64_RBS_OFFSET;
+        rbs_size = bspstore - rbs;
+
+        memcpy((void *)child_rbs,(void *)rbs,rbs_size);
+	swstack->ar_bspstore = child_rbs + rbs_size;
+	adp->esp[_cpuid] -= 16;	/* Provide for the (bloody) scratch area... */
+	}
+}
+
+void __adeos_cleanup_domain (adomain_t *adp)
+
+{
+    int _cpuid, nr_cpus = num_online_cpus();
+
+    adeos_unstall_pipeline_from(adp);
+
+    for (_cpuid = 0; _cpuid < nr_cpus; _cpuid++)
+	{
+#ifdef CONFIG_SMP
+	while (adp->cpudata[_cpuid].irq_pending_hi != 0)
+	    cpu_relax();
+
+	while (test_bit(IPIPE_XPEND_FLAG,&adp->cpudata[_cpuid].status))
+	    cpu_relax();
+#endif /* CONFIG_SMP */
+
+	if (adp->estackbase[_cpuid] != 0)
+	    free_domain_stack(adp->estackbase[_cpuid]);
+	}
+}
+
+int adeos_get_sysinfo (adsysinfo_t *info)
+
+{
+    info->ncpus = num_online_cpus();
+    info->cpufreq = adeos_cpu_freq();
+    info->archdep.tmirq = __adeos_tick_irq;
+
+    return 0;
+}
+
+void __adeos_set_itm (void)
+
+{
+    unsigned long itm_next = ia64_get_itc();
+    adeos_declare_cpuid;
+
+    adeos_load_cpuid();
+
+    itm_next += __adeos_itm_delta[cpuid];
+    ia64_set_itm(itm_next);
+
+    __adeos_itm_next[cpuid] = itm_next;    
+}
+
+int adeos_tune_timer (unsigned long ns, int flags)
+
+{
+    int _cpuid, nr_cpus = num_online_cpus();
+    unsigned long x;
+    unsigned _hz;
+    
+    if (flags & ADEOS_RESET_TIMER)
+	_hz = HZ;
+    else
+	_hz = 1000000000 / ns;
+
+    x = adeos_critical_enter(__adeos_set_itm); /* Sync with all CPUs */
+
+    for (_cpuid = 0; _cpuid < nr_cpus; _cpuid++)
+	__adeos_itm_delta[_cpuid] = (cpu_data(_cpuid)->itc_freq + _hz/2) / _hz;
+
+    __adeos_set_itm();
+
+    adeos_critical_exit(x);
+    
+    return 0;
+}
+
+/* adeos_trigger_ipi() -- Send the ADEOS service IPI to other
+   processors. */
+
+int adeos_trigger_ipi (int _cpuid)
+
+{
+#ifdef CONFIG_SMP
+    int nr_cpus = num_online_cpus();
+    unsigned long flags;
+    adeos_declare_cpuid;
+
+    adeos_lock_cpu(flags);
+
+    if (unlikely(_cpuid == cpuid)) /* Self-posting the service interrupt? */
+	adeos_trigger_irq(ADEOS_SERVICE_IPI);
+    else
+	{
+	if (_cpuid == ADEOS_OTHER_CPUS)
+	    {
+	    if (nr_cpus > 1)
+		/* Send the service IPI to all processors but the current one. */
+		__adeos_send_IPI_allbutself(ADEOS_SERVICE_VECTOR);
+	    }
+	else if (_cpuid >= 0 && _cpuid < nr_cpus)
+	    __adeos_send_IPI_other(_cpuid,ADEOS_SERVICE_VECTOR);
+	}
+
+    adeos_unlock_cpu(flags);
+
+    return _cpuid != ADEOS_OTHER_CPUS ? 1 : nr_cpus - 1;
+#else  /* !CONFIG_SMP */
+    return 0;
+#endif /* CONFIG_SMP */
+}
diff -uNrp linux-2.6.6-ia64/arch/ia64/Kconfig linux-2.6.6-ia64-adeos/arch/ia64/Kconfig
--- linux-2.6.6-ia64/arch/ia64/Kconfig	2004-06-17 11:19:10.000000000 +0200
+++ linux-2.6.6-ia64-adeos/arch/ia64/Kconfig	2004-06-17 11:45:45.000000000 +0200
@@ -377,6 +377,8 @@ source "arch/ia64/hp/sim/Kconfig"
 
 source "arch/ia64/oprofile/Kconfig"
 
+source "adeos/Kconfig"
+
 menu "Kernel hacking"
 
 choice
Binary files linux-2.6.6-ia64/arch/ia64/hp/sim/boot/bootloader and linux-2.6.6-ia64-adeos/arch/ia64/hp/sim/boot/bootloader differ
diff -uNrp linux-2.6.6-ia64/arch/ia64/kernel/Makefile linux-2.6.6-ia64-adeos/arch/ia64/kernel/Makefile
--- linux-2.6.6-ia64/arch/ia64/kernel/Makefile	2004-06-17 11:19:10.000000000 +0200
+++ linux-2.6.6-ia64-adeos/arch/ia64/kernel/Makefile	2004-06-17 11:45:44.000000000 +0200
@@ -8,6 +8,7 @@ obj-y := acpi.o entry.o efi.o efi_stub.o
 	 irq_lsapic.o ivt.o machvec.o pal.o patch.o process.o perfmon.o ptrace.o sal.o		\
 	 salinfo.o semaphore.o setup.o signal.o sys_ia64.o time.o traps.o unaligned.o unwind.o mca.o mca_asm.o
 
+obj-$(CONFIG_ADEOS_CORE)	+= adeos.o
 obj-$(CONFIG_IA64_BRL_EMU)	+= brl_emu.o
 obj-$(CONFIG_IA64_GENERIC)	+= acpi-ext.o
 obj-$(CONFIG_IA64_HP_ZX1)	+= acpi-ext.o
diff -uNrp linux-2.6.6-ia64/arch/ia64/kernel/adeos.c linux-2.6.6-ia64-adeos/arch/ia64/kernel/adeos.c
--- linux-2.6.6-ia64/arch/ia64/kernel/adeos.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.6-ia64-adeos/arch/ia64/kernel/adeos.c	2004-06-17 11:46:40.000000000 +0200
@@ -0,0 +1,661 @@
+/*
+ *   linux/arch/ia64/kernel/adeos.c
+ *
+ *   Copyright (C) 2002,2003,2004 Philippe Gerum.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ *   USA; either version 2 of the License, or (at your option) any later
+ *   version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *   Architecture-dependent ADEOS core support for ia64.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/smp.h>
+#include <linux/sched.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <asm/system.h>
+#include <asm/atomic.h>
+#include <asm/hw_irq.h>
+#include <asm/delay.h>
+#include <asm/irq.h>
+#include <asm/unistd.h>
+
+void __adeos_switch_domain(adomain_t *adp,
+			   int cpuid);
+
+extern spinlock_t __adeos_pipelock;
+
+struct pt_regs __adeos_tick_regs;
+
+int __adeos_tick_irq;
+
+int adp_pipelined = 0;
+
+volatile unsigned long __adeos_itm_next[ADEOS_NR_CPUS];
+
+volatile unsigned long __adeos_itm_delta[ADEOS_NR_CPUS];
+
+/* Regardless of what asm-ia64/bitops.h says, ia64_fls() actually
+   returns the last bit _set_ and not cleared in a 64-bit quantity. */
+#define flnz(w) ia64_fls(w)
+
+#ifdef CONFIG_SMP
+
+static volatile unsigned long __adeos_cpu_sync_map;
+
+static volatile unsigned long __adeos_cpu_lock_map;
+
+static spinlock_t __adeos_cpu_barrier = SPIN_LOCK_UNLOCKED;
+
+static atomic_t __adeos_critical_count = ATOMIC_INIT(0);
+
+static void (*__adeos_cpu_sync)(void);
+
+void __adeos_send_IPI_allbutself (int vector)
+
+{
+    int cpu, nr_cpus = num_online_cpus();
+    adeos_declare_cpuid;
+
+    adeos_load_cpuid();
+
+    for (cpu = 0; cpu < nr_cpus; cpu++)
+	if (cpu_online(cpu) && cpu != cpuid)
+	    platform_send_ipi(cpu,vector,IA64_IPI_DM_INT,0);
+}
+
+void __adeos_send_IPI_other (int cpu, int vector) {
+
+    platform_send_ipi(cpu,vector,IA64_IPI_DM_INT,0);
+}
+
+static void __adeos_do_critical_sync (unsigned irq)
+
+{
+    adeos_declare_cpuid;
+    unsigned long flags;
+
+    adeos_lock_cpu(flags);
+
+    set_bit(cpuid,&__adeos_cpu_sync_map);
+
+    /* Now we are in sync with the lock requestor running on another
+       CPU. Enter a spinning wait until he releases the global
+       lock. */
+    adeos_spin_lock(&__adeos_cpu_barrier);
+
+    /* Got it. Now get out. */
+
+    if (__adeos_cpu_sync)
+	/* Call the sync routine if any. */
+	__adeos_cpu_sync();
+
+    adeos_spin_unlock(&__adeos_cpu_barrier);
+
+    clear_bit(cpuid,&__adeos_cpu_sync_map);
+
+    adeos_unlock_cpu(flags);
+}
+
+#endif /* CONFIG_SMP */
+
+/* adeos_critical_enter() -- Grab the superlock excluding all CPUs
+   but the current one from a critical section. This lock is used when
+   we must enforce a global critical section for a single CPU in a
+   possibly SMP system whichever context the CPUs are running
+   (i.e. interrupt handler or regular thread). */
+
+unsigned long adeos_critical_enter (void (*syncfn)(void))
+
+{
+    unsigned long flags;
+
+    adeos_hw_local_irq_save(flags);
+
+#ifdef CONFIG_SMP
+    if (num_online_cpus() > 1) /* We might be running a SMP-kernel on a UP box... */
+	{
+	adeos_declare_cpuid;
+
+	adeos_load_cpuid();
+
+	if (!test_and_set_bit(cpuid,&__adeos_cpu_lock_map))
+	    {
+	    while (test_and_set_bit(BITS_PER_LONG - 1,&__adeos_cpu_lock_map))
+		{
+		int n = 0;
+		do { cpu_relax(); } while (++n < cpuid);
+		}
+
+	    adeos_spin_lock(&__adeos_cpu_barrier);
+
+	    __adeos_cpu_sync = syncfn;
+
+	    /* Send the sync IPI to all processors but the current one. */
+	    __adeos_send_IPI_allbutself(ADEOS_CRITICAL_VECTOR);
+
+	    while (__adeos_cpu_sync_map != (cpu_online_map & ~__adeos_cpu_lock_map))
+		cpu_relax();
+	    }
+
+	atomic_inc(&__adeos_critical_count);
+	}
+#endif /* CONFIG_SMP */
+
+    return flags;
+}
+
+/* adeos_critical_exit() -- Release the superlock. */
+
+void adeos_critical_exit (unsigned long flags)
+
+{
+#ifdef CONFIG_SMP
+    if (num_online_cpus() > 1) /* We might be running a SMP-kernel on a UP box... */
+	{
+	adeos_declare_cpuid;
+
+	adeos_load_cpuid();
+
+	if (atomic_dec_and_test(&__adeos_critical_count))
+	    {
+	    adeos_spin_unlock(&__adeos_cpu_barrier);
+
+	    while (__adeos_cpu_sync_map != 0)
+		cpu_relax();
+
+	    clear_bit(cpuid,&__adeos_cpu_lock_map);
+	    clear_bit(BITS_PER_LONG - 1,&__adeos_cpu_lock_map);
+	    }
+	}
+#endif /* CONFIG_SMP */
+
+    adeos_hw_local_irq_restore(flags);
+}
+
+int __adeos_acknowledge_irq (unsigned irq) {
+
+    return 1;
+}
+
+void __adeos_init_stage (adomain_t *adp)
+
+{
+    int cpuid, n;
+
+    for (cpuid = 0; cpuid < ADEOS_NR_CPUS; cpuid++)
+	{
+	adp->cpudata[cpuid].irq_pending_hi = 0;
+
+	for (n = 0; n < IPIPE_IRQ_IWORDS; n++)
+	    adp->cpudata[cpuid].irq_pending_lo[n] = 0;
+
+	for (n = 0; n < IPIPE_NR_IRQS; n++)
+	    adp->cpudata[cpuid].irq_hits[n] = 0;
+	}
+
+    for (n = 0; n < IPIPE_NR_IRQS; n++)
+	{
+	adp->irqs[n].acknowledge = NULL;
+	adp->irqs[n].handler = NULL;
+	adp->irqs[n].control = IPIPE_PASS_MASK;	/* Pass but don't handle */
+	}
+
+#ifdef CONFIG_SMP
+    adp->irqs[ADEOS_CRITICAL_IPI].acknowledge = (int (*)(unsigned))&__adeos_acknowledge_irq;
+    adp->irqs[ADEOS_CRITICAL_IPI].handler = &__adeos_do_critical_sync;
+    /* Immediately handle in the current domain but *never* pass */
+    adp->irqs[ADEOS_CRITICAL_IPI].control = IPIPE_HANDLE_MASK|IPIPE_STICKY_MASK|IPIPE_SYSTEM_MASK;
+#endif /* CONFIG_SMP */
+}
+
+/* __adeos_sync_stage() -- Flush the pending IRQs for the current
+   domain (and processor).  This routine flushes the interrupt log
+   (see "Optimistic interrupt protection" from D. Stodolsky et al. for
+   more on the deferred interrupt scheme). Every interrupt that
+   occurred while the pipeline was stalled gets played.  WARNING:
+   callers on SMP boxen should always check for CPU migration on
+   return of this routine. One can control the kind of interrupts
+   which are going to be sync'ed using the syncmask
+   parameter. IPIPE_IRQMASK_ANY plays them all, IPIPE_IRQMASK_VIRT
+   plays virtual interrupts only. */
+
+asmlinkage void __adeos_sync_stage (unsigned long syncmask)
+
+{
+    unsigned long mask, submask, flags;
+    struct adcpudata *cpudata;
+    adeos_declare_cpuid;
+    int level, rank;
+    adomain_t *adp;
+    unsigned irq;
+
+    adeos_lock_cpu(flags);
+
+    adp = adp_cpu_current[cpuid];
+    cpudata = &adp->cpudata[cpuid];
+
+    do
+	{
+	if (unlikely(test_and_set_bit(IPIPE_SYNC_FLAG,&cpudata->status)))
+	    goto release_cpu_and_exit;
+
+	/* The policy here is to keep the dispatching code
+	   interrupt-free by stalling the current stage. If the upper
+	   domain handler (which we call) wants to re-enable
+	   interrupts while in a safe portion of the code
+	   (e.g. SA_INTERRUPT flag unset for Linux's sigaction()), it
+	   will have to unstall (then stall again before returning to
+	   us!) the stage when it sees fit. */
+
+	while ((mask = (cpudata->irq_pending_hi & syncmask)) != 0)
+	    {
+	    /* Give a slight priority advantage to high-numbered IRQs
+	       like the virtual ones. */
+	    level = flnz(mask);
+	    clear_bit(level,&cpudata->irq_pending_hi);
+
+	    while ((submask = cpudata->irq_pending_lo[level]) != 0)
+		{
+		rank = flnz(submask);
+		irq = (level << IPIPE_IRQ_ISHIFT) + rank;
+
+		if (unlikely(test_bit(IPIPE_LOCK_FLAG,&adp->irqs[irq].control)))
+		    {
+		    clear_bit(rank,&cpudata->irq_pending_lo[level]);
+		    continue;
+		    }
+
+		if (likely(--cpudata->irq_hits[irq] == 0))
+		    clear_bit(rank,&cpudata->irq_pending_lo[level]);
+
+		/* Allow the sync routine to be reentered on behalf of
+		   the IRQ handler and any execution context switched
+		   in by the IRQ handler. The latter also means that
+		   returning from the switched out context is always
+		   safe even if the sync routine has been reentered in
+		   the meantime. */
+
+		set_bit(IPIPE_STALL_FLAG,&cpudata->status);
+
+		clear_bit(IPIPE_SYNC_FLAG,&cpudata->status);
+
+		adeos_unlock_cpu(flags);
+
+		adeos_hw_sti();
+
+		/* IPIPE_CALLASM_FLAG is dummy for this arch. */
+
+ 		if (adp == adp_root)
+		    {
+		    struct pt_regs regs;
+		    ia64_psr(&regs)->cpl = 0; /* For process times, implies CPL=0, kernel mode */
+		    void (*handler)(unsigned, struct pt_regs *) = (__typeof(handler))adp->irqs[irq].handler;
+		    handler(irq,&regs);
+		    }
+		else
+		    adp->irqs[irq].handler(irq);
+
+		adeos_lock_cpu(flags);
+
+#ifdef CONFIG_SMP
+		adeos_load_cpuid();
+		cpudata = &adp->cpudata[cpuid];
+#endif /* CONFIG_SMP */
+
+		clear_bit(IPIPE_STALL_FLAG,&cpudata->status);
+
+		if (test_and_set_bit(IPIPE_SYNC_FLAG,&cpudata->status))
+		    goto release_cpu_and_exit;
+		}
+	    }
+
+	clear_bit(IPIPE_SYNC_FLAG,&cpudata->status);
+	}
+    while ((cpudata->irq_pending_hi & syncmask) != 0);
+
+release_cpu_and_exit:
+
+    adeos_unlock_cpu(flags);
+}
+
+static inline void __adeos_walk_pipeline (struct list_head *pos, int cpuid)
+
+{
+    while (pos != &__adeos_pipeline)
+	{
+    	adomain_t *_adp = list_entry(pos,adomain_t,p_link);
+
+	if (test_bit(IPIPE_STALL_FLAG,&_adp->cpudata[cpuid].status))
+	    break; /* Stalled stage -- do not go further. */
+
+	if (_adp->cpudata[cpuid].irq_pending_hi != 0)
+	    {
+	    /* Since the critical IPI might be serviced by the
+	       following actions, the current domain might not be
+	       linked to the pipeline anymore after its handler
+	       returns on SMP boxes, even if the domain remains valid
+	       (see adeos_unregister_domain()), so don't make any
+	       hazardous assumptions here. */
+
+	    if (_adp == adp_cpu_current[cpuid])
+		__adeos_sync_stage(IPIPE_IRQMASK_ANY);
+	    else
+		{
+		__adeos_switch_to(_adp,cpuid);
+
+		adeos_load_cpuid(); /* Processor might have changed. */
+
+		if (!test_bit(IPIPE_STALL_FLAG,&adp_cpu_current[cpuid]->cpudata[cpuid].status) &&
+		    adp_cpu_current[cpuid]->cpudata[cpuid].irq_pending_hi != 0)
+		    __adeos_sync_stage(IPIPE_IRQMASK_ANY);
+		}
+
+	    break;
+	    }
+	else if (_adp == adp_cpu_current[cpuid])
+	    break;
+
+	pos = _adp->p_link.next;
+	}
+}
+
+void __adeos_handle_irq (long irq, struct pt_regs *regs)
+
+{
+    struct list_head *head, *pos;
+    adeos_declare_cpuid;
+    int m_ack, s_ack;
+
+    adeos_load_cpuid();
+
+    if (irq < 0)
+	{
+	m_ack = s_ack = 1;
+        irq = -irq;
+	}
+    else
+	m_ack = s_ack = 0;
+
+    if (unlikely(test_bit(IPIPE_STICKY_FLAG,&adp_cpu_current[cpuid]->irqs[irq].control)))
+	head = &adp_cpu_current[cpuid]->p_link;
+    else
+	head = __adeos_pipeline.next;
+
+    /* Ack the interrupt. */
+
+    pos = head;
+
+    while (pos != &__adeos_pipeline)
+	{
+    	adomain_t *_adp = list_entry(pos,adomain_t,p_link);
+
+	/* For each domain handling the incoming IRQ, mark it as
+           pending in its log. */
+
+	if (test_bit(IPIPE_HANDLE_FLAG,&_adp->irqs[irq].control))
+	    {
+	    /* Domains that handle this IRQ are polled for
+	       acknowledging it by decreasing priority order. The
+	       interrupt must be made pending _first_ in the domain's
+	       status flags before the PIC is unlocked. */
+
+	    _adp->cpudata[cpuid].irq_hits[irq]++;
+	    __adeos_set_irq_bit(_adp,cpuid,irq);
+
+	    /* Always get the first master acknowledge available. Once
+	       we've got it, allow slave acknowledge handlers to run
+	       (until one of them stops us). */
+
+	    if (!m_ack)
+		m_ack = _adp->irqs[irq].acknowledge(irq);
+	    else if (test_bit(IPIPE_SHARED_FLAG,&_adp->irqs[irq].control) && !s_ack)
+		s_ack = _adp->irqs[irq].acknowledge(irq);
+	    }
+
+	/* If the domain does not want the IRQ to be passed down the
+	   interrupt pipe, exit the loop now. */
+
+	if (!test_bit(IPIPE_PASS_FLAG,&_adp->irqs[irq].control))
+	    break;
+
+	pos = _adp->p_link.next;
+	}
+
+    if (likely(irq == __adeos_tick_irq))
+	{
+	unsigned long new_itm = __adeos_itm_next[cpuid];
+
+	do
+	    {
+	    new_itm += __adeos_itm_delta[cpuid];
+	    ia64_set_itm(new_itm);
+	    }
+	while (time_after_eq(ia64_get_itc(),new_itm));
+
+	__adeos_itm_next[cpuid] = new_itm;
+
+	__adeos_tick_regs.cr_iip = regs->cr_iip;
+	__adeos_tick_regs.cr_ipsr = regs->cr_ipsr;
+	__adeos_tick_regs.pr = regs->pr;
+	}
+
+    /* Now walk the pipeline, yielding control to the highest priority
+       domain that has pending interrupt(s) or immediately to the
+       current domain if the interrupt has been marked as
+       'sticky'. This search does not go beyond the current domain in
+       the pipeline. To understand this code properly, one must keep
+       in mind that domains having a higher priority than the current
+       one are sleeping on the adeos_suspend_domain() service. In
+       addition, domains having a lower priority have been preempted
+       by an interrupt dispatched to a more prioritary domain. Once
+       the first and most prioritary stage has been selected here, the
+       subsequent stages will be activated in turn when each visited
+       domain calls adeos_suspend_domain() to wake up its neighbour
+       down the pipeline. */
+
+    __adeos_walk_pipeline(head,cpuid);
+
+    adeos_load_cpuid();
+}
+
+/* adeos_trigger_irq() -- Push the interrupt to the pipeline entry
+   just like if it has been actually received from a hw source. This
+   both works for real and virtual interrupts. This also means that
+   the current domain might be immediately preempted by a more
+   prioritary domain who happens to handle this interrupt. */
+
+int adeos_trigger_irq (unsigned irq)
+
+{
+    struct pt_regs regs;
+
+    if (irq >= IPIPE_NR_IRQS ||
+	(adeos_virtual_irq_p(irq) && !test_bit(irq - IPIPE_VIRQ_BASE,&__adeos_virtual_irq_map)))
+	return -EINVAL;
+
+    ia64_psr(&regs)->cpl = 0;	/* For process times, implies CPL=0, kernel mode */
+
+    __adeos_handle_irq(-((long)irq),&regs);
+
+    return 1;
+}
+
+/*
+ * __adeos_switch_to() -- Switch domain contexts. The current domain
+ * is switched out while the domain pointed by "adp" is switched
+ * in. The current cpu identifier which is always known from callers
+ * is also passed to save a few cycles.
+ * This code works out the following tasks:
+ * - save it's stack pointer,
+ * - load the incoming domain's stack pointer,
+ * - update the global domain descriptor pointer,
+ * - then finally activate the incoming domain context.
+ *
+ * SMP version also provides for safe CPU migration (i.e. the domain
+ * may be switched back in on behalf of a different CPU than the one
+ * which switched it out).
+ */
+
+void __adeos_switch_to (adomain_t *adp, int cpuid)
+
+{
+    unsigned long flags;
+
+    adeos_hw_local_irq_save(flags);
+    __adeos_switch_domain(adp,cpuid);
+    adeos_hw_local_irq_restore(flags);
+    
+#ifdef CONFIG_SMP
+    adeos_load_cpuid();
+#endif /* CONFIG_SMP */
+    
+    if (adp_cpu_current[cpuid]->dswitch != NULL)
+	adp_cpu_current[cpuid]->dswitch();
+}
+
+asmlinkage int __adeos_enter_syscall (unsigned long scnum,
+				      struct pt_regs *regs,
+				      unsigned long a1,
+				      unsigned long a2,
+				      unsigned long a3,
+				      unsigned long a4,
+				      unsigned long a5)
+{
+    unsigned long old_regs[6];
+    int s;
+
+/* FIXME: The following way of intercepting the syscall args is
+   terminally sick, and wrecks all the optimization done by the kernel
+   guys regarding handling of user args over the syscall routines. We
+   must check for the existence of syscall monitors in the low-level
+   handling code (ivt.S) at the very least, so that we don't uselessly
+   run this ugly code when none exists. Eeek... */
+
+    if (unlikely(__adeos_event_monitors[ADEOS_SYSCALL_PROLOGUE] == 0))
+	return 0;
+
+    old_regs[0] = regs->r15;
+    old_regs[1] = regs->r16;
+    old_regs[2] = regs->r17;
+    old_regs[3] = regs->r18;
+    old_regs[4] = regs->r19;
+    old_regs[5] = regs->r20;
+
+    regs->r15 = scnum;
+    s = __adeos_handle_event(ADEOS_SYSCALL_PROLOGUE,regs);
+
+    regs->r15 = old_regs[0];
+    regs->r16 = old_regs[1];
+    regs->r17 = old_regs[2];
+    regs->r18 = old_regs[3];
+    regs->r19 = old_regs[4];
+    regs->r20 = old_regs[5];
+
+    return s;
+}
+
+asmlinkage int __adeos_exit_syscall (void) {
+
+    if (unlikely(__adeos_event_monitors[ADEOS_SYSCALL_EPILOGUE] > 0))
+	return __adeos_handle_event(ADEOS_SYSCALL_EPILOGUE,NULL);
+
+    return 0;
+}
+
+#ifdef ADEOS_DEBUG
+
+unsigned long __adeos_mark_array[ADEOS_NR_CPUS][32];
+
+long __adeos_max_mark[ADEOS_NR_CPUS];
+
+void __adeos_set_mark (int id)
+
+{
+    adeos_declare_cpuid;
+    unsigned long flags;
+
+    if (id < 0 || id >= 32)
+	return;
+
+    adeos_get_cpu(flags);
+
+    if (id > __adeos_max_mark[cpuid])
+	__adeos_max_mark[cpuid] = id;
+    
+    adeos_hw_tsc(__adeos_mark_array[cpuid][id]);
+
+    adeos_put_cpu(flags);
+}
+
+void __adeos_dump_marks (void)
+
+{
+    unsigned long t, ns, cpufreq = adeos_cpu_freq();
+    int cpuid, id;
+    long nr_marks;
+
+    printk("ADEOS: DUMPING MARKS\n");
+
+    for (cpuid = 0; cpuid < ADEOS_NR_CPUS; cpuid++)
+	{
+	nr_marks =__adeos_max_mark[cpuid];
+
+	for (id = 1; id <= nr_marks; id++)
+	    {
+	    t = __adeos_mark_array[cpuid][id] - __adeos_mark_array[cpuid][id-1];
+	    ns = t * 1000000000LL / cpufreq;
+	    printk("[%d] M%d -> M%d = %lu ns\n",cpuid,id-1,id,ns);
+	    }
+	}
+
+    printk("====================\n");
+}
+
+void __adeos_clear_marks (void)
+
+{
+    int cpuid;
+
+    for (cpuid = 0; cpuid < ADEOS_NR_CPUS; cpuid++)
+	__adeos_max_mark[cpuid] = 0;
+}
+
+EXPORT_SYMBOL(__adeos_set_mark);
+EXPORT_SYMBOL(__adeos_dump_marks);
+EXPORT_SYMBOL(__adeos_clear_marks);
+
+#endif /* ADEOS_DEBUG */
+
+EXPORT_SYMBOL(__adeos_init_stage);
+EXPORT_SYMBOL(__adeos_sync_stage);
+EXPORT_SYMBOL(__adeos_acknowledge_irq);
+EXPORT_SYMBOL(__adeos_switch_to);
+EXPORT_SYMBOL(__adeos_handle_irq);
+EXPORT_SYMBOL(__adeos_tick_regs);
+EXPORT_SYMBOL(__adeos_tick_irq);
+EXPORT_SYMBOL(__adeos_fork_domain);
+EXPORT_SYMBOL(adp_pipelined);
+EXPORT_SYMBOL(adeos_critical_enter);
+EXPORT_SYMBOL(adeos_critical_exit);
+EXPORT_SYMBOL(adeos_trigger_irq);
+#ifdef CONFIG_SMP
+EXPORT_SYMBOL(__adeos_send_IPI_allbutself);
+EXPORT_SYMBOL(__adeos_send_IPI_other);
+EXPORT_SYMBOL(__adeos_set_irq_affinity);
+#endif /* CONFIG_SMP */
diff -uNrp linux-2.6.6-ia64/arch/ia64/kernel/entry.S linux-2.6.6-ia64-adeos/arch/ia64/kernel/entry.S
--- linux-2.6.6-ia64/arch/ia64/kernel/entry.S	2004-06-13 12:55:53.000000000 +0200
+++ linux-2.6.6-ia64-adeos/arch/ia64/kernel/entry.S	2004-06-17 11:45:44.000000000 +0200
@@ -226,6 +226,179 @@ GLOBAL_ENTRY(ia64_switch_to)
 	br.cond.sptk .done
 END(ia64_switch_to)
 
+#ifdef CONFIG_ADEOS_CORE
+
+GLOBAL_ENTRY(__adeos_switch_domain)
+	.prologue
+	alloc r16=ar.pfs,2,0,0,0
+	DO_SAVE_SWITCH_STACK
+	.body
+	movl r26=adp_cpu_current
+#ifdef CONFIG_SMP
+	shl in1=in1,3			// CPU slot offset = cpuid * sizeof(pointer)
+	;; 
+	add r26=r26,in1			// r26=&adp_cpu_current[cpuid]
+#endif /* CONFIG_SMP */
+	;; 
+	ld8 r27=[r26]		        // r27=adp_cpu_current[cpuid]
+	st8 [r26]=in0		        // adp_cpu_current[cpuid]=incoming_domain
+	mov r26=in0
+	;;
+	adds r26=8,r26			// stack ptr restore area from new desc
+	adds r27=8,r27			// stack ptr save area into old desc
+#ifdef CONFIG_SMP
+	;;
+	add r26=r26,in1			// adjust to CPU slot
+	add r27=r27,in1
+#endif /* CONFIG_SMP */
+	;;
+	st8 [r27]=sp			// save old stack ptr
+	ld8 sp=[r26]
+	;;
+	DO_LOAD_SWITCH_STACK
+#ifdef CONFIG_SMP
+	sync.i				// ensure "fc"s done by this CPU are visible on other CPUs
+#endif /* CONFIG_SMP */
+	br.ret.sptk.many rp		// branch to incoming domain's resume point
+END(__adeos_switch_domain)
+
+GLOBAL_ENTRY(__adeos_fork_domain)
+	.prologue
+	alloc r16=ar.pfs,1,8,0,8
+	.rotr v[2]			// declare our 2 aliases for rotating
+	adds sp=-16,sp
+	DO_SAVE_SWITCH_STACK
+	.body
+	;;
+	mov r18=in0		        // r18 = new_domain->esp[cpuid] (copy destination)
+	mov r19=IA64_SWITCH_STACK_SIZE-8
+	;;
+	shr r19=r19,3			// r19=(8-bytes word count)-1
+	adds r18=-8,r18			// simulate initial pre-decrementation of dest index
+	adds r20=IA64_SWITCH_STACK_SIZE+8,sp // r20=((struct switch_stack *)sp + 1) + 8-bytes padding
+	;; 
+	mov ar.lc=r19			// loop count in repeat/until fashion
+	mov ar.ec=2			// two pipeline stages are active when copying
+	mov pr.rot=1<<16		// use p16(=1) and p17(=0) for predicates
+	;;
+copy_domain_stack:
+(p16)	ld8 v[0]=[r20],-8
+(p17)	st8 [r18]=v[1],-8
+	br.ctop.dptk.few copy_domain_stack
+	;;
+	.restore sp
+	adds sp=IA64_SWITCH_STACK_SIZE+16,sp
+	mov ar.pfs=r16
+	br.ret.sptk.many rp
+END(__adeos_fork_domain)
+
+GLOBAL_ENTRY(__adeos_ret_from_intr)
+	/* We have just returned from ia64_handle_irq(). Clear pIFast
+	if we are expected to exit the interrupt context through the
+	regular Linux path, i.e. if we are running over the
+	non-stalled root domain. Otherwise, make sure that we will
+	take the fast IRQ return path (i.e. no pending work processed
+	after the IRQ has been handled). */
+	cmp.eq pIFast,p0=r8,r0
+	movl r14=.adeos_leave_kernel
+	;; 
+	mov rp=r14
+	br.ret.sptk.many rp
+END(__adeos_ret_from_intr)
+
+/*
+ * __adeos_catch_syscall:	Feed the Adeos pipeline with the syscall event.
+ *	The value returned by __adeos_enter_syscall() will be passed
+ *	unmodified to our caller.
+ *	If zero is returned,	the syscall is going to be executed as required.
+ *	Otherwise, the syscall will be silently dropped.
+ *
+ *		  r15: syscall number + 1024 (must be preserved)
+ *		  r20: &pt_regs
+ *
+ * FIXME: the current approach for intercepting syscalls over ia64 is utterly
+ * intrusive. It clearly adds a fair amount of overhead per syscall
+ * where the kernel guys took extreme care of reducing it. --rpm
+ */
+
+GLOBAL_ENTRY(__adeos_catch_syscall)
+	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)
+	alloc loc1=ar.pfs,8,4,8,0
+	mov loc0=rp
+	.body
+	mov loc2=r15
+	mov loc3=b6
+	adds out0=-1024,r15
+	mov out1=r20
+        mov out2=in0
+        mov out3=in1
+        mov out4=in2
+        mov out5=in3
+        mov out6=in4
+        mov out7=in5
+        ;;
+	br.call.sptk.many rp=__adeos_enter_syscall
+	mov b6=loc3
+	mov r15=loc2
+	mov ar.pfs=loc1
+	mov rp=loc0
+	br.ret.sptk.many b6
+END(__adeos_catch_syscall)
+
+/*
+ * __adeos_ret_from_syscall: 
+ *	We branch here on the return path from each syscall so
+ *	that we can call the Adeos callout for syscall exit. A different
+ *	path is used when syscalls are traced (see ia64_trace_syscall).
+ *	This code has been lifted from ia64_leave_syscall.
+ */
+
+GLOBAL_ENTRY(__adeos_ret_from_syscall)
+	PT_REGS_UNWIND_INFO(0)
+	cmp.lt p6,p0=r8,r0			// syscall failed?
+	adds r2=PT(R8)+16,sp			// r2 = &pt_regs.r8
+	adds r3=PT(R10)+16,sp			// r3 = &pt_regs.r10
+	mov r10=0
+(p6)	br.cond.sptk .adeos_syscall_error	// syscall failed ->
+	;;					// avoid RAW on r10
+.adeos_save_retval:
+.mem.offset 0,0; st8.spill [r2]=r8		// store return value in slot for r8
+.mem.offset 8,0; st8.spill [r3]=r10		// clear error indication in slot for r10
+	br.call.sptk.many rp=__adeos_exit_syscall
+	/* If the exit callout wants us to bypass all the work usually
+	done when resuming in user-space from a syscall (r8 != 0),
+	just set pIFast before branching to the epilogue code. */
+	cmp.ne pIFast,p0=r8,r0
+	br.cond.sptk .adeos_leave_syscall
+
+.adeos_syscall_error:
+	ld8 r3=[r2]				// load pt_regs.r8
+	sub r9=0,r8				// negate return value to get errno value
+	;;
+	cmp.ne p6,p0=r3,r0			// is pt_regs.r8!=0?
+	adds r3=16,r2				// r3=&pt_regs.r10
+	;;
+(p6)	mov r10=-1
+(p6)	mov r8=r9
+	br.cond.sptk .adeos_save_retval
+END(__adeos_ret_from_syscall)
+
+/*
+ * __adeos_bypass_syscall: 
+ *	We branch here when some domain above Linux in the
+ *	pipeline intercepts and blocks the syscall.
+ */
+
+GLOBAL_ENTRY(__adeos_bypass_syscall)
+	PT_REGS_UNWIND_INFO(0)
+	adds r2=PT(R8)+16,sp	// r2 = &pt_regs.r8
+	;;
+	ld8 r8=[r2]		// load retval returned by domain
+	br.cond.sptk ia64_ret_from_syscall
+END(__adeos_bypass_syscall)
+
+#endif /* CONFIG_ADEOS_CORE */
+
 /*
  * Note that interrupts are enabled during save_switch_stack and load_switch_stack.  This
  * means that we may get an interrupt with "sp" pointing to the new kernel stack while
@@ -546,6 +719,11 @@ GLOBAL_ENTRY(ia64_trace_syscall)
 .strace_save_retval:
 .mem.offset 0,0; st8.spill [r2]=r8		// store return value in slot for r8
 .mem.offset 8,0; st8.spill [r3]=r10		// clear error indication in slot for r10
+#ifdef CONFIG_ADEOS_CORE
+	br.call.sptk.many rp=__adeos_exit_syscall
+	cmp.ne pIFast,p0=r8,r0
+(pIFast) br.cond.sptk .adeos_leave_syscall
+#endif /* CONFIG_ADEOS_CORE */
 	br.call.sptk.many rp=syscall_trace // give parent a chance to catch return value
 .ret3:	br.cond.sptk ia64_leave_syscall
 
@@ -658,6 +836,10 @@ END(ia64_ret_from_syscall)
  *	      ar.ssd: cleared
  */
 GLOBAL_ENTRY(ia64_leave_syscall)
+#ifdef CONFIG_ADEOS_CORE
+	cmp.ne pIFast,p0=r0,r0			// pIFast=0: regular exit from syscall
+.adeos_leave_syscall:
+#endif /* CONFIG_ADEOS_CORE */
 	PT_REGS_UNWIND_INFO(0)
 	/*
 	 * work.need_resched etc. mustn't get changed by this CPU before it returns to
@@ -694,8 +876,14 @@ GLOBAL_ENTRY(ia64_leave_syscall)
 	;;
 
 	mov.m ar.ccv=r0		// clear ar.ccv
+#ifdef CONFIG_ADEOS_CORE
+(pIFast) br.cond.spnt .adeos_skip_work
+#endif /* CONFIG_ADEOS_CORE */
 (p6)	cmp4.ne.unc p6,p0=r15, r0		// any special work pending?
 (p6)	br.cond.spnt .work_pending
+#ifdef CONFIG_ADEOS_CORE
+.adeos_skip_work:
+#endif /* CONFIG_ADEOS_CORE */
 	;;
 	// start restoring the state saved on the kernel stack (struct pt_regs):
 	ld8.fill r8=[r16],16
@@ -771,6 +959,10 @@ END(ia64_ret_from_ia32_execve_syscall)
 	// fall through
 #endif /* CONFIG_IA32_SUPPORT */
 GLOBAL_ENTRY(ia64_leave_kernel)
+#ifdef CONFIG_ADEOS_CORE
+	cmp.ne pIFast,p0=r0,r0			// pIFast=0: regular exit from interrupt
+.adeos_leave_kernel:
+#endif /* CONFIG_ADEOS_CORE */
 	PT_REGS_UNWIND_INFO(0)
 	/*
 	 * work.need_resched etc. mustn't get changed by this CPU before it returns to
@@ -818,7 +1010,13 @@ GLOBAL_ENTRY(ia64_leave_kernel)
 	;;
 	ld8 r29=[r2],16		// load b7
 	ld8 r30=[r3],16		// load ar.csd
+#ifdef CONFIG_ADEOS_CORE
+(pIFast)br.cond.sptk .adeos_fast_path
+(p6)	br.cond.spnt .work_pending
+.adeos_fast_path:	
+#else /* !CONFIG_ADEOS_CORE */
 (p6)	br.cond.spnt .work_pending
+#endif /* CONFIG_ADEOS_CORE */
 	;;
 	ld8 r31=[r2],16		// load ar.ssd
 	ld8.fill r8=[r3],16
diff -uNrp linux-2.6.6-ia64/arch/ia64/kernel/entry.h linux-2.6.6-ia64-adeos/arch/ia64/kernel/entry.h
--- linux-2.6.6-ia64/arch/ia64/kernel/entry.h	2004-06-13 12:29:08.000000000 +0200
+++ linux-2.6.6-ia64-adeos/arch/ia64/kernel/entry.h	2004-06-17 11:45:44.000000000 +0200
@@ -9,6 +9,9 @@
 #define pUStk		p3	/* will leave_{kernel,syscall} return to user-stacks? */
 #define pSys		p4	/* are we processing a (synchronous) system call? */
 #define pNonSys		p5	/* complement of pSys */
+#ifdef CONFIG_ADEOS_CORE
+#define pIFast    	p22	/* fast interrupt return path? */
+#endif /* CONFIG_ADEOS_CORE */
 
 #define PT(f)		(IA64_PT_REGS_##f##_OFFSET)
 #define SW(f)		(IA64_SWITCH_STACK_##f##_OFFSET)
diff -uNrp linux-2.6.6-ia64/arch/ia64/kernel/ia64_ksyms.c linux-2.6.6-ia64-adeos/arch/ia64/kernel/ia64_ksyms.c
--- linux-2.6.6-ia64/arch/ia64/kernel/ia64_ksyms.c	2004-06-13 12:29:08.000000000 +0200
+++ linux-2.6.6-ia64-adeos/arch/ia64/kernel/ia64_ksyms.c	2004-06-17 11:45:44.000000000 +0200
@@ -122,3 +122,20 @@ EXPORT_SYMBOL(ia64_spinlock_contention);
 #  endif
 # endif
 #endif
+
+#ifdef CONFIG_ADEOS_CORE
+/* The following are per-platform convenience exports which are needed
+   by some Adeos domains loaded as kernel modules. */
+extern struct tty_driver console_driver;
+EXPORT_SYMBOL(console_driver);
+extern void show_stack(struct task_struct *task, unsigned long *sp);
+EXPORT_SYMBOL(show_stack);
+#include <asm/hw_irq.h>
+EXPORT_SYMBOL(_irq_desc);
+extern void wrap_mmu_context(struct mm_struct *mm);
+EXPORT_SYMBOL(wrap_mmu_context);
+extern struct ia64_ctx ia64_ctx;
+EXPORT_SYMBOL(ia64_ctx);
+DECLARE_PER_CPU(u8,ia64_need_tlb_flush);
+EXPORT_SYMBOL(per_cpu__ia64_need_tlb_flush);
+#endif /* CONFIG_ADEOS_CORE */
diff -uNrp linux-2.6.6-ia64/arch/ia64/kernel/iosapic.c linux-2.6.6-ia64-adeos/arch/ia64/kernel/iosapic.c
--- linux-2.6.6-ia64/arch/ia64/kernel/iosapic.c	2004-06-13 12:55:53.000000000 +0200
+++ linux-2.6.6-ia64-adeos/arch/ia64/kernel/iosapic.c	2004-06-17 11:45:44.000000000 +0200
@@ -243,7 +243,11 @@ mask_irq (unsigned int irq)
 	if (rte_index < 0)
 		return;			/* not an IOSAPIC interrupt! */
 
+#ifdef CONFIG_ADEOS_CORE
+	adeos_spin_lock_irqsave(&iosapic_lock, flags);
+#else /* !CONFIG_ADEOS_CORE */
 	spin_lock_irqsave(&iosapic_lock, flags);
+#endif /* CONFIG_ADEOS_CORE */	
 	{
 		writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);
 
@@ -252,7 +256,11 @@ mask_irq (unsigned int irq)
 
 		writel(low32, addr + IOSAPIC_WINDOW);
 	}
+#ifdef CONFIG_ADEOS_CORE
+	adeos_spin_unlock_irqrestore(&iosapic_lock, flags);
+#else /* !CONFIG_ADEOS_CORE */
 	spin_unlock_irqrestore(&iosapic_lock, flags);
+#endif /* CONFIG_ADEOS_CORE */
 }
 
 static void
@@ -269,13 +277,21 @@ unmask_irq (unsigned int irq)
 	if (rte_index < 0)
 		return;			/* not an IOSAPIC interrupt! */
 
+#ifdef CONFIG_ADEOS_CORE
+	adeos_spin_lock_irqsave(&iosapic_lock, flags);
+#else /* !CONFIG_ADEOS_CORE */
 	spin_lock_irqsave(&iosapic_lock, flags);
+#endif /* CONFIG_ADEOS_CORE */	
 	{
 		writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);
 		low32 = iosapic_intr_info[vec].low32 &= ~IOSAPIC_MASK;
 		writel(low32, addr + IOSAPIC_WINDOW);
 	}
+#ifdef CONFIG_ADEOS_CORE
+	adeos_spin_unlock_irqrestore(&iosapic_lock, flags);
+#else /* !CONFIG_ADEOS_CORE */
 	spin_unlock_irqrestore(&iosapic_lock, flags);
+#endif /* CONFIG_ADEOS_CORE */
 }
 
 
@@ -309,7 +325,11 @@ iosapic_set_affinity (unsigned int irq, 
 	/* dest contains both id and eid */
 	high32 = dest << IOSAPIC_DEST_SHIFT;
 
+#ifdef CONFIG_ADEOS_CORE
+	adeos_spin_lock_irqsave(&iosapic_lock, flags);
+#else /* !CONFIG_ADEOS_CORE */
 	spin_lock_irqsave(&iosapic_lock, flags);
+#endif /* CONFIG_ADEOS_CORE */	
 	{
 		/* get current delivery mode by reading the low32 */
 		writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);
@@ -327,7 +347,12 @@ iosapic_set_affinity (unsigned int irq, 
 		writel(IOSAPIC_RTE_LOW(rte_index), addr + IOSAPIC_REG_SELECT);
 		writel(low32, addr + IOSAPIC_WINDOW);
 	}
+#ifdef CONFIG_ADEOS_CORE
+	adeos_spin_unlock_irqrestore(&iosapic_lock, flags);
+#else /* !CONFIG_ADEOS_CORE */
 	spin_unlock_irqrestore(&iosapic_lock, flags);
+#endif /* CONFIG_ADEOS_CORE */
+
 #endif
 }
 
diff -uNrp linux-2.6.6-ia64/arch/ia64/kernel/irq.c linux-2.6.6-ia64-adeos/arch/ia64/kernel/irq.c
--- linux-2.6.6-ia64/arch/ia64/kernel/irq.c	2004-06-13 12:29:08.000000000 +0200
+++ linux-2.6.6-ia64-adeos/arch/ia64/kernel/irq.c	2004-06-17 11:45:44.000000000 +0200
@@ -432,6 +432,29 @@ void enable_irq(unsigned int irq)
 }
 EXPORT_SYMBOL(enable_irq);
 
+#ifdef CONFIG_ADEOS_CORE
+
+/* Rollback vanilla changes from 2.6.3 -> 2.6.4: we _do_ need the IRQ
+   enter/exit stuff to be done by do_IRQ(), and not from
+   ia64_handle_irq(). Doing otherwise causes havoc. */
+
+static inline void
+irq_enter (void)
+{
+	preempt_count() += HARDIRQ_OFFSET;
+}
+
+static inline void
+irq_exit (void)
+{
+	preempt_count() -= IRQ_EXIT_OFFSET;
+	if (!in_interrupt() && local_softirq_pending())
+		do_softirq();
+	preempt_enable_no_resched();
+}
+
+#endif /* CONFIG_ADEOS_CORE */
+
 /*
  * do_IRQ handles all normal device IRQ's (the special
  * SMP cross-CPU interrupts have their own specific
@@ -455,17 +478,31 @@ unsigned int do_IRQ(unsigned long irq, s
 	unsigned int status;
 	int cpu;
 
+#ifdef CONFIG_ADEOS_CORE
+	irq_enter();
+#endif /* CONFIG_ADEOS_CORE */
 	cpu = smp_processor_id(); /* for CONFIG_PREEMPT, this must come after irq_enter()! */
 
 	kstat_cpu(cpu).irqs[irq]++;
 
 	if (desc->status & IRQ_PER_CPU) {
 		/* no locking required for CPU-local interrupts: */
+#ifdef CONFIG_ADEOS_CORE
+	    if (!adp_pipelined)
+#endif /* CONFIG_ADEOS_CORE */
 		desc->handler->ack(irq);
+#ifdef CONFIG_ADEOS_CORE
+		if (likely(adp_pipelined && __adeos_tick_irq == irq))
+		    action_ret = handle_IRQ_event(irq, &__adeos_tick_regs, desc->action);
+		else
+#endif /* CONFIG_ADEOS_CORE */
 		action_ret = handle_IRQ_event(irq, regs, desc->action);
 		desc->handler->end(irq);
 	} else {
 		spin_lock(&desc->lock);
+#ifdef CONFIG_ADEOS_CORE
+		if (!adp_pipelined)
+#endif /* CONFIG_ADEOS_CORE */
 		desc->handler->ack(irq);
 		/*
 		 * REPLAY is when Linux resends an IRQ that was dropped earlier
@@ -507,6 +544,11 @@ unsigned int do_IRQ(unsigned long irq, s
 		 */
 		for (;;) {
 			spin_unlock(&desc->lock);
+#ifdef CONFIG_ADEOS_CORE
+			if (likely(adp_pipelined && __adeos_tick_irq == irq))
+			    action_ret = handle_IRQ_event(irq,&__adeos_tick_regs,desc->action);
+			else
+#endif /* CONFIG_ADEOS_CORE */
 			action_ret = handle_IRQ_event(irq, regs, action);
 			spin_lock(&desc->lock);
 			if (!noirqdebug)
@@ -524,6 +566,9 @@ unsigned int do_IRQ(unsigned long irq, s
 		desc->handler->end(irq);
 		spin_unlock(&desc->lock);
 	}
+#ifdef CONFIG_ADEOS_CORE
+	irq_exit();
+#endif /* CONFIG_ADEOS_CORE */
 	return 1;
 }
 
@@ -998,6 +1043,32 @@ static int irq_affinity_write_proc (stru
 	return full_count;
 }
 
+#ifdef CONFIG_ADEOS_CORE
+
+unsigned long __adeos_set_irq_affinity (unsigned irq, unsigned long cpumask)
+
+{
+    unsigned long oldmask = irq_affinity[irq];
+
+    if (irq_descp(irq)->handler->set_affinity == NULL)
+	return 0;
+
+    if (cpumask == 0)
+	return oldmask; /* Return mask value -- no change. */
+
+    cpumask &= cpu_online_map;
+
+    if (cpumask == 0 || irq_descp(irq)->handler->set_affinity == NULL)
+	return 0;	/* Error -- bad mask value or non-routable IRQ. */
+
+    irq_affinity[irq] = cpumask;
+    irq_descp(irq)->handler->set_affinity(irq,cpumask);
+
+    return oldmask;
+}
+
+#endif /* CONFIG_ADEOS_CORE */
+
 #endif /* CONFIG_SMP */
 
 static int prof_cpu_mask_read_proc (char *page, char **start, off_t off,
diff -uNrp linux-2.6.6-ia64/arch/ia64/kernel/irq_ia64.c linux-2.6.6-ia64-adeos/arch/ia64/kernel/irq_ia64.c
--- linux-2.6.6-ia64/arch/ia64/kernel/irq_ia64.c	2004-06-13 12:55:53.000000000 +0200
+++ linux-2.6.6-ia64-adeos/arch/ia64/kernel/irq_ia64.c	2004-06-17 11:45:44.000000000 +0200
@@ -57,6 +57,8 @@ __u8 isa_irq_to_vector_map[16] = {
 };
 EXPORT_SYMBOL(isa_irq_to_vector_map);
 
+#ifndef CONFIG_ADEOS_CORE
+
 static inline void
 irq_enter (void)
 {
@@ -72,6 +74,8 @@ irq_exit (void)
 	preempt_enable_no_resched();
 }
 
+#endif /* !CONFIG_ADEOS_CORE */
+
 int
 assign_irq_vector (int irq)
 {
@@ -90,9 +94,24 @@ extern unsigned int do_IRQ(unsigned long
  * interrupt. This branches to the correct hardware IRQ handler via
  * function ptr.
  */
+#ifdef CONFIG_ADEOS_CORE
+
+/* The ifdef hell in the original implementation is required here,
+   because we don't want to miss changes from any later kernel
+   revisions when patching Adeos in, like it could happen with an
+   independent rewrite of this routine aside of the original code. */
+
+int
+ia64_handle_irq (ia64_vector vector, struct pt_regs *regs)
+{
+    adeos_declare_cpuid;
+
+    adeos_load_cpuid();
+#else /* !CONFIG_ADEOS_CORE */
 void
 ia64_handle_irq (ia64_vector vector, struct pt_regs *regs)
 {
+#endif /* CONFIG_ADEOS_CORE */
 	unsigned long saved_tpr;
 #ifdef CONFIG_SMP
 #	define IS_RESCHEDULE(vec)	(vec == IA64_IPI_RESCHEDULE)
@@ -135,7 +154,10 @@ ia64_handle_irq (ia64_vector vector, str
 	 * 16 (without this, it would be ~240, which could easily lead
 	 * to kernel stack overflows).
 	 */
+#ifndef CONFIG_ADEOS_CORE
+	/* Leave this to do_IRQ(). */
 	irq_enter();
+#endif /* !CONFIG_ADEOS_CORE */
 	saved_tpr = ia64_getreg(_IA64_REG_CR_TPR);
 	ia64_srlz_d();
 	while (vector != IA64_SPURIOUS_INT_VECTOR) {
@@ -143,6 +165,41 @@ ia64_handle_irq (ia64_vector vector, str
 			ia64_setreg(_IA64_REG_CR_TPR, vector);
 			ia64_srlz_d();
 
+#ifdef CONFIG_ADEOS_CORE
+			/* Note: we let the critical IPI flow down the
+			   pipeline, even if the latter is not enabled
+			   yet.  This exception case occurs once
+			   during __adeos_enable_pipeline(), and
+			   unless the IRQ is spurious, it must be
+			   related to the adeos_critical_enter()
+			   service. If it is spurious, then the
+			   default Linux handler will catch it
+			   properly anyway. */
+#ifdef CONFIG_SMP
+			if (likely(adp_pipelined || local_vector_to_irq(vector) == ADEOS_CRITICAL_IPI))
+#else /* !CONFIG_SMP */
+			if (likely(adp_pipelined))
+#endif /* CONFIG_SMP */
+			    {
+			    /* Send EOI _before_ running the handlers,
+			       otherwise, we would get massive jitter
+			       in domains pipelined above the Linux
+			       one. */
+			    adeos_hw_cli();
+			    ia64_setreg(_IA64_REG_CR_TPR,saved_tpr);
+			    ia64_eoi();
+			    __adeos_handle_irq(local_vector_to_irq(vector),regs);
+			    goto no_eoi;
+			    }
+
+			do_IRQ(local_vector_to_irq(vector),regs);
+			adeos_hw_cli();
+			ia64_setreg(_IA64_REG_CR_TPR,saved_tpr);
+		}
+		ia64_eoi();
+no_eoi:
+		adeos_load_cpuid(); /* Processor might have changed. */
+#else /* !CONFIG_ADEOS_CORE */
 			do_IRQ(local_vector_to_irq(vector), regs);
 
 			/*
@@ -152,6 +209,7 @@ ia64_handle_irq (ia64_vector vector, str
 			ia64_setreg(_IA64_REG_CR_TPR, saved_tpr);
 		}
 		ia64_eoi();
+#endif /* CONFIG_ADEOS_CORE */
 		vector = ia64_get_ivr();
 	}
 	/*
@@ -159,7 +217,11 @@ ia64_handle_irq (ia64_vector vector, str
 	 * handler needs to be able to wait for further keyboard interrupts, which can't
 	 * come through until ia64_eoi() has been done.
 	 */
+#ifdef CONFIG_ADEOS_CORE
+        return (adp_cpu_current[cpuid] == adp_root && !test_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status));
+#else /* !CONFIG_ADEOS_CORE */
 	irq_exit();
+#endif /* CONFIG_ADEOS_CORE */
 }
 
 #ifdef CONFIG_SMP
@@ -221,5 +283,14 @@ ia64_send_ipi (int cpu, int vector, int 
 	ipi_data = (delivery_mode << 8) | (vector & 0xff);
 	ipi_addr = ipi_base_addr | (phys_cpu_id << 4) | ((redirect & 1)  << 3);
 
+#ifdef CONFIG_ADEOS_CORE
+	{
+	unsigned long flags;
+	adeos_hw_local_irq_save(flags);
+#endif /* CONFIG_ADEOS_CORE*/
 	writeq(ipi_data, ipi_addr);
+#ifdef CONFIG_ADEOS_CORE
+	adeos_hw_local_irq_restore(flags);
+	}
+#endif /* CONFIG_ADEOS_CORE*/
 }
diff -uNrp linux-2.6.6-ia64/arch/ia64/kernel/ivt.S linux-2.6.6-ia64-adeos/arch/ia64/kernel/ivt.S
--- linux-2.6.6-ia64/arch/ia64/kernel/ivt.S	2004-06-17 11:19:11.000000000 +0200
+++ linux-2.6.6-ia64-adeos/arch/ia64/kernel/ivt.S	2004-06-17 11:45:45.000000000 +0200
@@ -735,11 +735,26 @@ ENTRY(break_fault)
 	;;
 (p15)	ssm psr.i				// restore psr.i
 	;;
+#ifdef CONFIG_ADEOS_CORE
+#if PT(B6) != 0
+# error This code assumes that b6 is the first field in pt_regs.
+#endif
+	;; 
+	adds r20=PT(B6)+16,sp			// r20 = &pt_regs
+	br.call.sptk.many b6=__adeos_catch_syscall
+	cmp.eq p0,p7=r8,r0
+(p7)	br.cond.spnt __adeos_bypass_syscall
+	;; 
+#endif /* CONFIG_ADEOS_CORE */
 	mov r3=NR_syscalls - 1
 	movl r16=sys_call_table
 
 	adds r15=-1024,r15			// r15 contains the syscall number---subtract 1024
+#ifdef CONFIG_ADEOS_CORE
+	movl r2=__adeos_ret_from_syscall
+#else /* !CONFIG_ADEOS_CORE */
 	movl r2=ia64_ret_from_syscall
+#endif /* CONFIG_ADEOS_CORE */
 	;;
 	shladd r20=r15,3,r16			// r20 = sys_call_table + 8*(syscall-1024)
 	cmp.leu p6,p7=r15,r3			// (syscall > 0 && syscall < 1024 + NR_syscalls) ?
@@ -780,7 +795,11 @@ ENTRY(interrupt)
 	add out1=16,sp		// pass pointer to pt_regs as second arg
 	;;
 	srlz.d			// make sure we see the effect of cr.ivr
+#ifdef CONFIG_ADEOS_CORE
+	movl r14=__adeos_ret_from_intr
+#else /* !CONFIG_ADEOS_CORE */
 	movl r14=ia64_leave_kernel
+#endif /* CONFIG_ADEOS_CORE */
 	;;
 	mov rp=r14
 	br.call.sptk.many b6=ia64_handle_irq
diff -uNrp linux-2.6.6-ia64/arch/ia64/kernel/process.c linux-2.6.6-ia64-adeos/arch/ia64/kernel/process.c
--- linux-2.6.6-ia64/arch/ia64/kernel/process.c	2004-06-17 11:19:11.000000000 +0200
+++ linux-2.6.6-ia64-adeos/arch/ia64/kernel/process.c	2004-06-17 11:45:45.000000000 +0200
@@ -150,6 +150,32 @@ do_notify_resume_user (sigset_t *oldset,
 		return;
 	}
 
+#ifdef CONFIG_ADEOS_CORE
+	/* Virtualizing all changes to psr.i (i.e. cli/sti) in entry.S
+	   for the ia64 arch would be clearly sub-optimal, without
+	   even any guarantee to get significantly better
+	   preemptability. For instance, preserving the scratch
+	   registers while calling the Adeos pipeline management would
+	   eat quite a few cycles and probably create much of a
+	   burden. It has been decided instead to selectively
+	   re-enable hardware interrupts for the C routines called
+	   from entry.S which are known to be invoked with interrupts
+	   off, while keeping the Linux domain stalled. This current
+	   routine is currently the only one which seems worth hacking
+	   this way. After a not so brief inspection, we assume that
+	   all return paths in entry.S never lock out the hardware
+	   interrupts for an unreasonably long time. However, in case
+	   of jitter, a potential source of such problem might be the
+	   recursive code cleaning up the stacked registers that
+	   starts from "dont_preserve_current_frame" in entry.S. */
+	{
+	unsigned long flags, _flags;
+	adeos_declare_cpuid;
+
+	flags = __adeos_test_and_stall_root();
+	adeos_hw_sti();
+#endif /* CONFIG_ADEOS_CORE */
+
 #ifdef CONFIG_PERFMON
 	if (current->thread.pfm_needs_checking)
 		pfm_handle_work();
@@ -158,6 +184,13 @@ do_notify_resume_user (sigset_t *oldset,
 	/* deal with pending signal delivery */
 	if (test_thread_flag(TIF_SIGPENDING))
 		ia64_do_signal(oldset, scr, in_syscall);
+
+#ifdef CONFIG_ADEOS_CORE
+	adeos_lock_cpu(_flags);
+	adeos_restore_pipeline_nosync(adp_root,flags,cpuid);
+	adeos_unlock_cpu(_flags);
+	}
+#endif /* CONFIG_ADEOS_CORE */
 }
 
 static int pal_halt = 1;
@@ -200,6 +233,9 @@ cpu_idle (void *unused)
 		while (!need_resched()) {
 			if (mark_idle)
 				(*mark_idle)(1);
+#ifdef CONFIG_ADEOS_CORE
+			adeos_suspend_domain();
+#endif /* CONFIG_ADEOS_CORE */
 			(*idle)();
 		}
 
@@ -619,6 +655,9 @@ kernel_thread_helper (int (*fn)(void *),
 		ia64_set_kr(IA64_KR_TSSD, current->thread.old_k1);
 	}
 #endif
+#ifdef CONFIG_ADEOS_CORE
+	__adeos_unstall_root();
+#endif /* CONFIG_ADEOS_CORE */
 	return (*fn)(arg);
 }
 
diff -uNrp linux-2.6.6-ia64/arch/ia64/kernel/time.c linux-2.6.6-ia64-adeos/arch/ia64/kernel/time.c
--- linux-2.6.6-ia64/arch/ia64/kernel/time.c	2004-06-13 12:29:08.000000000 +0200
+++ linux-2.6.6-ia64-adeos/arch/ia64/kernel/time.c	2004-06-17 11:45:45.000000000 +0200
@@ -246,7 +246,19 @@ timer_interrupt (int irq, void *dev_id, 
 
 	platform_timer_interrupt(irq, dev_id, regs);
 
-	new_itm = local_cpu_data->itm_next;
+#ifdef CONFIG_ADEOS_CORE
+	if (likely(adp_pipelined))
+	    {
+	    adeos_declare_cpuid;
+	    unsigned long flags;
+
+	    adeos_get_cpu(flags);
+	    new_itm = __adeos_itm_next[cpuid] - __adeos_itm_delta[cpuid];
+	    adeos_put_cpu(flags);
+	    }
+	else
+#endif /* CONFIG_ADEOS_CORE */
+	    new_itm = local_cpu_data->itm_next;
 
 	if (!time_after(ia64_get_itc(), new_itm))
 		printk(KERN_ERR "Oops: timer tick before it's due (itc=%lx,itm=%lx)\n",
@@ -254,6 +266,7 @@ timer_interrupt (int irq, void *dev_id, 
 
 	ia64_do_profile(regs);
 
+
 	while (1) {
 #ifdef CONFIG_SMP
 		/*
@@ -283,6 +296,9 @@ timer_interrupt (int irq, void *dev_id, 
 			break;
 	}
 
+#ifdef CONFIG_ADEOS_CORE
+	if (!adp_pipelined)
+#endif /* CONFIG_ADEOS_CORE */
 	do {
 		/*
 		 * If we're too close to the next clock tick for
diff -uNrp linux-2.6.6-ia64/include/asm-ia64/adeos.h linux-2.6.6-ia64-adeos/include/asm-ia64/adeos.h
--- linux-2.6.6-ia64/include/asm-ia64/adeos.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.6-ia64-adeos/include/asm-ia64/adeos.h	2004-06-17 11:46:40.000000000 +0200
@@ -0,0 +1,364 @@
+/*
+ *   include/asm-ia64/adeos.h
+ *
+ *   Copyright (C) 2003,2004 Philippe Gerum.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ *   USA; either version 2 of the License, or (at your option) any later
+ *   version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __IA64_ADEOS_H
+#define __IA64_ADEOS_H
+
+#include <asm/types.h>
+#include <asm/siginfo.h>
+#include <asm/ptrace.h>
+#include <asm/irq.h>
+#include <linux/list.h>
+#include <linux/threads.h>
+
+#define ADEOS_ARCH_STRING "ia64"
+
+extern int adp_pipelined;
+
+#ifdef CONFIG_SMP
+
+#include <asm/smp.h>
+#include <asm/gcc_intrin.h>
+
+#define ADEOS_NR_CPUS          NR_CPUS
+#define ADEOS_SERVICE_VECTOR   0xf1
+#define ADEOS_SERVICE_IPI      local_vector_to_irq(ADEOS_SERVICE_VECTOR)
+#define ADEOS_CRITICAL_VECTOR  0xf9 /* Used by adeos_critical_enter/exit() */
+#define ADEOS_CRITICAL_IPI     local_vector_to_irq(ADEOS_CRITICAL_VECTOR)
+
+/* Use Linux's dense CPU identifiers here -- referencing "current" on
+   ia64 is always safe, regardless of the calling context. */
+#define adeos_processor_id()   smp_processor_id()
+
+#define adeos_declare_cpuid    int cpuid
+#define adeos_load_cpuid()     do { \
+                                  (cpuid) = adeos_processor_id();	\
+                               } while(0)
+#define adeos_lock_cpu(flags)  do { \
+                                  adeos_hw_local_irq_save(flags); \
+				  ia64_stop();			  \
+                                  (cpuid) = adeos_processor_id(); \
+                               } while(0)
+#define adeos_unlock_cpu(flags) adeos_hw_local_irq_restore(flags)
+#define adeos_get_cpu(flags)    adeos_lock_cpu(flags)
+#define adeos_put_cpu(flags)    adeos_unlock_cpu(flags)
+#define adp_current            ({ adomain_t *__adp; \
+				unsigned long flags; \
+				adeos_hw_local_irq_save(flags); \
+				ia64_stop();			\
+				__adp = adp_cpu_current[adeos_processor_id()]; \
+				adeos_hw_local_irq_restore(flags); \
+				__adp; })
+#else  /* !CONFIG_SMP */
+
+#define ADEOS_NR_CPUS          1
+#define adeos_processor_id()   0
+/* Array references using this index should be optimized out. */
+#define adeos_declare_cpuid    const int cpuid = 0
+#define adeos_load_cpuid()      /* nop */
+#define adeos_lock_cpu(flags)   adeos_hw_local_irq_save(flags)
+#define adeos_unlock_cpu(flags) adeos_hw_local_irq_restore(flags)
+#define adeos_get_cpu(flags)    do { flags = flags; } while(0)
+#define adeos_put_cpu(flags)    /* nop */
+#define adp_current             (adp_cpu_current[0])
+
+#endif /* CONFIG_SMP */
+
+ /* IDT fault vectors */
+#define ADEOS_NR_FAULTS         32
+/* Pseudo-vectors used for kernel events */
+#define ADEOS_FIRST_KEVENT      ADEOS_NR_FAULTS
+#define ADEOS_SYSCALL_PROLOGUE  (ADEOS_FIRST_KEVENT)
+#define ADEOS_SYSCALL_EPILOGUE  (ADEOS_FIRST_KEVENT + 1)
+#define ADEOS_SCHEDULE_HEAD     (ADEOS_FIRST_KEVENT + 2)
+#define ADEOS_SCHEDULE_TAIL     (ADEOS_FIRST_KEVENT + 3)
+#define ADEOS_ENTER_PROCESS     (ADEOS_FIRST_KEVENT + 4)
+#define ADEOS_EXIT_PROCESS      (ADEOS_FIRST_KEVENT + 5)
+#define ADEOS_SIGNAL_PROCESS    (ADEOS_FIRST_KEVENT + 6)
+#define ADEOS_KICK_PROCESS      (ADEOS_FIRST_KEVENT + 7)
+#define ADEOS_RENICE_PROCESS    (ADEOS_FIRST_KEVENT + 8)
+#define ADEOS_USER_EVENT        (ADEOS_FIRST_KEVENT + 9)
+#define ADEOS_LAST_KEVENT       (ADEOS_USER_EVENT)
+
+#define ADEOS_NR_EVENTS         (ADEOS_LAST_KEVENT + 1)
+
+typedef struct adevinfo {
+
+    unsigned domid;
+    unsigned event;
+    void *evdata;
+
+    int propagate;		/* Private */
+
+} adevinfo_t;
+
+typedef struct adsysinfo {
+
+    int ncpus;			/* Number of CPUs on board */
+
+    u64 cpufreq;		/* CPU frequency (in Hz) */
+
+    /* Arch-dependent block */
+
+    struct {
+	unsigned tmirq;		/* Timer tick IRQ */
+    } archdep;
+
+} adsysinfo_t;
+
+#define IPIPE_NR_XIRQS   NR_IRQS
+/* Number of virtual IRQs */
+#define IPIPE_NR_VIRQS   BITS_PER_LONG
+/* First virtual IRQ # */
+#define IPIPE_VIRQ_BASE  (((IPIPE_NR_XIRQS + BITS_PER_LONG - 1) / BITS_PER_LONG) * BITS_PER_LONG)
+/* Total number of IRQ slots */
+#define IPIPE_NR_IRQS     (IPIPE_VIRQ_BASE + IPIPE_NR_VIRQS)
+/* Number of indirect words needed to map the whole IRQ space. */
+#define IPIPE_IRQ_IWORDS  ((IPIPE_NR_IRQS + BITS_PER_LONG - 1) / BITS_PER_LONG)
+#define IPIPE_IRQ_IMASK   (BITS_PER_LONG - 1)
+#define IPIPE_IRQ_ISHIFT  6	/* 2^6 for 64 bits arch. */
+
+#define IPIPE_IRQMASK_ANY   (~0L)
+#define IPIPE_IRQMASK_VIRT  (IPIPE_IRQMASK_ANY << (IPIPE_VIRQ_BASE / BITS_PER_LONG))
+
+typedef struct adomain {
+
+    /* -- Section: offset-based references are made on these fields
+       from inline assembly code. Please don't move or reorder. */
+    void (*dswitch)(void);	/* Domain switch hook */
+    unsigned long esp[ADEOS_NR_CPUS];	/* Domain stack pointers */
+    /* -- End of section. */
+
+    unsigned long estackbase[ADEOS_NR_CPUS];
+
+    unsigned long flags;
+
+    unsigned domid;
+
+    const char *name;
+
+    int priority;
+
+    struct adcpudata {
+	volatile unsigned long status;
+	volatile unsigned long irq_pending_hi;
+	volatile unsigned long irq_pending_lo[IPIPE_IRQ_IWORDS];
+	volatile unsigned long irq_hits[IPIPE_NR_IRQS];
+	adevinfo_t event_info;
+    } cpudata[ADEOS_NR_CPUS];
+
+    struct {
+	int (*acknowledge)(unsigned irq);
+	void (*handler)(unsigned irq);
+	unsigned long control;
+    } irqs[IPIPE_NR_IRQS];
+
+    struct {
+	void (*handler)(adevinfo_t *evinfo);
+    } events[ADEOS_NR_EVENTS];
+
+    int ptd_keymax;
+    int ptd_keycount;
+    unsigned long ptd_keymap;
+    void (*ptd_setfun)(int, void *);
+    void *(*ptd_getfun)(int);
+
+    struct adomain *m_link;	/* Link in mutex sleep queue */
+
+    struct list_head p_link;	/* Link in pipeline */
+
+} adomain_t;
+
+/* The following macros must be used hw interrupts off. */
+
+#define __adeos_set_irq_bit(adp,cpuid,irq) \
+do { \
+    if (!test_bit(IPIPE_LOCK_FLAG,&(adp)->irqs[irq].control)) { \
+        __set_bit(irq & IPIPE_IRQ_IMASK,&(adp)->cpudata[cpuid].irq_pending_lo[irq >> IPIPE_IRQ_ISHIFT]); \
+        __set_bit(irq >> IPIPE_IRQ_ISHIFT,&(adp)->cpudata[cpuid].irq_pending_hi); \
+       } \
+} while(0)
+
+#define __adeos_clear_pend(adp,cpuid,irq) \
+do { \
+    __clear_bit(irq & IPIPE_IRQ_IMASK,&(adp)->cpudata[cpuid].irq_pending_lo[irq >> IPIPE_IRQ_ISHIFT]); \
+    if (&(adp)->cpudata[cpuid].irq_pending_lo[irq >> IPIPE_IRQ_ISHIFT] == 0) \
+        __clear_bit(irq >> IPIPE_IRQ_ISHIFT,&(adp)->cpudata[cpuid].irq_pending_hi); \
+} while(0)
+
+#define __adeos_lock_irq(adp,cpuid,irq) \
+do { \
+    if (!test_and_set_bit(IPIPE_LOCK_FLAG,&(adp)->irqs[irq].control)) \
+	__adeos_clear_pend(adp,cpuid,irq); \
+} while(0)
+
+#define __adeos_unlock_irq(adp,irq) \
+do { \
+    int __cpuid, __nr_cpus = num_online_cpus();			       \
+    if (test_and_clear_bit(IPIPE_LOCK_FLAG,&(adp)->irqs[irq].control)) \
+	for (__cpuid = 0; __cpuid < __nr_cpus; __cpuid++)      \
+         if ((adp)->cpudata[__cpuid].irq_hits[irq] > 0) { \
+           set_bit(irq & IPIPE_IRQ_IMASK,&(adp)->cpudata[__cpuid].irq_pending_lo[irq >> IPIPE_IRQ_ISHIFT]); \
+           set_bit(irq >> IPIPE_IRQ_ISHIFT,&(adp)->cpudata[__cpuid].irq_pending_hi); \
+         } \
+} while(0)
+
+#define __adeos_clear_irq(adp,irq) \
+do { \
+    int __cpuid, __nr_cpus = num_online_cpus(); \
+    clear_bit(IPIPE_LOCK_FLAG,&(adp)->irqs[irq].control); \
+    for (__cpuid = 0; __cpuid < __nr_cpus; __cpuid++) {	\
+       (adp)->cpudata[__cpuid].irq_hits[irq] = 0; \
+       __adeos_clear_pend(adp,__cpuid,irq); \
+    } \
+} while(0)
+
+#define adeos_virtual_irq_p(irq) ((irq) >= IPIPE_VIRQ_BASE && \
+				  (irq) < IPIPE_NR_IRQS)
+
+#define adeos_hw_cli()		\
+do {				\
+	ia64_stop();		\
+	ia64_rsm(IA64_PSR_I);	\
+} while (0)
+
+#define adeos_hw_sti() ({ ia64_ssm(IA64_PSR_I); ia64_srlz_d(); })
+
+#define adeos_hw_save_flags_and_sti(x)	\
+do {                                    \
+    (x) = ia64_getreg(_IA64_REG_PSR);   \
+    adeos_hw_sti();                     \
+} while(0)
+
+#define adeos_hw_local_irq_save(x)	\
+do {					\
+	unsigned long __psr;		\
+        __psr = ia64_getreg(_IA64_REG_PSR);	\
+        ia64_stop();				\
+        ia64_rsm(IA64_PSR_I);			\
+	(x) = __psr;				\
+} while (0)
+      
+#define adeos_hw_local_irq_restore(x) \
+    ia64_intrin_local_irq_restore((x) & IA64_PSR_I)
+
+#define adeos_hw_local_irq_flags(x)   ((x) = ia64_getreg(_IA64_REG_PSR))
+#define adeos_hw_test_iflag(x) 	      ((x) & IA64_PSR_I)
+#define adeos_hw_irqs_disabled()	 \
+    ({					 \
+	unsigned long flags;		 \
+	adeos_hw_local_irq_flags(flags); \
+	!adeos_hw_test_iflag(flags);	 \
+    })
+
+#define adeos_hw_tsc(t)  __asm__ __volatile__("mov %0=ar.itc;;" : "=r"(t) :: "memory")
+#define adeos_cpu_freq() local_cpu_data->proc_freq
+
+#ifdef CONFIG_PREEMPT
+#define adeos_spin_lock(x)    _raw_spin_lock(x)
+#define adeos_spin_unlock(x)  _raw_spin_unlock(x)
+#define adeos_spin_trylock(x) _raw_spin_trylock(x)
+#else /* !CONFIG_PREEMPT */
+#define adeos_spin_lock(x)    spin_lock(x)
+#define adeos_spin_unlock(x)  spin_unlock(x)
+#define adeos_spin_trylock(x) spin_trylock(x)
+#endif /* CONFIG_PREEMPT */
+
+#define adeos_spin_lock_irqsave(x,flags)       do { adeos_hw_local_irq_save(flags); adeos_spin_lock(x); } while (0)
+#define adeos_spin_unlock_irqrestore(x,flags)  do { adeos_spin_unlock(x); adeos_hw_local_irq_restore(flags); } while (0)
+#define adeos_spin_lock_disable(x)             do { adeos_hw_cli(); adeos_spin_lock(x); } while (0)
+#define adeos_spin_unlock_enable(x)            do { adeos_spin_unlock(x); adeos_hw_sti(); } while (0)
+
+#ifndef STR
+#define __STR(x) #x
+#define STR(x) __STR(x)
+#endif
+
+#ifndef SYMBOL_NAME_STR
+#define SYMBOL_NAME_STR(X) #X
+#endif
+
+/* Private interface -- Internal use only */
+
+struct adattr;
+
+void __adeos_init(void);
+
+#define __adeos_check_machine() do { } while(0)
+
+void __adeos_init_domain(adomain_t *adp,
+			 struct adattr *attr);
+
+void __adeos_cleanup_domain(adomain_t *adp);
+
+void __adeos_send_IPI_allbutself(int vector);
+
+void __adeos_send_IPI_other(int cpu,
+			    int vector);
+
+int __adeos_fork_domain(unsigned long stacktop);
+
+void __adeos_switch_to(adomain_t *adp,
+		       int cpuid);
+
+#ifdef CONFIG_SMP
+
+unsigned long __adeos_set_irq_affinity(unsigned irq,
+				       unsigned long cpumask);
+
+#endif /* CONFIG_SMP */
+
+void __adeos_enable_pipeline(void);
+
+void __adeos_disable_pipeline(void);
+
+void __adeos_init_stage(adomain_t *adp);
+
+void __adeos_sync_stage(unsigned long syncmask);
+
+int __adeos_ack_system_irq(unsigned irq);
+
+void __adeos_handle_irq(long irq,
+			struct pt_regs *regs);
+
+extern struct list_head __adeos_pipeline;
+
+extern struct pt_regs __adeos_tick_regs;
+
+extern int __adeos_tick_irq;
+
+extern volatile unsigned long __adeos_itm_next[];
+
+extern volatile unsigned long __adeos_itm_delta[];
+
+#define ADEOS_DEBUG 1
+
+#ifdef ADEOS_DEBUG
+
+void __adeos_set_mark(int id);
+
+void __adeos_dump_marks(void);
+
+void __adeos_clear_marks(void);
+
+#endif /* ADEOS_DEBUG */
+
+#endif /* !__IA64_ADEOS_H */
diff -uNrp linux-2.6.6-ia64/include/asm-ia64/system.h linux-2.6.6-ia64-adeos/include/asm-ia64/system.h
--- linux-2.6.6-ia64/include/asm-ia64/system.h	2004-06-17 11:19:12.000000000 +0200
+++ linux-2.6.6-ia64-adeos/include/asm-ia64/system.h	2004-06-17 11:45:45.000000000 +0200
@@ -107,6 +107,39 @@ extern struct ia64_boot_param {
 
 #define safe_halt()         ia64_pal_halt_light()    /* PAL_HALT_LIGHT */
 
+#ifdef CONFIG_ADEOS_CORE
+
+extern inline void __adeos_stall_root(void);
+
+extern inline void __adeos_unstall_root(void);
+
+extern inline unsigned long __adeos_test_root(void);
+
+extern inline unsigned long __adeos_test_and_stall_root(void);
+
+void __adeos_restore_root(unsigned long flags);
+
+#define __local_irq_save(x)    ((x) = __adeos_test_and_stall_root())
+
+#define __local_irq_disable() 	__adeos_stall_root()
+
+#define __local_irq_restore(x)	__adeos_restore_root(x)
+
+#ifdef CONFIG_IA64_DEBUG_IRQ
+#error "ADEOS: no support for IRQ debug mode"
+#endif /* CONFIG_IA64_DEBUG_IRQ */
+
+#define local_irq_save(x)	__local_irq_save(x)
+#define local_irq_disable()	__local_irq_disable()
+#define local_irq_restore(x)	__local_irq_restore(x)
+
+#define local_irq_enable()	__adeos_unstall_root()
+#define local_save_flags(x)	((x) = __adeos_test_root())
+
+#define irqs_disabled()		__adeos_test_root()
+
+#else /* !CONFIG_ADEOS_CORE */
+
 /*
  * The group barrier in front of the rsm & ssm are necessary to ensure
  * that none of the previous instructions in the same group are
@@ -181,6 +214,8 @@ do {								\
 	(__ia64_id_flags & IA64_PSR_I) == 0;	\
 })
 
+#endif /* CONFIG_ADEOS_CORE */
+
 #ifdef __KERNEL__
 
 #define prepare_to_switch()    do { } while(0)
@@ -222,15 +257,38 @@ extern void ia64_load_extra (struct task
 	((t)->thread.flags & (IA64_THREAD_DBG_VALID|IA64_THREAD_PM_VALID)	\
 	 || IS_IA32_PROCESS(ia64_task_regs(t)) || PERFMON_IS_SYSWIDE())
 
-#define __switch_to(prev,next,last) do {							 \
-	if (IA64_HAS_EXTRA_STATE(prev))								 \
-		ia64_save_extra(prev);								 \
-	if (IA64_HAS_EXTRA_STATE(next))								 \
-		ia64_load_extra(next);								 \
-	ia64_psr(ia64_task_regs(next))->dfh = !ia64_is_local_fpu_owner(next);			 \
-	(last) = ia64_switch_to((next));							 \
+#ifdef CONFIG_ADEOS_CORE
+
+#define get_current_gp(t)            __asm__ __volatile__(";;mov %0=r1;;" : "=r"(t) :: "memory")
+#define set_current_gp(t)            __asm__ __volatile__("mov r1=%0;;" :: "r"(t) : "memory")
+
+#define __switch_to(prev,next,last) do {				\
+	volatile unsigned long gp;					\
+	if (IA64_HAS_EXTRA_STATE(prev))					\
+		ia64_save_extra(prev);					\
+	if (IA64_HAS_EXTRA_STATE(next))					\
+		ia64_load_extra(next);					\
+	ia64_psr(ia64_task_regs(next))->dfh = !ia64_is_local_fpu_owner(next); \
+	get_current_gp(gp);						\
+	(last) = ia64_switch_to((next));				\
+	set_current_gp(gp);						\
+} while (0)
+
+#else  /* !CONFIG_ADEOS_CORE */
+
+#define __switch_to(prev,next,last) do {				\
+	volatile unsigned long gp;					\
+	if (IA64_HAS_EXTRA_STATE(prev))					\
+		ia64_save_extra(prev);					\
+	if (IA64_HAS_EXTRA_STATE(next))					\
+		ia64_load_extra(next);					\
+	ia64_psr(ia64_task_regs(next))->dfh = !ia64_is_local_fpu_owner(next); \
+	(last) = ia64_switch_to((next));				\
+									\
 } while (0)
 
+#endif	/* CONFIG_ADEOS_CORE */
+
 #ifdef CONFIG_SMP
 /*
  * In the SMP case, we save the fph state when context-switching away from a thread that
@@ -274,11 +332,22 @@ extern void ia64_load_extra (struct task
  * of that CPU which will not be released, because there we wait for the
  * tasklist_lock to become available.
  */
+#ifdef CONFIG_ADEOS_CORE
+#define prepare_arch_switch(rq,prev,next) \
+do { \
+    struct { struct task_struct *prev, *next; } arg = { (prev), (next) }; \
+    __adeos_schedule_head(&arg); \
+    adeos_hw_cli(); \
+    spin_lock(&(next)->switch_lock);	\
+    spin_unlock(&(rq)->lock);		\
+} while(0)
+#else /* !CONFIG_ADEOS_CORE */
 #define prepare_arch_switch(rq, next)		\
 do {						\
 	spin_lock(&(next)->switch_lock);	\
 	spin_unlock(&(rq)->lock);		\
 } while (0)
+#endif /* CONFIG_ADEOS_CORE */
 #define finish_arch_switch(rq, prev)	spin_unlock_irq(&(prev)->switch_lock)
 #define task_running(rq, p) 		((rq)->curr == (p) || spin_is_locked(&(p)->switch_lock))
 
diff -uNrp linux-2.6.6-ia64/include/linux/adeos.h linux-2.6.6-ia64-adeos/include/linux/adeos.h
--- linux-2.6.6-ia64/include/linux/adeos.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.6-ia64-adeos/include/linux/adeos.h	2004-06-17 11:46:40.000000000 +0200
@@ -0,0 +1,476 @@
+/*
+ *   include/linux/adeos.h
+ *
+ *   Copyright (C) 2002 Philippe Gerum.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ *   USA; either version 2 of the License, or (at your option) any later
+ *   version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __LINUX_ADEOS_H
+#define __LINUX_ADEOS_H
+
+#include <asm/adeos.h>
+#include <linux/spinlock.h>
+
+#define ADEOS_VERSION_PREFIX  "2.6r5/"
+#define ADEOS_VERSION_STRING  (ADEOS_VERSION_PREFIX ADEOS_ARCH_STRING)
+#define ADEOS_RELEASE_NUMBER  0x020605ff
+
+#define ADEOS_ROOT_PRI       100
+#define ADEOS_ROOT_ID        0
+#define ADEOS_ROOT_NPTDKEYS  4	/* Must be <= 32 */
+
+#define ADEOS_OTHER_CPUS   (-1)
+#define ADEOS_RESET_TIMER  0x1
+#define ADEOS_SAME_HANDLER ((void (*)(unsigned))(-1))
+
+/* Global domain flags */
+#define ADEOS_SPRINTK_FLAG 0	/* Synchronous printk() allowed */
+#define ADEOS_PPRINTK_FLAG 1	/* Asynchronous printk() request pending */
+
+/* Per-cpu pipeline flags */
+#define IPIPE_STALL_FLAG   0	/* Stalls a pipeline stage */
+#define IPIPE_SYNC_FLAG    1	/* IRQ sync is undergoing */
+#define IPIPE_XPEND_FLAG   2	/* Exception notification is pending */
+#define IPIPE_SLEEP_FLAG   3	/* Domain has self-suspended */
+
+#define IPIPE_HANDLE_FLAG    0
+#define IPIPE_PASS_FLAG      1
+#define IPIPE_CALLASM_FLAG   2
+#define IPIPE_ENABLE_FLAG    3
+#define IPIPE_DYNAMIC_FLAG   IPIPE_HANDLE_FLAG
+#define IPIPE_EXCLUSIVE_FLAG 4
+#define IPIPE_STICKY_FLAG    5
+#define IPIPE_SYSTEM_FLAG    6
+#define IPIPE_LOCK_FLAG      7
+#define IPIPE_SHARED_FLAG    8
+
+#define IPIPE_HANDLE_MASK    (1 << IPIPE_HANDLE_FLAG)
+#define IPIPE_PASS_MASK      (1 << IPIPE_PASS_FLAG)
+#define IPIPE_CALLASM_MASK   (1 << IPIPE_CALLASM_FLAG)
+#define IPIPE_ENABLE_MASK    (1 << IPIPE_ENABLE_FLAG)
+#define IPIPE_DYNAMIC_MASK   IPIPE_HANDLE_MASK
+#define IPIPE_EXCLUSIVE_MASK (1 << IPIPE_EXCLUSIVE_FLAG)
+#define IPIPE_STICKY_MASK    (1 << IPIPE_STICKY_FLAG)
+#define IPIPE_SYSTEM_MASK    (1 << IPIPE_SYSTEM_FLAG)
+#define IPIPE_LOCK_MASK      (1 << IPIPE_LOCK_FLAG)
+#define IPIPE_SHARED_MASK    (1 << IPIPE_SHARED_FLAG)
+
+#define IPIPE_DEFAULT_MASK  (IPIPE_HANDLE_MASK|IPIPE_PASS_MASK)
+
+typedef struct adattr {
+
+    unsigned domid;		/* Domain identifier -- Magic value set by caller */
+    const char *name;		/* Domain name -- Warning: won't be dup'ed! */
+    int priority;		/* Priority in interrupt pipeline */
+    void (*entry)(int);		/* Domain entry point */
+    int estacksz;		/* Stack size for entry context -- 0 means unspec */
+    void (*dswitch)(void);	/* Handler called each time the domain is switched in */
+    int nptdkeys;		/* Max. number of per-thread data keys */
+    void (*ptdset)(int,void *);	/* Routine to set pt values */
+    void *(*ptdget)(int);	/* Routine to get pt values */
+
+} adattr_t;
+
+typedef struct admutex {
+
+    spinlock_t lock;
+
+    adomain_t *sleepq, /* Pending domains queue */
+	      *owner;	/* Domain owning the mutex */
+#ifdef CONFIG_SMP
+    volatile int owncpu;
+#define ADEOS_MUTEX_UNLOCKED { SPIN_LOCK_UNLOCKED, NULL, NULL, -1 }
+#else  /* !CONFIG_SMP */
+#define ADEOS_MUTEX_UNLOCKED { SPIN_LOCK_UNLOCKED, NULL, NULL }
+#endif /* CONFIG_SMP */
+
+} admutex_t;
+
+extern adomain_t *adp_cpu_current[],
+                 *adp_root;
+
+extern int __adeos_event_monitors[];
+
+extern unsigned __adeos_printk_virq;
+
+extern unsigned long __adeos_virtual_irq_map;
+
+/* Private interface */
+
+#ifdef CONFIG_PROC_FS
+void __adeos_init_proc(void);
+#endif /* CONFIG_PROC_FS */
+
+void __adeos_takeover(void);
+
+int __adeos_handle_event(unsigned event,
+			 void *evdata);
+
+void __adeos_sync_console(unsigned irq);
+
+void __adeos_dump_state(void);
+
+static inline void __adeos_schedule_head(void *evdata) {
+
+    if (unlikely(__adeos_event_monitors[ADEOS_SCHEDULE_HEAD] > 0))
+	__adeos_handle_event(ADEOS_SCHEDULE_HEAD,evdata);
+}
+
+static inline int __adeos_schedule_tail(void *evdata) {
+
+    if (unlikely(__adeos_event_monitors[ADEOS_SCHEDULE_TAIL] > 0))
+	return __adeos_handle_event(ADEOS_SCHEDULE_TAIL,evdata);
+
+    return 0;
+}
+
+static inline void __adeos_enter_process(void) {
+
+    if (unlikely(__adeos_event_monitors[ADEOS_ENTER_PROCESS] > 0))
+	__adeos_handle_event(ADEOS_ENTER_PROCESS,NULL);
+}
+
+static inline void __adeos_exit_process(void *evdata) {
+
+    if (unlikely(__adeos_event_monitors[ADEOS_EXIT_PROCESS] > 0))
+	__adeos_handle_event(ADEOS_EXIT_PROCESS,evdata);
+}
+
+static inline int __adeos_signal_process(void *evdata) {
+
+    if (unlikely(__adeos_event_monitors[ADEOS_SIGNAL_PROCESS] > 0))
+	return __adeos_handle_event(ADEOS_SIGNAL_PROCESS,evdata);
+
+    return 0;
+}
+
+static inline void __adeos_kick_process(void *evdata) {
+
+    if (unlikely(__adeos_event_monitors[ADEOS_KICK_PROCESS] > 0))
+	__adeos_handle_event(ADEOS_KICK_PROCESS,evdata);
+}
+
+static inline int __adeos_renice_process(void *evdata) {
+
+    if (unlikely(__adeos_event_monitors[ADEOS_RENICE_PROCESS] > 0))
+	return __adeos_handle_event(ADEOS_RENICE_PROCESS,evdata);
+
+    return 0;
+}
+
+extern inline void __adeos_stall_root (void)
+
+{
+    if (likely(adp_pipelined))
+	{
+	adeos_declare_cpuid;
+	unsigned long flags;
+
+	adeos_get_cpu(flags);
+	set_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status);
+	adeos_put_cpu(flags);
+	}
+    else
+	adeos_hw_cli();
+}
+
+extern inline void __adeos_unstall_root (void)
+
+{
+    adeos_hw_sti();	/* Absolutely needed. */
+
+    if (likely(adp_pipelined))
+	{
+	adeos_declare_cpuid;
+	unsigned long flags;
+
+	adeos_get_cpu(flags);
+
+	clear_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status);
+
+	if (adp_root->cpudata[cpuid].irq_pending_hi != 0)
+	    __adeos_sync_stage(IPIPE_IRQMASK_ANY);
+
+	adeos_put_cpu(flags);
+	}
+}
+
+extern inline unsigned long __adeos_test_root (void)
+
+{
+    if (likely(adp_pipelined))
+	{
+	unsigned long flags, s;
+	adeos_declare_cpuid;
+
+	adeos_get_cpu(flags);
+
+	s = test_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status);
+
+	adeos_put_cpu(flags);
+
+	return s;
+	}
+
+    return adeos_hw_irqs_disabled();
+}
+
+extern inline unsigned long __adeos_test_and_stall_root (void)
+
+{
+    unsigned long flags;
+
+    if (likely(adp_pipelined))
+	{
+	unsigned long flags, s;
+	adeos_declare_cpuid;
+
+	adeos_get_cpu(flags);
+
+	s = test_and_set_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status);
+
+	adeos_put_cpu(flags);
+
+	return s;
+	}
+
+    adeos_hw_local_irq_save(flags);
+
+    return !adeos_hw_test_iflag(flags);
+}
+
+void fastcall __adeos_restore_root(unsigned long flags);
+
+void __adeos_schedule_back_root(struct task_struct *prev);
+
+/* Public interface */
+
+int adeos_register_domain(adomain_t *adp,
+			  adattr_t *attr);
+
+int adeos_unregister_domain(adomain_t *adp);
+
+void adeos_renice_domain(int newpri);
+
+void adeos_suspend_domain(void);
+
+int adeos_virtualize_irq_from(adomain_t *adp,
+			      unsigned irq,
+			      void (*handler)(unsigned irq),
+			      int (*acknowledge)(unsigned irq),
+			      unsigned modemask);
+
+static inline int adeos_virtualize_irq(unsigned irq,
+				       void (*handler)(unsigned irq),
+				       int (*acknowledge)(unsigned irq),
+				       unsigned modemask) {
+
+    return adeos_virtualize_irq_from(adp_current,
+				     irq,
+				     handler,
+				     acknowledge,
+				     modemask);
+}
+
+int adeos_control_irq(unsigned irq,
+		      unsigned clrmask,
+		      unsigned setmask);
+
+unsigned long adeos_set_irq_affinity(unsigned irq,
+				     unsigned long cpumask);
+
+static inline int adeos_share_irq (unsigned irq, int (*acknowledge)(unsigned irq)) {
+
+    return adeos_virtualize_irq(irq,
+				ADEOS_SAME_HANDLER,
+				acknowledge,
+				IPIPE_SHARED_MASK|IPIPE_HANDLE_MASK|IPIPE_PASS_MASK);
+}
+
+unsigned adeos_alloc_irq(void);
+
+int adeos_free_irq(unsigned irq);
+
+int fastcall adeos_trigger_irq(unsigned irq);
+
+int fastcall adeos_propagate_irq(unsigned irq);
+
+int fastcall adeos_schedule_irq(unsigned irq);
+
+int fastcall adeos_trigger_ipi(int cpuid);
+
+static inline void adeos_stall_pipeline_from (adomain_t *adp) {
+
+    adeos_declare_cpuid;
+    unsigned long flags;
+
+    adeos_get_cpu(flags);
+    set_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status);
+    adeos_put_cpu(flags);
+}
+
+static inline void adeos_stall_pipeline (void) {
+
+    adeos_stall_pipeline_from(adp_current);
+}
+
+void fastcall adeos_unstall_pipeline_from(adomain_t *adp);
+
+static inline void adeos_unstall_pipeline (void) {
+
+    adeos_declare_cpuid;
+    unsigned long flags;
+
+    adeos_get_cpu(flags);
+
+    clear_bit(IPIPE_STALL_FLAG,&adp_current->cpudata[cpuid].status);
+
+    if (unlikely(adp_current->cpudata[cpuid].irq_pending_hi != 0))
+	__adeos_sync_stage(IPIPE_IRQMASK_ANY);
+
+    adeos_put_cpu(flags);
+}
+
+static inline unsigned long adeos_test_pipeline_from (adomain_t *adp) {
+
+    unsigned long flags, s;
+    adeos_declare_cpuid;
+    
+    adeos_get_cpu(flags);
+    s = test_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status);
+    adeos_put_cpu(flags);
+
+    return s;
+}
+
+static inline unsigned long adeos_test_pipeline (void) {
+
+    return adeos_test_pipeline_from(adp_current);
+}
+
+static inline unsigned long adeos_test_and_stall_pipeline_from (adomain_t *adp) {
+    
+    unsigned long flags, s;
+    adeos_declare_cpuid;
+    
+    adeos_get_cpu(flags);
+    s = test_and_set_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status);
+    adeos_put_cpu(flags);
+
+    return s;
+}
+
+static inline unsigned long adeos_test_and_stall_pipeline (void) {
+    
+    return adeos_test_and_stall_pipeline_from(adp_current);
+}
+
+static inline void adeos_restore_pipeline_from (adomain_t *adp, unsigned long flags) {
+
+    if (flags)
+	adeos_stall_pipeline_from(adp);
+    else
+	adeos_unstall_pipeline_from(adp);
+}
+
+static inline void adeos_restore_pipeline (unsigned long flags) {
+
+    unsigned long hwflags;
+    adeos_declare_cpuid;
+    adomain_t *adp;
+
+    adeos_get_cpu(hwflags);
+
+    adp = adp_cpu_current[cpuid];
+
+    if (flags)
+	set_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status);
+    else
+	{
+	clear_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status);
+
+	if (unlikely(adp->cpudata[cpuid].irq_pending_hi != 0))
+	    __adeos_sync_stage(IPIPE_IRQMASK_ANY);
+	}
+
+    adeos_put_cpu(hwflags);
+}
+
+static inline void adeos_restore_pipeline_nosync (adomain_t *adp, unsigned long flags, int cpuid) {
+
+    /* If cpuid is current, then it must be held on entry
+       (adeos_get_cpu/adeos_hw_local_irq_save/adeos_hw_cli). */
+
+    if (flags)
+	set_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status);
+    else
+	clear_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status);
+}
+
+int adeos_catch_event_from(adomain_t *adp,
+			   unsigned event,
+			   void (*handler)(adevinfo_t *));
+
+static inline int adeos_catch_event (unsigned event, void (*handler)(adevinfo_t *)) {
+    return adeos_catch_event_from(adp_current,event,handler);
+}
+
+static inline void adeos_propagate_event(adevinfo_t *evinfo) {
+
+    evinfo->propagate = 1;
+}
+
+void (*adeos_hook_dswitch(void (*handler)(void)))(void);
+
+void adeos_init_attr(adattr_t *attr);
+
+int adeos_get_sysinfo(adsysinfo_t *sysinfo);
+
+int adeos_tune_timer(unsigned long ns,
+		     int flags);
+
+int adeos_alloc_ptdkey(void);
+
+int adeos_free_ptdkey(int key);
+
+int adeos_set_ptd(int key,
+		  void *value);
+
+void *adeos_get_ptd(int key);
+
+unsigned long adeos_critical_enter(void (*syncfn)(void));
+
+void adeos_critical_exit(unsigned long flags);
+
+int adeos_init_mutex(admutex_t *mutex);
+
+int adeos_destroy_mutex(admutex_t *mutex);
+
+unsigned long fastcall adeos_lock_mutex(admutex_t *mutex);
+
+void fastcall adeos_unlock_mutex(admutex_t *mutex,
+				 unsigned long flags);
+
+static inline void adeos_set_printk_sync (adomain_t *adp) {
+    set_bit(ADEOS_SPRINTK_FLAG,&adp->flags);
+}
+
+static inline void adeos_set_printk_async (adomain_t *adp) {
+    clear_bit(ADEOS_SPRINTK_FLAG,&adp->flags);
+}
+
+#endif /* !__LINUX_ADEOS_H */
diff -uNrp linux-2.6.6-ia64/include/linux/init_task.h linux-2.6.6-ia64-adeos/include/linux/init_task.h
--- linux-2.6.6-ia64/include/linux/init_task.h	2004-06-17 11:50:35.000000000 +0200
+++ linux-2.6.6-ia64-adeos/include/linux/init_task.h	2004-06-17 11:50:51.000000000 +0200
@@ -64,6 +64,9 @@ extern struct group_info init_groups;
  *  INIT_TASK is used to set up the first task table, touch at
  * your own risk!. Base=0, limit=0x1fffff (=2MB)
  */
+
+#ifdef CONFIG_ADEOS_CORE
+
 #define INIT_TASK(tsk)	\
 {									\
 	.state		= 0,						\
@@ -112,8 +115,61 @@ extern struct group_info init_groups;
 	.proc_lock	= SPIN_LOCK_UNLOCKED,				\
 	.switch_lock	= SPIN_LOCK_UNLOCKED,				\
 	.journal_info	= NULL,						\
+        .ptd            = { [ 0 ... ADEOS_ROOT_NPTDKEYS - 1] = 0 }      \
 }
 
+#else /* !CONFIG_ADEOS_CORE */
+
+#define INIT_TASK(tsk)	\
+{									\
+	.state		= 0,						\
+	.thread_info	= &init_thread_info,				\
+	.usage		= ATOMIC_INIT(2),				\
+	.flags		= 0,						\
+	.lock_depth	= -1,						\
+	.prio		= MAX_PRIO-20,					\
+	.static_prio	= MAX_PRIO-20,					\
+	.policy		= SCHED_NORMAL,					\
+	.cpus_allowed	= CPU_MASK_ALL,					\
+	.mm		= NULL,						\
+	.active_mm	= &init_mm,					\
+	.run_list	= LIST_HEAD_INIT(tsk.run_list),			\
+	.time_slice	= HZ,						\
+	.tasks		= LIST_HEAD_INIT(tsk.tasks),			\
+	.ptrace_children= LIST_HEAD_INIT(tsk.ptrace_children),		\
+	.ptrace_list	= LIST_HEAD_INIT(tsk.ptrace_list),		\
+	.real_parent	= &tsk,						\
+	.parent		= &tsk,						\
+	.children	= LIST_HEAD_INIT(tsk.children),			\
+	.sibling	= LIST_HEAD_INIT(tsk.sibling),			\
+	.group_leader	= &tsk,						\
+	.wait_chldexit	= __WAIT_QUEUE_HEAD_INITIALIZER(tsk.wait_chldexit),\
+	.real_timer	= {						\
+		.function	= it_real_fn				\
+	},								\
+	.group_info	= &init_groups,					\
+	.cap_effective	= CAP_INIT_EFF_SET,				\
+	.cap_inheritable = CAP_INIT_INH_SET,				\
+	.cap_permitted	= CAP_FULL_SET,					\
+	.keep_capabilities = 0,						\
+	.rlim		= INIT_RLIMITS,					\
+	.user		= INIT_USER,					\
+	.comm		= "swapper",					\
+	.thread		= INIT_THREAD,					\
+	.fs		= &init_fs,					\
+	.files		= &init_files,					\
+	.signal		= &init_signals,				\
+	.sighand	= &init_sighand,				\
+	.pending	= {						\
+		.list = LIST_HEAD_INIT(tsk.pending.list),		\
+		.signal = {{0}}},					\
+	.blocked	= {{0}},					\
+	.alloc_lock	= SPIN_LOCK_UNLOCKED,				\
+	.proc_lock	= SPIN_LOCK_UNLOCKED,				\
+	.switch_lock	= SPIN_LOCK_UNLOCKED,				\
+	.journal_info	= NULL,						\
+}
 
+#endif /* CONFIG_ADEOS_CORE */
 
 #endif
diff -uNrp linux-2.6.6-ia64/include/linux/preempt.h linux-2.6.6-ia64-adeos/include/linux/preempt.h
--- linux-2.6.6-ia64/include/linux/preempt.h	2004-06-13 12:27:58.000000000 +0200
+++ linux-2.6.6-ia64-adeos/include/linux/preempt.h	2004-06-17 11:45:45.000000000 +0200
@@ -25,13 +25,54 @@ do { \
 
 asmlinkage void preempt_schedule(void);
 
+#ifdef CONFIG_ADEOS_CORE
+
+#include <asm/adeos.h>
+
+extern adomain_t *adp_cpu_current[],
+                 *adp_root;
+
 #define preempt_disable() \
 do { \
+   if (adp_current == adp_root) {	\
+       inc_preempt_count();						\
+       barrier();							\
+    }					\
+} while (0)
+
+#define preempt_enable_no_resched()		\
+do { \
+   if (adp_current == adp_root) {	\
+       dec_preempt_count();						\
+       barrier();							\
+   }									\
+} while (0)
+
+#define preempt_check_resched() \
+do { \
+   if (adp_current == adp_root) {	\
+       if (unlikely(test_thread_flag(TIF_NEED_RESCHED)))		\
+	   preempt_schedule();						\
+   }									\
+} while (0)
+
+#define preempt_enable() \
+do { \
+   if (adp_current == adp_root) {	\
+       preempt_enable_no_resched();					\
+       preempt_check_resched();						\
+   }									\
+} while (0)
+
+#else /* !CONFIG_ADEOS_CORE */
+
+#define preempt_disable()			\
+do { \
 	inc_preempt_count(); \
 	barrier(); \
 } while (0)
 
-#define preempt_enable_no_resched() \
+#define preempt_enable_no_resched()		\
 do { \
 	barrier(); \
 	dec_preempt_count(); \
@@ -49,7 +90,9 @@ do { \
 	preempt_check_resched(); \
 } while (0)
 
-#else
+#endif /* CONFIG_ADEOS_CORE */
+
+#else /* CONFIG_PREEMPT */
 
 #define preempt_disable()		do { } while (0)
 #define preempt_enable_no_resched()	do { } while (0)
diff -uNrp linux-2.6.6-ia64/include/linux/sched.h linux-2.6.6-ia64-adeos/include/linux/sched.h
--- linux-2.6.6-ia64/include/linux/sched.h	2004-06-17 11:19:12.000000000 +0200
+++ linux-2.6.6-ia64-adeos/include/linux/sched.h	2004-06-17 11:45:45.000000000 +0200
@@ -4,6 +4,9 @@
 #include <asm/param.h>	/* for HZ */
 
 #include <linux/config.h>
+#ifdef CONFIG_ADEOS_CORE
+#include <linux/adeos.h>
+#endif /* CONFIG_ADEOS_CORE */
 #include <linux/capability.h>
 #include <linux/threads.h>
 #include <linux/kernel.h>
@@ -504,6 +507,9 @@ struct task_struct {
 
 	unsigned long ptrace_message;
 	siginfo_t *last_siginfo; /* For ptrace use.  */
+#ifdef CONFIG_ADEOS_CORE
+        void *ptd[ADEOS_ROOT_NPTDKEYS];
+#endif /* CONFIG_ADEOS_CORE */
 };
 
 static inline pid_t process_group(struct task_struct *tsk)
diff -uNrp linux-2.6.6-ia64/init/main.c linux-2.6.6-ia64-adeos/init/main.c
--- linux-2.6.6-ia64/init/main.c	2004-06-13 12:57:06.000000000 +0200
+++ linux-2.6.6-ia64-adeos/init/main.c	2004-06-17 11:45:45.000000000 +0200
@@ -427,6 +427,9 @@ asmlinkage void __init start_kernel(void
 	trap_init();
 	rcu_init();
 	init_IRQ();
+#ifdef CONFIG_ADEOS_CORE
+ 	__adeos_init();
+#endif /* CONFIG_ADEOS_CORE */
 	pidhash_init();
 	sched_init();
 	softirq_init();
@@ -571,6 +574,12 @@ static void do_pre_smp_initcalls(void)
 	spawn_ksoftirqd();
 }
 
+static void foobar (adevinfo_t *ev)
+
+{
+    adeos_propagate_event(ev);
+}
+
 static void run_init_process(char *init_filename)
 {
 	argv_init[0] = init_filename;
@@ -605,6 +614,11 @@ static int init(void * unused)
 
 	do_basic_setup();
 
+ #ifdef CONFIG_ADEOS
+ 	__adeos_takeover();
+ 	adeos_catch_event(ADEOS_SYSCALL_PROLOGUE,&foobar);
+#endif /* CONFIG_ADEOS */
+
 	/*
 	 * check if there is an early userspace init.  If yes, let it do all
 	 * the work
diff -uNrp linux-2.6.6-ia64/kernel/Makefile linux-2.6.6-ia64-adeos/kernel/Makefile
--- linux-2.6.6-ia64/kernel/Makefile	2004-06-13 12:57:06.000000000 +0200
+++ linux-2.6.6-ia64-adeos/kernel/Makefile	2004-06-17 11:45:45.000000000 +0200
@@ -9,6 +9,7 @@ obj-y     = sched.o fork.o exec_domain.o
 	    rcupdate.o intermodule.o extable.o params.o posix-timers.o \
 	    kthread.o
 
+obj-$(CONFIG_ADEOS_CORE) += adeos.o
 obj-$(CONFIG_FUTEX) += futex.o
 obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
 obj-$(CONFIG_SMP) += cpu.o
diff -uNrp linux-2.6.6-ia64/kernel/adeos.c linux-2.6.6-ia64-adeos/kernel/adeos.c
--- linux-2.6.6-ia64/kernel/adeos.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.6-ia64-adeos/kernel/adeos.c	2004-06-17 11:46:40.000000000 +0200
@@ -0,0 +1,624 @@
+/*
+ *   linux/kernel/adeos.c
+ *
+ *   Copyright (C) 2002 Philippe Gerum.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ *   USA; either version 2 of the License, or (at your option) any later
+ *   version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *   Architecture-independent ADEOS core support.
+ */
+
+#include <linux/sched.h>
+#include <linux/module.h>
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#endif /* CONFIG_PROC_FS */
+
+/* The pre-defined domain slot for the root domain. */
+static adomain_t adeos_root_domain;
+
+/* A constant pointer to the root domain. */
+adomain_t *adp_root = &adeos_root_domain;
+
+/* A pointer to the current domain. */
+adomain_t *adp_cpu_current[ADEOS_NR_CPUS] = { [ 0 ... ADEOS_NR_CPUS - 1] = &adeos_root_domain };
+
+/* The spinlock protecting from races while modifying the pipeline. */
+spinlock_t __adeos_pipelock = SPIN_LOCK_UNLOCKED;
+
+/* The pipeline data structure. Enqueues adomain_t objects by priority. */
+struct list_head __adeos_pipeline;
+
+/* An array of global counters tracking domains monitoring events. */
+int __adeos_event_monitors[ADEOS_NR_EVENTS] = { [ 0 ... ADEOS_NR_EVENTS - 1] = 0 };
+
+/* The allocated VIRQ map. */
+unsigned long __adeos_virtual_irq_map = 0;
+
+/* A VIRQ to kick printk() output out when the root domain is in control. */
+unsigned __adeos_printk_virq;
+
+static void __adeos_set_root_ptd (int key, void *value) {
+
+    current->ptd[key] = value;
+}
+
+static void *__adeos_get_root_ptd (int key) {
+
+    return current->ptd[key];
+}
+
+/* adeos_init() -- Initialization routine of the ADEOS layer. Called
+   by the host kernel early during the boot procedure. */
+
+void __adeos_init (void)
+
+{
+    adomain_t *adp = &adeos_root_domain;
+
+    __adeos_check_machine();	/* Do platform dependent checks first. */
+
+    /*
+      A lightweight registration code for the root domain. Current
+      assumptions are:
+      - We are running on the boot CPU, and secondary CPUs are still
+      lost in space.
+      - adeos_root_domain has been zero'ed.
+    */
+
+    INIT_LIST_HEAD(&__adeos_pipeline);
+
+    adp->name = "Linux";
+    adp->domid = ADEOS_ROOT_ID;
+    adp->priority = ADEOS_ROOT_PRI;
+    adp->ptd_setfun = &__adeos_set_root_ptd;
+    adp->ptd_getfun = &__adeos_get_root_ptd;
+    adp->ptd_keymax = ADEOS_ROOT_NPTDKEYS;
+
+    __adeos_init_stage(adp);
+
+    INIT_LIST_HEAD(&adp->p_link);
+    list_add_tail(&adp->p_link,&__adeos_pipeline);
+
+    __adeos_printk_virq = adeos_alloc_irq(); /* Cannot fail here. */
+    adp->irqs[__adeos_printk_virq].handler = &__adeos_sync_console; 
+    adp->irqs[__adeos_printk_virq].acknowledge = NULL; 
+    adp->irqs[__adeos_printk_virq].control = IPIPE_HANDLE_MASK; 
+
+    printk(KERN_WARNING "Adeos %s: Root domain %s registered.\n",
+	   ADEOS_VERSION_STRING,
+	   adp->name);
+
+#ifdef adp_pipelined
+    /* If adp_pipelined is a macro, then Adeos's pipelining will
+       remain engaged during all Linux's lifetime. Therefore, take
+       over the box now and forever. Some archs/configurations do not
+       allow to take over the box this early, so this operation will
+       be postponed after the SMP boot procedure. */
+    __adeos_takeover();
+#endif /* adp_pipelined */
+}
+
+/* adeos_handle_event() -- Adeos' generic event handler. This routine
+calls the per-domain handlers registered for a given
+exception/event. Each domain before the one which raised the event in
+the pipeline will get a chance to process the event. The latter will
+eventually be allowed to process its own event too if a valid handler
+exists for it.  Handler executions are always scheduled by the domain
+which raised the event for the prioritary domains wanting to be
+notified of such event.  Note: evdata might be NULL. */
+
+int __adeos_handle_event (unsigned event, void *evdata)
+
+{
+    struct list_head *pos, *npos;
+    unsigned long flags;
+    adeos_declare_cpuid;
+    adevinfo_t evinfo;
+    int propagate = 1;
+
+    adeos_lock_cpu(flags);
+
+    list_for_each_safe(pos,npos,&__adeos_pipeline) {
+
+    	adomain_t *adp = list_entry(pos,adomain_t,p_link);
+
+	if (adp->events[event].handler != NULL)
+	    {
+	    if (adp == adp_cpu_current[cpuid])
+		{
+		evinfo.domid = adp->domid;
+		evinfo.event = event;
+		evinfo.evdata = evdata;
+		evinfo.propagate = 0;
+		adp->events[event].handler(&evinfo);
+		propagate = evinfo.propagate;
+		break;
+		}
+
+	    adp->cpudata[cpuid].event_info.domid = adp_cpu_current[cpuid]->domid;
+	    adp->cpudata[cpuid].event_info.event = event;
+	    adp->cpudata[cpuid].event_info.evdata = evdata;
+	    adp->cpudata[cpuid].event_info.propagate = 0;
+	    set_bit(IPIPE_XPEND_FLAG,&adp->cpudata[cpuid].status);
+
+	    /* Let the prioritary domain process the event. */
+	    __adeos_switch_to(adp,cpuid);
+	    
+#ifdef CONFIG_SMP
+	    adeos_load_cpuid();	/* Processor might have changed. */
+#endif /* CONFIG_SMP */
+
+	    if (!adp->cpudata[cpuid].event_info.propagate)
+		{
+		propagate = 0;
+		break;
+		}
+	    }
+
+	if (adp == adp_cpu_current[cpuid])
+	    break;
+    }
+
+    adeos_unlock_cpu(flags);
+
+    return !propagate;
+}
+
+void __adeos_stall_root (void)
+
+{
+    if (likely(adp_pipelined))
+	{
+	adeos_declare_cpuid;
+	unsigned long flags;
+
+	adeos_get_cpu(flags);
+	set_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status);
+	adeos_put_cpu(flags);
+	}
+    else
+	adeos_hw_cli();
+}
+
+void __adeos_unstall_root (void)
+
+{
+    adeos_hw_sti();	/* Absolutely needed. */
+
+    if (likely(adp_pipelined))
+	{
+	adeos_declare_cpuid;
+	unsigned long flags;
+
+	adeos_get_cpu(flags);
+
+	clear_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status);
+
+	if (adp_root->cpudata[cpuid].irq_pending_hi != 0)
+	    __adeos_sync_stage(IPIPE_IRQMASK_ANY);
+
+	adeos_put_cpu(flags);
+	}
+}
+
+asmlinkage void __adeos_unstall_iret_root (void)
+
+{
+    if (likely(adp_pipelined))
+	{
+	adeos_declare_cpuid;
+	unsigned long flags;
+
+	adeos_get_cpu(flags);
+
+	clear_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status);
+
+	/* Only sync virtual IRQs here, so that we don't recurse
+	   indefinitely in case of an external interrupt flood. */
+
+	if ((adp_root->cpudata[cpuid].irq_pending_hi & IPIPE_IRQMASK_VIRT) != 0)
+	    __adeos_sync_stage(IPIPE_IRQMASK_VIRT);
+
+	adeos_put_cpu(flags);
+	}
+}
+
+unsigned long __adeos_test_root (void)
+
+{
+    if (likely(adp_pipelined))
+	{
+	unsigned long flags, s;
+	adeos_declare_cpuid;
+
+	adeos_get_cpu(flags);
+
+	s = test_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status);
+
+	adeos_put_cpu(flags);
+
+	return s;
+	}
+
+    return adeos_hw_irqs_disabled();
+}
+
+unsigned long __adeos_test_and_stall_root (void)
+
+{
+    unsigned long flags;
+
+    if (likely(adp_pipelined))
+	{
+	unsigned long flags, s;
+	adeos_declare_cpuid;
+
+	adeos_get_cpu(flags);
+
+	s = test_and_set_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status);
+
+	adeos_put_cpu(flags);
+
+	return s;
+	}
+
+    adeos_hw_local_irq_save(flags);
+
+    return !adeos_hw_test_iflag(flags);
+}
+
+void fastcall __adeos_restore_root (unsigned long flags)
+
+{
+    if (likely(adp_pipelined))
+	{
+	unsigned long hwflags;
+	adeos_declare_cpuid;
+
+	adeos_get_cpu(hwflags);
+
+	if (flags)
+	    set_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status);
+	else
+	    {
+	    clear_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status);
+
+	    if (adp_root->cpudata[cpuid].irq_pending_hi != 0)
+		__adeos_sync_stage(IPIPE_IRQMASK_ANY);
+	    }
+
+	adeos_put_cpu(hwflags);
+	}
+    else if (flags)
+	adeos_hw_cli();
+    else
+	adeos_hw_sti();
+}
+
+/* adeos_suspend_domain() -- tell the ADEOS layer that the current
+   domain is now dormant. The calling domain is switched out, while
+   the next domain with work in progress or pending in the pipeline is
+   switched in. */
+
+#define __flush_pipeline_stage() \
+do { \
+    if (!test_bit(IPIPE_STALL_FLAG,&cpudata->status) && \
+	cpudata->irq_pending_hi != 0) \
+	{ \
+	__adeos_sync_stage(IPIPE_IRQMASK_ANY); \
+	adeos_load_cpuid(); \
+	cpudata = &adp->cpudata[cpuid]; \
+	} \
+    if (test_and_clear_bit(IPIPE_XPEND_FLAG,&cpudata->status)) \
+	adp->events[cpudata->event_info.event].handler(&cpudata->event_info); \
+} while(0)
+
+void adeos_suspend_domain (void)
+
+{
+    struct adcpudata *cpudata;
+    adomain_t *adp, *nadp;
+    struct list_head *ln;
+    unsigned long flags;
+    adeos_declare_cpuid;
+
+    adeos_lock_cpu(flags);
+    adp = nadp = adp_cpu_current[cpuid];
+    cpudata = &adp->cpudata[cpuid];
+
+    /* A suspending domain implicitely unstalls the pipeline. */
+    clear_bit(IPIPE_STALL_FLAG,&cpudata->status);
+
+    /* Make sure that no event remains stuck in the pipeline. This
+       could happen with emerging SMP instances, or domains which
+       forget to unstall their stage before calling us. */
+    __flush_pipeline_stage();
+
+    for (;;)
+	{
+	ln = nadp->p_link.next;
+
+	if (ln == &__adeos_pipeline)	/* End of pipeline reached? */
+	    /* Caller should loop on its idle task on return. */
+	    goto release_cpu_and_exit;
+
+	nadp = list_entry(ln,adomain_t,p_link);
+
+	/* Make sure the domain was preempted (i.e. not sleeping) or
+	   has some event to process before switching to it. */
+
+	if (!test_bit(IPIPE_SLEEP_FLAG,&nadp->cpudata[cpuid].status) ||
+	    (!test_bit(IPIPE_STALL_FLAG,&nadp->cpudata[cpuid].status) &&
+	     nadp->cpudata[cpuid].irq_pending_hi != 0) ||
+	    test_bit(IPIPE_XPEND_FLAG,&nadp->cpudata[cpuid].status))
+	    break;
+	}
+
+    /* Mark the outgoing domain as aslept (i.e. not preempted). */
+    set_bit(IPIPE_SLEEP_FLAG,&cpudata->status);
+
+    /* Suspend the calling domain, switching to the next one. */
+    __adeos_switch_to(nadp,cpuid);
+
+    /* Clear the sleep bit for the incoming domain (on the initial processor). */
+    clear_bit(IPIPE_SLEEP_FLAG,&cpudata->status);
+
+#ifdef CONFIG_SMP
+    adeos_load_cpuid();	/* Processor might have changed. */
+    cpudata = &adp->cpudata[cpuid];
+#endif /* CONFIG_SMP */
+
+    /* Now, we are back into the calling domain. Flush the interrupt
+       log and fire the event interposition handler if needed.  CPU
+       migration is allowed in SMP-mode on behalf of an event handler
+       provided that the current domain raised it. Otherwise, it's
+       not. */
+
+    __flush_pipeline_stage();
+
+release_cpu_and_exit:
+
+    adeos_unlock_cpu(flags);
+
+    /* Return to the point of suspension in the calling domain. */
+}
+
+/* adeos_alloc_irq() -- Allocate a virtual/soft pipelined interrupt.
+   Virtual interrupts are handled in exactly the same way than their
+   hw-generated counterparts. This is a very basic, one-way only,
+   inter-domain communication system (see adeos_trigger_irq()).  Note:
+   it is not necessary for a domain to allocate a virtual interrupt to
+   trap it using adeos_virtualize_irq(). The newly allocated VIRQ
+   number which can be passed to other IRQ-related services is
+   returned on success, zero otherwise (i.e. no more virtual interrupt
+   channel is available). We need this service as part of the Adeos
+   bootstrap code, hence it must reside in a built-in area. */
+
+unsigned adeos_alloc_irq (void)
+
+{
+    unsigned long flags, irq = 0;
+    int ipos;
+
+    adeos_spin_lock_irqsave(&__adeos_pipelock,flags);
+
+    if (__adeos_virtual_irq_map != ~0)
+	{
+	ipos = ffz(__adeos_virtual_irq_map);
+	set_bit(ipos,&__adeos_virtual_irq_map);
+	irq = ipos + IPIPE_VIRQ_BASE;
+	}
+
+    adeos_spin_unlock_irqrestore(&__adeos_pipelock,flags);
+
+    return irq;
+}
+
+#ifdef CONFIG_PROC_FS
+
+#include <linux/proc_fs.h>
+
+static struct proc_dir_entry *adeos_proc_entry;
+
+static int __adeos_read_proc (char *page,
+			      char **start,
+			      off_t off,
+			      int count,
+			      int *eof,
+			      void *data)
+{
+    unsigned long flags, ctlbits;
+    struct list_head *pos;
+    unsigned irq, _irq;
+    char *p = page;
+    int len;
+
+#ifdef CONFIG_ADEOS_MODULE
+    p += sprintf(p,"Adeos %s -- Pipelining: %s\n\n",ADEOS_VERSION_STRING,adp_pipelined ? "active" : "stopped");
+#else /* !CONFIG_ADEOS_MODULE */
+    p += sprintf(p,"Adeos %s -- Pipelining: permanent\n\n",ADEOS_VERSION_STRING);
+#endif /* CONFIG_ADEOS_MODULE */
+
+    adeos_hw_local_irq_save(flags);
+
+    list_for_each(pos,&__adeos_pipeline) {
+
+    	adomain_t *adp = list_entry(pos,adomain_t,p_link);
+
+	p += sprintf(p,"%8s: priority=%d, id=0x%.8x, ptdkeys=%d/%d\n",
+		     adp->name,
+		     adp->priority,
+		     adp->domid,
+		     adp->ptd_keycount,
+		     adp->ptd_keymax);
+	irq = 0;
+
+	while (irq < IPIPE_NR_IRQS)
+	    {
+	    ctlbits = (adp->irqs[irq].control & (IPIPE_HANDLE_MASK|IPIPE_PASS_MASK|IPIPE_STICKY_MASK));
+
+	    if (irq >= IPIPE_NR_XIRQS && !adeos_virtual_irq_p(irq))
+		{
+		/* There maybe a hole between the last external IRQ
+		   and the first virtual one; skip it. */
+		irq++;
+		continue;
+		}
+
+	    if (adeos_virtual_irq_p(irq) && !test_bit(irq - IPIPE_VIRQ_BASE,&__adeos_virtual_irq_map))
+		{
+		/* Non-allocated virtual IRQ; skip it. */
+		irq++;
+		continue;
+		}
+
+	    /* Attempt to group consecutive IRQ numbers having the
+	       same virtualization settings in a single line. */
+
+	    _irq = irq;
+
+	    while (++_irq < IPIPE_NR_IRQS)
+		{
+		if (adeos_virtual_irq_p(_irq) != adeos_virtual_irq_p(irq) ||
+		    (adeos_virtual_irq_p(_irq) && !test_bit(_irq - IPIPE_VIRQ_BASE,&__adeos_virtual_irq_map)) ||
+		    ctlbits != (adp->irqs[_irq].control & (IPIPE_HANDLE_MASK|IPIPE_PASS_MASK|IPIPE_STICKY_MASK)))
+		    break;
+		}
+
+	    if (_irq == irq + 1)
+		p += sprintf(p,"\tirq%u: ",irq);
+	    else
+		p += sprintf(p,"\tirq%u-%u: ",irq,_irq - 1);
+
+	    /* Statuses are as follows:
+	       o "accepted" means handled _and_ passed down the
+	       pipeline.
+	       o "grabbed" means handled, but the interrupt might be
+	       terminated _or_ passed down the pipeline depending on
+	       what the domain handler asks for to Adeos.
+	       o "passed" means unhandled by the domain but passed
+	       down the pipeline.
+	       o "discarded" means unhandled and _not_ passed down the
+	       pipeline. The interrupt merely disappears from the
+	       current domain down to the end of the pipeline. */
+
+	    if (ctlbits & IPIPE_HANDLE_MASK)
+		{
+		if (ctlbits & IPIPE_PASS_MASK)
+		    p += sprintf(p,"accepted");
+		else
+		    p += sprintf(p,"grabbed");
+		}
+	    else if (ctlbits & IPIPE_PASS_MASK)
+		p += sprintf(p,"passed");
+	    else
+		p += sprintf(p,"discarded");
+
+	    if (ctlbits & IPIPE_STICKY_MASK)
+		p += sprintf(p,", sticky");
+
+	    if (adeos_virtual_irq_p(irq))
+		p += sprintf(p,", virtual");
+
+	    p += sprintf(p,"\n");
+
+	    irq = _irq;
+	    }
+    }
+
+    adeos_hw_local_irq_restore(flags);
+
+    len = p - page;
+
+    if (len <= off + count)
+	*eof = 1;
+
+    *start = page + off;
+
+    len -= off;
+
+    if (len > count)
+	len = count;
+
+    if (len < 0)
+	len = 0;
+
+    return len;
+}
+
+void __adeos_init_proc (void) {
+
+    adeos_proc_entry = create_proc_read_entry("adeos",
+					      0444,
+					      NULL,
+					      &__adeos_read_proc,
+					      NULL);
+}
+
+#endif /* CONFIG_PROC_FS */
+
+void __adeos_dump_state (void)
+
+{
+    int _cpuid, nr_cpus = num_online_cpus();
+    struct list_head *pos;
+    unsigned long flags;
+    adeos_declare_cpuid;
+
+    adeos_lock_cpu(flags);
+
+    printk(KERN_WARNING "Adeos: Current domain=%s on CPU #%d [stackbase=%p]\n",
+	   adp_current->name,
+	   cpuid,
+	   (void *)adp_current->estackbase[cpuid]);
+
+    list_for_each(pos,&__adeos_pipeline) {
+
+        adomain_t *adp = list_entry(pos,adomain_t,p_link);
+
+        for (_cpuid = 0; _cpuid < nr_cpus; _cpuid++)
+            printk(KERN_WARNING "%8s[cpuid=%d]: priority=%d, status=0x%lx, pending_hi=0x%lx\n",
+                   adp->name,
+                   _cpuid,
+                   adp->priority,
+                   adp->cpudata[_cpuid].status,
+                   adp->cpudata[_cpuid].irq_pending_hi);
+    }
+
+    adeos_unlock_cpu(flags);
+}
+
+EXPORT_SYMBOL(adeos_suspend_domain);
+EXPORT_SYMBOL(adeos_alloc_irq);
+EXPORT_SYMBOL(adp_cpu_current);
+EXPORT_SYMBOL(adp_root);
+EXPORT_SYMBOL(__adeos_handle_event);
+EXPORT_SYMBOL(__adeos_unstall_root);
+EXPORT_SYMBOL(__adeos_stall_root);
+EXPORT_SYMBOL(__adeos_restore_root);
+EXPORT_SYMBOL(__adeos_test_and_stall_root);
+EXPORT_SYMBOL(__adeos_test_root);
+EXPORT_SYMBOL(__adeos_dump_state);
+EXPORT_SYMBOL(__adeos_pipeline);
+EXPORT_SYMBOL(__adeos_pipelock);
+EXPORT_SYMBOL(__adeos_virtual_irq_map);
+EXPORT_SYMBOL(__adeos_event_monitors);
+/* The following are convenience exports which are needed by some
+   Adeos domains loaded as kernel modules. */
+EXPORT_SYMBOL(__mmdrop);
+EXPORT_SYMBOL(do_fork);
+EXPORT_SYMBOL(do_exit);
diff -uNrp linux-2.6.6-ia64/kernel/exit.c linux-2.6.6-ia64-adeos/kernel/exit.c
--- linux-2.6.6-ia64/kernel/exit.c	2004-06-13 12:57:06.000000000 +0200
+++ linux-2.6.6-ia64-adeos/kernel/exit.c	2004-06-17 11:45:45.000000000 +0200
@@ -783,6 +783,9 @@ asmlinkage NORET_TYPE void do_exit(long 
 	}
 
 	acct_process(code);
+#ifdef CONFIG_ADEOS_CORE
+	__adeos_exit_process(tsk);
+#endif /* CONFIG_ADEOS_CORE */
 	__exit_mm(tsk);
 
 	exit_sem(tsk);
diff -uNrp linux-2.6.6-ia64/kernel/fork.c linux-2.6.6-ia64-adeos/kernel/fork.c
--- linux-2.6.6-ia64/kernel/fork.c	2004-06-13 12:57:06.000000000 +0200
+++ linux-2.6.6-ia64-adeos/kernel/fork.c	2004-06-17 11:45:45.000000000 +0200
@@ -1075,6 +1075,14 @@ struct task_struct *copy_process(unsigne
 
 	nr_threads++;
 	write_unlock_irq(&tasklist_lock);
+#ifdef CONFIG_ADEOS_CORE
+	{
+	int k;
+
+	for (k = 0; k < ADEOS_ROOT_NPTDKEYS; k++)
+	    p->ptd[k] = NULL;
+	}
+#endif /* CONFIG_ADEOS_CORE */
 	retval = 0;
 
 fork_out:
diff -uNrp linux-2.6.6-ia64/kernel/panic.c linux-2.6.6-ia64-adeos/kernel/panic.c
--- linux-2.6.6-ia64/kernel/panic.c	2004-06-13 12:30:04.000000000 +0200
+++ linux-2.6.6-ia64-adeos/kernel/panic.c	2004-06-17 11:45:45.000000000 +0200
@@ -66,6 +66,9 @@ NORET_TYPE void panic(const char * fmt, 
 		printk(KERN_EMERG "In idle task - not syncing\n");
 	else
 		sys_sync();
+#ifdef CONFIG_ADEOS_CORE
+	__adeos_dump_state();
+#endif /* CONFIG_ADEOS_CORE */
 	bust_spinlocks(0);
 
 #ifdef CONFIG_SMP
diff -uNrp linux-2.6.6-ia64/kernel/printk.c linux-2.6.6-ia64-adeos/kernel/printk.c
--- linux-2.6.6-ia64/kernel/printk.c	2004-06-17 11:19:12.000000000 +0200
+++ linux-2.6.6-ia64-adeos/kernel/printk.c	2004-06-17 11:45:45.000000000 +0200
@@ -33,6 +33,17 @@
 
 #include <asm/uaccess.h>
 
+#ifdef CONFIG_ADEOS_CORE
+#undef spin_lock_irq
+#define	spin_lock_irq(lock)                 adeos_spin_lock_disable(lock)
+#undef spin_unlock_irq
+#define	spin_unlock_irq(lock)               adeos_spin_unlock_enable(lock)
+#undef spin_lock_irqsave
+#define	spin_lock_irqsave(lock, flags)      adeos_spin_lock_irqsave(lock,flags)
+#undef spin_unlock_irqrestore
+#define spin_unlock_irqrestore(lock, flags) adeos_spin_unlock_irqrestore(lock,flags)
+#endif /* CONFIG_ADEOS_CORE */
+
 #define __LOG_BUF_LEN	(1 << CONFIG_LOG_BUF_SHIFT)
 
 /* printk's without a loglevel use this.. */
@@ -532,6 +543,24 @@ asmlinkage int printk(const char *fmt, .
 			log_level_unknown = 1;
 	}
 
+#ifdef CONFIG_ADEOS_CORE
+	if (adp_current != adp_root && !test_bit(ADEOS_SPRINTK_FLAG,&adp_current->flags)) {
+	    /* When operating in asynchronous printk() mode, ensure
+	       the console drivers and klogd wakeup are only run by
+	       Linux, delegating the actual output to the root domain
+	       by mean of a virtual IRQ kicking our sync handler. If
+	       the current domain has a lower priority than Linux,
+	       then we'll get immediately preempted by it. In
+	       synchronous printk() mode, immediately call the console
+	       drivers. */
+	    spin_unlock_irqrestore(&logbuf_lock, flags);
+
+	    if (!test_and_set_bit(ADEOS_PPRINTK_FLAG,&adp_root->flags))
+		adeos_trigger_irq(__adeos_printk_virq);
+
+	    goto out;
+	}
+#endif /* CONFIG_ADEOS_CORE */
 	if (!cpu_online(smp_processor_id()) &&
 	    system_state != SYSTEM_RUNNING) {
 		/*
@@ -543,7 +572,11 @@ asmlinkage int printk(const char *fmt, .
 		spin_unlock_irqrestore(&logbuf_lock, flags);
 		goto out;
 	}
-	if (!down_trylock(&console_sem)) {
+#ifdef CONFIG_ADEOS_CORE
+ 	if (adp_current != adp_root || !down_trylock(&console_sem)) {
+#else /* !CONFIG_ADEOS_CORE */
+ 	if (!down_trylock(&console_sem)) {
+#endif /* CONFIG_ADEOS_CORE */
 		console_locked = 1;
 		/*
 		 * We own the drivers.  We can drop the spinlock and let
@@ -622,6 +655,12 @@ void release_console_sem(void)
 	}
 	console_locked = 0;
 	console_may_schedule = 0;
+#ifdef CONFIG_ADEOS_CORE
+	if (adp_root != adp_current) {
+	    spin_unlock_irqrestore(&logbuf_lock, flags);
+	    return;
+	}
+#endif /* CONFIG_ADEOS_CORE */
 	up(&console_sem);
 	spin_unlock_irqrestore(&logbuf_lock, flags);
 	if (wake_klogd && !oops_in_progress && waitqueue_active(&log_wait))
@@ -629,6 +668,32 @@ void release_console_sem(void)
 }
 EXPORT_SYMBOL(release_console_sem);
 
+#ifdef CONFIG_ADEOS_CORE
+void __adeos_sync_console (unsigned virq) {
+
+    /* This handler always runs on behalf of the root (Linux) domain. */
+    unsigned long flags;
+
+    spin_lock_irqsave(&logbuf_lock, flags);
+
+    /* Not absolutely atomic wrt to the triggering point, but this is
+       harmless. We only try to reduce the useless triggers by a cheap
+       trick here. */
+
+    clear_bit(ADEOS_PPRINTK_FLAG,&adp_root->flags);
+
+    if (cpu_online(smp_processor_id()) &&
+	system_state == SYSTEM_RUNNING &&
+	!down_trylock(&console_sem)) {
+        console_locked = 1;
+	spin_unlock_irqrestore(&logbuf_lock, flags);
+        console_may_schedule = 0;
+	release_console_sem();
+    } else
+	spin_unlock_irqrestore(&logbuf_lock, flags);
+}
+#endif /* CONFIG_ADEOS_CORE */
+
 /** console_conditional_schedule - yield the CPU if required
  *
  * If the console code is currently allowed to sleep, and
diff -uNrp linux-2.6.6-ia64/kernel/sched.c linux-2.6.6-ia64-adeos/kernel/sched.c
--- linux-2.6.6-ia64/kernel/sched.c	2004-06-13 12:57:06.000000000 +0200
+++ linux-2.6.6-ia64-adeos/kernel/sched.c	2004-06-17 11:45:45.000000000 +0200
@@ -893,6 +893,10 @@ asmlinkage void schedule_tail(task_t *pr
 
 	if (current->set_child_tid)
 		put_user(current->pid, current->set_child_tid);
+
+#ifdef CONFIG_ADEOS_CORE
+	__adeos_enter_process();
+#endif /* CONFIG_ADEOS_CORE */
 }
 
 /*
@@ -1608,6 +1612,11 @@ asmlinkage void __sched schedule(void)
 	unsigned long run_time;
 	int idx;
 
+#ifdef CONFIG_ADEOS_CORE
+	if (adp_current != adp_root) /* Let's be helpful and	conservative. */
+	    return;
+#endif /* CONFIG_ADEOS_CORE */
+
 	/*
 	 * Test if we are atomic.  Since do_exit() needs to call into
 	 * schedule() atomically, we ignore that path for now.
@@ -1714,10 +1723,24 @@ switch_tasks:
 		rq->curr = next;
 		++*switch_count;
 
-		prepare_arch_switch(rq, next);
+#ifdef CONFIG_ADEOS_CORE
+		prepare_arch_switch(rq, prev, next);
+#else /* !CONFIG_ADEOS_CORE */
+  		prepare_arch_switch(rq, next);
+#endif /* CONFIG_ADEOS_CORE */
 		prev = context_switch(rq, prev, next);
 		barrier();
 
+#ifdef CONFIG_ADEOS_CORE
+		if (likely(adp_pipelined))
+		    adeos_hw_sti();
+
+		if (__adeos_schedule_tail(prev) > 0)
+		    /* Some event handler asked for a truncated
+		       scheduling tail. Just obey. */
+		    return;
+#endif /* CONFIG_ADEOS_CORE */
+
 		finish_task_switch(prev);
 	} else
 		spin_unlock_irq(&rq->lock);
@@ -1730,6 +1753,20 @@ switch_tasks:
 
 EXPORT_SYMBOL(schedule);
 
+#ifdef CONFIG_ADEOS_CORE
+
+void __adeos_schedule_back_root (struct task_struct *prev)
+
+{
+    finish_task_switch(prev);
+    reacquire_kernel_lock(current);
+    preempt_enable_no_resched();
+}
+
+EXPORT_SYMBOL(__adeos_schedule_back_root);
+
+#endif /* CONFIG_ADEOS_CORE */
+
 #ifdef CONFIG_PREEMPT
 /*
  * this is is the entry point to schedule() from in-kernel preemption
@@ -1740,6 +1777,15 @@ asmlinkage void __sched preempt_schedule
 {
 	struct thread_info *ti = current_thread_info();
 
+#ifdef CONFIG_ADEOS_CORE
+ 	/* The in-kernel preemption routine might be indirectly called
+ 	   from code running in other domains, so we must ensure that
+ 	   scheduling only takes place on behalf of the root (Linux)
+ 	   one. */
+	if (adp_current != adp_root)
+	    return;
+#endif /* CONFIG_ADEOS_CORE */
+
 	/*
 	 * If there is a non-zero preempt_count or interrupts are disabled,
 	 * we do not want to preempt the current task.  Just return..
@@ -2183,6 +2229,16 @@ static int setscheduler(pid_t pid, int p
 	if (retval)
 		goto out_unlock;
 
+#ifdef CONFIG_ADEOS_CORE
+	{
+	struct { struct task_struct *task; int policy; struct sched_param *param; } evdata = { p, policy, &lp };
+	if (__adeos_renice_process(&evdata))
+	    {
+	    retval = 0;
+	    goto out_unlock;
+	    }
+	}
+#endif /* CONFIG_ADEOS_CORE */
 	array = p->array;
 	if (array)
 		deactivate_task(p, task_rq(p));
diff -uNrp linux-2.6.6-ia64/kernel/signal.c linux-2.6.6-ia64-adeos/kernel/signal.c
--- linux-2.6.6-ia64/kernel/signal.c	2004-06-13 12:57:06.000000000 +0200
+++ linux-2.6.6-ia64-adeos/kernel/signal.c	2004-06-17 11:45:45.000000000 +0200
@@ -556,6 +556,13 @@ void signal_wake_up(struct task_struct *
 
 	set_tsk_thread_flag(t, TIF_SIGPENDING);
 
+#ifdef CONFIG_ADEOS_CORE
+	{
+	struct { struct task_struct *t; } evdata = { t };
+	__adeos_kick_process(&evdata);
+	}
+#endif /* CONFIG_ADEOS_CORE */
+
 	/*
 	 * If resume is set, we want to wake it up in the TASK_STOPPED case.
 	 * We don't check for TASK_STOPPED because there is a race with it
@@ -781,6 +788,17 @@ specific_send_sig_info(int sig, struct s
 		BUG();
 #endif
 
+#ifdef CONFIG_ADEOS_CORE
+	/* If some domain handler in the pipeline doesn't ask for
+	   propagation, return success pretending that 'sig' was
+	   delivered. */
+	{
+	struct { struct task_struct *task; int sig; } evdata = { t, sig };
+	if (__adeos_signal_process(&evdata))
+	    goto out;
+	}
+#endif /* CONFIG_ADEOS_CORE */
+
 	if (((unsigned long)info > 2) && (info->si_code == SI_TIMER))
 		/*
 		 * Set up a return to indicate that we dropped the signal.
diff -uNrp linux-2.6.6-ia64/kernel/sysctl.c linux-2.6.6-ia64-adeos/kernel/sysctl.c
--- linux-2.6.6-ia64/kernel/sysctl.c	2004-06-13 12:57:06.000000000 +0200
+++ linux-2.6.6-ia64-adeos/kernel/sysctl.c	2004-06-17 11:45:45.000000000 +0200
@@ -915,6 +915,9 @@ void __init sysctl_init(void)
 #ifdef CONFIG_PROC_FS
 	register_proc_table(root_table, proc_sys_root);
 	init_irq_proc();
+#ifdef CONFIG_ADEOS_CORE
+	__adeos_init_proc();
+#endif /* CONFIG_ADEOS_CORE */
 #endif
 }
 
