diff -uNrp linux-2.6.12/Makefile linux-2.6.12-ipipe-0.6/Makefile
--- linux-2.6.12/Makefile	2005-06-17 21:48:29.000000000 +0200
+++ linux-2.6.12-ipipe-0.6/Makefile	2005-06-19 11:38:37.000000000 +0200
@@ -564,6 +564,8 @@ export MODLIB
 ifeq ($(KBUILD_EXTMOD),)
 core-y		+= kernel/ mm/ fs/ ipc/ security/ crypto/
 
+core-$(CONFIG_IPIPE) += ipipe/
+
 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.12/arch/i386/Kconfig linux-2.6.12-ipipe-0.6/arch/i386/Kconfig
--- linux-2.6.12/arch/i386/Kconfig	2005-06-17 21:48:29.000000000 +0200
+++ linux-2.6.12-ipipe-0.6/arch/i386/Kconfig	2005-06-19 11:38:45.000000000 +0200
@@ -534,6 +534,8 @@ config PREEMPT_BKL
 	  Say Y here if you are building a kernel for a desktop system.
 	  Say N if you are unsure.
 
+source "ipipe/Kconfig"
+
 config X86_UP_APIC
 	bool "Local APIC support on uniprocessors"
 	depends on !SMP && !(X86_VISWS || X86_VOYAGER)
@@ -941,7 +943,6 @@ config SECCOMP
 
 endmenu
 
-
 menu "Power management options (ACPI, APM)"
 	depends on !X86_VOYAGER
 
diff -uNrp linux-2.6.12/arch/i386/kernel/Makefile linux-2.6.12-ipipe-0.6/arch/i386/kernel/Makefile
--- linux-2.6.12/arch/i386/kernel/Makefile	2005-06-17 21:48:29.000000000 +0200
+++ linux-2.6.12-ipipe-0.6/arch/i386/kernel/Makefile	2005-06-19 11:38:45.000000000 +0200
@@ -11,6 +11,7 @@ obj-y	:= process.o semaphore.o signal.o 
 
 obj-y				+= cpu/
 obj-y				+= timers/
+obj-$(CONFIG_IPIPE_CORE)	+= ipipe.o
 obj-$(CONFIG_ACPI_BOOT)		+= acpi/
 obj-$(CONFIG_X86_BIOS_REBOOT)	+= reboot.o
 obj-$(CONFIG_MCA)		+= mca.o
diff -uNrp linux-2.6.12/arch/i386/kernel/apic.c linux-2.6.12-ipipe-0.6/arch/i386/kernel/apic.c
--- linux-2.6.12/arch/i386/kernel/apic.c	2005-06-17 21:48:29.000000000 +0200
+++ linux-2.6.12-ipipe-0.6/arch/i386/kernel/apic.c	2005-06-19 11:38:45.000000000 +0200
@@ -62,7 +62,7 @@ void ack_bad_irq(unsigned int irq)
 	 * unexpected vectors occur) that might lock up the APIC
 	 * completely.
 	 */
-	ack_APIC_irq();
+	__ack_APIC_irq();
 }
 
 void __init apic_intr_init(void)
@@ -1161,6 +1161,10 @@ inline void smp_local_timer_interrupt(st
 fastcall void smp_apic_timer_interrupt(struct pt_regs *regs)
 {
 	int cpu = smp_processor_id();
+#ifdef CONFIG_IPIPE_CORE
+        if (ipipe_running)
+	    regs =  __ipipe_tick_regs + cpu;
+#endif /* CONFIG_IPIPE_CORE */
 
 	/*
 	 * the NMI deadlock-detector uses this.
@@ -1197,7 +1201,7 @@ fastcall void smp_spurious_interrupt(str
 	 */
 	v = apic_read(APIC_ISR + ((SPURIOUS_APIC_VECTOR & ~0x1f) >> 1));
 	if (v & (1 << (SPURIOUS_APIC_VECTOR & 0x1f)))
-		ack_APIC_irq();
+		__ack_APIC_irq();
 
 	/* see sw-dev-man vol 3, chapter 7.4.13.5 */
 	printk(KERN_INFO "spurious APIC interrupt on CPU#%d, should never happen.\n",
diff -uNrp linux-2.6.12/arch/i386/kernel/entry.S linux-2.6.12-ipipe-0.6/arch/i386/kernel/entry.S
--- linux-2.6.12/arch/i386/kernel/entry.S	2005-06-17 21:48:29.000000000 +0200
+++ linux-2.6.12-ipipe-0.6/arch/i386/kernel/entry.S	2005-06-19 11:38:45.000000000 +0200
@@ -75,11 +75,27 @@ DF_MASK		= 0x00000400 
 NT_MASK		= 0x00004000
 VM_MASK		= 0x00020000
 
+#ifdef CONFIG_IPIPE_CORE
+#define CLI                     call __ipipe_stall_root
+#define STI                     call __ipipe_unstall_root
+#define FIXUP_ROOT_IF           call __ipipe_if_fixup_root ; movl ORIG_EAX(%esp),%eax
+#define EMULATE_ROOT_IRET	call __ipipe_unstall_iret_root ; movl EAX(%esp),%eax
+#define TEST_PREEMPTIBLE(regs)  call __ipipe_kpreempt_root ; testl %eax,%eax
+#define restore_nocheck         .ipipe_unstall_and_restore_nocheck
+#else  /* !CONFIG_IPIPE_CORE */
+#define CLI                     cli
+#define STI                     sti
+#define FIXUP_ROOT_IF
+#define EMULATE_ROOT_IRET
+#define TEST_PREEMPTIBLE(regs)  testl $IF_MASK,EFLAGS(regs)
+#define restore_nmi             restore_all
+#endif /* CONFIG_IPIPE_CORE */
+
 #ifdef CONFIG_PREEMPT
-#define preempt_stop		cli
+#define preempt_stop	  CLI
 #else
 #define preempt_stop
-#define resume_kernel		restore_nocheck
+#define resume_kernel	  restore_nocheck
 #endif
 
 #define SAVE_ALL \
@@ -141,14 +157,14 @@ ENTRY(ret_from_fork)
 	ALIGN
 ret_from_exception:
 	preempt_stop
-ret_from_intr:
+ENTRY(ret_from_intr)
 	GET_THREAD_INFO(%ebp)
 	movl EFLAGS(%esp), %eax		# mix EFLAGS and CS
 	movb CS(%esp), %al
 	testl $(VM_MASK | 3), %eax
 	jz resume_kernel
 ENTRY(resume_userspace)
- 	cli				# make sure we don't miss an interrupt
+	CLI				# make sure we don't miss an interrupt
 					# setting need_resched or sigpending
 					# between sampling and the iret
 	movl TI_flags(%ebp), %ecx
@@ -159,14 +175,14 @@ ENTRY(resume_userspace)
 
 #ifdef CONFIG_PREEMPT
 ENTRY(resume_kernel)
-	cli
+	CLI
 	cmpl $0,TI_preempt_count(%ebp)	# non-zero preempt_count ?
 	jnz restore_nocheck
 need_resched:
 	movl TI_flags(%ebp), %ecx	# need_resched set ?
 	testb $_TIF_NEED_RESCHED, %cl
 	jz restore_all
-	testl $IF_MASK,EFLAGS(%esp)     # interrupts off (exception path) ?
+	TEST_PREEMPTIBLE(%esp)		# interrupts off (exception path) ?
 	jz restore_all
 	call preempt_schedule_irq
 	jmp need_resched
@@ -200,6 +216,7 @@ sysenter_past_esp:
 
 	pushl %eax
 	SAVE_ALL
+	FIXUP_ROOT_IF
 	GET_THREAD_INFO(%ebp)
 
 	/* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */
@@ -209,11 +226,12 @@ sysenter_past_esp:
 	jae syscall_badsys
 	call *sys_call_table(,%eax,4)
 	movl %eax,EAX(%esp)
-	cli
+	CLI
 	movl TI_flags(%ebp), %ecx
 	testw $_TIF_ALLWORK_MASK, %cx
 	jne syscall_exit_work
 /* if something modifies registers it must also disable sysexit */
+	EMULATE_ROOT_IRET
 	movl EIP(%esp), %edx
 	movl OLDESP(%esp), %ecx
 	xorl %ebp,%ebp
@@ -225,6 +243,7 @@ sysenter_past_esp:
 ENTRY(system_call)
 	pushl %eax			# save orig_eax
 	SAVE_ALL
+	FIXUP_ROOT_IF
 	GET_THREAD_INFO(%ebp)
 					# system call tracing in operation
 	/* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */
@@ -236,7 +255,7 @@ syscall_call:
 	call *sys_call_table(,%eax,4)
 	movl %eax,EAX(%esp)		# store the return value
 syscall_exit:
-	cli				# make sure we don't miss an interrupt
+ 	CLI				# make sure we don't miss an interrupt
 					# setting need_resched or sigpending
 					# between sampling and the iret
 	movl TI_flags(%ebp), %ecx
@@ -253,7 +272,15 @@ restore_all:
 	andl $(VM_MASK | (4 << 8) | 3), %eax
 	cmpl $((4 << 8) | 3), %eax
 	je ldt_ss			# returning to user-space with LDT SS
+#ifdef CONFIG_IPIPE_CORE
+.ipipe_unstall_and_restore_nocheck:
+	call __ipipe_unstall_iret_root
+restore_nmi:
+	# FIXME: we need to check for a return to
+	# user-space on a 16bit stack even in the NMI case
+#else /* !CONFIG_IPIPE_CORE */
 restore_nocheck:
+#endif /* CONFIG_IPIPE_CORE */
 	RESTORE_REGS
 	addl $4, %esp
 1:	iret
@@ -301,7 +328,7 @@ work_pending:
 	jz work_notifysig
 work_resched:
 	call schedule
-	cli				# make sure we don't miss an interrupt
+	CLI				# make sure we don't miss an interrupt
 					# setting need_resched or sigpending
 					# between sampling and the iret
 	movl TI_flags(%ebp), %ecx
@@ -348,7 +375,7 @@ syscall_trace_entry:
 syscall_exit_work:
 	testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP), %cl
 	jz work_pending
-	sti				# could let do_syscall_trace() call
+	STI				# could let do_syscall_trace() call
 					# schedule() instead
 	movl %esp, %eax
 	movl $1, %edx
@@ -399,7 +426,11 @@ ENTRY(interrupt)
 
 vector=0
 ENTRY(irq_entries_start)
+#ifdef CONFIG_IPIPE_CORE
+.rept 224
+#else
 .rept NR_IRQS
+#endif
 	ALIGN
 1:	pushl $vector-256
 	jmp common_interrupt
@@ -424,6 +455,36 @@ ENTRY(name)				\
 	call smp_/**/name;		\
 	jmp ret_from_intr;
 
+#ifdef CONFIG_IPIPE_CORE
+
+.data
+ENTRY(__ipipe_irq_trampolines)
+.text
+
+vector=0
+ENTRY(__ipipe_irq_entries)
+.rept 224
+	ALIGN
+1:	pushl $vector-256
+	jmp __ipipe_irq_common
+.data
+	.long 1b
+.text
+vector=vector+1
+.endr
+
+	ALIGN
+__ipipe_irq_common:
+	SAVE_ALL
+	call __ipipe_handle_irq
+	testl %eax,%eax
+	jnz  ret_from_intr
+	RESTORE_REGS
+	addl $4, %esp
+	iret	
+
+#endif /* CONFIG_IPIPE_CORE */
+	
 /* The include is where all of the SMP etc. interrupts come from */
 #include "entry_arch.h"
 
@@ -455,6 +516,7 @@ error_code:
 	movl %ecx, %es
 	movl %esp,%eax			# pt_regs pointer
 	call *%edi
+	FIXUP_ROOT_IF
 	jmp ret_from_exception
 
 ENTRY(coprocessor_error)
@@ -470,6 +532,7 @@ ENTRY(simd_coprocessor_error)
 ENTRY(device_not_available)
 	pushl $-1			# mark this as an int
 	SAVE_ALL
+	FIXUP_ROOT_IF
 	movl %cr0, %eax
 	testl $0x4, %eax		# EM (math emulation bit)
 	jne device_not_available_emulate
@@ -511,6 +574,7 @@ ENTRY(debug)
 debug_stack_correct:
 	pushl $-1			# mark this as an int
 	SAVE_ALL
+	FIXUP_ROOT_IF
 	xorl %edx,%edx			# error code 0
 	movl %esp,%eax			# pt_regs pointer
 	call do_debug
@@ -549,7 +613,7 @@ nmi_stack_correct:
 	xorl %edx,%edx		# zero error code
 	movl %esp,%eax		# pt_regs pointer
 	call do_nmi
-	jmp restore_all
+	jmp restore_nmi
 
 nmi_stack_fixup:
 	FIX_STACK(12,nmi_stack_correct, 1)
@@ -591,6 +655,7 @@ nmi_16bit_stack:
 ENTRY(int3)
 	pushl $-1			# mark this as an int
 	SAVE_ALL
+	FIXUP_ROOT_IF
 	xorl %edx,%edx		# zero error code
 	movl %esp,%eax		# pt_regs pointer
 	call do_int3
diff -uNrp linux-2.6.12/arch/i386/kernel/i386_ksyms.c linux-2.6.12-ipipe-0.6/arch/i386/kernel/i386_ksyms.c
--- linux-2.6.12/arch/i386/kernel/i386_ksyms.c	2005-06-17 21:48:29.000000000 +0200
+++ linux-2.6.12-ipipe-0.6/arch/i386/kernel/i386_ksyms.c	2005-06-19 11:38:45.000000000 +0200
@@ -36,6 +36,25 @@
 extern void dump_thread(struct pt_regs *, struct user *);
 extern spinlock_t rtc_lock;
 
+#ifdef CONFIG_IPIPE_CORE
+#ifdef CONFIG_IPIPE_MODULE
+extern int __ipipe_irq_trampolines;
+EXPORT_SYMBOL(__ipipe_irq_trampolines);
+#ifdef CONFIG_X86_LOCAL_APIC
+extern int using_apic_timer;
+EXPORT_SYMBOL(using_apic_timer);
+#endif /* CONFIG_X86_LOCAL_APIC */
+extern struct desc_struct idt_table[];
+EXPORT_SYMBOL(idt_table);
+#ifdef CONFIG_X86_IO_APIC
+EXPORT_SYMBOL(io_apic_irqs);
+EXPORT_SYMBOL(irq_vector);
+#endif /* CONFIG_X86_IO_APIC */
+#endif /* CONFIG_IPIPE_MODULE */
+extern irq_desc_t irq_desc[];
+EXPORT_SYMBOL(irq_desc);
+#endif /* CONFIG_IPIPE_CORE */
+
 /* This is definitely a GPL-only symbol */
 EXPORT_SYMBOL_GPL(cpu_gdt_table);
 
diff -uNrp linux-2.6.12/arch/i386/kernel/i8259.c linux-2.6.12-ipipe-0.6/arch/i386/kernel/i8259.c
--- linux-2.6.12/arch/i386/kernel/i8259.c	2005-06-17 21:48:29.000000000 +0200
+++ linux-2.6.12-ipipe-0.6/arch/i386/kernel/i8259.c	2005-06-19 11:38:45.000000000 +0200
@@ -170,6 +170,36 @@ static inline int i8259A_irq_real(unsign
  */
 static void mask_and_ack_8259A(unsigned int irq)
 {
+#ifdef CONFIG_IPIPE_CORE
+	unsigned int irqmask = 1 << irq;
+
+	spin_lock(&i8259A_lock);
+
+	if (cached_irq_mask & irqmask)
+		goto spurious_8259A_irq;
+
+	if (irq == 0) {
+	    /* Fast timer ack -- don't mask
+	      (unless supposedly spurious) */
+	    outb(0x20,PIC_MASTER_CMD);
+	    spin_unlock(&i8259A_lock);
+	    return;
+	}
+
+	cached_irq_mask |= irqmask;
+
+handle_real_irq:
+	if (irq & 8) {
+		outb(cached_slave_mask, PIC_SLAVE_IMR);
+		outb(0x60+(irq&7),PIC_SLAVE_CMD);/* 'Specific EOI' to slave */
+		outb(0x60+PIC_CASCADE_IR,PIC_MASTER_CMD); /* 'Specific EOI' to master-IRQ2 */
+	} else {
+		outb(cached_master_mask, PIC_MASTER_IMR);
+		outb(0x60+irq,PIC_MASTER_CMD);	/* 'Specific EOI to master */
+	}
+	spin_unlock(&i8259A_lock);
+	return;
+#else /* !CONFIG_IPIPE_CORE */
 	unsigned int irqmask = 1 << irq;
 	unsigned long flags;
 
@@ -206,6 +236,7 @@ handle_real_irq:
 	}
 	spin_unlock_irqrestore(&i8259A_lock, flags);
 	return;
+#endif /* CONFIG_IPIPE_CORE */
 
 spurious_8259A_irq:
 	/*
diff -uNrp linux-2.6.12/arch/i386/kernel/io_apic.c linux-2.6.12-ipipe-0.6/arch/i386/kernel/io_apic.c
--- linux-2.6.12/arch/i386/kernel/io_apic.c	2005-06-17 21:48:29.000000000 +0200
+++ linux-2.6.12-ipipe-0.6/arch/i386/kernel/io_apic.c	2005-06-19 11:38:45.000000000 +0200
@@ -1828,6 +1828,26 @@ static unsigned int startup_edge_ioapic_
  * interrupt for real. This prevents IRQ storms from unhandled
  * devices.
  */
+
+#ifdef CONFIG_IPIPE_CORE
+
+static void ack_edge_ioapic_irq (unsigned irq)
+
+{
+    move_irq(irq);
+    if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED)) == (IRQ_PENDING | IRQ_DISABLED))
+	{
+	unsigned long flags;
+	spin_lock_irqsave_hw(&ioapic_lock,flags);
+	__mask_IO_APIC_irq(irq);
+	spin_unlock_irqrestore_hw(&ioapic_lock,flags);
+	}
+
+    __ack_APIC_irq();
+}
+
+#else /* !CONFIG_IPIPE_CORE */
+
 static void ack_edge_ioapic_irq(unsigned int irq)
 {
 	move_irq(irq);
@@ -1837,6 +1857,8 @@ static void ack_edge_ioapic_irq(unsigned
 	ack_APIC_irq();
 }
 
+#endif /* CONFIG_IPIPE_CORE */
+
 /*
  * Level triggered interrupts can just be masked,
  * and shutting down and starting up the interrupt
@@ -1858,6 +1880,70 @@ static unsigned int startup_level_ioapic
 	return 0; /* don't check for pending */
 }
 
