diff -Naur linux-2.4.20/Documentation/Configure.help linux-2.4.20-rtai/Documentation/Configure.help
--- linux-2.4.20/Documentation/Configure.help	Fri Nov 29 19:01:31 2002
+++ linux-2.4.20-rtai/Documentation/Configure.help	Mon Dec  2 16:11:55 2002
@@ -254,6 +254,13 @@
   You will need a new lynxer.elf file to flash your firmware with - send
   email to Martin.Bligh@us.ibm.com
 
+Real-Time Harware Abstraction
+CONFIG_RTHAL
+  The Real-Time Hardware Abstraction Layer (RTHAL) is used by
+  the Real-Time Application Interface (RTAI) to provide a
+  hard real-time environment as part of Linux.  This feature
+  cannot be turned off, so say Y.
+
 Support for IBM Summit (EXA) systems
 CONFIG_X86_SUMMIT
   This option is needed for IBM systems that use the Summit/EXA chipset.
diff -Naur linux-2.4.20/arch/i386/config.in linux-2.4.20-rtai/arch/i386/config.in
--- linux-2.4.20/arch/i386/config.in	Fri Nov 29 19:01:34 2002
+++ linux-2.4.20-rtai/arch/i386/config.in	Mon Dec  2 16:11:55 2002
@@ -256,6 +256,8 @@
 if [ "$CONFIG_SMP" = "y" -a "$CONFIG_X86_CMPXCHG" = "y" ]; then
    define_bool CONFIG_HAVE_DEC_LOCK y
 fi
+comment 'CONFIG_RTHAL must be yes'
+bool 'Real-Time Hardware Abstraction Layer' CONFIG_RTHAL
 endmenu
 
 mainmenu_option next_comment
diff -Naur linux-2.4.20/arch/i386/defconfig linux-2.4.20-rtai/arch/i386/defconfig
--- linux-2.4.20/arch/i386/defconfig	Fri Nov 29 19:01:34 2002
+++ linux-2.4.20-rtai/arch/i386/defconfig	Mon Dec  2 16:11:55 2002
@@ -66,6 +66,7 @@
 # CONFIG_MULTIQUAD is not set
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_NR_CPUS=32
+CONFIG_RTHAL=y

 #
 # General setup
diff -Naur linux-2.4.20/arch/i386/kernel/entry.S linux-2.4.20-rtai/arch/i386/kernel/entry.S
--- linux-2.4.20/arch/i386/kernel/entry.S	Fri Nov 29 19:01:34 2002
+++ linux-2.4.20-rtai/arch/i386/kernel/entry.S	Mon Dec  2 16:11:55 2002
@@ -184,6 +184,7 @@
 
 
 ENTRY(ret_from_fork)
+	sti
 	pushl %ebx
 	call SYMBOL_NAME(schedule_tail)
 	addl $4, %esp
@@ -210,17 +211,20 @@
 	call *SYMBOL_NAME(sys_call_table)(,%eax,4)
 	movl %eax,EAX(%esp)		# save the return value
 ENTRY(ret_from_sys_call)
-	cli				# need_resched and signals atomic test
+	call *(SYMBOL_NAME(rthal) + 12)	# cli
 	cmpl $0,need_resched(%ebx)
 	jne reschedule
 	cmpl $0,sigpending(%ebx)
 	jne signal_return
+	sti
+	call *(SYMBOL_NAME(rthal) + 16)	# sti
 restore_all:
 	RESTORE_ALL
 
 	ALIGN
 signal_return:
-	sti				# we can get here from an interrupt handler
+	sti			# we can get here from an interrupt handler
+	call *(SYMBOL_NAME(rthal) + 16)	# sti
 	testl $(VM_MASK),EFLAGS(%esp)
 	movl %esp,%eax
 	jne v86_signal_return
diff -Naur linux-2.4.20/arch/i386/kernel/i386_ksyms.c linux-2.4.20-rtai/arch/i386/kernel/i386_ksyms.c
--- linux-2.4.20/arch/i386/kernel/i386_ksyms.c	Sat Aug  3 02:39:42 2002
+++ linux-2.4.20-rtai/arch/i386/kernel/i386_ksyms.c	Mon Dec  2 16:11:55 2002
@@ -32,6 +32,18 @@
 extern void dump_thread(struct pt_regs *, struct user *);
 extern spinlock_t rtc_lock;
 
+EXPORT_SYMBOL_NOVERS(rthal);
+
+#ifdef CONFIG_VT
+  #include <linux/vt_kern.h>
+  EXPORT_SYMBOL(kd_mksound);
+#endif
+
+#include <linux/console.h>
+EXPORT_SYMBOL(console_drivers);
+extern unsigned long cpu_khz;
+EXPORT_SYMBOL(cpu_khz);
+
 #if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
 extern void machine_real_restart(unsigned char *, int);
 EXPORT_SYMBOL(machine_real_restart);
@@ -172,6 +184,13 @@
 
 #ifdef CONFIG_HAVE_DEC_LOCK
 EXPORT_SYMBOL(atomic_dec_and_lock);
+#endif
+
+#ifdef CONFIG_X86_REMOTE_DEBUG
+#include <linux/gdb.h>
+EXPORT_SYMBOL(linux_debug_hook);
+EXPORT_SYMBOL(gdb_irq);
+EXPORT_SYMBOL(gdb_interrupt);
 #endif
 
 extern int is_sony_vaio_laptop;
diff -Naur linux-2.4.20/arch/i386/kernel/i8259.c linux-2.4.20-rtai/arch/i386/kernel/i8259.c
--- linux-2.4.20/arch/i386/kernel/i8259.c	Tue Sep 18 08:03:09 2001
+++ linux-2.4.20-rtai/arch/i386/kernel/i8259.c	Mon Dec  2 16:11:55 2002
@@ -290,12 +290,12 @@
 
 handle_real_irq:
 	if (irq & 8) {
-		inb(0xA1);		/* DUMMY - (do we need this?) */
+//		inb(0xA1);		/* DUMMY - (do we need this?) */
 		outb(cached_A1,0xA1);
 		outb(0x60+(irq&7),0xA0);/* 'Specific EOI' to slave */
 		outb(0x62,0x20);	/* 'Specific EOI' to master-IRQ2 */
 	} else {
-		inb(0x21);		/* DUMMY - (do we need this?) */
+//		inb(0x21);		/* DUMMY - (do we need this?) */
 		outb(cached_21,0x21);
 		outb(0x60+irq,0x20);	/* 'Specific EOI' to master */
 	}
@@ -508,3 +508,17 @@
 	if (boot_cpu_data.hard_math && !cpu_has_fpu)
 		setup_irq(13, &irq13);
 }
+
+void ack_8259_irq(unsigned int irq)
+{
+	spin_lock(&i8259A_lock);
+	if (irq & 8) {
+		outb(0x62,0x20);
+		outb(0x20,0xA0);
+	} else {
+		outb(0x20,0x20);
+	}
+	spin_unlock(&i8259A_lock);
+	return;
+}
+
diff -Naur linux-2.4.20/arch/i386/kernel/io_apic.c linux-2.4.20-rtai/arch/i386/kernel/io_apic.c
--- linux-2.4.20/arch/i386/kernel/io_apic.c	Fri Nov 29 19:01:34 2002
+++ linux-2.4.20-rtai/arch/i386/kernel/io_apic.c	Mon Dec  2 16:11:55 2002
@@ -38,7 +38,7 @@
 
 #undef APIC_LOCKUP_DEBUG
 
-#define APIC_LOCKUP_DEBUG
+//#define APIC_LOCKUP_DEBUG
 
 static spinlock_t ioapic_lock = SPIN_LOCK_UNLOCKED;
 
@@ -1282,11 +1282,10 @@
 #define enable_level_ioapic_irq		unmask_IO_APIC_irq
 #define disable_level_ioapic_irq	mask_IO_APIC_irq
 
+static unsigned long strange_level;
+
 static void end_level_ioapic_irq (unsigned int irq)
 {
-	unsigned long v;
-	int i;
-
 /*
  * It appears there is an erratum which affects at least version 0x11
  * of I/O APIC (that's the 82093AA and cores integrated into various
@@ -1306,12 +1305,8 @@
  * operation to prevent an edge-triggered interrupt escaping meanwhile.
  * The idea is from Manfred Spraul.  --macro
  */
-	i = IO_APIC_VECTOR(irq);
-	v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1));
-
-	ack_APIC_irq();
 
-	if (!(v & (1 << (i & 0x1f)))) {
+	if (test_and_clear_bit(irq, &strange_level)) {
 #ifdef APIC_LOCKUP_DEBUG
 		struct irq_pin_list *entry;
 #endif
@@ -1320,7 +1315,6 @@
 		atomic_inc(&irq_mis_count);
 #endif
 		spin_lock(&ioapic_lock);
-		__mask_and_edge_IO_APIC_irq(irq);
 #ifdef APIC_LOCKUP_DEBUG
 		for (entry = irq_2_pin + irq;;) {
 			unsigned int reg;
@@ -1338,10 +1332,30 @@
 #endif
 		__unmask_and_level_IO_APIC_irq(irq);
 		spin_unlock(&ioapic_lock);
+	} else {
+		spin_lock(&ioapic_lock);
+		__unmask_IO_APIC_irq(irq);
+		spin_unlock(&ioapic_lock);
 	}
 }
 
-static void mask_and_ack_level_ioapic_irq (unsigned int irq) { /* nothing */ }
+static void mask_and_ack_level_ioapic_irq (unsigned int irq)
+{
+	unsigned long i;
+
+	i = IO_APIC_VECTOR(irq);
+	if (!(apic_read(APIC_TMR + ((i & ~0x1f) >> 1)) & (1 << (i & 0x1f)))) {
+		test_and_set_bit(irq, &strange_level);
+		spin_lock(&ioapic_lock);
+		__mask_and_edge_IO_APIC_irq(irq);
+		spin_unlock(&ioapic_lock);
+	} else {
+		spin_lock(&ioapic_lock);
+		__mask_IO_APIC_irq(irq);
+		spin_unlock(&ioapic_lock);
+	}
+	ack_APIC_irq();
+}

 #ifndef CONFIG_SMP

diff -Naur linux-2.4.20/arch/i386/kernel/irq.c linux-2.4.20-rtai/arch/i386/kernel/irq.c
--- linux-2.4.20/arch/i386/kernel/irq.c	Fri Nov 29 19:01:34 2002
+++ linux-2.4.20-rtai/arch/i386/kernel/irq.c	Mon Dec  2 16:11:55 2002
@@ -1212,3 +1212,71 @@
 		register_irq_proc(i);
 }
 