+#ifdef CONFIG_IPIPE_CORE
+
+/* Prevent low priority IRQs grabbed by high priority domains from
+   being delayed, waiting for a high priority interrupt handler
+   running in a low priority domain to complete. */
+
+static unsigned long bugous_edge_triggers;
+
+static void end_level_ioapic_irq (unsigned irq)
+
+{
+    move_irq(irq);
+
+    spin_lock(&ioapic_lock);
+
+    if (test_and_clear_bit(irq,&bugous_edge_triggers))
+	{
+	atomic_inc(&irq_mis_count);
+	__unmask_and_level_IO_APIC_irq(irq);
+	}
+    else
+	__unmask_IO_APIC_irq(irq);
+
+    spin_unlock(&ioapic_lock);
+}
+
+static void mask_and_ack_level_ioapic_irq (unsigned irq)
+
+{
+    unsigned long v;
+    int i;
+
+    i = IO_APIC_VECTOR(irq);
+    v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1));
+
+    spin_lock(&ioapic_lock);
+
+    if (!(v & (1 << (i & 0x1f))))
+	{
+	set_bit(irq,&bugous_edge_triggers);
+	__mask_and_edge_IO_APIC_irq(irq);
+	}
+    else
+	__mask_IO_APIC_irq(irq);
+
+    spin_unlock(&ioapic_lock);
+
+    __ack_APIC_irq();
+}
+
+#ifdef CONFIG_PCI_MSI
+
+static inline void mask_and_ack_level_ioapic_vector(unsigned int vector)
+
+{
+	int irq = vector_to_irq(vector);
+
+	mask_and_ack_level_ioapic_irq(irq);
+}
+
+#endif /* CONFIG_PCI_MSI */
+
+#else /* !CONFIG_IPIPE_CORE */
+
 static void end_level_ioapic_irq (unsigned int irq)
 {
 	unsigned long v;
@@ -1898,6 +1984,8 @@ static void end_level_ioapic_irq (unsign
 	}
 }
 
+#endif /* CONFIG_IPIPE_CORE */
+
 #ifdef CONFIG_PCI_MSI
 static unsigned int startup_edge_ioapic_vector(unsigned int vector)
 {
@@ -2035,7 +2123,7 @@ static void disable_lapic_irq (unsigned 
 
 static void ack_lapic_irq (unsigned int irq)
 {
-	ack_APIC_irq();
+	__ack_APIC_irq();
 }
 
 static void end_lapic_irq (unsigned int i) { /* nothing */ }
diff -uNrp linux-2.6.12/arch/i386/kernel/ipipe.c linux-2.6.12-ipipe-0.6/arch/i386/kernel/ipipe.c
--- linux-2.6.12/arch/i386/kernel/ipipe.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.12-ipipe-0.6/arch/i386/kernel/ipipe.c	2005-06-19 17:24:44.000000000 +0200
@@ -0,0 +1,647 @@
+/*   -*- linux-c -*-
+ *   linux/arch/i386/kernel/ipipe.c
+ *
+ *   Copyright (C) 2002-2005 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 I-PIPE core support for x86.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/smp.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <asm/system.h>
+#include <asm/atomic.h>
+#include <asm/hw_irq.h>
+#include <asm/irq.h>
+#include <asm/desc.h>
+#include <asm/io.h>
+#ifdef CONFIG_X86_LOCAL_APIC
+#include <asm/fixmap.h>
+#include <asm/bitops.h>
+#include <asm/mpspec.h>
+#ifdef CONFIG_X86_IO_APIC
+#include <asm/io_apic.h>
+#endif	/* CONFIG_X86_IO_APIC */
+#include <asm/apic.h>
+#include <mach_ipi.h>
+#endif	/* CONFIG_X86_LOCAL_APIC */
+
+struct pt_regs __ipipe_tick_regs[IPIPE_NR_CPUS];
+
+int __ipipe_tick_irq;
+
+#ifdef CONFIG_SMP
+
+static cpumask_t __ipipe_cpu_sync_map;
+
+static cpumask_t __ipipe_cpu_lock_map;
+
+static raw_spinlock_t __ipipe_cpu_barrier = RAW_SPIN_LOCK_UNLOCKED;
+
+static atomic_t __ipipe_critical_count = ATOMIC_INIT(0);
+
+static void (*__ipipe_cpu_sync) (void);
+
+#endif	/* CONFIG_SMP */
+
+#define __ipipe_call_asm_irq_handler(ipd,irq) \
+   __asm__ __volatile__ ("pushfl\n\t" \
+                         "push %%cs\n\t" \
+                         "call *%1\n" \
+			 : /* no output */ \
+			 : "a" (irq), "m" ((ipd)->irqs[irq].handler))
+
+#define __ipipe_call_c_root_irq_handler(ipd,irq) \
+   __asm__ __volatile__ ("pushfl\n\t" \
+                         "pushl %%cs\n\t" \
+                         "pushl $1f\n\t" \
+	                 "pushl $-1\n\t" \
+	                 "pushl %%es\n\t" \
+	                 "pushl %%ds\n\t" \
+	                 "pushl %%eax\n\t" \
+	                 "pushl %%ebp\n\t" \
+	                 "pushl %%edi\n\t" \
+	                 "pushl %%esi\n\t" \
+	                 "pushl %%edx\n\t" \
+	                 "pushl %%ecx\n\t" \
+	                 "pushl %%ebx\n\t" \
+                         "pushl %%eax\n\t" \
+                         "call *%1\n\t" \
+			 "addl $4,%%esp\n\t" \
+	                 "jmp ret_from_intr\n\t" \
+	                 "1:\n" \
+			 : /* no output */ \
+			 : "a" (irq), "m" ((ipd)->irqs[irq].handler))
+
+/* Do _not_ forcibly re-enable hw IRQs in the following trampoline
+   used for non-root domains; unlike Linux handlers, non-root domain
+   handlers are fully in control of the hw masking state. */
+
+#define __ipipe_call_c_irq_handler(ipd,irq) \
+   __asm__ __volatile__ ("pushl %%ebp\n\t" \
+	                 "pushl %%edi\n\t" \
+                      	 "pushl %%esi\n\t" \
+	                 "pushl %%edx\n\t" \
+                         "pushl %%ecx\n\t" \
+	                 "pushl %%ebx\n\t" \
+                         "pushl %%eax\n\t" \
+                         "call *%1\n\t" \
+                         "addl $4,%%esp\n\t" \
+                         "popl %%ebx\n\t" \
+                         "popl %%ecx\n\t" \
+	                 "popl %%edx\n\t" \
+	                 "popl %%esi\n\t" \
+	                 "popl %%edi\n\t" \
+	                 "popl %%ebp\n" \
+			 : /* no output */ \
+			 : "a" (irq), "m" ((ipd)->irqs[irq].handler))
+
+static __inline__ unsigned long flnz(unsigned long word)
+{
+      __asm__("bsrl %1, %0":"=r"(word)
+      :	"r"(word));
+	return word;
+}
+
+int __ipipe_ack_system_irq(unsigned irq)
+{
+#ifdef CONFIG_X86_LOCAL_APIC
+	__ack_APIC_irq();
+#endif	/* CONFIG_X86_LOCAL_APIC */
+	return 1;
+}
+
+#ifdef CONFIG_SMP
+
+/* Always called with hw interrupts off. */
+
+static void __ipipe_do_critical_sync(unsigned irq)
+{
+	ipipe_declare_cpuid;
+
+	ipipe_load_cpuid();
+
+	cpu_set(cpuid, __ipipe_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. */
+	spin_lock_hw(&__ipipe_cpu_barrier);
+
+	/* Got it. Now get out. */
+
+	if (__ipipe_cpu_sync)
+		/* Call the sync routine if any. */
+		__ipipe_cpu_sync();
+
+	spin_unlock_hw(&__ipipe_cpu_barrier);
+
+	cpu_clear(cpuid, __ipipe_cpu_sync_map);
+}
+
+#endif	/* CONFIG_SMP */
+
+/* ipipe_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. */
+
+unsigned long ipipe_critical_enter(void (*syncfn) (void))
+{
+	unsigned long flags;
+
+	local_irq_save_hw(flags);
+
+#ifdef CONFIG_SMP
+	if (num_online_cpus() > 1) {	/* We might be running a SMP-kernel on a UP box... */
+		ipipe_declare_cpuid;
+		cpumask_t lock_map;
+
+		ipipe_load_cpuid();
+
+		if (!cpu_test_and_set(cpuid, __ipipe_cpu_lock_map)) {
+			while (cpu_test_and_set
+			       (BITS_PER_LONG - 1, __ipipe_cpu_lock_map)) {
+				int n = 0;
+				do {
+					cpu_relax();
+				} while (++n < cpuid);
+			}
+
+			spin_lock_hw(&__ipipe_cpu_barrier);
+
+			__ipipe_cpu_sync = syncfn;
+
+			/* Send the sync IPI to all processors but the current one. */
+			send_IPI_allbutself(IPIPE_CRITICAL_VECTOR);
+
+			cpus_andnot(lock_map, cpu_online_map,
+				    __ipipe_cpu_lock_map);
+
+			while (!cpus_equal(__ipipe_cpu_sync_map, lock_map))
+				cpu_relax();
+		}
+
+		atomic_inc(&__ipipe_critical_count);
+	}
+#endif	/* CONFIG_SMP */
+
+	return flags;
+}
+
+/* ipipe_critical_exit() -- Release the superlock. */
+
+void ipipe_critical_exit(unsigned long flags)
+{
+#ifdef CONFIG_SMP
+	if (num_online_cpus() > 1) {	/* We might be running a SMP-kernel on a UP box... */
+		ipipe_declare_cpuid;
+
+		ipipe_load_cpuid();
+
+		if (atomic_dec_and_test(&__ipipe_critical_count)) {
+			spin_unlock_hw(&__ipipe_cpu_barrier);
+
+			while (!cpus_empty(__ipipe_cpu_sync_map))
+				cpu_relax();
+
+			cpu_clear(cpuid, __ipipe_cpu_lock_map);
+			cpu_clear(BITS_PER_LONG - 1, __ipipe_cpu_lock_map);
+		}
+	}
+#endif	/* CONFIG_SMP */
+
+	local_irq_restore_hw(flags);
+}
+
+void __ipipe_init_stage(struct ipipe_domain *ipd)
+{
+	int cpuid, n;
+
+	for (cpuid = 0; cpuid < IPIPE_NR_CPUS; cpuid++) {
+		ipd->cpudata[cpuid].irq_pending_hi = 0;
+
+		for (n = 0; n < IPIPE_IRQ_IWORDS; n++)
+			ipd->cpudata[cpuid].irq_pending_lo[n] = 0;
+
+		for (n = 0; n < IPIPE_NR_IRQS; n++)
+			ipd->cpudata[cpuid].irq_hits[n] = 0;
+	}
+
+	for (n = 0; n < IPIPE_NR_IRQS; n++) {
+		ipd->irqs[n].acknowledge = NULL;
+		ipd->irqs[n].handler = NULL;
+		ipd->irqs[n].control = IPIPE_PASS_MASK;	/* Pass but don't handle */
+	}
+
+#ifdef CONFIG_SMP
+	ipd->irqs[IPIPE_CRITICAL_IPI].acknowledge = &__ipipe_ack_system_irq;
+	ipd->irqs[IPIPE_CRITICAL_IPI].handler = &__ipipe_do_critical_sync;
+	/* Immediately handle in the current domain but *never* pass */
+	ipd->irqs[IPIPE_CRITICAL_IPI].control =
+	    IPIPE_HANDLE_MASK | IPIPE_STICKY_MASK | IPIPE_SYSTEM_MASK;
+#endif	/* CONFIG_SMP */
+}
+
+/* __ipipe_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. This routine must be called with hw
+   interrupts off. */
+
+void fastcall __ipipe_sync_stage(unsigned long syncmask)
+{
+	unsigned long mask, submask;
+	struct ipcpudata *cpudata;
+	struct ipipe_domain *ipd;
+	int level, rank, sync;
+	ipipe_declare_cpuid;
+	unsigned irq;
+
+	ipipe_load_cpuid();
+	ipd = ipipe_percpu_domain[cpuid];
+	cpudata = &ipd->cpudata[cpuid];
+
+	sync = __test_and_set_bit(IPIPE_SYNC_FLAG, &cpudata->status);
+
+	/* 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 (test_bit(IPIPE_LOCK_FLAG, &ipd->irqs[irq].control)) {
+				__clear_bit(rank,
+					    &cpudata->irq_pending_lo[level]);
+				continue;
+			}
+
+			if (--cpudata->irq_hits[irq] == 0)
+				__clear_bit(rank,
+					    &cpudata->irq_pending_lo[level]);
+
+			__set_bit(IPIPE_STALL_FLAG, &cpudata->status);
+
+			if (ipd == ipipe_root_domain) {
+				/* Make sure to re-enable hw interrupts to reduce
+				   preemption latency by higher priority domains when
+				   calling the Linux handlers in the next two
+				   trampolines. Additionally, this ensures that the
+				   forged interrupt frame will allow the final check
+				   for a rescheduling opportunity in ret_from_intr. */
+
+				local_irq_enable_hw();
+
+				if (!test_bit
+				    (IPIPE_CALLASM_FLAG,
+				     &ipd->irqs[irq].control)) {
+					irq_enter();
+					__ipipe_call_c_root_irq_handler(ipd,irq);
+					irq_exit();
+				} else
+					__ipipe_call_asm_irq_handler(ipd, irq);
+			} else
+				__ipipe_call_c_irq_handler(ipd, irq);
+
+			local_irq_disable_hw();
+
+#ifdef CONFIG_SMP
+			{
+				int _cpuid = ipipe_processor_id();
+
+				if (_cpuid != cpuid) {	/* Handle CPU migration. */
+					/* We expect any domain to clear the SYNC bit each
+					   time it switches in a new task, so that preemptions
+					   and/or CPU migrations (in the SMP case) over the
+					   ISR do not lock out the log syncer for some
+					   indefinite amount of time. In the Linux case,
+					   schedule() handles this (see kernel/sched.c). For
+					   this reason, we don't bother clearing it here for
+					   the source CPU in the migration handling case,
+					   since it must have scheduled another task in by
+					   now. */
+					cpuid = _cpuid;
+					cpudata = &ipd->cpudata[cpuid];
+					__set_bit(IPIPE_SYNC_FLAG,
+						  &cpudata->status);
+				}
+			}
+#endif	/* CONFIG_SMP */
+
+			__clear_bit(IPIPE_STALL_FLAG, &cpudata->status);
+		}
+	}
+
+	if (!sync)
+		__clear_bit(IPIPE_SYNC_FLAG, &cpudata->status);
+}
+
+/* __ipipe_walk_pipeline(): Plays interrupts pending in the log. Must
+   be called with local hw interrupts disabled. */
+
+static inline void __ipipe_walk_pipeline(struct list_head *pos, int cpuid)
+{
+	struct ipipe_domain *this_domain = ipipe_percpu_domain[cpuid];
+
+	while (pos != &__ipipe_pipeline) {
+		struct ipipe_domain *next_domain =
+		    list_entry(pos, struct ipipe_domain, p_link);
+
+		if (test_bit
+		    (IPIPE_STALL_FLAG, &next_domain->cpudata[cpuid].status))
+			break;	/* Stalled stage -- do not go further. */
+
+		if (next_domain->cpudata[cpuid].irq_pending_hi != 0) {
+
+			if (next_domain == this_domain)
+				__ipipe_sync_stage(IPIPE_IRQMASK_ANY);
+			else {
+				__ipipe_switch_to(this_domain, next_domain,
+						  cpuid);
+
+				ipipe_load_cpuid();	/* Processor might have changed. */
+
+				if (this_domain->cpudata[cpuid].
+				    irq_pending_hi != 0
+				    && !test_bit(IPIPE_STALL_FLAG,
+						 &this_domain->cpudata[cpuid].
+						 status)
+				    && !test_bit(IPIPE_SYNC_FLAG,
+						 &this_domain->cpudata[cpuid].
+						 status))
+					__ipipe_sync_stage(IPIPE_IRQMASK_ANY);
+			}
+
+			break;
+		} else if (next_domain == this_domain)
+			break;
+
+		pos = next_domain->p_link.next;
+	}
+}
+
+/* __ipipe_handle_irq() -- IPIPE's generic IRQ handler. An optimistic
+   interrupt protection log is maintained here for each domain.  Hw
+   interrupts are off on entry. */
+
+int __ipipe_handle_irq(struct pt_regs regs)
+{
+	int hw_gen = regs.orig_eax < 0, m_ack = !hw_gen, s_ack;
+	unsigned irq = regs.orig_eax & 0xff;
+	struct list_head *head, *pos;
+	struct ipipe_domain *this_domain;
+	ipipe_declare_cpuid;
+
+	ipipe_load_cpuid();
+
+	this_domain = ipipe_percpu_domain[cpuid];
+
+	s_ack = m_ack;
+
+	if (test_bit(IPIPE_STICKY_FLAG, &this_domain->irqs[irq].control))
+		head = &this_domain->p_link;
+	else
+		head = __ipipe_pipeline.next;
+
+	/* Ack the interrupt. */
+
+	pos = head;
+
+	while (pos != &__ipipe_pipeline) {
+		struct ipipe_domain *next_domain =
+		    list_entry(pos, struct ipipe_domain, p_link);
+
+		/* For each domain handling the incoming IRQ, mark it as
+		   pending in its log. */
+
+		if (test_bit
+		    (IPIPE_HANDLE_FLAG, &next_domain->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. */
+
+			next_domain->cpudata[cpuid].irq_hits[irq]++;
+			__ipipe_set_irq_bit(next_domain, 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 = next_domain->irqs[irq].acknowledge(irq);
+			else if (test_bit
+				 (IPIPE_SHARED_FLAG,
+				  &next_domain->irqs[irq].control) && !s_ack)
+				s_ack = next_domain->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, &next_domain->irqs[irq].control))
+			break;
+
+		pos = next_domain->p_link.next;
+	}
+
+	if (irq == __ipipe_tick_irq) {
+		__ipipe_tick_regs[cpuid].eflags = regs.eflags;
+		__ipipe_tick_regs[cpuid].eip = regs.eip;
+		__ipipe_tick_regs[cpuid].xcs = regs.xcs;
+#if defined(CONFIG_SMP) && defined(CONFIG_FRAME_POINTER)
+		/* Linux profiling code needs this. */
+		__ipipe_tick_regs[cpuid].ebp = regs.ebp;
+#endif	/* CONFIG_SMP && CONFIG_FRAME_POINTER */
+	}
+
+	/* 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. */
+
+	__ipipe_walk_pipeline(head, cpuid);
+
+	ipipe_load_cpuid();
+
+	if (ipipe_percpu_domain[cpuid] != ipipe_root_domain ||
+	    test_bit(IPIPE_STALL_FLAG,
+		     &ipipe_root_domain->cpudata[cpuid].status))
+		return 0;
+
+#ifdef CONFIG_SMP
+	/* Prevent a spurious rescheduling from being triggered on
+	   preemptible kernels along the way out through ret_from_intr. */
+	if (hw_gen)
+		__set_bit(IPIPE_STALL_FLAG, &ipipe_root_domain->cpudata[cpuid].status);
+#endif	/* CONFIG_SMP */
+
+	return 1;
+}
+
+/* ipipe_trigger_irq() -- Push the interrupt at front of the pipeline
+   just like if it has been actually received from a hw source. Also
+   works for virtual interrupts. */
+
+int fastcall ipipe_trigger_irq(unsigned irq)
+{
+	struct pt_regs regs;
+	unsigned long flags;
+
+	if (irq >= IPIPE_NR_IRQS ||
+	    (ipipe_virtual_irq_p(irq) &&
+	     !test_bit(irq - IPIPE_VIRQ_BASE, &__ipipe_virtual_irq_map)))
+		return -EINVAL;
+
+	local_irq_save_hw(flags);
+
+	regs.orig_eax = irq;	/* Won't be acked */
+	regs.xcs = __KERNEL_CS;
+	regs.eflags = flags;
+
+	__ipipe_handle_irq(regs);
+
+	local_irq_restore_hw(flags);
+
+	return 1;
+}
+
+static inline void __fixup_if(struct pt_regs *regs)
+{
+	ipipe_declare_cpuid;
+	unsigned long flags;
+
+	ipipe_get_cpu(flags);
+
+	if (ipipe_percpu_domain[cpuid] == ipipe_root_domain) {
+		/* Have the saved hw state look like the domain stall bit, so
+		   that __ipipe_unstall_iret_root() restores the proper
+		   pipeline state for the root stage upon exit. */
+
+		if (test_bit
+		    (IPIPE_STALL_FLAG,
+		     &ipipe_root_domain->cpudata[cpuid].status))
+			regs->eflags &= ~X86_EFLAGS_IF;
+		else
+			regs->eflags |= X86_EFLAGS_IF;
+	}
+
+	ipipe_put_cpu(flags);
+}
+
+asmlinkage void __ipipe_if_fixup_root(struct pt_regs regs)
+{
+	if (ipipe_running)
+		__fixup_if(&regs);
+}
+
+/*  Check the interrupt flag to make sure the existing preemption
+    opportunity upon in-kernel resumption could be exploited. If
+    pipelining is active, the stall bit of the root domain is checked,
+    otherwise, the EFLAGS register from the stacked interrupt frame is
+    tested. In case a rescheduling could take place in pipelined mode,
+    the root stage is stalled before the hw interrupts are
+    re-enabled. This routine must be called with hw interrupts off. */
+
+asmlinkage int __ipipe_kpreempt_root(struct pt_regs regs)
+{
+	ipipe_declare_cpuid;
+	unsigned long flags;
+
+	if (!ipipe_running)
+		return !!(regs.eflags & X86_EFLAGS_IF);
+
+	ipipe_get_cpu(flags);
+
+	if (test_bit
+	    (IPIPE_STALL_FLAG, &ipipe_root_domain->cpudata[cpuid].status)) {
+		ipipe_put_cpu(flags);
+		return 0;	/* Root stage is stalled: rescheduling denied. */
+	}
+
+	__ipipe_stall_root();
+	local_irq_enable_hw();
+
+	return 1;		/* Ok, may reschedule now. */
+}
+
+asmlinkage void __ipipe_unstall_iret_root(struct pt_regs regs)
+{
+	ipipe_declare_cpuid;
+
+	if (!ipipe_running)
+		return;
+
+	/* Emulate IRET's handling of the interrupt flag. */
+
+	local_irq_disable_hw();
+
+	ipipe_load_cpuid();
+
+	/* Restore the software state as it used to be on kernel
+	   entry. CAUTION: NMIs must *not* return through this
+	   emulation. */
+
+	if (!(regs.eflags & X86_EFLAGS_IF)) {
+		__set_bit(IPIPE_STALL_FLAG,
+			  &ipipe_root_domain->cpudata[cpuid].status);
+		regs.eflags |= X86_EFLAGS_IF;
+	} else {
+		__clear_bit(IPIPE_STALL_FLAG,
+			    &ipipe_root_domain->cpudata[cpuid].status);
+
+		/* Only sync virtual IRQs here, so that we don't recurse
+		   indefinitely in case of an external interrupt flood. */
+
+		if ((ipipe_root_domain->cpudata[cpuid].
+		     irq_pending_hi & IPIPE_IRQMASK_VIRT) != 0)
+			__ipipe_sync_stage(IPIPE_IRQMASK_VIRT);
+	}
+}
+
+EXPORT_SYMBOL(__ipipe_init_stage);
+EXPORT_SYMBOL(__ipipe_sync_stage);
+EXPORT_SYMBOL(__ipipe_ack_system_irq);
+EXPORT_SYMBOL(__ipipe_handle_irq);
+EXPORT_SYMBOL(__ipipe_tick_irq);
+EXPORT_SYMBOL(ipipe_critical_enter);
+EXPORT_SYMBOL(ipipe_critical_exit);
+EXPORT_SYMBOL(ipipe_trigger_irq);
diff -uNrp linux-2.6.12/arch/i386/kernel/process.c linux-2.6.12-ipipe-0.6/arch/i386/kernel/process.c
--- linux-2.6.12/arch/i386/kernel/process.c	2005-06-17 21:48:29.000000000 +0200
+++ linux-2.6.12-ipipe-0.6/arch/i386/kernel/process.c	2005-06-19 11:38:45.000000000 +0200
@@ -161,6 +161,7 @@ void cpu_idle (void)
 				idle = default_idle;
 
 			__get_cpu_var(irq_stat).idle_timestamp = jiffies;
+ 			ipipe_suspend_domain();
 			idle();
 		}
 		schedule();