+static void linux_cli(void)
+{
+	hard_cli();
+}
+
+static void linux_sti(void)
+{
+	hard_sti();
+}
+
+static unsigned int linux_save_flags(void)
+{
+	int flags;
+	hard_save_flags(flags);
+	return flags;
+}
+
+static void linux_restore_flags(unsigned int flags)
+{
+	hard_restore_flags(flags);
+}
+
+static unsigned int linux_save_flags_and_cli(void)
+{
+	int flags;
+	hard_save_flags_and_cli(flags);
+	return flags;
+}
+
+#include <asm/mmu_context.h>
+
+#ifndef CONFIG_X86_IO_APIC
+int irq_vector[];
+#endif
+#ifndef CONFIG_SMP
+void smp_invalidate_interrupt(void) { }
+static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL };
+static volatile int physical_apicid_2_cpu[1];
+#endif
+
+extern void *ret_from_intr;
+extern struct desc_struct idt_table[];
+extern void ack_8259_irq(unsigned int);
+extern int idle_weight;
+extern void smp_invalidate_interrupt(void);
+extern void switch_mem(struct task_struct *, struct task_struct *, int);
+extern volatile int physical_apicid_2_cpu[];
+
+struct rt_hal rthal = {
+	ret_from_intr:			&ret_from_intr,
+	__switch_to:			__switch_to,
+	idt_table:			idt_table,
+	disint:				linux_cli,
+	enint:				linux_sti,
+	getflags:			linux_save_flags,
+	setflags:			linux_restore_flags,
+	getflags_and_cli:		linux_save_flags_and_cli,
+	irq_desc:			irq_desc,
+	irq_vector:			irq_vector,
+	irq_affinity:			irq_affinity,
+	smp_invalidate_interrupt:	smp_invalidate_interrupt,
+	ack_8259_irq:			ack_8259_irq,
+	idle_weight:			&idle_weight,
+	lxrt_global_cli:		NULL,
+	switch_mem:			switch_mem,
+	init_tasks:			init_tasks,
+	apicmap:			physical_apicid_2_cpu,
+};
diff -Naur linux-2.4.20/arch/i386/kernel/smp.c linux-2.4.20-rtai/arch/i386/kernel/smp.c
--- linux-2.4.20/arch/i386/kernel/smp.c	Fri Nov 29 19:01:34 2002
+++ linux-2.4.20-rtai/arch/i386/kernel/smp.c	Mon Dec  2 16:11:55 2002
@@ -160,8 +160,7 @@
 	unsigned long cfg;
 	unsigned long flags;
 
-	__save_flags(flags);
-	__cli();
+	hard_save_flags_and_cli(flags);
 
 		
 	/*
@@ -185,7 +184,7 @@
 	 */
 	apic_write_around(APIC_ICR, cfg);
 
-	__restore_flags(flags);
+	hard_restore_flags(flags);
 }
 
 static inline void send_IPI_mask_sequence(int mask, int vector)
diff -Naur linux-2.4.20/arch/i386/kernel/time.c linux-2.4.20-rtai/arch/i386/kernel/time.c
--- linux-2.4.20/arch/i386/kernel/time.c	Fri Nov 29 19:01:34 2002
+++ linux-2.4.20-rtai/arch/i386/kernel/time.c	Mon Dec  2 16:11:55 2002
@@ -673,6 +673,7 @@
 
 		rdtscl(last_tsc_low);
 
+#if 0
 		spin_lock(&i8253_lock);
 		outb_p(0x00, 0x43);     /* latch the count ASAP */
 
@@ -704,6 +705,7 @@
 
 		count = ((LATCH-1) - count) * TICK_SIZE;
 		delay_at_last_interrupt = (count + LATCH/2) / LATCH;
+#endif
 	}
 
 	do_timer_interrupt(irq, NULL, regs);
diff -Naur linux-2.4.20/arch/i386/mm/fault.c linux-2.4.20-rtai/arch/i386/mm/fault.c
--- linux-2.4.20/arch/i386/mm/fault.c	Fri Nov 29 19:01:34 2002
+++ linux-2.4.20-rtai/arch/i386/mm/fault.c	Mon Dec  2 16:11:55 2002
@@ -153,7 +153,7 @@
 
 	/* It's safe to allow irq's after cr2 has been saved */
 	if (regs->eflags & X86_EFLAGS_IF)
-		local_irq_enable();
+		hard_sti();
 
 	tsk = current;
 
diff -Naur linux-2.4.20/arch/i386/mm/ioremap.c linux-2.4.20-rtai/arch/i386/mm/ioremap.c
--- linux-2.4.20/arch/i386/mm/ioremap.c	Sat Aug  3 02:39:42 2002
+++ linux-2.4.20-rtai/arch/i386/mm/ioremap.c	Mon Dec  2 16:11:55 2002
@@ -81,6 +81,7 @@
 		if (remap_area_pmd(pmd, address, end - address,
 					 phys_addr + address, flags))
 			break;
+		set_pgdir(address, *dir);
 		error = 0;
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
diff -Naur linux-2.4.20/arch/ppc/config.in linux-2.4.20-rtai/arch/ppc/config.in
--- linux-2.4.20/arch/ppc/config.in	Fri Nov 29 19:01:45 2002
+++ linux-2.4.20-rtai/arch/ppc/config.in	Mon Dec  2 16:11:55 2002
@@ -125,6 +125,9 @@
   bool '  Distribute interrupts on all CPUs by default' CONFIG_IRQ_ALL_CPUS
 fi
 
+#bool 'Real-Time Hardware Abstraction Layer' CONFIG_RTHAL
+define_bool CONFIG_RTHAL y
+
 if [ "$CONFIG_6xx" = "y" -a "$CONFIG_8260" = "n" ];then
   bool 'AltiVec Support' CONFIG_ALTIVEC
   bool 'Thermal Management Support' CONFIG_TAU
diff -Naur linux-2.4.20/arch/ppc/kernel/entry.S linux-2.4.20-rtai/arch/ppc/kernel/entry.S
--- linux-2.4.20/arch/ppc/kernel/entry.S	Fri Nov 29 19:01:45 2002
+++ linux-2.4.20-rtai/arch/ppc/kernel/entry.S	Mon Dec  2 16:11:55 2002
@@ -291,6 +291,7 @@
 	bl	do_signal
 	.globl	do_signal_ret
 do_signal_ret:
+	bl	do_soft_sti
 	.globl ret_to_user_hook
 ret_to_user_hook:
 	nop
diff -Naur linux-2.4.20/arch/ppc/kernel/irq.c linux-2.4.20-rtai/arch/ppc/kernel/irq.c
--- linux-2.4.20/arch/ppc/kernel/irq.c	Fri Nov 29 19:01:45 2002
+++ linux-2.4.20-rtai/arch/ppc/kernel/irq.c	Mon Dec  2 16:11:55 2002
@@ -510,6 +510,17 @@
 	spin_unlock(&desc->lock);
 }
 
+void do_soft_cli(void)
+{
+}
+
+void (*rtai_soft_sti)(void);
+
+void do_soft_sti(void)
+{
+	if(rtai_soft_sti)rtai_soft_sti();
+}
+
 int do_IRQ(struct pt_regs *regs)
 {
 	int cpu = smp_processor_id();
diff -Naur linux-2.4.20/arch/ppc/kernel/traps.c linux-2.4.20-rtai/arch/ppc/kernel/traps.c
--- linux-2.4.20/arch/ppc/kernel/traps.c        Sat Nov  3 02:43:54 2001
+++ linux-2.4.20-rtai/arch/ppc/kernel/traps.c   Mon Dec  2 16:11:55 2002
@@ -320,9 +320,15 @@
 	return retval;
 }
 
+int (*rtai_srq_bckdr)(struct pt_regs *regs) = NULL;
+
 void
 ProgramCheckException(struct pt_regs *regs)
 {
+	if (rtai_srq_bckdr && !rtai_srq_bckdr(regs)) {
+		return;
+	}
+{
 	unsigned int reason = get_reason(regs);
 	extern int do_mathemu(struct pt_regs *regs);
 
@@ -378,6 +384,7 @@
 	}
 
 	_exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
+}
 }
 
 void
diff -Naur linux-2.4.20/arch/ppc/kernel/ppc_ksyms.c linux-2.4.20-rtai/arch/ppc/kernel/ppc_ksyms.c
--- linux-2.4.20/arch/ppc/kernel/ppc_ksyms.c	Fri Nov 29 19:01:46 2002
+++ linux-2.4.20-rtai/arch/ppc/kernel/ppc_ksyms.c	Mon Dec  2 16:11:55 2002
@@ -220,6 +220,12 @@
 EXPORT_SYMBOL(synchronize_irq);
 #endif
 
+extern int (*rtai_srq_bckdr)(struct pt_regs *);
+EXPORT_SYMBOL(rtai_srq_bckdr);
+
+extern void (*rtai_soft_sti)(void);
+EXPORT_SYMBOL(rtai_soft_sti);
+
 EXPORT_SYMBOL(ppc_md);
 
 #ifdef CONFIG_ADB
diff -Naur linux-2.4.20/include/asm-i386/hw_irq.h linux-2.4.20-rtai/include/asm-i386/hw_irq.h
--- linux-2.4.20/include/asm-i386/hw_irq.h	Thu Nov 22 20:46:18 2001
+++ linux-2.4.20-rtai/include/asm-i386/hw_irq.h	Mon Dec  2 16:16:00 2002
@@ -37,18 +37,31 @@
  *
  *  Vectors 0xf0-0xfa are free (reserved for future Linux use).
  */
+#ifdef CONFIG_RTHAL
+/* the standard definitions conflict with LXRT */
+#define SPURIOUS_APIC_VECTOR	0xdf
+#define ERROR_APIC_VECTOR	0xde
+#define INVALIDATE_TLB_VECTOR	0xdd
+#define RESCHEDULE_VECTOR	0xdc
+#define CALL_FUNCTION_VECTOR	0xdb
+#else
 #define SPURIOUS_APIC_VECTOR	0xff
 #define ERROR_APIC_VECTOR	0xfe
 #define INVALIDATE_TLB_VECTOR	0xfd
 #define RESCHEDULE_VECTOR	0xfc
 #define CALL_FUNCTION_VECTOR	0xfb