diff -uNrp linux-2.6.12/arch/i386/kernel/smp.c linux-2.6.12-ipipe-0.6/arch/i386/kernel/smp.c
--- linux-2.6.12/arch/i386/kernel/smp.c	2005-06-17 21:48:29.000000000 +0200
+++ linux-2.6.12-ipipe-0.6/arch/i386/kernel/smp.c	2005-06-19 11:38:45.000000000 +0200
@@ -131,6 +131,9 @@ void __send_IPI_shortcut(unsigned int sh
 	 * to the APIC.
 	 */
 	unsigned int cfg;
+	unsigned long flags;
+
+	local_irq_save_hw_cond(flags);
 
 	/*
 	 * Wait for idle.
@@ -146,6 +149,8 @@ void __send_IPI_shortcut(unsigned int sh
 	 * Send the IPI. The write to APIC_ICR fires this off.
 	 */
 	apic_write_around(APIC_ICR, cfg);
+
+	local_irq_restore_hw_cond(flags);
 }
 
 void fastcall send_IPI_self(int vector)
@@ -162,7 +167,7 @@ void send_IPI_mask_bitmask(cpumask_t cpu
 	unsigned long cfg;
 	unsigned long flags;
 
-	local_irq_save(flags);
+	local_irq_save_hw(flags);
 		
 	/*
 	 * Wait for idle.
@@ -185,7 +190,7 @@ void send_IPI_mask_bitmask(cpumask_t cpu
 	 */
 	apic_write_around(APIC_ICR, cfg);
 
-	local_irq_restore(flags);
+	local_irq_restore_hw(flags);
 }
 
 void send_IPI_mask_sequence(cpumask_t mask, int vector)