+#endif
 
 /*
  * Local APIC timer IRQ vector is on a different priority level,
  * to work around the 'lost local interrupt if more than 2 IRQ
  * sources per level' errata.
  */
+#ifdef CONFIG_RTHAL
+#define LOCAL_TIMER_VECTOR	0xcf
+#else
 #define LOCAL_TIMER_VECTOR	0xef
+#endif
 
 /*
  * First APIC vector available to drivers: (vectors 0x30-0xee)
@@ -56,7 +69,11 @@
  * levels. (0x80 is the syscall vector)
  */
 #define FIRST_DEVICE_VECTOR	0x31
+#ifdef CONFIG_RTHAL
+#define FIRST_SYSTEM_VECTOR	0xcf
+#else
 #define FIRST_SYSTEM_VECTOR	0xef
+#endif
 
 extern int irq_vector[NR_IRQS];
 #define IO_APIC_VECTOR(irq)	irq_vector[irq]
diff -Naur linux-2.4.20/include/asm-i386/irq.h linux-2.4.20-rtai/include/asm-i386/irq.h
--- linux-2.4.20/include/asm-i386/irq.h	Sat Aug  3 02:39:45 2002
+++ linux-2.4.20-rtai/include/asm-i386/irq.h	Mon Dec  2 16:11:55 2002
@@ -26,7 +26,7 @@
 #ifdef CONFIG_X86_IO_APIC
 #define NR_IRQS 224
 #else
-#define NR_IRQS 16
+#define NR_IRQS 32 /* 2.4.19 vanilla has 16, this is rtai back compatibility */
 #endif
 
 static __inline__ int irq_cannonicalize(int irq)
diff -Naur linux-2.4.20/include/asm-i386/pgalloc.h linux-2.4.20-rtai/include/asm-i386/pgalloc.h
--- linux-2.4.20/include/asm-i386/pgalloc.h	Sat Aug  3 02:39:45 2002
+++ linux-2.4.20-rtai/include/asm-i386/pgalloc.h	Mon Dec  2 16:16:00 2002
@@ -158,6 +158,33 @@
 
 extern int do_check_pgt_cache(int, int);
 
+extern inline void set_pgdir(unsigned long address, pgd_t entry)
+{
+	struct task_struct * p;
+	pgd_t *pgd;
+#ifdef CONFIG_SMP
+	int i;
+#endif	
+
+	read_lock(&tasklist_lock);
+	for_each_task(p) {
+		if (!p->mm)
+			continue;
+		*pgd_offset(p->mm,address) = entry;
+	}
+	read_unlock(&tasklist_lock);
+#ifndef CONFIG_SMP
+	for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
+		pgd[address >> PGDIR_SHIFT] = entry;
+#else
+	/* To pgd_alloc/pgd_free, one holds master kernel lock and so does our callee, so we can
+	   modify pgd caches of other CPUs as well. -jj */
+	for (i = 0; i < NR_CPUS; i++)
+		for (pgd = (pgd_t *)cpu_data[i].pgd_quick; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
+			pgd[address >> PGDIR_SHIFT] = entry;
+#endif
+}
+
 /*
  * TLB flushing:
  *
diff -Naur linux-2.4.20/include/asm-i386/system.h linux-2.4.20-rtai/include/asm-i386/system.h
--- linux-2.4.20/include/asm-i386/system.h	Fri Nov 29 19:02:50 2002
+++ linux-2.4.20-rtai/include/asm-i386/system.h	Mon Dec  2 16:16:00 2002
@@ -12,7 +12,12 @@
 struct task_struct;	/* one of the stranger aspects of C forward declarations.. */
 extern void FASTCALL(__switch_to(struct task_struct *prev, struct task_struct *next));
 
-#define prepare_to_switch()	do { } while(0)
+#define prepare_to_switch() do {					\
+	if (rthal.lxrt_global_cli) {					\
+		rthal.lxrt_global_cli();				\
+	}								\
+} while(0)
+
 #define switch_to(prev,next,last) do {					\
 	asm volatile("pushl %%esi\n\t"					\
 		     "pushl %%edi\n\t"					\
@@ -23,6 +28,7 @@
 		     "pushl %4\n\t"		/* restore EIP */	\
 		     "jmp __switch_to\n"				\
 		     "1:\t"						\
+		     "sti\n\t"						\
 		     "popl %%ebp\n\t"					\
 		     "popl %%edi\n\t"					\
 		     "popl %%esi\n\t"					\
@@ -315,29 +321,59 @@
 
 #define set_wmb(var, value) do { var = value; wmb(); } while (0)
 
+struct rt_hal {
+	void *ret_from_intr;
+	void *__switch_to;
+	struct desc_struct *idt_table;
+	void (*disint)(void);
+	void (*enint)(void);
+	unsigned int (*getflags)(void);
+	void (*setflags)(unsigned int flags);
+	unsigned int (*getflags_and_cli)(void);
+	void *irq_desc;
+	int *irq_vector;
+	unsigned long *irq_affinity;
+	void (*smp_invalidate_interrupt)(void);
+	void (*ack_8259_irq)(unsigned int);
+	int *idle_weight;
+	void (*lxrt_global_cli)(void);
+	void (*switch_mem)(struct task_struct *, struct task_struct *, int);
+	struct task_struct **init_tasks;
+	unsigned int *apicmap;
+};
+
+extern struct rt_hal rthal;
+
 /* interrupt control.. */
-#define __save_flags(x)		__asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */)
-#define __restore_flags(x) 	__asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory", "cc")
-#define __cli() 		__asm__ __volatile__("cli": : :"memory")
-#define __sti()			__asm__ __volatile__("sti": : :"memory")
-/* used in the idle loop; sti takes one instruction cycle to complete */
-#define safe_halt()		__asm__ __volatile__("sti; hlt": : :"memory")
+#define hard_save_flags(x)		__asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */)
+#define hard_restore_flags(x) 		__asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory", "cc")
+#define hard_cli() 			__asm__ __volatile__("cli": : :"memory")
+#define hard_sti()			__asm__ __volatile__("sti": : :"memory")
+#define hard_save_flags_and_cli(x)     __asm__ __volatile__("pushfl; popl %0; cli":"=g" (x): /* no input */)
+
+#define __cli()		do { rthal.disint(); } while (0)
+#define __sti()		do { rthal.enint(); } while (0)
+#define __save_flags(x)	do { x = rthal.getflags(); } while (0)
+#define __restore_flags(x)	do { rthal.setflags(x); } while (0)
+
+#define __save_and_cli(x)	do { x = rthal.getflags_and_cli(); } while (0)
+#define __save_and_sti(x)	do { x = rthal.getflags(); rthal.enint(); } while (0) 
 
-#define __save_and_cli(x)	do { __save_flags(x); __cli(); } while(0);
-#define __save_and_sti(x)	do { __save_flags(x); __sti(); } while(0);
+/* used in the idle loop; sti takes one instruction cycle to complete */
+#define safe_halt()		__asm__ __volatile__("call *"SYMBOL_NAME_STR(rthal + 16)"; hlt": : :"memory")
 
 /* For spinlocks etc */
 #if 0
 #define local_irq_save(x)	__asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory")
 #define local_irq_set(x)	__asm__ __volatile__("pushfl ; popl %0 ; sti":"=g" (x): /* no input */ :"memory")
 #else
-#define local_irq_save(x)	__save_and_cli(x)
-#define local_irq_set(x)	__save_and_sti(x)
+#define local_irq_save(x)	do { x = rthal.getflags_and_cli(); } while (0)
+#define local_irq_set(x)	do { x = rthal.getflags(); rthal.enint(); } while (0) 
 #endif
 
-#define local_irq_restore(x)	__restore_flags(x)
-#define local_irq_disable()	__cli()
-#define local_irq_enable()	__sti()
+#define local_irq_restore(x)	do { rthal.setflags(x); } while (0)
+#define local_irq_disable()	do { rthal.disint(); } while (0)
+#define local_irq_enable()	do { rthal.enint(); } while (0)
 
 #ifdef CONFIG_SMP
 
diff -Naur linux-2.4.20/include/asm-ppc/system.h linux-2.4.20-rtai/include/asm-ppc/system.h
--- linux-2.4.20/include/asm-ppc/system.h	Sat Aug  3 02:39:45 2002
+++ linux-2.4.20-rtai/include/asm-ppc/system.h	Mon Dec  2 16:11:55 2002
@@ -82,6 +82,7 @@
 
 struct task_struct;
 #define prepare_to_switch()	do { } while(0)
+#define end_switch()		do { } while(0)
 #define switch_to(prev,next,last) _switch_to((prev),(next),&(last))
 extern void _switch_to(struct task_struct *, struct task_struct *,
 		       struct task_struct **);
diff -Naur linux-2.4.20/include/linux/sched.h linux-2.4.20-rtai/include/linux/sched.h
--- linux-2.4.20/include/linux/sched.h	Fri Nov 29 19:03:06 2002
+++ linux-2.4.20-rtai/include/linux/sched.h	Mon Dec  2 16:16:00 2002
@@ -415,6 +415,8 @@
 
 /* journalling filesystem info */
 	void *journal_info;
+
+	void *this_rt_task[2];
 };
 
 /*
@@ -509,6 +511,7 @@
     blocked:		{{0}},						\
     alloc_lock:		SPIN_LOCK_UNLOCKED,				\
     journal_info:	NULL,						\
+    this_rt_task:	{0,0},						\
 }
 
 
diff -Naur linux-2.4.20/kernel/exit.c linux-2.4.20-rtai/kernel/exit.c
--- linux-2.4.20/kernel/exit.c	Fri Nov 29 19:03:07 2002
+++ linux-2.4.20-rtai/kernel/exit.c	Mon Dec  2 16:11:55 2002
@@ -422,6 +422,71 @@
 	write_unlock_irq(&tasklist_lock);
 }
 
+//
+// PGGC added these lines to callback rtai when a task dies.
+// A list of functions allows different rt_modules to be informed.
+//
+static struct t_callback {
+	void (*rtai_callback)(struct task_struct *tsk);
+	struct t_callback *next;
+	} *rtai_callback_list;
+
+extern int  set_rtai_callback(    void (*fun)(struct task_struct *tsk));
+extern void remove_rtai_callback( void (*fun)(struct task_struct *tsk));
+
+void inform_rtai(void)
+{
+	struct t_callback *pt;
+
+	pt = rtai_callback_list;
+	while (pt) {
+		(*(pt->rtai_callback))(current);
+		pt = pt->next;
+	}
+//printk( "Task pid %d going down\n", current->pid);
+}
+
+int set_rtai_callback( void (*pt)(struct task_struct *tsk))
+{
+	struct t_callback *ptn;
+
+	ptn = kmalloc(sizeof(struct t_callback), GFP_KERNEL);
+	if (!ptn) {
+		return -ENOMEM;
+	}
+	ptn->rtai_callback = pt;
+	ptn->next = rtai_callback_list ? rtai_callback_list : 0;
+	rtai_callback_list = ptn;
+	return 0;
+}
+
+void remove_rtai_callback(void (*pt)(struct task_struct *tsk))
+{
+	struct t_callback *pto, *ptoo, *ptd;
+
+	pto  = rtai_callback_list;
+	ptoo = 0;
+	while (pto) {
+		if (pto->rtai_callback == pt) {
+			if (!ptoo) {
+				rtai_callback_list = pto->next;
+			} else {
+				ptoo->next = pto->next; 
+			}
+ 			ptd = pto;
+			pto = pto->next;
+			kfree(ptd);
+		} else {
+			ptoo = pto;
+			pto = pto->next;
+		}	
+	}
+//printk("rtai_callback_list %X\n", rtai_callback_list);
+}
+//
+//
+//
+
 NORET_TYPE void do_exit(long code)
 {
 	struct task_struct *tsk = current;
@@ -439,6 +504,18 @@
 #ifdef CONFIG_BSD_PROCESS_ACCT
 	acct_process(code);
 #endif
+
+/*
+ * PGGC added these lines to callback rtai when a task dies.
+ * This assumes that a LXRT task should/will always set its
+ * scheduling police to SCHED_FIFO or SCHED_RR.
+ * We may want to enforce this in rt_task_init(...).
+ * (For the moment it is not so, thus let's inform LXRT anyhow (Paolo))
+ */
+	if(tsk->this_rt_task[0]) {
+		inform_rtai();
+	}
+
 	__exit_mm(tsk);
 
 	lock_kernel();