@@ -199,7 +204,7 @@ void send_IPI_mask_sequence(cpumask_t ma
 	 * should be modified to do 1 message per cluster ID - mbligh
 	 */ 
 
-	local_irq_save(flags);
+	local_irq_save_hw(flags);
 
 	for (query_cpu = 0; query_cpu < NR_CPUS; ++query_cpu) {
 		if (cpu_isset(query_cpu, mask)) {
@@ -226,7 +231,7 @@ void send_IPI_mask_sequence(cpumask_t ma
 			apic_write_around(APIC_ICR, cfg);
 		}
 	}
-	local_irq_restore(flags);
+	local_irq_restore_hw(flags);
 }
 
 #include <mach_ipi.h> /* must come after the send_IPI functions above for inlining */
@@ -310,7 +315,9 @@ static inline void leave_mm (unsigned lo
 
 fastcall void smp_invalidate_interrupt(struct pt_regs *regs)
 {
-	unsigned long cpu;
+    	unsigned long cpu, flags;
+
+	local_irq_save_hw_cond(flags);
 
 	cpu = get_cpu();
 
@@ -340,6 +347,7 @@ fastcall void smp_invalidate_interrupt(s
 	smp_mb__after_clear_bit();
 out:
 	put_cpu_no_resched();
+	local_irq_restore_hw_cond(flags);
 }
 
 static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
@@ -400,14 +408,19 @@ void flush_tlb_current_task(void)
 {
 	struct mm_struct *mm = current->mm;
 	cpumask_t cpu_mask;
+	unsigned long flags;
 
 	preempt_disable();
+	local_irq_save_hw_cond(flags);
+
 	cpu_mask = mm->cpu_vm_mask;
 	cpu_clear(smp_processor_id(), cpu_mask);
 
 	local_flush_tlb();
 	if (!cpus_empty(cpu_mask))
 		flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
+
+	local_irq_restore_hw_cond(flags);
 	preempt_enable();
 }
 
@@ -435,8 +448,11 @@ void flush_tlb_page(struct vm_area_struc
 {
 	struct mm_struct *mm = vma->vm_mm;
 	cpumask_t cpu_mask;
+	unsigned long flags;
 
 	preempt_disable();
+	local_irq_save_hw_cond(flags);
+
 	cpu_mask = mm->cpu_vm_mask;
 	cpu_clear(smp_processor_id(), cpu_mask);
 
@@ -447,6 +463,8 @@ void flush_tlb_page(struct vm_area_struc
 		 	leave_mm(smp_processor_id());
 	}
 
+	local_irq_restore_hw_cond(flags);
+
 	if (!cpus_empty(cpu_mask))
 		flush_tlb_others(cpu_mask, mm, va);
 
@@ -609,4 +627,3 @@ fastcall void smp_call_function_interrup
 		atomic_inc(&call_data->finished);
 	}
 }
-
diff -uNrp linux-2.6.12/arch/i386/kernel/time.c linux-2.6.12-ipipe-0.6/arch/i386/kernel/time.c
--- linux-2.6.12/arch/i386/kernel/time.c	2005-06-17 21:48:29.000000000 +0200
+++ linux-2.6.12-ipipe-0.6/arch/i386/kernel/time.c	2005-06-19 11:38:45.000000000 +0200
@@ -258,11 +258,12 @@ static inline void do_timer_interrupt(in
 		 * This will also deassert NMI lines for the watchdog if run
 		 * on an 82489DX-based system.
 		 */
-		spin_lock(&i8259A_lock);
+		unsigned long flags;
+		spin_lock_irqsave_hw_cond(&i8259A_lock,flags);
 		outb(0x0c, PIC_MASTER_OCW3);
 		/* Ack the IRQ; AEOI will end it automatically. */
 		inb(PIC_MASTER_POLL);
-		spin_unlock(&i8259A_lock);
+		spin_unlock_irqrestore_hw_cond(&i8259A_lock,flags);
 	}
 #endif
 
diff -uNrp linux-2.6.12/arch/i386/kernel/traps.c linux-2.6.12-ipipe-0.6/arch/i386/kernel/traps.c
--- linux-2.6.12/arch/i386/kernel/traps.c	2005-06-17 21:48:29.000000000 +0200
+++ linux-2.6.12-ipipe-0.6/arch/i386/kernel/traps.c	2005-06-19 11:38:45.000000000 +0200
@@ -226,6 +226,11 @@ void show_registers(struct pt_regs *regs
 		regs->esi, regs->edi, regs->ebp, esp);
 	printk("ds: %04x   es: %04x   ss: %04x\n",
 		regs->xds & 0xffff, regs->xes & 0xffff, ss);
+#ifdef CONFIG_IPIPE_CORE
+	if (ipipe_current_domain != ipipe_root_domain)
+	    printk("I-pipe domain %s",ipipe_current_domain->name);
+	else
+#endif /* CONFIG_IPIPE_CORE */
 	printk("Process %s (pid: %d, threadinfo=%p task=%p)",
 		current->comm, current->pid, current_thread_info(), current);
 	/*
@@ -946,12 +951,15 @@ asmlinkage void math_state_restore(struc
 {
 	struct thread_info *thread = current_thread_info();
 	struct task_struct *tsk = thread->task;
+	unsigned long flags;
 
+	local_irq_save_hw_cond(flags);
 	clts();		/* Allow maths ops (or we recurse) */
 	if (!tsk_used_math(tsk))
 		init_fpu(tsk);
 	restore_fpu(tsk);
 	thread->status |= TS_USEDFPU;	/* So we fnsave on switch_to() */
+	local_irq_restore_hw_cond(flags);
 }
 
 #ifndef CONFIG_MATH_EMULATION
diff -uNrp linux-2.6.12/arch/i386/mm/fault.c linux-2.6.12-ipipe-0.6/arch/i386/mm/fault.c
--- linux-2.6.12/arch/i386/mm/fault.c	2005-06-17 21:48:29.000000000 +0200
+++ linux-2.6.12-ipipe-0.6/arch/i386/mm/fault.c	2005-06-19 11:38:45.000000000 +0200
@@ -224,6 +224,8 @@ fastcall void do_page_fault(struct pt_re
 	/* get the address */
 	__asm__("movl %%cr2,%0":"=r" (address));
 
+	local_irq_enable_hw_cond();
+
 	if (notify_die(DIE_PAGE_FAULT, "page fault", regs, error_code, 14,
 					SIGSEGV) == NOTIFY_STOP)
 		return;
diff -uNrp linux-2.6.12/arch/i386/mm/ioremap.c linux-2.6.12-ipipe-0.6/arch/i386/mm/ioremap.c
--- linux-2.6.12/arch/i386/mm/ioremap.c	2005-06-17 21:48:29.000000000 +0200
+++ linux-2.6.12-ipipe-0.6/arch/i386/mm/ioremap.c	2005-06-19 11:38:45.000000000 +0200
@@ -16,6 +16,7 @@
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
 #include <asm/pgtable.h>
+#include <asm/pgalloc.h>
 
 #define ISA_START_ADDRESS	0xa0000
 #define ISA_END_ADDRESS		0x100000
@@ -92,6 +93,7 @@ static int ioremap_page_range(unsigned l
 		err = ioremap_pud_range(pgd, addr, next, phys_addr+addr, flags);
 		if (err)
 			break;
+		set_pgdir(addr, *pgd);
 	} while (pgd++, addr = next, addr != end);
 	spin_unlock(&init_mm.page_table_lock);
 	flush_tlb_all();
diff -uNrp linux-2.6.12/include/asm-i386/apic.h linux-2.6.12-ipipe-0.6/include/asm-i386/apic.h
--- linux-2.6.12/include/asm-i386/apic.h	2005-06-17 21:48:29.000000000 +0200
+++ linux-2.6.12-ipipe-0.6/include/asm-i386/apic.h	2005-06-19 11:38:45.000000000 +0200
@@ -69,7 +69,13 @@ int get_physical_broadcast(void);
 # define apic_write_around(x,y) apic_write_atomic((x),(y))
 #endif
 
+#ifdef CONFIG_IPIPE_CORE
+#define ack_APIC_irq() do { if (!ipipe_running) __ack_APIC_irq(); } while(0)
+static inline void __ack_APIC_irq(void)
+#else /* !CONFIG_IPIPE_CORE */
+#define __ack_APIC_irq() ack_APIC_irq()
 static inline void ack_APIC_irq(void)
+#endif /* CONFIG_IPIPE_CORE */
 {
 	/*
 	 * ack_APIC_irq() actually gets compiled as a single instruction:
diff -uNrp linux-2.6.12/include/asm-i386/io_apic.h linux-2.6.12-ipipe-0.6/include/asm-i386/io_apic.h
--- linux-2.6.12/include/asm-i386/io_apic.h	2005-06-17 21:48:29.000000000 +0200
+++ linux-2.6.12-ipipe-0.6/include/asm-i386/io_apic.h	2005-06-19 11:38:45.000000000 +0200
@@ -16,7 +16,9 @@
 #ifdef CONFIG_PCI_MSI
 static inline int use_pci_vector(void)	{return 1;}
 static inline void disable_edge_ioapic_vector(unsigned int vector) { }
+#ifndef CONFIG_IPIPE_CORE
 static inline void mask_and_ack_level_ioapic_vector(unsigned int vector) { }
+#endif /* !CONFIG_IPIPE_CORE */
 static inline void end_edge_ioapic_vector (unsigned int vector) { }
 #define startup_level_ioapic	startup_level_ioapic_vector
 #define shutdown_level_ioapic	mask_IO_APIC_vector
@@ -35,7 +37,9 @@ static inline void end_edge_ioapic_vecto
 #else
 static inline int use_pci_vector(void)	{return 0;}
 static inline void disable_edge_ioapic_irq(unsigned int irq) { }
+#ifndef CONFIG_IPIPE_CORE
 static inline void mask_and_ack_level_ioapic_irq(unsigned int irq) { }
+#endif /* !CONFIG_IPIPE_CORE */
 static inline void end_edge_ioapic_irq (unsigned int irq) { }
 #define startup_level_ioapic	startup_level_ioapic_irq
 #define shutdown_level_ioapic	mask_IO_APIC_irq
diff -uNrp linux-2.6.12/include/asm-i386/ipipe.h linux-2.6.12-ipipe-0.6/include/asm-i386/ipipe.h
--- linux-2.6.12/include/asm-i386/ipipe.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.12-ipipe-0.6/include/asm-i386/ipipe.h	2005-06-19 19:36:17.000000000 +0200
@@ -0,0 +1,309 @@
+/*   -*- linux-c -*-
+ *   include/asm-i386/ipipe.h
+ *
+ *   Copyright (C) 2002-2005 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 __I386_IPIPE_H
+#define __I386_IPIPE_H
+
+#include <irq_vectors.h>
+#include <asm/ptrace.h>
+#include <linux/cpumask.h>
+#include <linux/list.h>
+#include <linux/threads.h>
+
+#define IPIPE_ARCH_STRING   "0.6-00/x86"
+#define IPIPE_MAJOR_NUMBER  0
+#define IPIPE_MINOR_NUMBER  6
+#define IPIPE_PATCH_NUMBER  0
+
+#ifdef CONFIG_SMP
+
+#include <asm/fixmap.h>
+#include <asm/mpspec.h>
+#include <mach_apicdef.h>
+#include <linux/thread_info.h>
+
+#define IPIPE_NR_CPUS          NR_CPUS
+#define IPIPE_CRITICAL_VECTOR  0xf9	/* Used by ipipe_critical_enter/exit() */
+#define IPIPE_CRITICAL_IPI     (IPIPE_CRITICAL_VECTOR - FIRST_EXTERNAL_VECTOR)
+
+#define ipipe_processor_id()   (current_thread_info()->cpu)
+
+#define ipipe_declare_cpuid    int cpuid
+#define ipipe_load_cpuid()     do { \
+                                  (cpuid) = ipipe_processor_id();	\
+                               } while(0)
+#define ipipe_lock_cpu(flags)  do { \
+                                  local_irq_save_hw(flags); \
+                                  (cpuid) = ipipe_processor_id(); \
+                               } while(0)
+#define ipipe_unlock_cpu(flags) local_irq_restore_hw(flags)
+#define ipipe_get_cpu(flags)    ipipe_lock_cpu(flags)
+#define ipipe_put_cpu(flags)    ipipe_unlock_cpu(flags)
+#define ipipe_current_domain    (ipipe_percpu_domain[ipipe_processor_id()])
+
+#else	/* !CONFIG_SMP */
+
+#define IPIPE_NR_CPUS           1
+#define ipipe_processor_id()    0
+#define ipipe_declare_cpuid     const int cpuid = 0
+#define ipipe_load_cpuid()	/* nop */
+#define ipipe_lock_cpu(flags)   local_irq_save_hw(flags)
+#define ipipe_unlock_cpu(flags) local_irq_restore_hw(flags)
+#define ipipe_get_cpu(flags)    do { flags = flags; } while(0)
+#define ipipe_put_cpu(flags)	/* nop */
+#define ipipe_current_domain    (ipipe_percpu_domain[0])
+
+#endif	/* CONFIG_SMP */
+
+#define prepare_arch_switch(rq, next)	do { } while (0)
+#define finish_arch_switch(rq, prev)	do {	\
+	__clear_bit(IPIPE_SYNC_FLAG,&ipipe_root_domain->cpudata[task_cpu(prev)].status); \
+	spin_unlock_irq(&(rq)->lock);		\
+} while(0)
+#define task_running(rq, p)		((rq)->curr == (p))
+
+struct ipipe_sysinfo {
+
+	int ncpus;		/* Number of CPUs on board */
+	u64 cpufreq;		/* CPU frequency (in Hz) */
+
+	/* Arch-dependent block */
+
+	struct {
+		unsigned tmirq;	/* Timer tick IRQ */
+		u64 tmfreq;	/* Timer frequency */
+	} archdep;
+};
+
+#ifdef CONFIG_X86_LOCAL_APIC
+/* We must cover the whole IRQ space to map the local timer interrupt
+   (#207). */
+#ifdef CONFIG_PCI_MSI
+#define IPIPE_NR_XIRQS NR_IRQS
+#else	/* CONFIG_PCI_MSI */
+#define IPIPE_NR_XIRQS   224
+#endif	/* CONFIG_PCI_MSI */
+#else	/* !CONFIG_X86_LOCAL_APIC */
+#define IPIPE_NR_XIRQS   NR_IRQS
+#endif	/* CONFIG_X86_LOCAL_APIC */
+
+/* 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  5	/* 2^5 for 32bits arch. */
+
+#define IPIPE_IRQMASK_ANY   (~0L)
+#define IPIPE_IRQMASK_VIRT  (IPIPE_IRQMASK_ANY << (IPIPE_VIRQ_BASE / BITS_PER_LONG))
+
+struct ipipe_domain {
+
+	struct list_head p_link;	/* Link in pipeline */
+
+	struct ipcpudata {
+		volatile unsigned long status;
+		volatile unsigned long irq_pending_hi;
+		volatile unsigned long irq_pending_lo[IPIPE_IRQ_IWORDS];
+		volatile unsigned irq_hits[IPIPE_NR_IRQS];
+	} cpudata[IPIPE_NR_CPUS];
+
+	struct {
+		int (*acknowledge) (unsigned irq);
+		void (*handler) (unsigned irq);
+		unsigned long control;
+	} irqs[IPIPE_NR_IRQS];
+
+	unsigned long flags;
+	unsigned domid;
+	const char *name;
+	int priority;
+	void *pdd;
+};
+
+/* The following macros must be used hw interrupts off. */
+
+#define __ipipe_set_irq_bit(ipd,cpuid,irq) \
+do { \
+    if (!test_bit(IPIPE_LOCK_FLAG,&(ipd)->irqs[irq].control)) { \
+        __set_bit(irq & IPIPE_IRQ_IMASK,&(ipd)->cpudata[cpuid].irq_pending_lo[irq >> IPIPE_IRQ_ISHIFT]); \
+        __set_bit(irq >> IPIPE_IRQ_ISHIFT,&(ipd)->cpudata[cpuid].irq_pending_hi); \
+       } \
+} while(0)
+
+#define __ipipe_clear_pend(ipd,cpuid,irq) \
+do { \
+    __clear_bit(irq & IPIPE_IRQ_IMASK,&(ipd)->cpudata[cpuid].irq_pending_lo[irq >> IPIPE_IRQ_ISHIFT]); \
+    if ((ipd)->cpudata[cpuid].irq_pending_lo[irq >> IPIPE_IRQ_ISHIFT] == 0) \
+        __clear_bit(irq >> IPIPE_IRQ_ISHIFT,&(ipd)->cpudata[cpuid].irq_pending_hi); \
+} while(0)
+
+#define __ipipe_lock_irq(ipd,cpuid,irq) \
+do { \
+    if (!test_and_set_bit(IPIPE_LOCK_FLAG,&(ipd)->irqs[irq].control)) \
+	__ipipe_clear_pend(ipd,cpuid,irq); \
+} while(0)
+
+#define __ipipe_unlock_irq(ipd,irq) \
+do { \
+    int __cpuid, __nr_cpus = num_online_cpus();			       \
+    if (test_and_clear_bit(IPIPE_LOCK_FLAG,&(ipd)->irqs[irq].control)) \
+	for (__cpuid = 0; __cpuid < __nr_cpus; __cpuid++)      \
+         if ((ipd)->cpudata[__cpuid].irq_hits[irq] > 0) { /* We need atomic ops next. */ \
+           set_bit(irq & IPIPE_IRQ_IMASK,&(ipd)->cpudata[__cpuid].irq_pending_lo[irq >> IPIPE_IRQ_ISHIFT]); \
+           set_bit(irq >> IPIPE_IRQ_ISHIFT,&(ipd)->cpudata[__cpuid].irq_pending_hi); \
+         } \
+} while(0)
+
+#define __ipipe_clear_irq(ipd,irq) \
+do { \
+    int __cpuid, __nr_cpus = num_online_cpus(); \
+    clear_bit(IPIPE_LOCK_FLAG,&(ipd)->irqs[irq].control); \
+    for (__cpuid = 0; __cpuid < __nr_cpus; __cpuid++) {	\
+       (ipd)->cpudata[__cpuid].irq_hits[irq] = 0; \
+       __ipipe_clear_pend(ipd,__cpuid,irq); \
+    } \
+} while(0)
+
+#define ipipe_virtual_irq_p(irq) ((irq) >= IPIPE_VIRQ_BASE && \
+				  (irq) < IPIPE_NR_IRQS)
+
+#define ipipe_hw_save_flags_and_sti(x)	__asm__ __volatile__("pushfl ; popl %0 ; sti":"=g" (x): /* no input */ :"memory")
+#define local_irq_disable_hw() 			__asm__ __volatile__("cli": : :"memory")
+#define local_irq_enable_hw()			__asm__ __volatile__("sti": : :"memory")
+#define local_irq_save_hw(x)    __asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory")
+#define local_irq_restore_hw(x) __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory", "cc")
+#define local_save_flags_hw(x)   __asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */)
+#define local_test_iflag_hw(x)   ((x) & (1<<9))
+#define irqs_disabled_hw()	\
+({					\
+	unsigned long flags;		\
+	local_save_flags_hw(flags);	\
+	!local_test_iflag_hw(flags);	\
+})
+
+#define ipipe_read_tsc(t)  __asm__ __volatile__("rdtsc" : "=A" (t))
+#define ipipe_cpu_freq() ({ unsigned long long __freq = cpu_has_tsc?(1000LL * cpu_khz):CLOCK_TICK_RATE; __freq; })
+
+#ifdef CONFIG_IPIPE_PREEMPT_RT
+/* We are over a combo I-pipe+PREEMPT_RT _patched_ kernel, but
+   CONFIG_PREEMPT_RT is not necessarily enabled; use the raw spinlock
+   support for the I-pipe. */
+#define spin_lock_hw(x)     __raw_spin_lock(x)
+#define spin_unlock_hw(x)   __raw_spin_unlock(x)
+#define spin_trylock_hw(x)  __raw_spin_trylock(x)
+#define write_lock_hw(x)    __raw_write_lock(x)
+#define write_unlock_hw(x)  __raw_write_unlock(x)
+#define write_trylock_hw(x) __raw_write_trylock(x)
+#define read_lock_hw(x)     __raw_read_lock(x)
+#define read_unlock_hw(x)   __raw_read_unlock(x)
+#else	/* !CONFIG_IPIPE_PREEMPT_RT */
+#define spin_lock_hw(x)     _spin_lock(x)
+#define spin_unlock_hw(x)   _spin_unlock(x)
+#define spin_trylock_hw(x)  _spin_trylock(x)
+#define write_lock_hw(x)    _write_lock(x)
+#define write_unlock_hw(x)  _write_unlock(x)
+#define write_trylock_hw(x) _write_trylock(x)
+#define read_lock_hw(x)     _read_lock(x)
+#define read_unlock_hw(x)   _read_unlock(x)
+#define raw_spinlock_t         spinlock_t
+#define RAW_SPIN_LOCK_UNLOCKED SPIN_LOCK_UNLOCKED
+#define raw_rwlock_t           rwlock_t
+#define RAW_RW_LOCK_UNLOCKED   RW_LOCK_UNLOCKED
+#endif	/* CONFIG_IPIPE_PREEMPT_RT */
+
+#define spin_lock_irqsave_hw(x,flags)  \
+do { \
+   local_irq_save_hw(flags); \
+   spin_lock_hw(x); \
+} while (0)
+
+#define spin_unlock_irqrestore_hw(x,flags)  \
+do { \
+   spin_unlock_hw(x); \
+   local_irq_restore_hw(flags); \
+} while (0)
+
+#define spin_lock_irq_hw(x)  \
+do { \
+   local_irq_disable_hw(); \
+   spin_lock_hw(x); \
+} while (0)
+
+#define spin_unlock_irq_hw(x)  \
+do { \
+   spin_unlock_hw(x); \
+   local_irq_enable_hw(); \
+} while (0)
+
+#define read_lock_irqsave_hw(lock, flags) \
+do { \
+   local_irq_save_hw(flags); \
+   read_lock_hw(lock); \
+} while (0)
+
+#define read_unlock_irqrestore_hw(lock, flags) \
+do { \
+   read_unlock_hw(lock); \
+   local_irq_restore_hw(flags); \
+} while (0)
+
+#define write_lock_irqsave_hw(lock, flags) \
+do { \
+   local_irq_save_hw(flags); \
+   write_lock_hw(lock); \
+} while (0)
+
+#define write_unlock_irqrestore_hw(lock, flags) \
+do { \
+   write_unlock_hw(lock); \
+   local_irq_restore_hw(flags); \
+} while (0)
+
+/* Private interface -- Internal use only */
+
+void __ipipe_cleanup_domain(struct ipipe_domain *ipd);
+
+#define __ipipe_check_platform() do { } while(0)
+
+#define __ipipe_init_platform() do { } while(0)
+
+void __ipipe_enable_pipeline(void);
+
+void __ipipe_disable_pipeline(void);
+
+void __ipipe_init_stage(struct ipipe_domain *ipd);
+
+void fastcall __ipipe_sync_stage(unsigned long syncmask);
+
+int __ipipe_ack_system_irq(unsigned irq);
+
+int __ipipe_handle_irq(struct pt_regs regs);
+
+extern struct pt_regs __ipipe_tick_regs[];
+
+extern int __ipipe_tick_irq;
+
+#endif	/* !__I386_IPIPE_H */
diff -uNrp linux-2.6.12/include/asm-i386/mach-default/do_timer.h linux-2.6.12-ipipe-0.6/include/asm-i386/mach-default/do_timer.h
--- linux-2.6.12/include/asm-i386/mach-default/do_timer.h	2005-06-17 21:48:29.000000000 +0200
+++ linux-2.6.12-ipipe-0.6/include/asm-i386/mach-default/do_timer.h	2005-06-19 11:38:45.000000000 +0200
@@ -49,14 +49,15 @@ static inline void do_timer_interrupt_ho
 static inline int do_timer_overflow(int count)
 {
 	int i;
+	unsigned long flags;
 
-	spin_lock(&i8259A_lock);
+	spin_lock_irqsave_hw_cond(&i8259A_lock, flags);
 	/*
 	 * This is tricky when I/O APICs are used;
 	 * see do_timer_interrupt().
 	 */
 	i = inb(0x20);
-	spin_unlock(&i8259A_lock);
+	spin_unlock_irqrestore_hw_cond(&i8259A_lock, flags);
 	
 	/* assumption about timer being IRQ0 */
 	if (i & 0x01) {
diff -uNrp linux-2.6.12/include/asm-i386/mach-visws/do_timer.h linux-2.6.12-ipipe-0.6/include/asm-i386/mach-visws/do_timer.h
--- linux-2.6.12/include/asm-i386/mach-visws/do_timer.h	2005-06-17 21:48:29.000000000 +0200
+++ linux-2.6.12-ipipe-0.6/include/asm-i386/mach-visws/do_timer.h	2005-06-19 11:38:45.000000000 +0200
@@ -28,14 +28,15 @@ static inline void do_timer_interrupt_ho
 static inline int do_timer_overflow(int count)
 {
 	int i;
+	unsigned long flags;
 
-	spin_lock(&i8259A_lock);
+	spin_lock_irqsave_hw_cond(&i8259A_lock, flags);
 	/*
 	 * This is tricky when I/O APICs are used;
 	 * see do_timer_interrupt().
 	 */
 	i = inb(0x20);
-	spin_unlock(&i8259A_lock);
+	spin_unlock_irqrestore_hw_cond(&i8259A_lock, flags);
 	
 	/* assumption about timer being IRQ0 */
 	if (i & 0x01) {
diff -uNrp linux-2.6.12/include/asm-i386/pgalloc.h linux-2.6.12-ipipe-0.6/include/asm-i386/pgalloc.h
--- linux-2.6.12/include/asm-i386/pgalloc.h	2005-06-17 21:48:29.000000000 +0200
+++ linux-2.6.12-ipipe-0.6/include/asm-i386/pgalloc.h	2005-06-19 11:38:45.000000000 +0200
@@ -47,4 +47,27 @@ static inline void pte_free(struct page 
 
 #define check_pgt_cache()	do { } while (0)
 
+static inline void set_pgdir(unsigned long address, pgd_t entry)
+{
+#ifdef CONFIG_IPIPE_CORE
+	struct task_struct * p;
+	struct page *page;
+	pgd_t *pgd;
+	
+	read_lock(&tasklist_lock);
+
+	for_each_process(p) {
+		if(p->mm) 
+		    *pgd_offset(p->mm,address) = entry;
+	}
+
+	read_unlock(&tasklist_lock);
+
+	for (page = pgd_list; page; page = (struct page *)page->index) {
+		pgd = (pgd_t *)page_address(page);
+		pgd[address >> PGDIR_SHIFT] = entry;
+	}
+#endif /* CONFIG_IPIPE_CORE */
+}
+
 #endif /* _I386_PGALLOC_H */
diff -uNrp linux-2.6.12/include/asm-i386/spinlock.h linux-2.6.12-ipipe-0.6/include/asm-i386/spinlock.h
--- linux-2.6.12/include/asm-i386/spinlock.h	2005-06-17 21:48:29.000000000 +0200
+++ linux-2.6.12-ipipe-0.6/include/asm-i386/spinlock.h	2005-06-19 11:38:45.000000000 +0200
@@ -57,6 +57,9 @@ typedef struct {
 	"jmp 1b\n" \
 	"3:\n\t"
 
+#ifdef CONFIG_IPIPE_CORE
+#define spin_lock_string_flags spin_lock_string
+#else /* !CONFIG_IPIPE_CORE */
 #define spin_lock_string_flags \
 	"\n1:\t" \
 	"lock ; decb %0\n\t" \
@@ -72,6 +75,7 @@ typedef struct {
 	"cli\n\t" \
 	"jmp 1b\n" \
 	"4:\n\t"
+#endif /* CONFIG_IPIPE_CORE */
 
 /*
  * This works. Despite all the confusion.
diff -uNrp linux-2.6.12/include/asm-i386/system.h linux-2.6.12-ipipe-0.6/include/asm-i386/system.h
--- linux-2.6.12/include/asm-i386/system.h	2005-06-17 21:48:29.000000000 +0200
+++ linux-2.6.12-ipipe-0.6/include/asm-i386/system.h	2005-06-19 11:38:45.000000000 +0200
@@ -441,6 +441,35 @@ struct alt_instr { 
 #define set_wmb(var, value) do { var = value; wmb(); } while (0)
 
 /* interrupt control.. */
+#ifdef CONFIG_IPIPE_CORE
+
+#include <linux/linkage.h>
+
+void __ipipe_stall_root(void);
+
+void __ipipe_unstall_root(void);
+
+unsigned long __ipipe_test_root(void);
+
+unsigned long __ipipe_test_and_stall_root(void);
+
+void fastcall __ipipe_restore_root(unsigned long flags);
+
+#define local_save_flags(x)	((x) = __ipipe_test_root())
+#define local_irq_save(x)	((x) = __ipipe_test_and_stall_root())
+#define local_irq_restore(x)	__ipipe_restore_root(x)
+#define local_irq_disable()	__ipipe_stall_root()
+#define local_irq_enable()	__ipipe_unstall_root()
+
+#define irqs_disabled()		__ipipe_test_root()
+
+#define safe_halt() do { \
+    __ipipe_unstall_root(); \
+    __asm__ __volatile__("sti; hlt": : :"memory"); \
+} while(0)
+
+#else /* !CONFIG_IPIPE_CORE */
+
 #define local_save_flags(x)	do { typecheck(unsigned long,x); __asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */); } while (0)
 #define local_irq_restore(x) 	do { typecheck(unsigned long,x); __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory", "cc"); } while (0)
 #define local_irq_disable() 	__asm__ __volatile__("cli": : :"memory")
@@ -458,6 +487,8 @@ struct alt_instr { 
 /* For spinlocks etc */
 #define local_irq_save(x)	__asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory")
 
+#endif /* CONFIG_IPIPE_CORE */
+
 /*
  * disable hlt during certain critical i/o operations
  */
diff -uNrp linux-2.6.12/include/linux/hardirq.h linux-2.6.12-ipipe-0.6/include/linux/hardirq.h
--- linux-2.6.12/include/linux/hardirq.h	2005-06-17 21:48:29.000000000 +0200
+++ linux-2.6.12-ipipe-0.6/include/linux/hardirq.h	2005-06-19 11:38:37.000000000 +0200
@@ -86,8 +86,21 @@ extern void synchronize_irq(unsigned int
 # define synchronize_irq(irq)	barrier()
 #endif
 
+#ifdef CONFIG_IPIPE_CORE
+#define nmi_enter() \
+do { \
+    if (ipipe_current_domain == ipipe_root_domain) \
+	irq_enter(); \
+} while(0)
+#define nmi_exit() \
+do { \
+    if (ipipe_current_domain == ipipe_root_domain) \
+	sub_preempt_count(HARDIRQ_OFFSET); \
+} while(0)
+#else /* !CONFIG_IPIPE_CORE */
 #define nmi_enter()		irq_enter()
 #define nmi_exit()		sub_preempt_count(HARDIRQ_OFFSET)
+#endif /* CONFIG_IPIPE_CORE */
 
 #ifndef CONFIG_VIRT_CPU_ACCOUNTING
 static inline void account_user_vtime(struct task_struct *tsk)
diff -uNrp linux-2.6.12/include/linux/ipipe.h linux-2.6.12-ipipe-0.6/include/linux/ipipe.h
--- linux-2.6.12/include/linux/ipipe.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.12-ipipe-0.6/include/linux/ipipe.h	2005-06-19 19:21:34.000000000 +0200
@@ -0,0 +1,368 @@
+/*   -*- linux-c -*-
+ *   include/linux/ipipe.h
+ *
+ *   Copyright (C) 2002-2005 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_IPIPE_H
+#define __LINUX_IPIPE_H
+
+#ifdef CONFIG_IPIPE_CORE
+
+#include <linux/spinlock.h>
+#include <asm/ipipe.h>
+
+#define IPIPE_VERSION_STRING  IPIPE_ARCH_STRING
+#define IPIPE_RELEASE_NUMBER  ((IPIPE_MAJOR_NUMBER<<16)|(IPIPE_MINOR_NUMBER<<8)|(IPIPE_PATCH_NUMBER))
+
+#define IPIPE_ROOT_PRI       100
+#define IPIPE_ROOT_ID        0
+
+#define IPIPE_SAME_HANDLER ((void (*)(unsigned))(-1))
+
+/* Global domain flags */
+#define IPIPE_SPRINTK_FLAG 0	/* Synchronous printk() allowed */
+#define IPIPE_PPRINTK_FLAG 1	/* Asynchronous printk() request pending */
+
+#define IPIPE_STALL_FLAG   0	/* Stalls a pipeline stage */
+#define IPIPE_SYNC_FLAG    1	/* The interrupt syncer is running for the domain */
+
+#define IPIPE_HANDLE_FLAG    0
+#define IPIPE_PASS_FLAG      1
+#define IPIPE_ENABLE_FLAG    2
+#define IPIPE_DYNAMIC_FLAG   IPIPE_HANDLE_FLAG
+#define IPIPE_EXCLUSIVE_FLAG 3
+#define IPIPE_STICKY_FLAG    4
+#define IPIPE_SYSTEM_FLAG    5
+#define IPIPE_LOCK_FLAG      6
+#define IPIPE_SHARED_FLAG    7
+#define IPIPE_CALLASM_FLAG   8	/* Arch-dependent -- might be unused. */
+
+#define IPIPE_HANDLE_MASK    (1 << IPIPE_HANDLE_FLAG)
+#define IPIPE_PASS_MASK      (1 << IPIPE_PASS_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_SYNC_MASK      (1 << IPIPE_SYNC_FLAG)
+#define IPIPE_CALLASM_MASK   (1 << IPIPE_CALLASM_FLAG)
+
+#define IPIPE_DEFAULT_MASK  (IPIPE_HANDLE_MASK|IPIPE_PASS_MASK)
+
+struct ipipe_domain_attr {
+
+	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) (void);	/* Domain entry point */
+	void *pdd;		/* Per-domain (opaque) data pointer */
+};
+
+extern int ipipe_running;
+
+extern struct ipipe_domain *ipipe_percpu_domain[], *ipipe_root_domain;
+
+extern unsigned __ipipe_printk_virq;
+
+extern unsigned long __ipipe_virtual_irq_map;
+
+extern struct list_head __ipipe_pipeline;
+
+extern raw_spinlock_t __ipipe_pipelock;
+
+/* Private interface */
+
+void ipipe_init(void);
+
+#ifdef CONFIG_PROC_FS
+void __ipipe_init_proc(void);
+#endif	/* CONFIG_PROC_FS */
+
+void __ipipe_sync_console(unsigned irq);
+
+void __ipipe_stall_root(void);
+
+void __ipipe_unstall_root(void);
+
+unsigned long __ipipe_test_root(void);
+
+unsigned long __ipipe_test_and_stall_root(void);
+
+void fastcall __ipipe_restore_root(unsigned long flags);
+
+int fastcall __ipipe_schedule_irq(unsigned irq, struct list_head *head);
+
+#define __ipipe_pipeline_head_p(ipd) (&(ipd)->p_link == __ipipe_pipeline.next)
+
+/* Called with hw interrupts off. */
+static inline void __ipipe_switch_to(struct ipipe_domain *out,
+				     struct ipipe_domain *in, int cpuid)
+{
+	void ipipe_suspend_domain(void);
+
+	/* "in" is guaranteed to be closer than "out" from the head of the
+	   pipeline (and obviously different). */
+
+	ipipe_percpu_domain[cpuid] = in;
+
+	ipipe_suspend_domain();	/* Sync stage and propagate interrupts. */
+	ipipe_load_cpuid();	/* Processor might have changed. */
+
+	if (ipipe_percpu_domain[cpuid] == in)
+		/* Otherwise, something has changed the current domain under
+		   our feet recycling the register set; do not override. */
+		ipipe_percpu_domain[cpuid] = out;
+}
+
+/* Public interface */
+
+int ipipe_register_domain(struct ipipe_domain *ipd,
+			  struct ipipe_domain_attr *attr);
+
+int ipipe_unregister_domain(struct ipipe_domain *ipd);
+
+void ipipe_suspend_domain(void);
+
+int ipipe_virtualize_irq_from(struct ipipe_domain *ipd,
+			      unsigned irq,
+			      void (*handler) (unsigned irq),
+			      int (*acknowledge) (unsigned irq),
+			      unsigned modemask);
+
+static inline int ipipe_virtualize_irq(unsigned irq,
+				       void (*handler) (unsigned irq),
+				       int (*acknowledge) (unsigned irq),
+				       unsigned modemask)
+{
+	return ipipe_virtualize_irq_from(ipipe_current_domain,
+					 irq, handler, acknowledge, modemask);
+}
+
+static inline int ipipe_share_irq(unsigned irq,
+				  int (*acknowledge) (unsigned irq))
+{
+	return ipipe_virtualize_irq(irq,
+				    IPIPE_SAME_HANDLER,
+				    acknowledge,
+				    IPIPE_SHARED_MASK | IPIPE_HANDLE_MASK |
+				    IPIPE_PASS_MASK);
+}
+
+int ipipe_control_irq(unsigned irq,
+		      unsigned clrmask,
+		      unsigned setmask);
+
+unsigned ipipe_alloc_virq(void);
+
+int ipipe_free_virq(unsigned virq);
+
+int fastcall ipipe_trigger_irq(unsigned irq);
+
+static inline int ipipe_propagate_irq(unsigned irq)
+{
+
+	return __ipipe_schedule_irq(irq, ipipe_current_domain->p_link.next);
+}
+
+static inline int ipipe_schedule_irq(unsigned irq)
+{
+
+	return __ipipe_schedule_irq(irq, &ipipe_current_domain->p_link);
+}
+
+static inline void ipipe_stall_pipeline_from(struct ipipe_domain *ipd)
+{
+	ipipe_declare_cpuid;
+#ifdef CONFIG_SMP
+	unsigned long flags;
+
+	ipipe_lock_cpu(flags); /* Care for migration. */
+
+	__set_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status);
+
+	if (!__ipipe_pipeline_head_p(ipd))
+		ipipe_unlock_cpu(flags);
+#else	/* CONFIG_SMP */
+	set_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status);
+
+	if (__ipipe_pipeline_head_p(ipd))
+		local_irq_disable_hw();
+#endif	/* CONFIG_SMP */
+}
+
+static inline unsigned long ipipe_test_pipeline_from(struct ipipe_domain *ipd)
+{
+	unsigned long flags, s;
+	ipipe_declare_cpuid;
+
+	ipipe_get_cpu(flags);
+	s = test_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status);
+	ipipe_put_cpu(flags);
+
+	return s;
+}
+
+static inline unsigned long ipipe_test_and_stall_pipeline_from(struct
+							       ipipe_domain
+							       *ipd)
+{
+	ipipe_declare_cpuid;
+	unsigned long s;
+#ifdef CONFIG_SMP
+	unsigned long flags;
+
+	ipipe_lock_cpu(flags); /* Care for migration. */
+
+	s = __test_and_set_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status);
+
+	if (!__ipipe_pipeline_head_p(ipd))
+		ipipe_unlock_cpu(flags);
+#else	/* CONFIG_SMP */
+	s = test_and_set_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status);
+
+	if (__ipipe_pipeline_head_p(ipd))
+		local_irq_disable_hw();
+#endif	/* CONFIG_SMP */
+
+	return s;
+}
+
+void fastcall ipipe_unstall_pipeline_from(struct ipipe_domain *ipd);
+
+static inline unsigned long ipipe_test_and_unstall_pipeline_from(struct
+								 ipipe_domain
+								 *ipd)
+{
+	unsigned long flags, s;
+	ipipe_declare_cpuid;
+
+	ipipe_get_cpu(flags);
+	s = test_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status);
+	ipipe_unstall_pipeline_from(ipd);
+	ipipe_put_cpu(flags);
+
+	return s;
+}
+
+static inline void ipipe_unstall_pipeline(void)
+{
+	ipipe_unstall_pipeline_from(ipipe_current_domain);
+}
+
+static inline unsigned long ipipe_test_and_unstall_pipeline(void)
+{
+	return ipipe_test_and_unstall_pipeline_from(ipipe_current_domain);
+}
+
+static inline unsigned long ipipe_test_pipeline(void)
+{
+	return ipipe_test_pipeline_from(ipipe_current_domain);
+}
+
+static inline unsigned long ipipe_test_and_stall_pipeline(void)
+{
+	return ipipe_test_and_stall_pipeline_from(ipipe_current_domain);
+}
+
+static inline void ipipe_restore_pipeline_from(struct ipipe_domain *ipd,
+					       unsigned long flags)
+{
+	if (flags)
+		ipipe_stall_pipeline_from(ipd);
+	else
+		ipipe_unstall_pipeline_from(ipd);
+}
+
+static inline void ipipe_stall_pipeline(void)
+{
+	ipipe_stall_pipeline_from(ipipe_current_domain);
+}
+
+static inline void ipipe_restore_pipeline(unsigned long flags)
+{
+	ipipe_restore_pipeline_from(ipipe_current_domain, flags);
+}
+
+static inline void ipipe_restore_pipeline_nosync(struct ipipe_domain *ipd,
+						 unsigned long flags, int cpuid)
+{
+	/* If cpuid is current, then it must be held on entry
+	   (ipipe_get_cpu/local_irq_save_hw/local_irq_disable_hw). */
+
+	if (flags)
+		__set_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status);
+	else
+		__clear_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status);
+}
+
+void ipipe_init_attr(struct ipipe_domain_attr *attr);
+
+int ipipe_get_sysinfo(struct ipipe_sysinfo *sysinfo);
+
+unsigned long ipipe_critical_enter(void (*syncfn) (void));
+
+void ipipe_critical_exit(unsigned long flags);
+
+static inline void ipipe_set_printk_sync(struct ipipe_domain *ipd)
+{
+	set_bit(IPIPE_SPRINTK_FLAG, &ipd->flags);
+}
+
+static inline void ipipe_set_printk_async(struct ipipe_domain *ipd)
+{
+	clear_bit(IPIPE_SPRINTK_FLAG, &ipd->flags);
+}
+
+#define local_irq_enable_hw_cond()                 local_irq_enable_hw()
+#define local_irq_save_hw_cond(flags)              local_irq_save_hw(flags)
+#define local_irq_restore_hw_cond(flags)           local_irq_restore_hw(flags)
+#define spin_lock_irqsave_hw_cond(lock,flags)      spin_lock_irqsave_hw(lock,flags)
+#define spin_unlock_irqrestore_hw_cond(lock,flags) spin_unlock_irqrestore_hw(lock,flags)
+
+#else	/* !CONFIG_IPIPE_CORE */
+
+#define ipipe_init()              do { } while(0)
+#define ipipe_suspend_domain()    do { } while(0)
+
+#define spin_lock_hw(lock)                    spin_lock(lock)
+#define spin_unlock_hw(lock)                  spin_unlock(lock)
+#define spin_lock_irq_hw(lock)                spin_lock_irq(lock)
+#define spin_unlock_irq_hw(lock)              spin_unlock_irq(lock)
+#define spin_lock_irqsave_hw(lock,flags)      spin_lock_irqsave(lock, flags)
+#define spin_unlock_irqrestore_hw(lock,flags) spin_unlock_irqrestore(lock, flags)
+#define local_irq_save_hw(flags)              local_irq_save(flags)
+#define local_irq_restore_hw(flags)           local_irq_restore(flags)
+
+#define local_irq_enable_hw_cond()                 do { } while(0)
+#define local_irq_save_hw_cond(flags)              do { flags = 0; /* Optimized out */ } while(0)
+#define local_irq_restore_hw_cond(flags)           do { } while(0)
+#define spin_lock_irqsave_hw_cond(lock,flags)      do { flags = 0; spin_lock(lock); } while(0)
+#define spin_unlock_irqrestore_hw_cond(lock,flags) spin_unlock(lock)
+
+#endif	/* CONFIG_IPIPE_CORE */
+
+#ifdef CONFIG_IPIPE
+void ipipe_takeover(void);
+#else	/* CONFIG_IPIPE */
+#define ipipe_takeover()  do { } while(0)
+#endif	/* CONFIG_IPIPE */
+
+#endif	/* !__LINUX_IPIPE_H */
diff -uNrp linux-2.6.12/include/linux/sched.h linux-2.6.12-ipipe-0.6/include/linux/sched.h
--- linux-2.6.12/include/linux/sched.h	2005-06-17 21:48:29.000000000 +0200
+++ linux-2.6.12-ipipe-0.6/include/linux/sched.h	2005-06-19 11:38:37.000000000 +0200
@@ -4,6 +4,7 @@
 #include <asm/param.h>	/* for HZ */
 
 #include <linux/config.h>
+#include <linux/ipipe.h>
 #include <linux/capability.h>
 #include <linux/threads.h>
 #include <linux/kernel.h>
diff -uNrp linux-2.6.12/init/Kconfig linux-2.6.12-ipipe-0.6/init/Kconfig
--- linux-2.6.12/init/Kconfig	2005-06-17 21:48:29.000000000 +0200
+++ linux-2.6.12-ipipe-0.6/init/Kconfig	2005-06-19 11:38:37.000000000 +0200
@@ -69,6 +69,7 @@ menu "General setup"
 
 config LOCALVERSION
 	string "Local version - append to kernel release"
+	default "-ipipe"
 	help
 	  Append an extra string to the end of your kernel version.
 	  This will show up when you type uname, for example.
diff -uNrp linux-2.6.12/init/main.c linux-2.6.12-ipipe-0.6/init/main.c
--- linux-2.6.12/init/main.c	2005-06-17 21:48:29.000000000 +0200
+++ linux-2.6.12-ipipe-0.6/init/main.c	2005-06-19 11:38:37.000000000 +0200
@@ -464,6 +464,7 @@ asmlinkage void __init start_kernel(void
 	trap_init();
 	rcu_init();
 	init_IRQ();
+ 	ipipe_init();
 	pidhash_init();
 	init_timers();
 	softirq_init();
@@ -596,6 +597,8 @@ static void __init do_basic_setup(void)
 	sock_init();
 
 	do_initcalls();
+
+	ipipe_takeover();
 }
 
 static void do_pre_smp_initcalls(void)