diff -Naur linux-2.4.20/kernel/fork.c linux-2.4.20-rtai/kernel/fork.c
--- linux-2.4.20/kernel/fork.c	Fri Nov 29 19:03:07 2002
+++ linux-2.4.20-rtai/kernel/fork.c	Mon Dec  2 16:11:55 2002
@@ -233,7 +233,9 @@
 	atomic_set(&mm->mm_count, 1);
 	init_rwsem(&mm->mmap_sem);
 	mm->page_table_lock = SPIN_LOCK_UNLOCKED;
+	lock_kernel();
 	mm->pgd = pgd_alloc(mm);
+	unlock_kernel();
 	mm->def_flags = 0;
 	if (mm->pgd)
 		return mm;
@@ -265,7 +267,9 @@
 inline void __mmdrop(struct mm_struct *mm)
 {
 	BUG_ON(mm == &init_mm);
+	lock_kernel();
 	pgd_free(mm->pgd);
+	unlock_kernel();
	check_pgt_cache();
 	destroy_context(mm);
 	free_mm(mm);
diff -Naur linux-2.4.20/kernel/ksyms.c linux-2.4.20-rtai/kernel/ksyms.c
--- linux-2.4.20/kernel/ksyms.c	Fri Nov 29 19:03:07 2002
+++ linux-2.4.20-rtai/kernel/ksyms.c	Mon Dec  2 16:11:55 2002
@@ -600,3 +600,44 @@
 /* To match ksyms with System.map */
 extern const char _end[];
 EXPORT_SYMBOL(_end);
+
+/*
+ * used to inform rtai a task is about to die.
+ */
+extern int  set_rtai_callback(   void (*fun)(struct task_struct *tsk));
+extern void remove_rtai_callback(void (*fun)(struct task_struct *tsk));
+extern NORET_TYPE void do_exit(long code);
+EXPORT_SYMBOL(set_rtai_callback);
+EXPORT_SYMBOL(remove_rtai_callback);
+EXPORT_SYMBOL(do_exit);
+
+/*
+ * used to inform RTAI LXRT a task should deal with a Linux signal, and for rt_lxrt_fork()
+ */
+extern int (*rtai_signal_handler)(struct task_struct *lnxt, int sig);
+EXPORT_SYMBOL(rtai_signal_handler);
+extern int do_fork(unsigned long clone_flags, unsigned long stack_start, struct pt_regs *regs, unsigned long stack_size);
+EXPORT_SYMBOL(do_fork);
+
+/*
+ * used to provide async io support (aio) to RTAI LXRT.
+ */
+extern ssize_t sys_read(unsigned int fd, char * buf, size_t count);
+extern ssize_t sys_write(unsigned int fd, const char * buf, size_t count);
+extern ssize_t sys_pread(unsigned int fd, char * buf,
+				                             size_t count, loff_t pos);
+extern ssize_t sys_pwrite(unsigned int fd, const char * buf,
+				                              size_t count, loff_t pos);
+extern long sys_fsync(unsigned int fd);
+extern long sys_fdatasync(unsigned int fd);
+extern long sys_open(const char * filename, int flags, int mode);
+extern long sys_close(unsigned int fd);
+
+EXPORT_SYMBOL(sys_read);
+EXPORT_SYMBOL(sys_write);
+EXPORT_SYMBOL(sys_open);
+//EXPORT_SYMBOL(sys_close);
+EXPORT_SYMBOL(sys_pread);
+EXPORT_SYMBOL(sys_pwrite);
+EXPORT_SYMBOL(sys_fsync);
+EXPORT_SYMBOL(sys_fdatasync);
diff -Naur linux-2.4.20/kernel/sched.c linux-2.4.20-rtai/kernel/sched.c
--- linux-2.4.20/kernel/sched.c	Fri Nov 29 19:03:07 2002
+++ linux-2.4.20-rtai/kernel/sched.c	Mon Dec  2 16:11:55 2002
@@ -544,6 +544,43 @@
  * tasks can run. It can not be killed, and it cannot sleep. The 'state'
  * information in task[0] is never used.
  */
+
+int idle_weight = -1000;
+#define MAX_MM 1024  // How large should it be?
+static struct smm_t { int in, out; struct mm_struct *mm[MAX_MM]; } smm[NR_CPUS];
+#define incpnd(x) do { x = (x + 1) & (MAX_MM - 1); } while(0)
+
+static inline void pend_mm(struct mm_struct *mm, int cpu)
+{
+	if (rthal.lxrt_global_cli) {
+        	struct smm_t *p = smm + cpu;
+        	p->mm[p->in] = mm;
+	        incpnd(p->in);
+	} else {
+		mmdrop(mm);
+	}
+}
+
+static inline void drop_mm(void)
+{
+	if (rthal.lxrt_global_cli) {
+        	struct smm_t *p = smm + smp_processor_id();
+	        while (p->out != p->in) {
+        	        mmdrop(p->mm[p->out]);
+              		incpnd(p->out);
+        	}
+        }
+}
+
+void switch_mem(struct task_struct *prevp, struct task_struct *nextp, int cpuid)
+{
+	struct mm_struct *oldmm = prevp->active_mm;
+	switch_mm(oldmm, nextp->active_mm, nextp, cpuid & 0x0FFFFFFF);
+	if (!nextp->mm) {
+		enter_lazy_tlb(oldmm, nextp, cpuid & 0x0FFFFFFF);
+	}
+}
+
 asmlinkage void schedule(void)
 {
 	struct schedule_data * sched_data;
@@ -602,7 +639,7 @@
 	 * Default process to select..
 	 */
 	next = idle_task(this_cpu);
-	c = -1000;
+	c = idle_weight;
 	list_for_each(tmp, &runqueue_head) {
 		p = list_entry(tmp, struct task_struct, run_list);
 		if (can_schedule(p, this_cpu)) {
@@ -684,7 +721,7 @@
 
 		if (!prev->mm) {
 			prev->active_mm = NULL;
-			mmdrop(oldmm);
+			pend_mm(oldmm, this_cpu);
 		}
 	}
 
@@ -693,6 +730,7 @@
 	 * stack.
 	 */
 	switch_to(prev, next, prev);
+	drop_mm();
 	__schedule_tail(prev);
 
 same_process:
diff -Naur linux-2.4.20/kernel/signal.c linux-2.4.20-rtai/kernel/signal.c
--- linux-2.4.20/kernel/signal.c	Fri Nov 29 19:03:07 2002
+++ linux-2.4.20-rtai/kernel/signal.c	Mon Dec  2 16:11:55 2002
@@ -1010,9 +1010,30 @@
 	return ret;
 }
 
+//
+//  Add this pointer to the RTAI signal handler.
+//
+int (*rtai_signal_handler)(struct task_struct *lnxt, int sig);
+
 asmlinkage long
 sys_kill(int pid, int sig)
 {
+// Add this section to call the RTAI signal handler.
+//
+	{
+	struct task_struct *p;
+	int ret;
+
+	if (rtai_signal_handler) {
+	    p = find_task_by_pid(pid);
+		if(p && (p->policy == SCHED_FIFO || p->policy == SCHED_RR) && p->this_rt_task[0]) {
+			ret = rtai_signal_handler(p, sig);
+			if(!ret) return 0; //let Linux deal with it.
+			}
+		}
+	}
+
+	{
 	struct siginfo info;
 
 	info.si_signo = sig;
@@ -1022,6 +1043,7 @@
 	info.si_uid = current->uid;
 
 	return kill_something_info(sig, &info, pid);
+	}
 }
 
 /*
diff -Naur linux-2.4.20/mm/vmalloc.c linux-2.4.20-rtai/mm/vmalloc.c
--- linux-2.4.20/mm/vmalloc.c	Fri Nov 29 19:03:09 2002
+++ linux-2.4.20-rtai/mm/vmalloc.c	Mon Dec  2 16:11:55 2002
@@ -166,6 +166,9 @@
 	spin_lock(&init_mm.page_table_lock);
 	do {
 		pmd_t *pmd;
+#ifdef CONFIG_X86
+		pgd_t olddir = *dir;
+#endif
 		
 		pmd = pmd_alloc(&init_mm, dir, address);
 		ret = -ENOMEM;
@@ -175,6 +178,10 @@
 		ret = -ENOMEM;
 		if (alloc_area_pmd(pmd, address, end - address, gfp_mask, prot, pages))
 			break;
+#ifdef CONFIG_X86
+		if (pgd_val(olddir) != pgd_val(*dir))
+			set_pgdir(address, *dir);
+#endif
 
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;