diff -uNrp linux-2.6.12/ipipe/Kconfig linux-2.6.12-ipipe-0.6/ipipe/Kconfig
--- linux-2.6.12/ipipe/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.12-ipipe-0.6/ipipe/Kconfig	2005-06-19 11:38:37.000000000 +0200
@@ -0,0 +1,12 @@
+config IPIPE
+	tristate "Interrupt pipeline"
+	default y
+	---help---
+	  Activate this option if you want the interrupt pipeline to be
+	  compiled in.
+
+config IPIPE_CORE
+	def_bool IPIPE
+
+config IPIPE_PREEMPT_RT
+	def_bool PREEMPT_NONE || PREEMPT_VOLUNTARY || PREEMPT_DESKTOP || PREEMPT_RT
diff -uNrp linux-2.6.12/ipipe/Makefile linux-2.6.12-ipipe-0.6/ipipe/Makefile
--- linux-2.6.12/ipipe/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.12-ipipe-0.6/ipipe/Makefile	2005-06-19 11:38:37.000000000 +0200
@@ -0,0 +1,9 @@
+#
+# Makefile for the I-pipe support.
+#
+
+obj-$(CONFIG_IPIPE)	+= ipipe.o
+
+ipipe-objs		:= generic.o
+
+ipipe-$(CONFIG_X86)	+= x86.o
diff -uNrp linux-2.6.12/ipipe/generic.c linux-2.6.12-ipipe-0.6/ipipe/generic.c
--- linux-2.6.12/ipipe/generic.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.12-ipipe-0.6/ipipe/generic.c	2005-06-19 11:38:37.000000000 +0200
@@ -0,0 +1,265 @@
+/*   -*- linux-c -*-
+ *   linux/ipipe/generic.c
+ *
+ *   Copyright (C) 2002-2005 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 I-PIPE 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("I-pipe");
+MODULE_LICENSE("GPL");
+
+/* ipipe_register_domain() -- Link a new domain to the pipeline. */
+
+int ipipe_register_domain(struct ipipe_domain *ipd,
+			  struct ipipe_domain_attr *attr)
+{
+	struct list_head *pos;
+	unsigned long flags;
+
+	if (ipipe_current_domain != ipipe_root_domain) {
+		printk(KERN_WARNING
+		       "I-pipe: Only the root domain may register a new domain.\n");
+		return -EPERM;
+	}
+
+	flags = ipipe_critical_enter(NULL);
+
+	list_for_each(pos, &__ipipe_pipeline) {
+		struct ipipe_domain *_ipd =
+		    list_entry(pos, struct ipipe_domain, p_link);
+		if (_ipd->domid == attr->domid)
+			break;
+	}
+
+	ipipe_critical_exit(flags);
+
+	if (pos != &__ipipe_pipeline)
+		/* A domain with the given id already exists -- fail. */
+		return -EBUSY;
+
+	ipd->name = attr->name;
+	ipd->priority = attr->priority;
+	ipd->domid = attr->domid;
+	ipd->pdd = attr->pdd;
+	ipd->flags = 0;
+
+	__ipipe_init_stage(ipd);
+
+	INIT_LIST_HEAD(&ipd->p_link);
+
+	flags = ipipe_critical_enter(NULL);
+
+	list_for_each(pos, &__ipipe_pipeline) {
+		struct ipipe_domain *_ipd =
+		    list_entry(pos, struct ipipe_domain, p_link);
+		if (ipd->priority > _ipd->priority)
+			break;
+	}
+
+	list_add_tail(&ipd->p_link, pos);
+
+	ipipe_critical_exit(flags);
+
+	printk(KERN_WARNING "I-pipe: Domain %s registered.\n", ipd->name);
+
+	/* Finally, allow the new domain to perform its initialization
+	   chores. */
+
+	if (attr->entry != NULL) {
+		ipipe_declare_cpuid;
+
+		ipipe_lock_cpu(flags);
+
+		ipipe_percpu_domain[cpuid] = ipd;
+		attr->entry();
+		ipipe_percpu_domain[cpuid] = ipipe_root_domain;
+
+		ipipe_load_cpuid();	/* Processor might have changed. */
+
+		if (ipipe_root_domain->cpudata[cpuid].irq_pending_hi != 0 &&
+		    !test_bit(IPIPE_STALL_FLAG,
+			      &ipipe_root_domain->cpudata[cpuid].status))
+			__ipipe_sync_stage(IPIPE_IRQMASK_ANY);
+
+		ipipe_unlock_cpu(flags);
+	}
+
+	return 0;
+}
+
+/* ipipe_unregister_domain() -- Remove a domain from the pipeline. */
+
+int ipipe_unregister_domain(struct ipipe_domain *ipd)
+{
+	unsigned long flags;
+
+	if (ipipe_current_domain != ipipe_root_domain) {
+		printk(KERN_WARNING
+		       "I-pipe: Only the root domain may unregister a domain.\n");
+		return -EPERM;
+	}
+
+	if (ipd == ipipe_root_domain) {
+		printk(KERN_WARNING
+		       "I-pipe: Cannot unregister the root domain.\n");
+		return -EPERM;
+	}
+#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. */
+
+		ipipe_unstall_pipeline_from(ipd);
+
+		flags = ipipe_critical_enter(NULL);
+
+		for (irq = 0; irq < IPIPE_NR_IRQS; irq++) {
+			clear_bit(IPIPE_HANDLE_FLAG, &ipd->irqs[irq].control);
+			clear_bit(IPIPE_STICKY_FLAG, &ipd->irqs[irq].control);
+			set_bit(IPIPE_PASS_FLAG, &ipd->irqs[irq].control);
+		}
+
+		ipipe_critical_exit(flags);
+
+		for (_cpuid = 0; _cpuid < nr_cpus; _cpuid++)
+			for (irq = 0; irq < IPIPE_NR_IRQS; irq++)
+				while (ipd->cpudata[_cpuid].irq_hits[irq] > 0)
+					cpu_relax();
+	}
+#endif	/* CONFIG_SMP */
+
+	/* Simply remove the domain from the pipeline and we are almost
+	   done. */
+
+	flags = ipipe_critical_enter(NULL);
+	list_del_init(&ipd->p_link);
+	ipipe_critical_exit(flags);
+
+	__ipipe_cleanup_domain(ipd);
+
+	printk(KERN_WARNING "I-pipe: Domain %s unregistered.\n", ipd->name);
+
+	return 0;
+}
+
+/* ipipe_propagate_irq() -- Force a given IRQ propagation on behalf of
+   a running interrupt handler to the next domain down the pipeline.
+   ipipe_schedule_irq() -- Does almost the same as above, but attempts
+   to pend the interrupt for the current domain first. */
+
+int fastcall __ipipe_schedule_irq(unsigned irq, struct list_head *head)
+{
+	struct list_head *ln;
+	unsigned long flags;
+	ipipe_declare_cpuid;
+
+	if (irq >= IPIPE_NR_IRQS ||
+	    (ipipe_virtual_irq_p(irq)
+	     && !test_bit(irq - IPIPE_VIRQ_BASE, &__ipipe_virtual_irq_map)))
+		return -EINVAL;
+
+	ipipe_lock_cpu(flags);
+
+	ln = head;
+
+	while (ln != &__ipipe_pipeline) {
+		struct ipipe_domain *ipd =
+		    list_entry(ln, struct ipipe_domain, p_link);
+
+		if (test_bit(IPIPE_HANDLE_FLAG, &ipd->irqs[irq].control)) {
+			ipd->cpudata[cpuid].irq_hits[irq]++;
+			__ipipe_set_irq_bit(ipd, cpuid, irq);
+			ipipe_unlock_cpu(flags);
+			return 1;
+		}
+
+		ln = ipd->p_link.next;
+	}
+
+	ipipe_unlock_cpu(flags);
+
+	return 0;
+}
+
+/* ipipe_free_virq() -- Release a virtual/soft interrupt. */
+
+int ipipe_free_virq(unsigned virq)
+{
+	if (!ipipe_virtual_irq_p(virq))
+		return -EINVAL;
+
+	clear_bit(virq - IPIPE_VIRQ_BASE, &__ipipe_virtual_irq_map);
+
+	return 0;
+}
+
+void ipipe_init_attr(struct ipipe_domain_attr *attr)
+{
+	attr->name = "anon";
+	attr->domid = 1;
+	attr->entry = NULL;
+	attr->priority = IPIPE_ROOT_PRI;
+	attr->pdd = NULL;
+}
+
+#ifdef CONFIG_IPIPE_MODULE
+
+static int __init ipipe_init_module(void)
+{
+	__ipipe_enable_pipeline();
+	return 0;
+}
+
+static void __exit ipipe_exit_module(void)
+{
+	__ipipe_disable_pipeline();
+}
+
+module_init(ipipe_init_module);
+module_exit(ipipe_exit_module);
+
+#else	/* !CONFIG_IPIPE_MODULE */
+
+void ipipe_takeover(void)
+{
+	/* Take over the box at boot time. */
+	__ipipe_enable_pipeline();
+}
+
+#endif	/* CONFIG_IPIPE_MODULE */
+
+EXPORT_SYMBOL(ipipe_register_domain);
+EXPORT_SYMBOL(ipipe_unregister_domain);
+EXPORT_SYMBOL(ipipe_virtualize_irq_from);
+EXPORT_SYMBOL(ipipe_control_irq);
+EXPORT_SYMBOL(ipipe_free_virq);
+EXPORT_SYMBOL(ipipe_init_attr);
+EXPORT_SYMBOL(ipipe_get_sysinfo);
+EXPORT_SYMBOL(__ipipe_schedule_irq);
diff -uNrp linux-2.6.12/ipipe/x86.c linux-2.6.12-ipipe-0.6/ipipe/x86.c
--- linux-2.6.12/ipipe/x86.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.12-ipipe-0.6/ipipe/x86.c	2005-06-19 11:38:45.000000000 +0200
@@ -0,0 +1,577 @@
+/*   -*- linux-c -*-
+ *   linux/ipipe/x86.c
+ *
+ *   Copyright (C) 2002-2005 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 I-PIPE support for x86.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.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/irq.h>
+#include <asm/desc.h>
+#include <asm/io.h>
+#ifdef CONFIG_X86_LOCAL_APIC
+#include <asm/fixmap.h>
+#include <asm/bitops.h>
+#include <asm/mpspec.h>
+#ifdef CONFIG_X86_IO_APIC
+#include <asm/io_apic.h>
+#endif	/* CONFIG_X86_IO_APIC */
+#include <asm/apic.h>
+#include <mach_ipi.h>
+#endif	/* CONFIG_X86_LOCAL_APIC */
+
+extern struct desc_struct idt_table[];
+
+extern void (*__ipipe_irq_trampolines[]) (void);	/* in entry.S */
+
+static void (*__ipipe_std_vector_table[256]) (void);
+
+static struct hw_interrupt_type __ipipe_std_irq_dtype[NR_IRQS];
+
+/* Lifted from arch/i386/kernel/traps.c */
+#define __ipipe_set_gate(gate_addr,type,dpl,addr)  \
+do { \
+  int __d0, __d1; \
+  __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \
+	"movw %4,%%dx\n\t" \
+	"movl %%eax,%0\n\t" \
+	"movl %%edx,%1" \
+	:"=m" (*((long *) (gate_addr))), \
+	 "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \
+	:"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \
+	 "3" ((char *) (addr)),"2" (__KERNEL_CS << 16)); \
+} while (0)
+
+#define __ipipe_get_gate_addr(v) \
+	((void *)((idt_table[v].b & 0xffff0000)|(idt_table[v].a & 0xffff)))
+
+#define __ipipe_set_irq_gate(vector,addr) \
+__ipipe_set_gate(idt_table+vector,14,0,addr)
+
+#define __ipipe_set_trap_gate(vector,addr) \
+__ipipe_set_gate(idt_table+vector,15,0,addr)
+
+#define __ipipe_set_sys_gate(vector,addr) \
+__ipipe_set_gate(idt_table+vector,15,3,addr)
+
+static int __ipipe_ack_common_irq(unsigned irq)
+{
+	preempt_disable();
+	__ipipe_std_irq_dtype[irq].ack(irq);
+	preempt_enable_no_resched();
+
+	return 1;
+}
+
+static unsigned __ipipe_override_irq_startup(unsigned irq)
+{
+	unsigned long adflags, hwflags;
+	ipipe_declare_cpuid;
+	unsigned s;
+
+	ipipe_lock_cpu(hwflags);
+	adflags = ipipe_test_and_stall_pipeline();
+	preempt_disable();
+	__ipipe_unlock_irq(ipipe_percpu_domain[cpuid], irq);
+	s = __ipipe_std_irq_dtype[irq].startup(irq);
+	preempt_enable_no_resched();
+	ipipe_restore_pipeline_nosync(ipipe_percpu_domain[cpuid], adflags,
+				      cpuid);
+	ipipe_unlock_cpu(hwflags);
+
+	return s;
+}
+
+static void __ipipe_override_irq_shutdown(unsigned irq)
+{
+	unsigned long adflags, hwflags;
+	ipipe_declare_cpuid;
+
+	ipipe_lock_cpu(hwflags);
+	adflags = ipipe_test_and_stall_pipeline();
+	preempt_disable();
+	__ipipe_std_irq_dtype[irq].shutdown(irq);
+	__ipipe_clear_irq(ipipe_percpu_domain[cpuid], irq);
+	preempt_enable_no_resched();
+	ipipe_restore_pipeline_nosync(ipipe_percpu_domain[cpuid], adflags,
+				      cpuid);
+	ipipe_unlock_cpu(hwflags);
+}
+
+static void __ipipe_override_irq_enable(unsigned irq)
+{
+	unsigned long adflags, hwflags;
+	ipipe_declare_cpuid;
+
+	ipipe_lock_cpu(hwflags);
+	adflags = ipipe_test_and_stall_pipeline();
+	preempt_disable();
+	__ipipe_unlock_irq(ipipe_percpu_domain[cpuid], irq);
+	__ipipe_std_irq_dtype[irq].enable(irq);
+	preempt_enable_no_resched();
+	ipipe_restore_pipeline_nosync(ipipe_percpu_domain[cpuid], adflags,
+				      cpuid);
+	ipipe_unlock_cpu(hwflags);
+}
+
+static void __ipipe_override_irq_disable(unsigned irq)
+{
+	unsigned long adflags, hwflags;
+	ipipe_declare_cpuid;
+
+	ipipe_lock_cpu(hwflags);
+	adflags = ipipe_test_and_stall_pipeline();
+	preempt_disable();
+	__ipipe_std_irq_dtype[irq].disable(irq);
+	__ipipe_lock_irq(ipipe_percpu_domain[cpuid], cpuid, irq);
+	preempt_enable_no_resched();
+	ipipe_restore_pipeline_nosync(ipipe_percpu_domain[cpuid], adflags,
+				      cpuid);
+	ipipe_unlock_cpu(hwflags);
+}
+
+static void __ipipe_override_irq_ack(unsigned irq)
+{
+	if (!ipipe_running)
+		__ipipe_std_irq_dtype[irq].ack(irq);
+}
+
+static void __ipipe_override_irq_end(unsigned irq)
+{
+	unsigned long adflags, hwflags;
+	ipipe_declare_cpuid;
+
+	ipipe_lock_cpu(hwflags);
+	adflags = ipipe_test_and_stall_pipeline();
+	preempt_disable();
+
+	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+		__ipipe_unlock_irq(ipipe_percpu_domain[cpuid], irq);
+
+	__ipipe_std_irq_dtype[irq].end(irq);
+
+	preempt_enable_no_resched();
+	ipipe_restore_pipeline_nosync(ipipe_percpu_domain[cpuid], adflags,
+				      cpuid);
+	ipipe_unlock_cpu(hwflags);
+}
+
+static void __ipipe_override_irq_affinity(unsigned irq, cpumask_t mask)
+{
+	unsigned long adflags, hwflags;
+	ipipe_declare_cpuid;
+
+	ipipe_lock_cpu(hwflags);
+	adflags = ipipe_test_and_stall_pipeline();
+	preempt_disable();
+	__ipipe_std_irq_dtype[irq].set_affinity(irq, mask);
+	preempt_enable_no_resched();
+	ipipe_restore_pipeline_nosync(ipipe_percpu_domain[cpuid], adflags,
+				      cpuid);
+	ipipe_unlock_cpu(hwflags);
+}
+
+/* __ipipe_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 __ipipe_enable_pipeline(void)
+{
+	unsigned vector, irq, rirq;
+	unsigned long flags;
+
+	/* Collect the original vector table. */
+
+	for (vector = 0; vector < 256; vector++)
+		__ipipe_std_vector_table[vector] =
+		    __ipipe_get_gate_addr(vector);
+
+#ifdef CONFIG_SMP
+
+	/* This vector must be set up prior to call
+	   ipipe_critical_enter(). */
+
+	__ipipe_set_irq_gate(IPIPE_CRITICAL_VECTOR,
+			     __ipipe_irq_trampolines[IPIPE_CRITICAL_IPI]);
+
+#endif	/* CONFIG_SMP */
+
+	flags = ipipe_critical_enter(NULL);
+
+	/* First, grab the ISA and IO-APIC interrupts. */
+
+	for (irq = 0;
+	     irq < NR_IRQS && irq + FIRST_EXTERNAL_VECTOR < FIRST_SYSTEM_VECTOR;
+	     irq++) {
+		rirq = irq;
+
+#ifdef CONFIG_X86_IO_APIC
+		if (IO_APIC_IRQ(irq)) {
+			vector = IO_APIC_VECTOR(irq);
+
+			if (vector == 0)
+				continue;
+
+#ifdef CONFIG_PCI_MSI
+			/* Account specifically for MSI routing. */
+			if (!platform_legacy_irq(irq))
+				rirq = vector;
+#endif	/* CONFIG_PCI_MSI */
+		} else
+#endif	/* CONFIG_X86_IO_APIC */
+		{
+			vector = irq + FIRST_EXTERNAL_VECTOR;
+
+			if (vector == SYSCALL_VECTOR)
+				continue;
+		}
+
+		/* Fails for IPIPE_CRITICAL_IPI but that's ok. */
+
+		ipipe_virtualize_irq(rirq,
+				     (void (*)(unsigned))
+				     __ipipe_std_vector_table[vector],
+				     &__ipipe_ack_common_irq,
+				     IPIPE_CALLASM_MASK | IPIPE_HANDLE_MASK |
+				     IPIPE_PASS_MASK);
+
+		__ipipe_set_irq_gate(vector, __ipipe_irq_trampolines[rirq]);
+	}
+
+	/* 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++)
+		__ipipe_std_irq_dtype[irq] = *irq_desc[irq].handler;
+
+	/* The original controller structs may be shared, so we first
+	   save them all before changing any of them. Notice that we
+	   don't redirect the ack handler since the relevant
+	   XT-PIC/IO-APIC management code is already IPIPE-aware. */
+
+	for (irq = 0; irq < NR_IRQS; irq++) {
+		irq_desc[irq].handler->startup = &__ipipe_override_irq_startup;
+		irq_desc[irq].handler->shutdown =
+		    &__ipipe_override_irq_shutdown;
+		irq_desc[irq].handler->enable = &__ipipe_override_irq_enable;
+		irq_desc[irq].handler->disable = &__ipipe_override_irq_disable;
+		irq_desc[irq].handler->ack = &__ipipe_override_irq_ack;
+		irq_desc[irq].handler->end = &__ipipe_override_irq_end;
+
+		if (irq_desc[irq].handler->set_affinity != NULL)
+			irq_desc[irq].handler->set_affinity =
+			    &__ipipe_override_irq_affinity;
+	}
+
+#ifdef CONFIG_X86_LOCAL_APIC
+
+	/* Map the APIC system vectors including the unused ones so that
+	   client domains can virtualize the corresponding IRQs. */
+
+	for (vector = FIRST_SYSTEM_VECTOR; vector < CALL_FUNCTION_VECTOR;
+	     vector++) {
+		ipipe_virtualize_irq(vector - FIRST_EXTERNAL_VECTOR,
+				     (void (*)(unsigned))
+				     __ipipe_std_vector_table[vector],
+				     &__ipipe_ack_system_irq,
+				     IPIPE_CALLASM_MASK | IPIPE_HANDLE_MASK |
+				     IPIPE_PASS_MASK);
+
+		__ipipe_set_irq_gate(vector,
+				     __ipipe_irq_trampolines[vector -
+							     FIRST_EXTERNAL_VECTOR]);
+	}
+
+	__ipipe_tick_irq =
+	    using_apic_timer ? LOCAL_TIMER_VECTOR - FIRST_EXTERNAL_VECTOR : 0;
+
+#else	/* !CONFIG_X86_LOCAL_APIC */
+
+	__ipipe_tick_irq = 0;
+
+#endif	/* CONFIG_X86_LOCAL_APIC */
+
+#ifdef CONFIG_SMP
+
+	/* All interrupts must be pipelined, but the spurious one since we
+	   don't even want to acknowledge it. */
+
+	for (vector = CALL_FUNCTION_VECTOR; vector < SPURIOUS_APIC_VECTOR;
+	     vector++) {
+		ipipe_virtualize_irq(vector - FIRST_EXTERNAL_VECTOR,
+				     (void (*)(unsigned))
+				     __ipipe_std_vector_table[vector],
+				     &__ipipe_ack_system_irq,
+				     IPIPE_CALLASM_MASK | IPIPE_HANDLE_MASK |
+				     IPIPE_PASS_MASK);
+
+		__ipipe_set_irq_gate(vector,
+				     __ipipe_irq_trampolines[vector -
+							     FIRST_EXTERNAL_VECTOR]);
+	}
+
+#endif	/* CONFIG_SMP */
+
+	ipipe_running = 1;
+
+	ipipe_critical_exit(flags);
+
+	printk(KERN_WARNING "I-pipe: Pipelining started.\n");
+}
+
+/* __ipipe_disable_pipeline() -- Disengage the pipeline. */
+
+void __ipipe_disable_pipeline(void)
+{
+	unsigned vector, irq;
+	unsigned long flags;
+
+	flags = ipipe_critical_enter(NULL);
+
+	/* Restore interrupt controllers. */
+
+	for (irq = 0; irq < NR_IRQS; irq++)
+		*irq_desc[irq].handler = __ipipe_std_irq_dtype[irq];
+
+	/* Restore original IDT settings. */
+
+	for (irq = 0;
+	     irq < NR_IRQS && irq + FIRST_EXTERNAL_VECTOR < FIRST_SYSTEM_VECTOR;
+	     irq++) {
+#ifdef CONFIG_X86_IO_APIC
+		if (IO_APIC_IRQ(irq)) {
+			vector = IO_APIC_VECTOR(irq);
+
+			if (vector == 0)
+				continue;
+		} else
+#endif	/* CONFIG_X86_IO_APIC */
+		{
+			vector = irq + FIRST_EXTERNAL_VECTOR;
+
+			if (vector == SYSCALL_VECTOR)
+				continue;
+		}
+
+		__ipipe_set_irq_gate(vector, __ipipe_std_vector_table[vector]);
+	}
+
+#ifdef CONFIG_X86_LOCAL_APIC
+
+	for (vector = FIRST_SYSTEM_VECTOR; vector < CALL_FUNCTION_VECTOR;
+	     vector++)
+		__ipipe_set_irq_gate(vector, __ipipe_std_vector_table[vector]);
+
+#endif	/* CONFIG_X86_LOCAL_APIC */
+
+#ifdef CONFIG_SMP
+
+	for (vector = CALL_FUNCTION_VECTOR; vector < SPURIOUS_APIC_VECTOR;
+	     vector++)
+		__ipipe_set_irq_gate(vector, __ipipe_std_vector_table[vector]);
+
+	__ipipe_set_irq_gate(IPIPE_CRITICAL_VECTOR,
+			     __ipipe_std_vector_table[IPIPE_CRITICAL_VECTOR]);
+
+#endif	/* CONFIG_SMP */
+
+	ipipe_running = 0;
+
+	ipipe_critical_exit(flags);
+
+	printk(KERN_WARNING "I-pipe: Pipelining stopped.\n");
+}
+
+/* ipipe_virtualize_irq_from() -- Attach a handler (and optionally a
+   hw acknowledge routine) to an interrupt for the given domain. */
+
+int ipipe_virtualize_irq_from(struct ipipe_domain *ipd,
+			      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 (ipd->irqs[irq].control & IPIPE_SYSTEM_MASK)
+		return -EPERM;
+
+	spin_lock_irqsave_hw(&__ipipe_pipelock, flags);
+
+	if (handler != NULL) {
+
+		if (handler == IPIPE_SAME_HANDLER) {
+			handler = ipd->irqs[irq].handler;
+
+			if (handler == NULL) {
+				err = -EINVAL;
+				goto unlock_and_exit;
+			}
+		} else if ((modemask & IPIPE_EXCLUSIVE_MASK) != 0 &&
+			   ipd->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 = ipipe_root_domain->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;
+		}
+	}
+
+	ipd->irqs[irq].handler = handler;
+	ipd->irqs[irq].acknowledge = acknowledge;
+	ipd->irqs[irq].control = modemask;
+
+	if (irq < NR_IRQS &&
+	    handler != NULL &&
+	    !ipipe_virtual_irq_p(irq) && (modemask & IPIPE_ENABLE_MASK) != 0) {
+		if (ipd != ipipe_current_domain) {
+			/* 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 'ipd' descriptor which
+			   thus may be different from ipipe_current_domain. */
+			err = -EPERM;
+			goto unlock_and_exit;
+		}
+
+		irq_desc[irq].handler->enable(irq);
+	}
+
+	err = 0;
+
+      unlock_and_exit:
+
+	spin_unlock_irqrestore_hw(&__ipipe_pipelock, flags);
+
+	return err;
+}
+
+/* ipipe_control_irq() -- Change modes of a pipelined interrupt for
+ * the current domain. */
+
+int ipipe_control_irq(unsigned irq, unsigned clrmask, unsigned setmask)
+{
+	struct ipipe_domain *ipd;
+	unsigned long flags;
+	irq_desc_t *desc;
+
+	if (irq >= IPIPE_NR_IRQS)
+		return -EINVAL;
+
+	ipd = ipipe_current_domain;
+
+	if (ipd->irqs[irq].control & IPIPE_SYSTEM_MASK)
+		return -EPERM;
+
+	if (((setmask | clrmask) & IPIPE_SHARED_MASK) != 0)
+		return -EINVAL;
+
+	desc = irq_desc + irq;
+
+	if (ipd->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);
+
+	spin_lock_irqsave_hw(&__ipipe_pipelock, flags);
+
+	ipd->irqs[irq].control &= ~clrmask;
+	ipd->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);
+
+	spin_unlock_irqrestore_hw(&__ipipe_pipelock, flags);
+
+	return 0;
+}
+
+void __ipipe_cleanup_domain(struct ipipe_domain *ipd)
+{
+	ipipe_unstall_pipeline_from(ipd);
+
+#ifdef CONFIG_SMP
+	{
+		int nr_cpus = num_online_cpus(), _cpuid;
+
+		for (_cpuid = 0; _cpuid < nr_cpus; _cpuid++)
+			while (ipd->cpudata[_cpuid].irq_pending_hi != 0)
+				cpu_relax();
+	}
+#endif	/* CONFIG_SMP */
+}
+
+int ipipe_get_sysinfo(struct ipipe_sysinfo *info)
+{
+	info->ncpus = num_online_cpus();
+	info->cpufreq = ipipe_cpu_freq();
+	info->archdep.tmirq = __ipipe_tick_irq;
+#ifdef CONFIG_X86_TSC
+	info->archdep.tmfreq = ipipe_cpu_freq();
+#else	/* !CONFIG_X86_TSC */
+	info->archdep.tmfreq = CLOCK_TICK_RATE;
+#endif	/* CONFIG_X86_TSC */
+
+	return 0;
+}
diff -uNrp linux-2.6.12/kernel/Makefile linux-2.6.12-ipipe-0.6/kernel/Makefile
--- linux-2.6.12/kernel/Makefile	2005-06-17 21:48:29.000000000 +0200
+++ linux-2.6.12-ipipe-0.6/kernel/Makefile	2005-06-19 11:38:37.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 wait.o kfifo.o sys_ni.o posix-cpu-timers.o
 
+obj-$(CONFIG_IPIPE_CORE) += ipipe.o
 obj-$(CONFIG_FUTEX) += futex.o
 obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
 obj-$(CONFIG_SMP) += cpu.o spinlock.o
diff -uNrp linux-2.6.12/kernel/ipipe.c linux-2.6.12-ipipe-0.6/kernel/ipipe.c
--- linux-2.6.12/kernel/ipipe.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.12-ipipe-0.6/kernel/ipipe.c	2005-06-19 11:38:37.000000000 +0200
@@ -0,0 +1,479 @@
+/*   -*- linux-c -*-
+ *   linux/kernel/ipipe.c
+ *
+ *   Copyright (C) 2002-2005 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 I-PIPE core support.
+ */
+
+#include <linux/sched.h>
+#include <linux/module.h>
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#endif	/* CONFIG_PROC_FS */
+
+static struct ipipe_domain ipipe_root;
+
+struct ipipe_domain *ipipe_root_domain = &ipipe_root;
+
+struct ipipe_domain *ipipe_percpu_domain[IPIPE_NR_CPUS] =
+    {[0 ... IPIPE_NR_CPUS - 1] = &ipipe_root };
+
+raw_spinlock_t __ipipe_pipelock = RAW_SPIN_LOCK_UNLOCKED;
+
+struct list_head __ipipe_pipeline;
+
+int ipipe_running;
+
+unsigned long __ipipe_virtual_irq_map = 0;
+
+unsigned __ipipe_printk_virq;
+
+/* ipipe_init() -- Initialization routine of the IPIPE layer. Called
+   by the host kernel early during the boot procedure. */
+
+void ipipe_init(void)
+{
+	struct ipipe_domain *ipd = &ipipe_root;
+
+	__ipipe_check_platform();	/* Do platform dependent checks first. */
+
+	/*
+	   A lightweight registration code for the root domain. We are
+	   running on the boot CPU, and secondary CPUs are still lost
+	   in space.
+	 */
+
+	INIT_LIST_HEAD(&__ipipe_pipeline);
+
+	ipd->name = "Linux";
+	ipd->domid = IPIPE_ROOT_ID;
+	ipd->priority = IPIPE_ROOT_PRI;
+
+	__ipipe_init_stage(ipd);
+
+	INIT_LIST_HEAD(&ipd->p_link);
+	list_add_tail(&ipd->p_link, &__ipipe_pipeline);
+
+	__ipipe_init_platform();
+
+	__ipipe_printk_virq = ipipe_alloc_virq();	/* Cannot fail here. */
+	ipd->irqs[__ipipe_printk_virq].handler = &__ipipe_sync_console;
+	ipd->irqs[__ipipe_printk_virq].acknowledge = NULL;
+	ipd->irqs[__ipipe_printk_virq].control = IPIPE_HANDLE_MASK;
+
+	printk(KERN_INFO "I-pipe %s: Root domain %s registered.\n",
+	       IPIPE_VERSION_STRING, ipd->name);
+}
+
+void __ipipe_stall_root(void)
+{
+	if (ipipe_running) {
+		ipipe_declare_cpuid;
+
+#ifdef CONFIG_SMP
+		unsigned long flags;
+		ipipe_lock_cpu(flags); /* Care for migration. */
+		__set_bit(IPIPE_STALL_FLAG,
+			  &ipipe_root_domain->cpudata[cpuid].status);
+		ipipe_unlock_cpu(flags);
+#else	/* !CONFIG_SMP */
+		set_bit(IPIPE_STALL_FLAG,
+			&ipipe_root_domain->cpudata[cpuid].status);
+#endif	/* CONFIG_SMP */
+	} else
+		local_irq_disable_hw();
+}
+
+void __ipipe_unstall_root(void)
+{
+	if (ipipe_running) {
+		ipipe_declare_cpuid;
+
+		local_irq_disable_hw();
+
+		ipipe_load_cpuid();
+
+		__clear_bit(IPIPE_STALL_FLAG,
+			    &ipipe_root_domain->cpudata[cpuid].status);
+
+		if (ipipe_root_domain->cpudata[cpuid].irq_pending_hi != 0)
+			__ipipe_sync_stage(IPIPE_IRQMASK_ANY);
+	}
+
+	local_irq_enable_hw();	/* Needed in both cases. */
+}
+
+unsigned long __ipipe_test_root(void)
+{
+	if (ipipe_running) {
+		ipipe_declare_cpuid;
+		unsigned long s;
+
+#ifdef CONFIG_SMP
+		unsigned long flags;
+		ipipe_lock_cpu(flags); /* Care for migration. */
+		s = test_bit(IPIPE_STALL_FLAG,
+			     &ipipe_root_domain->cpudata[cpuid].status);
+		ipipe_unlock_cpu(flags);
+#else	/* !CONFIG_SMP */
+		s = test_bit(IPIPE_STALL_FLAG,
+			     &ipipe_root_domain->cpudata[cpuid].status);
+#endif	/* CONFIG_SMP */
+
+		return s;
+	}
+
+	return irqs_disabled_hw();
+}
+
+unsigned long __ipipe_test_and_stall_root(void)
+{
+	unsigned long flags;
+
+	if (ipipe_running) {
+		ipipe_declare_cpuid;
+		unsigned long s;
+
+#ifdef CONFIG_SMP
+		ipipe_lock_cpu(flags); /* Care for migration. */
+		s = __test_and_set_bit(IPIPE_STALL_FLAG,
+				       &ipipe_root_domain->cpudata[cpuid].
+				       status);
+		ipipe_unlock_cpu(flags);
+#else	/* !CONFIG_SMP */
+		s = test_and_set_bit(IPIPE_STALL_FLAG,
+				     &ipipe_root_domain->cpudata[cpuid].status);
+#endif	/* CONFIG_SMP */
+
+		return s;
+	}
+
+	local_irq_save_hw(flags);
+
+	return !local_test_iflag_hw(flags);
+}
+
+void fastcall __ipipe_restore_root(unsigned long flags)
+{
+	if (flags)
+		__ipipe_stall_root();
+	else
+		__ipipe_unstall_root();
+}
+
+/* ipipe_unstall_pipeline_from() -- Unstall the pipeline and
+   synchronize pending interrupts for a given domain. See
+   __ipipe_walk_pipeline() for more information. */
+
+void fastcall ipipe_unstall_pipeline_from(struct ipipe_domain *ipd)
+{
+	struct ipipe_domain *this_domain;
+	struct list_head *pos;
+	unsigned long flags;
+	ipipe_declare_cpuid;
+
+	ipipe_lock_cpu(flags);
+
+	__clear_bit(IPIPE_STALL_FLAG, &ipd->cpudata[cpuid].status);
+
+	this_domain = ipipe_percpu_domain[cpuid];
+
+	if (ipd == this_domain) {
+		if (ipd->cpudata[cpuid].irq_pending_hi != 0)
+			__ipipe_sync_stage(IPIPE_IRQMASK_ANY);
+
+		goto release_cpu_and_exit;
+	}
+
+	list_for_each(pos, &__ipipe_pipeline) {
+
+		struct ipipe_domain *next_domain =
+		    list_entry(pos, struct ipipe_domain, p_link);
+
+		if (test_bit
+		    (IPIPE_STALL_FLAG, &next_domain->cpudata[cpuid].status))
+			break;	/* Stalled stage -- do not go further. */
+
+		if (next_domain->cpudata[cpuid].irq_pending_hi != 0) {
+
+			if (next_domain == this_domain)
+				__ipipe_sync_stage(IPIPE_IRQMASK_ANY);
+			else {
+				__ipipe_switch_to(this_domain, next_domain,
+						  cpuid);
+
+				ipipe_load_cpuid();	/* Processor might have changed. */
+
+				if (this_domain->cpudata[cpuid].
+				    irq_pending_hi != 0
+				    && !test_bit(IPIPE_STALL_FLAG,
+						 &this_domain->cpudata[cpuid].
+						 status)
+				    && !test_bit(IPIPE_SYNC_FLAG,
+						 &this_domain->cpudata[cpuid].
+						 status))
+					__ipipe_sync_stage(IPIPE_IRQMASK_ANY);
+			}
+
+			break;
+		} else if (next_domain == this_domain)
+			break;
+	}
+
+      release_cpu_and_exit:
+
+	if (__ipipe_pipeline_head_p(ipd))
+		local_irq_enable_hw();
+	else
+		ipipe_unlock_cpu(flags);
+}
+
+/* ipipe_suspend_domain() -- Suspend the current domain, switching to
+   the next one which has pending work down the pipeline. */
+
+void ipipe_suspend_domain(void)
+{
+	struct ipipe_domain *this_domain, *next_domain;
+	struct list_head *ln;
+	unsigned long flags;
+	ipipe_declare_cpuid;
+
+	ipipe_lock_cpu(flags);
+
+	this_domain = next_domain = ipipe_percpu_domain[cpuid];
+
+	__clear_bit(IPIPE_STALL_FLAG, &this_domain->cpudata[cpuid].status);
+
+	if (this_domain->cpudata[cpuid].irq_pending_hi != 0)
+		goto sync_stage;
+
+	for (;;) {
+		ln = next_domain->p_link.next;
+
+		if (ln == &__ipipe_pipeline)
+			break;
+
+		next_domain = list_entry(ln, struct ipipe_domain, p_link);
+
+		if (test_bit
+		    (IPIPE_STALL_FLAG, &next_domain->cpudata[cpuid].status))
+			break;
+
+		if (next_domain->cpudata[cpuid].irq_pending_hi == 0)
+			continue;
+
+		ipipe_percpu_domain[cpuid] = next_domain;
+
+	      sync_stage:
+
+		__ipipe_sync_stage(IPIPE_IRQMASK_ANY);
+
+		ipipe_load_cpuid();	/* Processor might have changed. */
+
+		if (ipipe_percpu_domain[cpuid] != next_domain)
+			/* Something has changed the current domain under our feet
+			   recycling the register set; take note. */
+			this_domain = ipipe_percpu_domain[cpuid];
+	}
+
+	ipipe_percpu_domain[cpuid] = this_domain;
+
+	ipipe_unlock_cpu(flags);
+}
+
+/* ipipe_alloc_virq() -- Allocate a pipelined virtual/soft interrupt.
+   Virtual interrupts are handled in exactly the same way than their
+   hw-generated counterparts wrt pipelining. */
+
+unsigned ipipe_alloc_virq(void)
+{
+	unsigned long flags, irq = 0;
+	int ipos;
+
+	spin_lock_irqsave_hw(&__ipipe_pipelock, flags);
+
+	if (__ipipe_virtual_irq_map != ~0) {
+		ipos = ffz(__ipipe_virtual_irq_map);
+		set_bit(ipos, &__ipipe_virtual_irq_map);
+		irq = ipos + IPIPE_VIRQ_BASE;
+	}
+
+	spin_unlock_irqrestore_hw(&__ipipe_pipelock, flags);
+
+	return irq;
+}
+
+#ifdef CONFIG_PROC_FS
+
+#include <linux/proc_fs.h>
+
+static struct proc_dir_entry *ipipe_proc_entry;
+
+static int __ipipe_read_proc(char *page,
+			     char **start,
+			     off_t off, int count, int *eof, void *data)
+{
+	unsigned long ctlbits;
+	struct list_head *pos;
+	unsigned irq, _irq;
+	char *p = page;
+	int len;
+
+#ifdef CONFIG_IPIPE_MODULE
+	p += sprintf(p, "%s -- Pipelining: %s\n", IPIPE_VERSION_STRING,
+		     ipipe_running ? "active" : "stopped");
+#else	/* !CONFIG_IPIPE_MODULE */
+	p += sprintf(p, "%s -- Pipelining: permanent\n", IPIPE_VERSION_STRING);
+#endif	/* CONFIG_IPIPE_MODULE */
+
+	spin_lock(&__ipipe_pipelock);
+
+	list_for_each(pos, &__ipipe_pipeline) {
+
+		struct ipipe_domain *ipd =
+		    list_entry(pos, struct ipipe_domain, p_link);
+
+		p += sprintf(p, "%8s: priority=%d, id=0x%.8x\n",
+			     ipd->name, ipd->priority, ipd->domid);
+		irq = 0;
+
+		while (irq < IPIPE_NR_IRQS) {
+			ctlbits =
+			    (ipd->irqs[irq].
+			     control & (IPIPE_HANDLE_MASK | IPIPE_PASS_MASK |
+					IPIPE_STICKY_MASK));
+
+			if (irq >= IPIPE_NR_XIRQS && !ipipe_virtual_irq_p(irq)) {
+				/* There might be a hole between the last external IRQ
+				   and the first virtual one; skip it. */
+				irq++;
+				continue;
+			}
+
+			if (ipipe_virtual_irq_p(irq)
+			    && !test_bit(irq - IPIPE_VIRQ_BASE,
+					 &__ipipe_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 (ipipe_virtual_irq_p(_irq) !=
+				    ipipe_virtual_irq_p(irq)
+				    || (ipipe_virtual_irq_p(_irq)
+					&& !test_bit(_irq - IPIPE_VIRQ_BASE,
+						     &__ipipe_virtual_irq_map))
+				    || ctlbits !=
+				    (ipd->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 the I-pipe.
+			   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 (ipipe_virtual_irq_p(irq))
+				p += sprintf(p, ", virtual");
+
+			p += sprintf(p, "\n");
+
+			irq = _irq;
+		}
+	}
+
+	spin_unlock(&__ipipe_pipelock);
+
+	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 __ipipe_init_proc(void)
+{
+
+	ipipe_proc_entry = create_proc_read_entry("ipipe",
+						  0444,
+						  NULL,
+						  &__ipipe_read_proc, NULL);
+}
+
+#endif	/* CONFIG_PROC_FS */
+
+EXPORT_SYMBOL(ipipe_suspend_domain);
+EXPORT_SYMBOL(ipipe_alloc_virq);
+EXPORT_SYMBOL(ipipe_unstall_pipeline_from);
+EXPORT_SYMBOL(ipipe_percpu_domain);
+EXPORT_SYMBOL(ipipe_root_domain);
+EXPORT_SYMBOL(ipipe_running);
+EXPORT_SYMBOL(__ipipe_unstall_root);
+EXPORT_SYMBOL(__ipipe_stall_root);
+EXPORT_SYMBOL(__ipipe_restore_root);
+EXPORT_SYMBOL(__ipipe_test_and_stall_root);
+EXPORT_SYMBOL(__ipipe_test_root);
+EXPORT_SYMBOL(__ipipe_pipeline);
+EXPORT_SYMBOL(__ipipe_pipelock);
+EXPORT_SYMBOL(__ipipe_virtual_irq_map);
diff -uNrp linux-2.6.12/kernel/irq/handle.c linux-2.6.12-ipipe-0.6/kernel/irq/handle.c
--- linux-2.6.12/kernel/irq/handle.c	2005-06-17 21:48:29.000000000 +0200
+++ linux-2.6.12-ipipe-0.6/kernel/irq/handle.c	2005-06-19 11:38:37.000000000 +0200
@@ -81,6 +81,15 @@ fastcall int handle_IRQ_event(unsigned i
 {
 	int ret, retval = 0, status = 0;
 
+#ifdef CONFIG_IPIPE_CORE
+	/* If processing a timer tick, pass the original regs as
+	   collected during preemption and not our phony - always
+	   kernel-originated - frame, so that we don't wreck the
+	   profiling code. */
+	if (ipipe_running && __ipipe_tick_irq == irq)
+		regs = __ipipe_tick_regs + smp_processor_id();
+#endif /* CONFIG_IPIPE_CORE */
+
 	if (!(action->flags & SA_INTERRUPT))
 		local_irq_enable();
 
diff -uNrp linux-2.6.12/kernel/printk.c linux-2.6.12-ipipe-0.6/kernel/printk.c
--- linux-2.6.12/kernel/printk.c	2005-06-17 21:48:29.000000000 +0200
+++ linux-2.6.12-ipipe-0.6/kernel/printk.c	2005-06-19 11:38:37.000000000 +0200
@@ -248,18 +248,18 @@ int do_syslog(int type, char __user * bu
 		if (error)
 			goto out;
 		i = 0;
-		spin_lock_irq(&logbuf_lock);
+		spin_lock_irq_hw(&logbuf_lock);
 		while (!error && (log_start != log_end) && i < len) {
 			c = LOG_BUF(log_start);
 			log_start++;
-			spin_unlock_irq(&logbuf_lock);
+			spin_unlock_irq_hw(&logbuf_lock);
 			error = __put_user(c,buf);
 			buf++;
 			i++;
 			cond_resched();
-			spin_lock_irq(&logbuf_lock);
+			spin_lock_irq_hw(&logbuf_lock);
 		}
-		spin_unlock_irq(&logbuf_lock);
+		spin_unlock_irq_hw(&logbuf_lock);
 		if (!error)
 			error = i;
 		break;
@@ -280,7 +280,7 @@ int do_syslog(int type, char __user * bu
 		count = len;
 		if (count > log_buf_len)
 			count = log_buf_len;
-		spin_lock_irq(&logbuf_lock);
+		spin_lock_irq_hw(&logbuf_lock);
 		if (count > logged_chars)
 			count = logged_chars;
 		if (do_clear)
@@ -297,12 +297,12 @@ int do_syslog(int type, char __user * bu
 			if (j + log_buf_len < log_end)
 				break;
 			c = LOG_BUF(j);
-			spin_unlock_irq(&logbuf_lock);
+			spin_unlock_irq_hw(&logbuf_lock);
 			error = __put_user(c,&buf[count-1-i]);
 			cond_resched();
-			spin_lock_irq(&logbuf_lock);
+			spin_lock_irq_hw(&logbuf_lock);
 		}
-		spin_unlock_irq(&logbuf_lock);
+		spin_unlock_irq_hw(&logbuf_lock);
 		if (error)
 			break;
 		error = i;
@@ -526,7 +526,7 @@ asmlinkage int vprintk(const char *fmt, 
 		zap_locks();
 
 	/* This stops the holder of console_sem just where we want him */
-	spin_lock_irqsave(&logbuf_lock, flags);
+	spin_lock_irqsave_hw(&logbuf_lock, flags);
 
 	/* Emit the output into the temporary buffer */
 	printed_len = vscnprintf(printk_buf, sizeof(printk_buf), fmt, args);
@@ -588,6 +588,26 @@ asmlinkage int vprintk(const char *fmt, 
 			log_level_unknown = 1;
 	}
 
+#ifdef CONFIG_IPIPE_CORE
+	if (ipipe_current_domain != ipipe_root_domain &&
+	    !test_bit(IPIPE_SPRINTK_FLAG,&ipipe_current_domain->flags) &&
+	    !oops_in_progress) {
+	/* 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. Oopsing overrides the
+	   mode to synchronous. */
+ 	    spin_unlock_irqrestore_hw(&logbuf_lock, flags);
+ 
+ 	    if (!test_and_set_bit(IPIPE_PPRINTK_FLAG,&ipipe_root_domain->flags))
+ 		ipipe_trigger_irq(__ipipe_printk_virq);
+ 
+ 	    goto out;
+ 	}
+#endif /* CONFIG_IPIPE_CORE */
 	if (!cpu_online(smp_processor_id()) &&
 	    system_state != SYSTEM_RUNNING) {
 		/*
@@ -596,16 +616,20 @@ asmlinkage int vprintk(const char *fmt, 
 		 * CPU until it is officially up.  We shouldn't be calling into
 		 * random console drivers on a CPU which doesn't exist yet..
 		 */
-		spin_unlock_irqrestore(&logbuf_lock, flags);
+		spin_unlock_irqrestore_hw(&logbuf_lock, flags);
 		goto out;
 	}
-	if (!down_trylock(&console_sem)) {
+#ifdef CONFIG_IPIPE_CORE
+ 	if (ipipe_current_domain != ipipe_root_domain || !down_trylock(&console_sem)) {
+#else /* !CONFIG_IPIPE_CORE */
+ 	if (!down_trylock(&console_sem)) {
+#endif /* CONFIG_IPIPE_CORE */
 		console_locked = 1;
 		/*
 		 * We own the drivers.  We can drop the spinlock and let
 		 * release_console_sem() print the text
 		 */
-		spin_unlock_irqrestore(&logbuf_lock, flags);
+		spin_unlock_irqrestore_hw(&logbuf_lock, flags);
 		console_may_schedule = 0;
 		release_console_sem();
 	} else {
@@ -614,7 +638,7 @@ asmlinkage int vprintk(const char *fmt, 
 		 * allows the semaphore holder to proceed and to call the
 		 * console drivers with the output which we just produced.
 		 */
-		spin_unlock_irqrestore(&logbuf_lock, flags);
+		spin_unlock_irqrestore_hw(&logbuf_lock, flags);
 	}
 out:
 	return printed_len;
@@ -725,26 +749,60 @@ void release_console_sem(void)
 	unsigned long wake_klogd = 0;
 
 	for ( ; ; ) {
-		spin_lock_irqsave(&logbuf_lock, flags);
+		spin_lock_irqsave_hw(&logbuf_lock, flags);
 		wake_klogd |= log_start - log_end;
 		if (con_start == log_end)
 			break;			/* Nothing to print */
 		_con_start = con_start;
 		_log_end = log_end;
 		con_start = log_end;		/* Flush */
-		spin_unlock(&logbuf_lock);
+		spin_unlock_hw(&logbuf_lock);
 		call_console_drivers(_con_start, _log_end);
-		local_irq_restore(flags);
+		local_irq_restore_hw(flags);
 	}
 	console_locked = 0;
 	console_may_schedule = 0;
+#ifdef CONFIG_IPIPE_CORE
+	if (ipipe_root_domain != ipipe_current_domain) {
+	    spin_unlock_irqrestore_hw(&logbuf_lock, flags);
+	    return;
+	}
+	spin_unlock_irqrestore_hw(&logbuf_lock, flags);
+	up(&console_sem);
+#else /* !CONFIG_IPIPE_CORE */
 	up(&console_sem);
-	spin_unlock_irqrestore(&logbuf_lock, flags);
+	spin_unlock_irqrestore_hw(&logbuf_lock, flags);
+#endif /* CONFIG_IPIPE_CORE */
 	if (wake_klogd && !oops_in_progress && waitqueue_active(&log_wait))
 		wake_up_interruptible(&log_wait);
 }
 EXPORT_SYMBOL(release_console_sem);
 
+#ifdef CONFIG_IPIPE_CORE
+void __ipipe_sync_console (unsigned virq) {
+
+    /* This handler always runs on behalf of the root (Linux) domain. */
+
+    unsigned long flags;
+
+    spin_lock_irqsave_hw(&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(IPIPE_PPRINTK_FLAG,&ipipe_root_domain->flags);
+
+    if (cpu_online(smp_processor_id()) && system_state == SYSTEM_RUNNING && !down_trylock(&console_sem)) {
+        console_locked = 1;
+	spin_unlock_irqrestore_hw(&logbuf_lock, flags);
+        console_may_schedule = 0;
+	release_console_sem();
+    } else
+	spin_unlock_irqrestore_hw(&logbuf_lock, flags);
+}
+#endif /* CONFIG_IPIPE_CORE */
+
 /** console_conditional_schedule - yield the CPU if required
  *
  * If the console code is currently allowed to sleep, and
@@ -906,9 +964,9 @@ void register_console(struct console * c
 		 * release_console_sem() will print out the buffered messages
 		 * for us.
 		 */
-		spin_lock_irqsave(&logbuf_lock, flags);
+		spin_lock_irqsave_hw(&logbuf_lock, flags);
 		con_start = log_start;
-		spin_unlock_irqrestore(&logbuf_lock, flags);
+		spin_unlock_irqrestore_hw(&logbuf_lock, flags);
 	}
 	release_console_sem();
 }
@@ -977,7 +1035,7 @@ int __printk_ratelimit(int ratelimit_jif
 	unsigned long flags;
 	unsigned long now = jiffies;
 
-	spin_lock_irqsave(&ratelimit_lock, flags);
+	spin_lock_irqsave_hw(&ratelimit_lock, flags);
 	toks += now - last_msg;
 	last_msg = now;
 	if (toks > (ratelimit_burst * ratelimit_jiffies))
@@ -986,13 +1044,13 @@ int __printk_ratelimit(int ratelimit_jif
 		int lost = missed;
 		missed = 0;
 		toks -= ratelimit_jiffies;
-		spin_unlock_irqrestore(&ratelimit_lock, flags);
+		spin_unlock_irqrestore_hw(&ratelimit_lock, flags);
 		if (lost)
 			printk(KERN_WARNING "printk: %d messages suppressed.\n", lost);
 		return 1;
 	}
 	missed++;
-	spin_unlock_irqrestore(&ratelimit_lock, flags);
+	spin_unlock_irqrestore_hw(&ratelimit_lock, flags);
 	return 0;
 }
 EXPORT_SYMBOL(__printk_ratelimit);
diff -uNrp linux-2.6.12/kernel/sysctl.c linux-2.6.12-ipipe-0.6/kernel/sysctl.c
--- linux-2.6.12/kernel/sysctl.c	2005-06-17 21:48:29.000000000 +0200
+++ linux-2.6.12-ipipe-0.6/kernel/sysctl.c	2005-06-19 11:38:37.000000000 +0200
@@ -968,6 +968,9 @@ void __init sysctl_init(void)
 #ifdef CONFIG_PROC_FS
 	register_proc_table(root_table, proc_sys_root);
 	init_irq_proc();
+#ifdef CONFIG_IPIPE_CORE
+	__ipipe_init_proc();
+#endif /* CONFIG_IPIPE_CORE */
 #endif
 }
 
diff -uNrp linux-2.6.12/lib/kernel_lock.c linux-2.6.12-ipipe-0.6/lib/kernel_lock.c
--- linux-2.6.12/lib/kernel_lock.c	2005-06-17 21:48:29.000000000 +0200
+++ linux-2.6.12-ipipe-0.6/lib/kernel_lock.c	2005-06-19 11:38:37.000000000 +0200
@@ -20,6 +20,10 @@ unsigned int smp_processor_id(void)
 	unsigned long preempt_count = preempt_count();
 	int this_cpu = __smp_processor_id();
 	cpumask_t this_mask;
+#ifdef CONFIG_IPIPE_CORE
+	if (ipipe_current_domain != ipipe_root_domain)
+	    return this_cpu;
+#endif /* CONFIG_IPIPE_CORE */
 
 	if (likely(preempt_count))
 		goto out;
diff -uNrp linux-2.6.12/mm/vmalloc.c linux-2.6.12-ipipe-0.6/mm/vmalloc.c
--- linux-2.6.12/mm/vmalloc.c	2005-06-17 21:48:29.000000000 +0200
+++ linux-2.6.12-ipipe-0.6/mm/vmalloc.c	2005-06-19 11:38:37.000000000 +0200
@@ -18,6 +18,7 @@
 
 #include <asm/uaccess.h>
 #include <asm/tlbflush.h>
+#include <asm/pgalloc.h>
 
 
 DEFINE_RWLOCK(vmlist_lock);
@@ -148,10 +149,13 @@ int map_vm_area(struct vm_struct *area, 
 	pgd = pgd_offset_k(addr);
 	spin_lock(&init_mm.page_table_lock);
 	do {
+		pgd_t oldpgd = *pgd;
 		next = pgd_addr_end(addr, end);
 		err = vmap_pud_range(pgd, addr, next, prot, pages);
 		if (err)
 			break;
+		if (pgd_val(oldpgd) != pgd_val(*pgd))
+			set_pgdir(addr, *pgd);
 	} while (pgd++, addr = next, addr != end);
 	spin_unlock(&init_mm.page_table_lock);
 	flush_cache_vmap((unsigned long) area->addr, end);
