Resent-Date: Mon, 6 Sep 1999 18:57:53 +0200 (MET DST)
Date: Mon, 6 Sep 1999 18:56:38 +0200 (MET DST)
From: Roman Zippel <zippel@fh-brandenburg.de>
X-Sender: zippel@zeus
To: Jes Sorensen <Jes.Sorensen@cern.ch>
cc: Linux/m68k <linux-m68k@lists.linux-m68k.org>
Subject: Re: 2.3.16
In-Reply-To: <199909031629.SAA27926@lxp03.cern.ch>
Resent-From: linux-m68k@phil.uni-sb.de

Hi,

Here a few patches from me.
First the interrupt patch, in case someone wants a stable system, only a
few small bugfixes, but otherwise only ported to 2.3.16. Maybe it wasn't
clear enough, the new sys_request_irq() is an internal interface, the
external interface is still mach_request_irq() and it's up to
mach_request_irq() which interface it exports to the drivers.

Second, some misc patches:
- head.S: better solution for the __INITDATA problem, makes it independend
of any config option.
- ptrace.c: make use of general functions in kernel/ptrace,c
- signal.c I found some unix98 specs and according to them default
behaviour of some signals were not correct.
- some changes to sun3 stuff: Why was the call to base_trap_init() moved,
it shouldn't make any difference. In movs.h we don't want to introduce
intel syntax, or don't we? :-) (movs.h also slightly improved)
- adding some PAGE_OFFSET, the kernel itself is now independend of the
start position.
- some more address conversion improvement/fixes. (Jes, page.h really
should look like this and I'm quite sure that the "hacky workaround" for
sun3 there can now also be removed).

Last the syscall patch, it includes some optimization to the signal
handling, instead of handling with to pointers for pt_regs/switch_stack
only one is enough. While working on this I noticed some strange
initialisation of esp0 in the task struct, it's only used by ptrace.h and
it expects pt_regs directly behind the switch_stack, but esp0 was
initialized at two placed where this wasn't the case, I did uncomment them
and it doesn't seem to make a difference, gdb still works as expected.

have fun with it...

bye, Roman

diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16/arch/m68k/amiga/amiints.c linux-2.3.16-int/arch/m68k/amiga/amiints.c
--- linux-2.3.16/arch/m68k/amiga/amiints.c	Fri Sep  3 21:44:29 1999
+++ linux-2.3.16-int/arch/m68k/amiga/amiints.c	Sat Sep  4 21:57:28 1999
@@ -19,31 +19,20 @@
  *                           called again.
  *           The whole interrupt handling for CIAs is moved to cia.c
  *           /Roman Zippel
- *
- * 07/08/99: rewamp of the interrupt handling - we now have two types of
- *           interrupts, normal and fast handlers, fast handlers being
- *           marked with SA_INTERRUPT and runs with all other interrupts
- *           disabled. Normal interrupts disable their own source but
- *           run with all other interrupt sources enabled.
- *           PORTS and EXTER interrupts are always shared even if the
- *           drivers do not explicitly mark this when calling
- *           request_irq which they really should do.
- *           This is similar to the way interrupts are handled on all
- *           other architectures and makes a ton of sense besides
- *           having the advantage of making it easier to share
- *           drivers.
- *           /Jes
  */
 
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 #include <linux/init.h>
 
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/traps.h>
+#include <asm/pgtable.h>
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
 #include <asm/amipcmcia.h>
@@ -52,26 +41,25 @@
                            void (*handler)(int, void *, struct pt_regs *),
                            unsigned long flags, const char *devname, void *dev_id);
 extern void cia_free_irq(struct ciabase *base, unsigned int irq, void *dev_id);
-extern void cia_init_IRQ(struct ciabase *base);
-extern int cia_get_irq_list(struct ciabase *base, char *buf);
-
-/* irq node variables for amiga interrupt sources */
-static irq_node_t *ami_irq_list[AMI_STD_IRQS];
+extern void cia_init_IRQ(void);
 
 unsigned short ami_intena_vals[AMI_STD_IRQS] = {
-	IF_VERTB, IF_COPER, IF_AUD0, IF_AUD1, IF_AUD2, IF_AUD3, IF_BLIT,
-	IF_DSKSYN, IF_DSKBLK, IF_RBF, IF_TBE, IF_SOFT, IF_PORTS, IF_EXTER
+	IF_TBE, IF_DSKBLK, IF_SOFT, IF_PORTS, IF_COPPER, IF_VERTB, IF_BLIT,
+	IF_AUD0, IF_AUD1, IF_AUD2, IF_AUD3, IF_RBF, IF_DSKSYN, IF_EXTER
 };
-static const unsigned char ami_servers[AMI_STD_IRQS] = {
-	1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1
+static const unsigned char ami_servers[AMI_IRQS] = {
+	0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 };
 
 static short ami_ablecount[AMI_IRQS];
 
-static void ami_badint(int irq, void *dev_id, struct pt_regs *fp)
-{
-	num_spurious += 1;
-}
+static void ami_int1(int irq, void *dev_id, struct pt_regs *fp);
+static void ami_int2(int irq, void *dev_id, struct pt_regs *fp);
+static void ami_int3(int irq, void *dev_id, struct pt_regs *fp);
+static void ami_int4(int irq, void *dev_id, struct pt_regs *fp);
+static void ami_int5(int irq, void *dev_id, struct pt_regs *fp);
+static void ami_int6(int irq, void *dev_id, struct pt_regs *fp);
 
 /*
  * void amiga_init_IRQ(void)
@@ -88,22 +76,11 @@
 {
 	int i;
 
-	/* initialize handlers */
-	for (i = 0; i < AMI_STD_IRQS; i++) {
-		if (ami_servers[i]) {
-			ami_irq_list[i] = NULL;
-		} else {
-			ami_irq_list[i] = new_irq_node();
-			ami_irq_list[i]->handler = ami_badint;
-			ami_irq_list[i]->flags   = 0;
-			ami_irq_list[i]->dev_id  = NULL;
-			ami_irq_list[i]->devname = NULL;
-			ami_irq_list[i]->next    = NULL;
-		}
-	}
 	for (i = 0; i < AMI_IRQS; i++)
 		ami_ablecount[i] = 0;
 
+	vectors[VEC_INT7] = amiga_nmi_handler;
+
 	/* turn off PCMCIA interrupts */
 	if (AMIGAHW_PRESENT(PCMCIA))
 		pcmcia_disable_irq();
@@ -113,67 +90,14 @@
 	custom.intreq = 0x7fff;
 	custom.intena = IF_SETCLR | IF_INTEN;
 
-	cia_init_IRQ(&ciaa_base);
-	cia_init_IRQ(&ciab_base);
-}
-
-static inline int amiga_insert_irq(irq_node_t **list, irq_node_t *node)
-{
-	unsigned long flags;
-	irq_node_t *cur;
-
-	if (!node->dev_id)
-		printk("%s: Warning: dev_id of %s is zero\n",
-		       __FUNCTION__, node->devname);
-
-	save_flags(flags);
-	cli();
-
-	cur = *list;
-
-	if (node->flags & SA_INTERRUPT) {
-		if (node->flags & SA_SHIRQ)
-			return -EBUSY;
-		/*
-		 * There should never be more than one
-		 */
-		while (cur && cur->flags & SA_INTERRUPT) {
-			list = &cur->next;
-			cur = cur->next;
-		}
-	} else {
-		while (cur) {
-			list = &cur->next;
-			cur = cur->next;
-		}
-	}
+	request_irq(IRQ_AMIGA_AUTO_1, ami_int1, IRQ_FLG_FAST, "int1 handler", NULL);
+	request_irq(IRQ_AMIGA_AUTO_2, ami_int2, IRQ_FLG_FAST, "int2 handler", NULL);
+	request_irq(IRQ_AMIGA_AUTO_3, ami_int3, IRQ_FLG_FAST, "int3 handler", NULL);
+	request_irq(IRQ_AMIGA_AUTO_4, ami_int4, IRQ_FLG_FAST, "int4 handler", NULL);
+	request_irq(IRQ_AMIGA_AUTO_5, ami_int5, IRQ_FLG_FAST, "int5 handler", NULL);
+	request_irq(IRQ_AMIGA_AUTO_6, ami_int6, IRQ_FLG_FAST, "int6 handler", NULL);
 
-	node->next = cur;
-	*list = node;
-
-	restore_flags(flags);
-	return 0;
-}
-
-static inline void amiga_delete_irq(irq_node_t **list, void *dev_id)
-{
-	unsigned long flags;
-	irq_node_t *node;
-
-	save_flags(flags);
-	cli();
-
-	for (node = *list; node; list = &node->next, node = *list) {
-		if (node->dev_id == dev_id) {
-			*list = node->next;
-			/* Mark it as free. */
-			node->handler = NULL;
-			restore_flags(flags);
-			return;
-		}
-	}
-	restore_flags(flags);
-	printk ("%s: tried to remove invalid irq\n", __FUNCTION__);
+	cia_init_IRQ();
 }
 
 /*
@@ -182,22 +106,30 @@
  *                     If the addition was successful, it returns 0.
  */
 
-int amiga_request_irq(unsigned int irq,
-		      void (*handler)(int, void *, struct pt_regs *),
+int amiga_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
                       unsigned long flags, const char *devname, void *dev_id)
 {
-	irq_node_t *node;
-	int error = 0;
+	unsigned int vec;
+	int res;
 
 	if (irq >= AMI_IRQS) {
-		printk ("%s: Unknown IRQ %d from %s\n", __FUNCTION__,
-			irq, devname);
+		printk("%s: Unknown IRQ %d from %s\n", __FUNCTION__, irq, devname);
 		return -ENXIO;
 	}
 
-	if (irq >= IRQ_AMIGA_AUTO)
-		return sys_request_irq(irq - IRQ_AMIGA_AUTO, handler,
-		                       flags, devname, dev_id);
+	flags &= ~IRQ_FLG_LIST;
+	if (flags & SA_INTERRUPT)
+		flags |= IRQ_FLG_FAST;
+
+	if (irq >= IRQ_AMIGA_AUTO) {
+		vec = irq - IRQ_AMIGA_AUTO + VEC_SPUR;
+
+		res = sys_request_irq(vec, handler, flags, devname, dev_id);
+		if (!res)
+			vectors[vec] = amiga_inthandler;
+
+		return res;
+	}
 
 	if (irq >= IRQ_AMIGA_CIAB)
 		return cia_request_irq(&ciab_base, irq - IRQ_AMIGA_CIAB,
@@ -207,43 +139,44 @@
 		return cia_request_irq(&ciaa_base, irq - IRQ_AMIGA_CIAA,
 		                       handler, flags, devname, dev_id);
 
-	/*
-	 * IRQ_AMIGA_PORTS & IRQ_AMIGA_EXTER defaults to shared,
-	 * we could add a check here for the SA_SHIRQ flag but all drivers
-	 * should be aware of sharing anyway.
-	 */
-	if (ami_servers[irq]) {
-		if (!(node = new_irq_node()))
-			return -ENOMEM;
-		node->handler = handler;
-		node->flags   = flags;
-		node->dev_id  = dev_id;
-		node->devname = devname;
-		node->next    = NULL;
-		error = amiga_insert_irq(&ami_irq_list[irq], node);
-	} else {
-		ami_irq_list[irq]->handler = handler;
-		ami_irq_list[irq]->flags   = flags;
-		ami_irq_list[irq]->dev_id  = dev_id;
-		ami_irq_list[irq]->devname = devname;
+	vec = irq + VEC_USER;
+	if (ami_servers[irq])
+		flags |= IRQ_FLG_LIST;
+
+	res = sys_request_irq(vec, handler, flags, devname, dev_id);
+	if (!res) {
+		if (flags & IRQ_FLG_FASTQUEUE)
+			amiga_fastintmask |= 1 << irq;
+		else
+			amiga_slowintmask |= 1 << irq;
+		flush_icache_range((unsigned long)&amiga_slowintmask,
+		                   ((unsigned long)&amiga_fastintmask)+2);
+
+		/* enable the interrupt */
+		if (!ami_ablecount[irq])
+			custom.intena = IF_SETCLR | ami_intena_vals[irq];
 	}
 
-	/* enable the interrupt */
-	if (irq < IRQ_AMIGA_PORTS && !ami_ablecount[irq])
-		custom.intena = IF_SETCLR | ami_intena_vals[irq];
-
-	return error;
+	return res;
 }
 
 void amiga_free_irq(unsigned int irq, void *dev_id)
 {
+	unsigned int vec;
+
 	if (irq >= AMI_IRQS) {
 		printk ("%s: Unknown IRQ %d\n", __FUNCTION__, irq);
 		return;
 	}
 
-	if (irq >= IRQ_AMIGA_AUTO)
-		sys_free_irq(irq - IRQ_AMIGA_AUTO, dev_id);
+	if (irq >= IRQ_AMIGA_AUTO) {
+		vec = irq - IRQ_AMIGA_AUTO + VEC_SPUR;
+
+		sys_free_irq(vec, dev_id);
+		vectors[vec] = bad_interrupt;
+
+		return;
+	}
 
 	if (irq >= IRQ_AMIGA_CIAB) {
 		cia_free_irq(&ciab_base, irq - IRQ_AMIGA_CIAB, dev_id);
@@ -255,21 +188,18 @@
 		return;
 	}
 
-	if (ami_servers[irq]) {
-		amiga_delete_irq(&ami_irq_list[irq], dev_id);
-		/* if server list empty, disable the interrupt */
-		if (!ami_irq_list[irq] && irq < IRQ_AMIGA_PORTS)
-			custom.intena = ami_intena_vals[irq];
-	} else {
-		if (ami_irq_list[irq]->dev_id != dev_id)
-			printk("%s: removing probably wrong IRQ %d from %s\n",
-			       __FUNCTION__, irq, ami_irq_list[irq]->devname);
-		ami_irq_list[irq]->handler = ami_badint;
-		ami_irq_list[irq]->flags   = 0;
-		ami_irq_list[irq]->dev_id  = NULL;
-		ami_irq_list[irq]->devname = NULL;
+	vec = irq + VEC_USER;
+	sys_free_irq(vec, dev_id);
+
+	/* if list empty, disable the interrupt */
+	if (!userirq_list[irq])
+		amiga_fastintmask &= ~(1 << irq);
+	if (!userirq_slowlist[irq])
+		amiga_slowintmask &= ~(1 << irq);
+	flush_icache_range((unsigned long)&amiga_slowintmask,
+		((unsigned long)&amiga_fastintmask)+2);
+	if (!userirq_list[irq] && !userirq_slowlist[irq])
 		custom.intena = ami_intena_vals[irq];
-	}
 }
 
 /*
@@ -346,79 +276,12 @@
 	custom.intena = ami_intena_vals[irq];
 }
 
-inline void amiga_do_irq(int irq, struct pt_regs *fp)
-{
-	kstat.irqs[0][SYS_IRQS + irq]++;
-	ami_irq_list[irq]->handler(irq, ami_irq_list[irq]->dev_id, fp);
-}
-
-void amiga_do_irq_list(int irq, struct pt_regs *fp, struct irq_server *server)
-{
-	irq_node_t *node, *slow_nodes;
-	unsigned short flags, intena;
-
-	kstat.irqs[0][SYS_IRQS + irq]++;
-	if (server->count++)
-		server->reentrance = 1;
-
-	intena = ami_intena_vals[irq];
-	custom.intreq = intena;
-
-	/* serve first fast handlers - there can only be one of these */
-	node = ami_irq_list[irq];
-
-	/*
-	 * Timer interrupts show up like this
-	 */
-	if (!node) {
-		server->count--;
-		return;
-	}
-
-	if (node && (node->flags & SA_INTERRUPT)) {
-		save_flags(flags);
-		cli();
-		node->handler(irq, node->dev_id, fp);
-		restore_flags(flags);
-
-		server->count--;
-		return;
-	}
-
-	/*
-	 * Disable the interrupt source in question and reenable all
-	 * other interrupts. No interrupt handler should ever touch
-	 * the intena flags directly!
-	 */
-	custom.intena = intena;
-	save_flags(flags);
-	sti();
-
-	slow_nodes = node;
-	for (;;) {
-		for (; node; node = node->next)
-			node->handler(irq, node->dev_id, fp);
-
-		if (!server->reentrance) {
-			server->count--;
-			restore_flags(flags);
-			custom.intena = IF_SETCLR | intena;
-			return;
-		}
-
-		server->reentrance = 0;
-		node = slow_nodes;
-	}
-}
-
 /*
  * The builtin Amiga hardware interrupt handlers.
  */
 
-static void ami_int1(int irq, void *dev_id, struct pt_regs *fp)
+static void ami_int1(int ints, void *dev_id, struct pt_regs *fp)
 {
-	unsigned short ints = custom.intreqr & custom.intenar;
-
 	/* if serial transmit buffer empty, interrupt */
 	if (ints & IF_TBE) {
 		custom.intreq = IF_TBE;
@@ -438,11 +301,16 @@
 	}
 }
 
-static void ami_int3(int irq, void *dev_id, struct pt_regs *fp)
+static void ami_int2(int ints, void *dev_id, struct pt_regs *fp)
 {
-	unsigned short ints = custom.intreqr & custom.intenar;
-	static struct irq_server server = {0, 0};
+	if (ints & IF_PORTS) {
+		custom.intreq = IF_PORTS;
+		amiga_do_irq_list(IRQ_AMIGA_PORTS, fp);
+	}
+}
 
+static void ami_int3(int ints, void *dev_id, struct pt_regs *fp)
+{
 	/* if a blitter interrupt */
 	if (ints & IF_BLIT) {
 		custom.intreq = IF_BLIT;
@@ -450,20 +318,20 @@
 	}
 
 	/* if a copper interrupt */
-	if (ints & IF_COPER) {
-		custom.intreq = IF_COPER;
+	if (ints & IF_COPPER) {
+		custom.intreq = IF_COPPER;
 		amiga_do_irq(IRQ_AMIGA_COPPER, fp);
 	}
 
 	/* if a vertical blank interrupt */
-	if (ints & IF_VERTB)
-		amiga_do_irq_list(IRQ_AMIGA_VERTB, fp, &server);
+	if (ints & IF_VERTB) {
+		custom.intreq = IF_VERTB;
+		amiga_do_irq_list(IRQ_AMIGA_VERTB, fp);
+	}
 }
 
-static void ami_int4(int irq, void *dev_id, struct pt_regs *fp)
+static void ami_int4(int ints, void *dev_id, struct pt_regs *fp)
 {
-	unsigned short ints = custom.intreqr & custom.intenar;
-
 	/* if audio 0 interrupt */
 	if (ints & IF_AUD0) {
 		custom.intreq = IF_AUD0;
@@ -489,10 +357,8 @@
 	}
 }
 
-static void ami_int5(int irq, void *dev_id, struct pt_regs *fp)
+static void ami_int5(int ints, void *dev_id, struct pt_regs *fp)
 {
-	unsigned short ints = custom.intreqr & custom.intenar;
-
 	/* if serial receive buffer full interrupt */
 	if (ints & IF_RBF) {
 		/* acknowledge of IF_RBF must be done by the serial interrupt */
@@ -506,38 +372,41 @@
 	}
 }
 
-static void ami_int7(int irq, void *dev_id, struct pt_regs *fp)
+static void ami_int6(int ints, void *dev_id, struct pt_regs *fp)
 {
-	panic ("level 7 interrupt received\n");
+	if (ints & IF_EXTER) {
+		custom.intreq = IF_EXTER;
+		amiga_do_irq_list(IRQ_AMIGA_EXTER, fp);
+	}
 }
 
-void (*amiga_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
-	ami_badint, ami_int1, ami_badint, ami_int3,
-	ami_int4, ami_int5, ami_badint, ami_int7
-};
-
-int amiga_get_irq_list(char *buf)
-{
-	int i, len = 0;
-	irq_node_t *node;
-
-	for (i = 0; i < AMI_STD_IRQS; i++) {
-		if (!(node = ami_irq_list[i]))
-			continue;
-		len += sprintf(buf+len, "ami  %2d: %10u ", i,
-		               kstat.irqs[0][SYS_IRQS + i]);
-		do {
-			if (node->flags & SA_INTERRUPT)
-				len += sprintf(buf+len, "F ");
-			else
-				len += sprintf(buf+len, "  ");
-			len += sprintf(buf+len, "%s\n", node->devname);
-			if ((node = node->next))
-				len += sprintf(buf+len, "                    ");
-		} while (node);
-	}
-
-	len += cia_get_irq_list(&ciaa_base, buf+len);
-	len += cia_get_irq_list(&ciab_base, buf+len);
-	return len;
+void amiga_do_slowirq_request(void)
+{
+	int old_mask, old_request, irq;
+	static struct pt_regs dummy_regs;
+
+	old_request = xchg(&slowirq_request, 0);
+	old_mask = old_request;
+	custom.intreq = old_mask & (0x3fff & ~IF_RBF);
+	while (old_request) {
+#ifdef CONFIG_APUS
+#else
+		asm ("bfffo %1{#0,#32},%0; bfclr %1{%0,#1}"
+		     : "=&d" (irq), "=d" (old_request)
+		     : "1" (old_request): "cc");
+		irq = 31 - irq;
+#endif
+		if (ami_servers[irq])
+			amiga_do_slowirq_list(irq, &dummy_regs);
+		else
+			amiga_do_slowirq(irq, &dummy_regs);
+	}
+	custom.intena = IF_SETCLR | (old_mask & 0x3fff);
+	if ((old_mask >>= AMI_STD_IRQS)) {
+		cia_able_irq(&ciaa_base, CIA_ICR_SETCLR | (old_mask & CIA_ICR_ALL));
+		if ((old_mask >>= CIA_IRQS))
+			cia_able_irq(&ciab_base, CIA_ICR_SETCLR | old_mask);
+	}
+	if (bh_active & bh_mask)
+		do_bottom_half();
 }
diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16/arch/m68k/amiga/cia.c linux-2.3.16-int/arch/m68k/amiga/cia.c
--- linux-2.3.16/arch/m68k/amiga/cia.c	Fri Aug 20 20:46:52 1999
+++ linux-2.3.16-int/arch/m68k/amiga/cia.c	Sat Sep  4 21:57:28 1999
@@ -18,27 +18,24 @@
 #include <linux/init.h>
 
 #include <asm/irq.h>
+#include <asm/traps.h>
+#include <asm/system.h>
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
 
 struct ciabase {
 	volatile struct CIA *cia;
-	u_char icr_mask, icr_data;
+	int cia_irq;
 	u_short int_mask;
-	int handler_irq, cia_irq, server_irq;
-	char *name;
-	struct irq_server server;
-	irq_handler_t irq_list[CIA_IRQS];
+	u_char allocmask, pad;
+	u_char icr_mask, icr_data;
+	u_char fastmask, slowmask;
 } ciaa_base = {
-	&ciaa, 0, 0, IF_PORTS,
-	IRQ_AMIGA_AUTO_2, IRQ_AMIGA_CIAA,
-	IRQ_AMIGA_PORTS,
-	"CIAA handler", {0, 0}
+	&ciaa, IRQ_AMIGA_CIAA,
+	IF_PORTS, CIA_ICR_ALL, 0, 0, 0, 0, 0
 }, ciab_base = {
-	&ciab, 0, 0, IF_EXTER,
-	IRQ_AMIGA_AUTO_6, IRQ_AMIGA_CIAB,
-	IRQ_AMIGA_EXTER,
-	"CIAB handler", {0, 0}
+	&ciab, IRQ_AMIGA_CIAB,
+	IF_EXTER, CIA_ICR_ALL, 0, 0, 0, 0, 0
 };
 
 /*
@@ -66,23 +63,17 @@
 
 unsigned char cia_able_irq(struct ciabase *base, unsigned char mask)
 {
-	u_char old, tmp;
-	int i;
+	u_char old;
 
 	old = base->icr_mask;
 	base->icr_data |= base->cia->icr;
+	mask &= CIA_ICR_SETCLR | base->allocmask;
 	base->cia->icr = mask;
 	if (mask & CIA_ICR_SETCLR)
 		base->icr_mask |= mask;
 	else
 		base->icr_mask &= ~mask;
 	base->icr_mask &= CIA_ICR_ALL;
-	for (i = 0, tmp = 1; i < CIA_IRQS; i++, tmp <<= 1) {
-		if ((tmp & base->icr_mask) && !base->irq_list[i].handler) {
-			base->icr_mask &= ~tmp;
-			base->cia->icr = tmp;
-		}
-	}
 	if (base->icr_data & base->icr_mask)
 		custom.intreq = IF_SETCLR | base->int_mask;
 	return old;
@@ -92,83 +83,87 @@
                     void (*handler)(int, void *, struct pt_regs *),
                     unsigned long flags, const char *devname, void *dev_id)
 {
+	unsigned int vec;
+	int res;
 	u_char mask;
 
-	base->irq_list[irq].handler = handler;
-	base->irq_list[irq].flags   = flags;
-	base->irq_list[irq].dev_id  = dev_id;
-	base->irq_list[irq].devname = devname;
+	vec = VEC_USER + base->cia_irq + irq;
+	res = sys_request_irq(vec, handler, flags, devname, dev_id);
 
-	/* enable the interrupt */
-	mask = 1 << irq;
-	cia_set_irq(base, mask);
-	cia_able_irq(base, CIA_ICR_SETCLR | mask);
+	if (!res) {
+		mask = 1 << irq;
+		if (flags & IRQ_FLG_FASTQUEUE)
+			base->fastmask |= mask;
+		else
+			base->slowmask |= mask;
+		/* enable the interrupt */
+		base->allocmask |= mask;
+		cia_set_irq(base, mask);
+		cia_able_irq(base, CIA_ICR_SETCLR | mask);
+	}
 	return 0;
 }
 
 void cia_free_irq(struct ciabase *base, unsigned int irq, void *dev_id)
 {
-	if (base->irq_list[irq].dev_id != dev_id)
-		printk("%s: removing probably wrong IRQ %i from %s\n",
-		       __FUNCTION__, base->cia_irq + irq,
-		       base->irq_list[irq].devname);
+	unsigned int vec;
+	u_char mask;
 
-	base->irq_list[irq].handler = NULL;
-	base->irq_list[irq].flags   = 0;
+	vec = VEC_USER + base->cia_irq + irq;
+	sys_free_irq(vec, dev_id);
 
-	cia_able_irq(base, 1 << irq);
+	mask = 1 << irq;
+	if (!userirq_list[base->cia_irq + irq])
+		base->fastmask &= ~mask;
+	if (!userirq_slowlist[base->cia_irq + irq])
+		base->slowmask &= ~mask;
+	if (!userirq_list[base->cia_irq + irq] &&
+	    !userirq_slowlist[base->cia_irq + irq]) {
+		cia_able_irq(base, mask);
+		base->allocmask &= ~mask;
+	}
 }
 
 static void cia_handler(int irq, void *dev_id, struct pt_regs *fp)
 {
 	struct ciabase *base = (struct ciabase *)dev_id;
-	int mach_irq, i;
-	unsigned char ints;
+	unsigned char ints, slowints;
 
-	mach_irq = base->cia_irq;
-	irq = SYS_IRQS + mach_irq;
 	ints = cia_set_irq(base, CIA_ICR_ALL);
+	if ((slowints = ints & base->slowmask)) {
+		set_slowirq_request(slowints << base->cia_irq);
+		cia_able_irq(base, slowints);
+	}
+	ints &= base->fastmask;
+
 	custom.intreq = base->int_mask;
-	for (i = 0; i < CIA_IRQS; i++, irq++, mach_irq++) {
-		if (ints & 1) {
-			kstat.irqs[0][irq]++;
-			base->irq_list[i].handler(mach_irq, base->irq_list[i].dev_id, fp);
+	if ( ints ) {
+		unsigned int irq = base->cia_irq + CIA_IRQS - 1;
+		irq_node_t **list = &userirq_list[irq];
+		unsigned int *stat = &kstat.irqs[0][irq + AUTO_IRQ_NR];
+		for (ints <<= 3; ints; ints <<= 1) {
+			if ( ints & 0x80 ) {
+				(*stat)++;
+				(*list)->handler(irq, (*list)->dev_id, fp);
+			}
+			stat--; list--; irq--;
 		}
-		ints >>= 1;
 	}
-	amiga_do_irq_list(base->server_irq, fp, &base->server);
 }
 
-void __init cia_init_IRQ(struct ciabase *base)
+void __init cia_init_IRQ(void)
 {
-	int i;
-
-	/* init isr handlers */
-	for (i = 0; i < CIA_IRQS; i++) {
-		base->irq_list[i].handler = NULL;
-		base->irq_list[i].flags   = 0;
-	}
-
 	/* clear any pending interrupt and turn off all interrupts */
-	cia_set_irq(base, CIA_ICR_ALL);
-	cia_able_irq(base, CIA_ICR_ALL);
+	cia_set_irq(&ciaa_base, CIA_ICR_ALL);
+	cia_able_irq(&ciaa_base, CIA_ICR_ALL);
+	cia_set_irq(&ciab_base, CIA_ICR_ALL);
+	cia_able_irq(&ciab_base, CIA_ICR_ALL);
+	ciaa_base.allocmask = ciab_base.allocmask = 0;
 
 	/* install CIA handler */
-	request_irq(base->handler_irq, cia_handler, 0, base->name, base);
+	request_irq(IRQ_AMIGA_PORTS, cia_handler, IRQ_FLG_FAST|IRQ_FLG_REALTIME,
+	            "ciaa handler", &ciaa_base);
+	request_irq(IRQ_AMIGA_EXTER, cia_handler, IRQ_FLG_FAST|IRQ_FLG_REALTIME,
+	            "ciab handler", &ciab_base);
 
-	custom.intena = IF_SETCLR | base->int_mask;
-}
-
-int cia_get_irq_list(struct ciabase *base, char *buf)
-{
-	int i, j, len = 0;
-
-	j = base->cia_irq;
-	for (i = 0; i < CIA_IRQS; i++) {
-		len += sprintf(buf+len, "cia  %2d: %10d ", j + i,
-			       kstat.irqs[0][SYS_IRQS + j + i]);
-			len += sprintf(buf+len, "  ");
-		len += sprintf(buf+len, "%s\n", base->irq_list[i].devname);
-	}
-	return len;
 }
diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16/arch/m68k/amiga/config.c linux-2.3.16-int/arch/m68k/amiga/config.c
--- linux-2.3.16/arch/m68k/amiga/config.c	Fri Aug 20 20:46:53 1999
+++ linux-2.3.16-int/arch/m68k/amiga/config.c	Sat Sep  4 21:57:28 1999
@@ -54,7 +54,6 @@
 extern int amiga_kbdrate (struct kbd_repeat *);
 /* amiga specific irq functions */
 extern void amiga_init_IRQ (void);
-extern void (*amiga_default_handler[]) (int, void *, struct pt_regs *);
 extern int amiga_request_irq (unsigned int irq,
 			      void (*handler)(int, void *, struct pt_regs *),
                               unsigned long flags, const char *devname,
@@ -64,7 +63,6 @@
 extern void amiga_disable_irq (unsigned int);
 static void amiga_get_model(char *model);
 static int amiga_get_hardware_list(char *buffer);
-extern int amiga_get_irq_list (char *);
 /* amiga specific timer functions */
 static unsigned long amiga_gettimeoffset (void);
 static void a3000_gettod (int *, int *, int *, int *, int *, int *);
@@ -343,14 +341,12 @@
   mach_keyb_init       = amiga_keyb_init;
   mach_kbdrate         = amiga_kbdrate;
   mach_init_IRQ        = amiga_init_IRQ;
-  mach_default_handler = &amiga_default_handler;
   mach_request_irq     = amiga_request_irq;
   mach_free_irq        = amiga_free_irq;
   enable_irq           = amiga_enable_irq;
   disable_irq          = amiga_disable_irq;
   mach_get_model       = amiga_get_model;
   mach_get_hardware_list = amiga_get_hardware_list;
-  mach_get_irq_list    = amiga_get_irq_list;
   mach_gettimeoffset   = amiga_gettimeoffset;
   if (AMIGAHW_PRESENT(A3000_CLK)){
     mach_gettod  = a3000_gettod;
diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16/arch/m68k/kernel/entry.S linux-2.3.16-int/arch/m68k/kernel/entry.S
--- linux-2.3.16/arch/m68k/kernel/entry.S	Fri Sep  3 21:44:32 1999
+++ linux-2.3.16-int/arch/m68k/kernel/entry.S	Sat Sep  4 23:53:17 1999
@@ -37,16 +37,15 @@
 #include <asm/errno.h>
 #include <asm/setup.h>
 #include <asm/segment.h>
+#include <asm/irq.h>
 #include <asm/traps.h>
 
 #include "m68k_defs.h"
 
 .globl SYMBOL_NAME(system_call), SYMBOL_NAME(buserr), SYMBOL_NAME(trap)
 .globl SYMBOL_NAME(resume), SYMBOL_NAME(ret_from_exception)
-.globl SYMBOL_NAME(ret_from_signal)
-.globl SYMBOL_NAME(inthandler), SYMBOL_NAME(sys_call_table)
+.globl SYMBOL_NAME(ret_from_signal), SYMBOL_NAME(sys_call_table)
 .globl SYMBOL_NAME(sys_fork), SYMBOL_NAME(sys_clone), SYMBOL_NAME(sys_vfork)
-.globl SYMBOL_NAME(ret_from_interrupt), SYMBOL_NAME(bad_interrupt)
 
 .text
 ENTRY(buserr)
@@ -128,10 +127,6 @@
 	andw	#ALLOWINT,%sr
 	tstl	%curptr@(TASK_NEEDRESCHED)
 	jne	SYMBOL_NAME(reschedule)
-#if 0
-	cmpl	#SYMBOL_NAME(task),%curptr	| task[0] cannot have signals
-	jeq	2f
-#endif
 					| check for delayed trace
 	bclr	#PF_DTRACE_BIT,%curptr@(TASK_FLAGS+PF_DTRACE_OFF)
 	jne	do_delayed_trace
@@ -164,86 +159,181 @@
 	addql	#4,%sp
 	jra	5b
 
+/*
+** Interrupt construction set. :-)
+** You can build your own interrupts with these macros.
+*/
 
-#if 0
-#if CONFIG_AMIGA
-SYMBOL_NAME_LABEL(ami_inthandler)
+| general interrupt entry
+| intnodes - vector of ptr to interrupt nodes
+| firstvec, firststatvec - first entry in intnodes/int stats
+| -> %a0 contains first int node, %d0 exception vector
+.macro	int_entry intnodes, firstvec, firststatvec=VEC_SPUR
 	addql	#1,SYMBOL_NAME(local_irq_count)
 	SAVE_ALL_INT
 	GET_CURRENT(%d0)
 
+| extract exception vector, do some statistic and get (first) int node
 	bfextu	%sp@(PT_VECTOR){#4,#12},%d0
 	movel	%d0,%a0
-	addql	#1,%a0@(SYMBOL_NAME(kstat)+STAT_IRQ-VECOFF(VEC_SPUR))
-	movel	%a0@(SYMBOL_NAME(autoirq_list)-VECOFF(VEC_SPUR)),%a0
+	addql	#1,%a0@(SYMBOL_NAME(kstat)+STAT_IRQ-VECOFF(\firststatvec))
+	movel	%a0@(SYMBOL_NAME(\intnodes)-VECOFF(\firstvec)),%a0
+.endm
 
-| amiga vector int handler get the req mask instead of irq vector
-	lea	CUSTOMBASE,%a1
-	movew	%a1@(C_INTREQR),%d0
-	andw	%a1@(C_INTENAR),%d0
-
-| prepare stack (push frame pointer, dev_id & req mask)
+| call a single interrupt node
+.macro	int_callnode exit=SYMBOL_NAME(ret_from_interrupt_cleanup)
 	pea	%sp@
 	movel	%a0@(IRQ_DEVID),%sp@-
 	movel	%d0,%sp@-
-	pea	%pc@(SYMBOL_NAME(ret_from_interrupt):w)
-	jbra	@(IRQ_HANDLER,%a0)@(0)
-
-ENTRY(nmi_handler)
-	rte
+	pea	%pc@(\exit:w)
+	jra	@(IRQ_HANDLER,%a0)@(0)
+.endm
+
+| after int_callnode the stack must be cleaned up
+.macro	int_cleanup
+	lea	%sp@(12),%sp
+.endm
+
+| call a list of interrupt nodes
+.macro	int_callnodelist exit=SYMBOL_NAME(ret_from_interrupt)
+	movel	%a0@(IRQ_NEXT),%sp@-
+	pea	%sp@(4)
+	movel	%a0@(IRQ_DEVID),%sp@-
+	movel	%d0,%sp@-
+1:	jsr	@(IRQ_HANDLER,%a0)@(0)
+	movel	%sp@(12),%d0
+	jeq	2f
+	movel	%d0,%a0
+| only modify devid on stack, we expect the rest to be unmodified
+	movel	%a0@(IRQ_DEVID),%sp@(4)
+	movel	%a0@(IRQ_NEXT),%sp@(12)
+	jra	1b
+2:	lea	%sp@(16),%sp
+	jra	\exit
+.endm
+
+| help macro for the two exit macro to check for a nested interrupt.
+| For the 060 we can be sure that at least one instruction of an
+| exception is executed, so the counter check is sufficient.
+.macro int_returncheck dest
+#ifndef CPU_M68060_ONLY
+#if MAX_NOINT_IPL == 0
+	bftst	%sp@(PT_SR){#5,#3}
+	jne	\dest
+#else
+	bfextu	%sp@(PT_SR){#5,#3},%d0
+	cmpiw	#MAX_NOINT_IPL,%d0
+	jhi	\dest
 #endif
 #endif
+.endm
 
-/*
-** This is the main interrupt handler, responsible for calling process_int()
-*/
-SYMBOL_NAME_LABEL(inthandler)
-	SAVE_ALL_INT
-	GET_CURRENT(%d0)
-	addql	#1,SYMBOL_NAME(local_irq_count)
-					|  put exception # in d0
-	bfextu %sp@(PT_VECTOR){#4,#10},%d0
-
-	movel	%sp,%sp@-
-	movel	%d0,%sp@- 		|  put vector # on stack
-#if defined(MACH_Q40_ONLY) && defined(CONFIG_BLK_DEV_FD)
-	btstb	#4,0xff000000	| Q40 floppy needs very special treatment ...
-	jbeq	1f
-	btstb	#3,0xff000004		
-	jbeq	1f
-	jbsr	SYMBOL_NAME(floppy_hardint)
-	jbra	3f
-1:
-#endif		
-	jbsr	SYMBOL_NAME(process_int)|  process the IRQ
-3:     	addql	#8,%sp			|  pop parameters off stack
-
-SYMBOL_NAME_LABEL(ret_from_interrupt)
+.macro	int_return
 	subql	#1,SYMBOL_NAME(local_irq_count)
-	jeq	1f
-2:
-	RESTORE_ALL
+	jeq	2f
 1:
-#if 1
-	bfextu  %sp@(PT_SR){#5,#3},%d0	| Check for nested interrupt.
-#if MAX_NOINT_IPL > 0
-	cmpiw	#MAX_NOINT_IPL,%d0
-#endif
-	jhi	2b
-#endif
-	/* check if we need to do software interrupts */
+	restore_all
+	ALIGN
+2:
+	int_returncheck 1b
 
+	/* check if we need to do software interrupts */
 	movel	SYMBOL_NAME(bh_active),%d0
 	andl	SYMBOL_NAME(bh_mask),%d0
 	jeq	SYMBOL_NAME(ret_from_exception)
 
 	pea	SYMBOL_NAME(ret_from_exception)
 	jra	SYMBOL_NAME(do_bottom_half)
+.endm
 
+.macro	int_slowreturn do_slowrequest
+	movel	SYMBOL_NAME(local_irq_count),%d0
+	subql	#1,%d0
+	jeq	2f
+1:	movel	%d0,SYMBOL_NAME(local_irq_count)
+	restore_all
+	ALIGN
+2:
+	int_returncheck 1b
+3:
+	andw	#0xf8ff,%sr
+	jsr	\do_slowrequest
+
+	orw	#0x0700,%sr
+	tstl	SYMBOL_NAME(slowirq_request)
+	jne	3b
+	clrl	SYMBOL_NAME(local_irq_count)
+	jra	SYMBOL_NAME(ret_from_exception)
+.endm
 
+
+#ifdef CONFIG_AMIGA
+/*
+** Special Amiga interrupt handler
+*/
+ENTRY(amiga_inthandler)
+	int_entry autoirq_list,VEC_SPUR
+
+| amiga vector int handler get the req mask instead of irq vector
+       lea     CUSTOMBASE,%a1
+       movew   %a1@(C_INTREQR),%d0
+       andw    %a1@(C_INTENAR),%d0
+
+.globl	SYMBOL_NAME(amiga_slowintmask),SYMBOL_NAME(amiga_fastintmask)
+
+| disable slow ints and modify req mask
+	movew	%d0,%d1
+.equ	SYMBOL_NAME(amiga_slowintmask),.+2
+	andw	#0:w,%d1
+	jeq	1f
+	orw	%d1,SYMBOL_NAME(slowirq_request+2)
+	movew	%d1,%a1@(C_INTENA)
+.equ	SYMBOL_NAME(amiga_fastintmask),.+2
+1:	andw	#0:w,%d0
+	jeq	SYMBOL_NAME(amiga_fastret_from_irq)
+
+	int_callnode SYMBOL_NAME(amiga_ret_from_irq)
+
+ENTRY(amiga_ret_from_irq)
+	int_cleanup
+SYMBOL_NAME_LABEL(amiga_fastret_from_irq)
+	int_slowreturn SYMBOL_NAME(amiga_do_slowirq_request)
+
+ENTRY(amiga_nmi_handler)
+	rte
+#endif
+
+#if defined(CONFIG_HP300)
+ENTRY(autoirq_handler)
+	int_entry autoirq_list,VEC_SPUR
+	lsrl	#2,%d0
+	int_callnode SYMBOL_NAME(cleanup_from_interrupt)
+
+ENTRY(autoirq_listhandler)
+	int_entry autoirq_list,VEC_SPUR
+	lsrl	#2,%d0
+	int_callnodelist SYMBOL_NAME(ret_from_interrupt)
+
+ENTRY(cleanup_from_interrupt)
+	int_cleanup
+SYMBOL_NAME_LABEL(ret_from_interrupt)
+	int_return
+#endif
+
+#if defined(CONFIG_APOLLO)
+ENTRY(appolloirq_handler)
+	int_entry userirq_list, 160, 160+VEC_SPUR
+	lsrl	#2,%d0
+	int_callnode SYMBOL_NAME(apollo_ret_from_irq)
+
+ENTRY(appollo_ret_from_irq)
+	int_cleanup
+#warning add something
+	int_return
+#endif
 /* Handler for uninitialized and spurious interrupts */
 
-SYMBOL_NAME_LABEL(bad_interrupt)
+ENTRY(bad_interrupt)
 	addql	#1,SYMBOL_NAME(num_spurious)
 	rte
 
diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16/arch/m68k/kernel/ints.c linux-2.3.16-int/arch/m68k/kernel/ints.c
--- linux-2.3.16/arch/m68k/kernel/ints.c	Fri Aug 20 20:46:58 1999
+++ linux-2.3.16-int/arch/m68k/kernel/ints.c	Sat Sep  4 21:57:28 1999
@@ -23,11 +23,17 @@
  *           If you want to replace a default handler you should know what
  *           you're doing, since it might handle different other irq sources
  *           which must be served                               /Roman Zippel
+ * 01/08/99: new interrupt managemant, that handles user vector interrupts as
+ *           well, sys_request_irq takes now the vector number from traps.h as
+ *           argument, process_int() is gone, every machine has to provide its
+ *           own interrupt entry and insert it into the vector table, examples
+ *           are in entry.S.                                    /Roman Zippel
  */
 
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/sched.h>
+#include <linux/malloc.h>
 #include <linux/kernel_stat.h>
 #include <linux/errno.h>
 #include <linux/init.h>
@@ -43,23 +49,29 @@
 #include <asm/q40ints.h>
 #endif
 
-/* table for system interrupt handlers */
-static irq_handler_t irq_list[SYS_IRQS];
-
-static const char *default_names[SYS_IRQS] = {
-	"spurious int", "int1 handler", "int2 handler", "int3 handler",
-	"int4 handler", "int5 handler", "int6 handler", "int7 handler"
-};
-
 /* The number of spurious interrupts */
 volatile unsigned int num_spurious;
 
-#define NUM_IRQ_NODES 100
-static irq_node_t nodes[NUM_IRQ_NODES];
-
-unsigned int local_irq_count[NR_CPUS];
+/* static irq nodes used during bootup */
+#define NUM_IRQ_NODES 16
+static irq_node_t boot_nodes[NUM_IRQ_NODES];
+
+/* table for auto vector interrupt handlers */
+irq_node_t *autoirq_list[AUTO_IRQ_NR] = { NULL };
+irq_node_t *autoirq_slowlist[AUTO_IRQ_NR] = { NULL };
+
+#if USER_IRQ_NR
+/* table for user vector interrupt handlers */
+irq_node_t *userirq_list[USER_IRQ_NR] = { NULL };
+irq_node_t *userirq_slowlist[USER_IRQ_NR] = { NULL };
+#endif
 
-unsigned int local_bh_count[NR_CPUS];
+unsigned int local_irq_count[NR_CPUS] = { 0 };
+unsigned int local_bh_count[NR_CPUS] = { 0 };
+unsigned int local_slowirq_count[NR_CPUS] = { 0 };
+volatile int slowirq_enable = 0;
+volatile int slowirq_request = 0;
+volatile int slowirq_busycnt = 1;
 
 static void dummy_enable_irq(unsigned int irq);
 static void dummy_disable_irq(unsigned int irq);
@@ -90,31 +102,104 @@
 {
 	int i;
 
-	for (i = 0; i < SYS_IRQS; i++) {
-		if (mach_default_handler)
-			irq_list[i].handler = (*mach_default_handler)[i];
-		irq_list[i].flags   = 0;
-		irq_list[i].dev_id  = NULL;
-		irq_list[i].devname = default_names[i];
-	}
+	for (i = 0; i < AUTO_IRQ_NR; i++)
+		autoirq_list[i] = NULL;
+
+#if USER_IRQ_NR
+	for (i = 0; i < USER_IRQ_NR; i++)
+		userirq_list[i] = NULL;
+#endif
 
 	for (i = 0; i < NUM_IRQ_NODES; i++)
-		nodes[i].handler = NULL;
+		boot_nodes[i].handler = NULL;
 
-	mach_init_IRQ ();
+	mach_init_IRQ();
 }
 
 irq_node_t *new_irq_node(void)
 {
 	irq_node_t *node;
-	short i;
+	int i;
 
-	for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--)
+	for (node = boot_nodes, i = 0; i < NUM_IRQ_NODES; node++, i++)
 		if (!node->handler)
-			return node;
+			break;
+
+	if (node->handler)
+		node = kmalloc(sizeof(irq_node_t), GFP_KERNEL);
+
+	if (node) {
+		node->handler = NULL;
+		node->flags = 0;
+	}
+
+	return node;
+}
+
+void free_irq_node(irq_node_t *node)
+{
+	if (node >= &boot_nodes[0] && node < &boot_nodes[NUM_IRQ_NODES])
+		node->handler = NULL;
+	else
+		kfree(node);
+}
+
+static irq_node_t **get_irqlist(unsigned int irq, unsigned long flags)
+{
+	irq_node_t **list = NULL;
 
-	printk ("new_irq_node: out of nodes\n");
-	return NULL;
+	if (irq > VEC_SPUR && irq <= VEC_INT7) {
+		list = &autoirq_slowlist[irq - VEC_SPUR];
+		if (flags & IRQ_FLG_FASTQUEUE)
+			list = &autoirq_list[irq - VEC_SPUR];
+	}
+
+#if USER_IRQ_NR
+	if (irq >= VEC_USER && irq <= VEC_USER + USER_IRQ_NR) {
+		list = &userirq_slowlist[irq - VEC_USER];
+		if (flags & IRQ_FLG_FASTQUEUE)
+			list = &userirq_list[irq - VEC_USER];
+	}
+#endif
+
+	return list;
+}
+
+static irq_node_t **find_irqnode(unsigned int irq, void *dev_id)
+{
+	irq_node_t **list = NULL;
+	irq_node_t **slowlist = NULL;
+
+	if (irq > VEC_SPUR && irq <= VEC_INT7) {
+		list = &autoirq_list[irq - VEC_SPUR];
+		slowlist = &autoirq_slowlist[irq - VEC_SPUR];
+	}
+
+#if USER_IRQ_NR
+	if (irq >= VEC_USER && irq <= VEC_USER + USER_IRQ_NR) {
+		list = &userirq_list[irq - VEC_USER];
+		slowlist = &userirq_slowlist[irq - VEC_USER];
+	}
+#endif
+
+	/* First scan fast list and continue with slow list */
+	while (list) {
+		if (!*list) {
+			list = slowlist;
+			slowlist = NULL;
+			continue;
+		}
+
+		if (!*list)
+			return NULL;
+
+		if ((*list)->dev_id == dev_id)
+			break;
+
+		list = &(*list)->next;
+	}
+
+	return list;
 }
 
 /*
@@ -138,49 +223,82 @@
                     void (*handler)(int, void *, struct pt_regs *), 
                     unsigned long flags, const char *devname, void *dev_id)
 {
-	if (irq < IRQ1 || irq > IRQ7) {
-		printk("%s: Incorrect IRQ %d from %s\n",
-		       __FUNCTION__, irq, devname);
-		return -ENXIO;
-	}
+	irq_node_t **list;
+	irq_node_t *node;
 
-#if 0
-	if (!(irq_list[irq].flags & IRQ_FLG_STD)) {
-		if (irq_list[irq].flags & IRQ_FLG_LOCK) {
-			printk("%s: IRQ %d from %s is not replaceable\n",
-			       __FUNCTION__, irq, irq_list[irq].devname);
+	list = find_irqnode(irq, dev_id);
+	if (list) {
+		if (!(flags & IRQ_FLG_REPLACE)) {
+			printk("%s: %s can't replace IRQ %x from %s\n",
+			       __FUNCTION__, devname, irq, (*list)->devname);
 			return -EBUSY;
 		}
-		if (!(flags & IRQ_FLG_REPLACE)) {
-			printk("%s: %s can't replace IRQ %d from %s\n",
-			       __FUNCTION__, devname, irq, irq_list[irq].devname);
+		if ((*list)->flags & IRQ_FLG_LOCK) {
+			printk("%s: IRQ %x from %s is not replaceable\n",
+			       __FUNCTION__, irq, (*list)->devname);
+			return -EBUSY;
+		}
+
+		node = *list;
+		*list = node->next;
+
+		list = get_irqlist(irq, flags);
+	} else {
+		list = get_irqlist(irq, flags);
+		if (!list) {
+			printk("%s: Incorrect IRQ %x from %s\n",
+			       __FUNCTION__, irq, devname);
+			return -ENXIO;
+		}
+
+		if (*list && !(flags & IRQ_FLG_LIST)) {
+			printk("%s: IRQ %x is busy (%s)\n", __FUNCTION__,
+			       irq, (*list)->devname);
 			return -EBUSY;
 		}
+
+		node = new_irq_node();
+		if (!node)
+			return -ENOMEM;
+	}
+
+	node->handler = handler;
+	node->flags   = flags;
+	node->dev_id  = dev_id;
+	node->devname = devname;
+
+	if (node->flags & IRQ_FLG_SLOW) {
+		while (*list)
+			list = &(*list)->next;
+	} else if (node->flags & IRQ_FLG_FAST) {
+		while (*list && (*list)->flags & IRQ_FLG_FAST)
+			list = &(*list)->next;
+	} else {
+		while (*list && !((*list)->flags & IRQ_FLG_SLOW))
+			list = &(*list)->next;
 	}
-#endif
 
-	irq_list[irq].handler = handler;
-	irq_list[irq].flags   = flags;
-	irq_list[irq].dev_id  = dev_id;
-	irq_list[irq].devname = devname;
+	node->next = *list;
+	*list = node;
+
 	return 0;
 }
 
 void sys_free_irq(unsigned int irq, void *dev_id)
 {
-	if (irq < IRQ1 || irq > IRQ7) {
-		printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
+	irq_node_t **list;
+	irq_node_t *node;
+
+	list = find_irqnode(irq, dev_id);
+	if (!list) {
+		printk("%s: No handler with id 0x%p found for IRQ %x\n",
+		       __FUNCTION__, dev_id, irq);
 		return;
 	}
 
-	if (irq_list[irq].dev_id != dev_id)
-		printk("%s: Removing probably wrong IRQ %d from %s\n",
-		       __FUNCTION__, irq, irq_list[irq].devname);
-
-	irq_list[irq].handler = (*mach_default_handler)[irq];
-	irq_list[irq].flags   = 0;
-	irq_list[irq].dev_id  = NULL;
-	irq_list[irq].devname = default_names[irq];
+	node = *list;
+	*list = node->next;
+	free_irq_node(node);
 }
 
 /*
@@ -229,35 +347,81 @@
 	printk("calling uninitialized disable_irq()\n");
 }
 
-asmlinkage void process_int(unsigned long vec, struct pt_regs *fp)
-{
-	if (vec >= VEC_INT1 && vec <= VEC_INT7 && !MACH_IS_BVME6000) {
-		vec -= VEC_SPUR;
-		kstat.irqs[0][vec]++;
-		irq_list[vec].handler(vec, irq_list[vec].dev_id, fp);
-	} else {
-		if (mach_process_int)
-			mach_process_int(vec, fp);
-		else
-			panic("Can't process interrupt vector %ld\n", vec);
-		return;
-	}
-}
-
 int get_irq_list(char *buf)
 {
-	int i, len = 0;
+	irq_node_t **list;
+	irq_node_t **slowlist;
+	int i, len;
+
+	len = sprintf(buf, "auto %2x: %10u     spurious int\n",
+	              0, num_spurious);
 
 	/* autovector interrupts */
-	if (mach_default_handler) {
-		for (i = 0; i < SYS_IRQS; i++) {
-			len += sprintf(buf+len, "auto %2d: %10u ", i,
-			               i ? kstat.irqs[0][i] : num_spurious);
-				len += sprintf(buf+len, "  ");
-			len += sprintf(buf+len, "%s\n", irq_list[i].devname);
+	for (i = 1; i < AUTO_IRQ_NR; i++) {
+		list = &autoirq_list[i];
+		slowlist = &autoirq_slowlist[i];
+		if (!*list && !*slowlist)
+			continue;
+		len += sprintf(buf+len, "auto %2d: %10u ",
+		               i, kstat.irqs[0][i]);
+		if (!*list) {
+			list = slowlist;
+			slowlist = NULL;
+		}
+		while (1) {
+			len += sprintf(buf+len, "%c%c%c %s\n",
+			               (*list)->flags & IRQ_FLG_REALTIME ? 'R' : ' ',
+			               (*list)->flags & IRQ_FLG_LOCK ? 'L' : ' ',
+			               (*list)->flags & IRQ_FLG_FAST ? 'F' :
+			               ((*list)->flags & IRQ_FLG_SLOW ? 'S' : ' '),
+			               (*list)->devname);
+			list = &(*list)->next;
+			if (!*list) {
+				if (!(list = slowlist))
+					break;
+				slowlist = NULL;
+			}
+			if (!*list)
+				break;
+			len += sprintf(buf+len, "                    ");
+		}
+	}
+
+#if USER_IRQ_NR
+	/* uservector interrupts */
+	for (i = 0; i < USER_IRQ_NR; i++) {
+		list = &userirq_list[i];
+		slowlist = &userirq_slowlist[i];
+		if (!*list && !*slowlist)
+			continue;
+		len += sprintf(buf+len, "user %2d: %10u ",
+		               i, kstat.irqs[0][AUTO_IRQ_NR+i]);
+		if (!*list) {
+			list = slowlist;
+			slowlist = NULL;
+		}
+		while (1) {
+			len += sprintf(buf+len, "%c%c%c %s\n",
+			               (*list)->flags & IRQ_FLG_REALTIME ? 'R' : ' ',
+			               (*list)->flags & IRQ_FLG_LOCK ? 'L' : ' ',
+			               (*list)->flags & IRQ_FLG_FAST ? 'F' :
+			               ((*list)->flags & IRQ_FLG_SLOW ? 'S' : ' '),
+			               (*list)->devname);
+			list = &(*list)->next;
+			if (!*list) {
+				if (!(list = slowlist))
+					break;
+				slowlist = NULL;
+			}
+			if (!*list)
+				break;
+			len += sprintf(buf+len, "                    ");
 		}
 	}
+#endif
+
+	if (mach_get_irq_list)
+		len += mach_get_irq_list(buf+len);
 
-	len += mach_get_irq_list(buf+len);
 	return len;
 }
diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16/arch/m68k/kernel/traps.c linux-2.3.16-int/arch/m68k/kernel/traps.c
--- linux-2.3.16/arch/m68k/kernel/traps.c	Fri Sep  3 21:44:40 1999
+++ linux-2.3.16-int/arch/m68k/kernel/traps.c	Sat Sep  4 22:04:54 1999
@@ -33,6 +33,7 @@
 #include <asm/fpu.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
+#include <asm/irq.h>
 #include <asm/traps.h>
 #include <asm/pgtable.h>
 #include <asm/machdep.h>
@@ -55,19 +56,14 @@
 	0, 0, buserr, trap, trap, trap, trap, trap,
 	trap, trap, trap, trap, trap, trap, trap, trap,
 	trap, trap, trap, trap, trap, trap, trap, trap,
-	inthandler, inthandler, inthandler, inthandler,
-	inthandler, inthandler, inthandler, inthandler,
+	bad_interrupt, bad_interrupt, bad_interrupt, bad_interrupt,
+	bad_interrupt, bad_interrupt, bad_interrupt, bad_interrupt,
 	/* TRAP #0-15 */
 	system_call, trap, trap, trap, trap, trap, trap, trap,
 	trap, trap, trap, trap, trap, trap, trap, trap,
 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 };
 
-/* nmi handler for the Amiga */
-asm(".text\n"
-    __ALIGN_STR "\n"
-    SYMBOL_NAME_STR(nmihandler) ": rte");
-
 void __init base_trap_init(void)
 {
 #ifdef CONFIG_SUN3
@@ -143,17 +139,13 @@
 			vectors[i] = trap;
 
 	for (i = 64; i < 256; i++)
-		vectors[i] = inthandler;
+		vectors[i] = bad_interrupt;
 
 #ifdef CONFIG_M68KFPU_EMU
 	if (FPU_IS_EMU)
 		vectors[VEC_LINE11] = fpu_emu;
 #endif
 
-        /* if running on an amiga, make the NMI interrupt do nothing */
-	if (MACH_IS_AMIGA) {
-		vectors[VEC_INT7] = nmihandler;
-	}
 #ifdef CONFIG_SUN3
 	/* Moved from setup_arch() */
 	base_trap_init();
diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16/drivers/video/amifb.c linux-2.3.16-int/drivers/video/amifb.c
--- linux-2.3.16/drivers/video/amifb.c	Fri Sep  3 21:46:21 1999
+++ linux-2.3.16-int/drivers/video/amifb.c	Sat Sep  4 21:57:28 1999
@@ -599,8 +599,8 @@
 
 #define arraysize(x)	(sizeof(x)/sizeof(*(x)))
 
-#define VBlankOn()	custom.intena = IF_SETCLR|IF_COPER
-#define VBlankOff()	custom.intena = IF_COPER
+#define VBlankOn()	custom.intena = IF_SETCLR|IF_COPPER
+#define VBlankOff()	custom.intena = IF_COPPER
 
 
 	/*
@@ -1785,13 +1785,10 @@
 
 	ami_init_copper();
 
-	if (request_irq(IRQ_AMIGA_AUTO_3, amifb_interrupt, 0,
+	if (request_irq(IRQ_AMIGA_COPPER, amifb_interrupt,
+	                IRQ_FLG_FAST|IRQ_FLG_LOCK, 
 	                "fb vertb handler", NULL))
 		panic("Couldn't add vblank interrupt\n");
-	ami_intena_vals[IRQ_AMIGA_VERTB] = IF_COPER;
-	ami_intena_vals[IRQ_AMIGA_COPPER] = 0;
-	custom.intena = IF_VERTB;
-	custom.intena = IF_SETCLR | IF_COPER;
 
 	amifb_set_var(&var, -1, &fb_info);
 
@@ -1876,57 +1873,41 @@
 
 static void amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp)
 {
-	u_short ints = custom.intreqr & custom.intenar;
-	static struct irq_server server = {0, 0};
 	unsigned long flags;
 
-	if (ints & IF_BLIT) {
-		custom.intreq = IF_BLIT;
-		amiga_do_irq(IRQ_AMIGA_BLIT, fp);
-	}
-
-	if (ints & IF_COPER) {
-		custom.intreq = IF_COPER;
-		if (do_vmode_pan || do_vmode_full)
-			ami_update_display();
-
-		if (do_vmode_full)
-			ami_init_display();
-
-		if (do_vmode_pan) {
-			flash_cursor();
-			ami_rebuild_copper();
-			do_cursor = do_vmode_pan = 0;
-		} else if (do_cursor) {
-			flash_cursor();
-			ami_set_sprite();
-			do_cursor = 0;
-		} else {
-			if (flash_cursor())
-				ami_set_sprite();
-		}
+	if (do_vmode_pan || do_vmode_full)
+		ami_update_display();
 
-		save_flags(flags);
-		cli();
-		if (get_vbpos() < down2(currentpar.diwstrt_v - 6))
-			custom.copjmp2 = 0;
-		restore_flags(flags);
+	if (do_vmode_full)
+		ami_init_display();
 
-		if (do_blank) {
-			ami_do_blank();
-			do_blank = 0;
-		}
+	if (do_vmode_pan) {
+		flash_cursor();
+		ami_rebuild_copper();
+		do_cursor = do_vmode_pan = 0;
+	} else if (do_cursor) {
+		flash_cursor();
+		ami_set_sprite();
+		do_cursor = 0;
+	} else {
+		if (flash_cursor())
+			ami_set_sprite();
+	}
 
-		if (do_vmode_full) {
-			ami_reinit_copper();
-			do_vmode_full = 0;
-		}
-		amiga_do_irq_list(IRQ_AMIGA_VERTB, fp, &server);
+	__save_flags(flags);
+	__cli();
+	if (get_vbpos() < down2(currentpar.diwstrt_v - 6))
+		custom.copjmp2 = 0;
+	__restore_flags(flags);
+
+	if (do_blank) {
+		ami_do_blank();
+		do_blank = 0;
 	}
 
-	if (ints & IF_VERTB) {
-		printk("%s: Warning: IF_VERTB was enabled\n", __FUNCTION__);
-		custom.intena = IF_VERTB;
+	if (do_vmode_full) {
+		ami_reinit_copper();
+		do_vmode_full = 0;
 	}
 }
 
@@ -3182,7 +3163,7 @@
 		(cop++)->l = CMOVE2(loww(p), sprpt[i]);
 	}
 
-	(cop++)->l = CMOVE(IF_SETCLR | IF_COPER, intreq);
+	(cop++)->l = CMOVE(IF_SETCLR | IF_COPPER, intreq);
 	copdisplay.wait = cop;
 	(cop++)->l = CEND;
 	(cop++)->l = CMOVE(0, copjmp2);
diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16/include/asm-m68k/amigaints.h linux-2.3.16-int/include/asm-m68k/amigaints.h
--- linux-2.3.16/include/asm-m68k/amigaints.h	Tue May 18 16:01:03 1999
+++ linux-2.3.16-int/include/asm-m68k/amigaints.h	Sat Sep  4 21:57:28 1999
@@ -10,8 +10,12 @@
 ** Created 10/2/92 by Greg Harp
 */
 
-#ifndef _ASMm68k_AMIGAINTS_H_
-#define _ASMm68k_AMIGAINTS_H_
+#ifndef _M68K_AMIGAINTS_H_
+#define _M68K_AMIGAINTS_H_
+
+#include <linux/linkage.h>
+#include <linux/kernel_stat.h>
+#include <asm/irq.h>
 
 /*
 ** Amiga Interrupt sources.
@@ -23,35 +27,21 @@
 #define CIA_IRQS            (5)
 #define AMI_IRQS            (32) /* AUTO_IRQS+AMI_STD_IRQS+2*CIA_IRQS */
 
-/* vertical blanking interrupt */
-#define IRQ_AMIGA_VERTB     0
-
-/* copper interrupt */
-#define IRQ_AMIGA_COPPER    1
-
-/* Audio interrupts */
-#define IRQ_AMIGA_AUD0	    2
-#define IRQ_AMIGA_AUD1	    3
-#define IRQ_AMIGA_AUD2	    4
-#define IRQ_AMIGA_AUD3	    5
-
-/* Blitter done interrupt */
-#define IRQ_AMIGA_BLIT	    6
-
-/* floppy disk interrupts */
-#define IRQ_AMIGA_DSKSYN    7
-#define IRQ_AMIGA_DSKBLK    8
-
-/* builtin serial port interrupts */
-#define IRQ_AMIGA_RBF	    9
-#define IRQ_AMIGA_TBE	    10
-
-/* software interrupts */
-#define IRQ_AMIGA_SOFT      11
-
-/* interrupts from external hardware */
-#define IRQ_AMIGA_PORTS	    12
-#define IRQ_AMIGA_EXTER	    13
+/* Amiga standard interrupt sources */
+#define IRQ_AMIGA_TBE		0
+#define IRQ_AMIGA_DSKBLK	1
+#define IRQ_AMIGA_SOFT		2
+#define IRQ_AMIGA_PORTS		3
+#define IRQ_AMIGA_COPPER	4
+#define IRQ_AMIGA_VERTB		5
+#define IRQ_AMIGA_BLIT		6
+#define IRQ_AMIGA_AUD0		7
+#define IRQ_AMIGA_AUD1		8
+#define IRQ_AMIGA_AUD2		9
+#define IRQ_AMIGA_AUD3		10
+#define IRQ_AMIGA_RBF		11
+#define IRQ_AMIGA_DSKSYN	12
+#define IRQ_AMIGA_EXTER		13
 
 /* CIA interrupt sources */
 #define IRQ_AMIGA_CIAA      14
@@ -78,8 +68,6 @@
 #define IRQ_AMIGA_AUTO_6    30
 #define IRQ_AMIGA_AUTO_7    31
 
-#define IRQ_FLOPPY	    IRQ_AMIGA_DSKBLK
-
 /* INTREQR masks */
 #define IRQ1_MASK   0x0007	/* INTREQR mask for IRQ 1 */
 #define IRQ2_MASK   0x0008	/* INTREQR mask for IRQ 2 */
@@ -100,21 +88,54 @@
 #define IF_AUD0     0x0080	/* audio channel 0 done interrupt */
 #define IF_BLIT     0x0040	/* blitter done interrupt */
 #define IF_VERTB    0x0020	/* vertical blanking interrupt */
-#define IF_COPER    0x0010	/* copper interrupt */
+#define IF_COPPER   0x0010	/* copper interrupt */
 #define IF_PORTS    0x0008	/* external level 2 and CIA A interrupt */
 #define IF_SOFT     0x0004	/* software initiated interrupt */
 #define IF_DSKBLK   0x0002	/* diskblock DMA finished */
 #define IF_TBE	    0x0001	/* serial transmit buffer empty interrupt */
 
-struct irq_server {
-	unsigned short count, reentrance;
-};
+extern unsigned short amiga_slowintmask, amiga_fastintmask;
 
-extern void amiga_do_irq(int irq, struct pt_regs *fp);
-extern void amiga_do_irq_list(int irq, struct pt_regs *fp, struct irq_server *server);
+asmlinkage void amiga_inthandler(void);
+asmlinkage void amiga_nmi_handler(void);
+asmlinkage void amiga_do_slowirq_request(void);
+
+extern inline void amiga_do_irq(int irq, struct pt_regs *fp)
+{
+	kstat.irqs[0][AUTO_IRQ_NR + irq]++;
+	userirq_list[irq]->handler(irq, userirq_list[irq]->dev_id, fp);
+}
+
+extern inline void amiga_do_irq_list(int irq, struct pt_regs *fp)
+{
+	irq_node_t *node;
+
+	kstat.irqs[0][AUTO_IRQ_NR + irq]++;
+	/* serve handlers */
+	for (node = userirq_list[irq]; node; node = node->next)
+		node->handler(irq, node->dev_id, fp);
+}
+
+extern inline void amiga_do_slowirq(int irq, struct pt_regs *fp)
+{
+	kstat.irqs[0][AUTO_IRQ_NR + irq]++;
+	userirq_slowlist[irq]->handler(irq, userirq_slowlist[irq]->dev_id, fp);
+}
+
+extern inline void amiga_do_slowirq_list(int irq, struct pt_regs *fp)
+{
+	irq_node_t *node;
+
+	/* serve handlers */
+	for (node = userirq_slowlist[irq]; node; node = node->next)
+		node->handler(irq, node->dev_id, fp);
+}
 
-/* CIA interrupt control register bits */
+/*
+ * CIA specific definitions
+ */
 
+/* CIA interrupt control register bits */
 #define CIA_ICR_TA	0x01
 #define CIA_ICR_TB	0x02
 #define CIA_ICR_ALRM	0x04
@@ -132,4 +153,4 @@
 extern unsigned char cia_set_irq(struct ciabase *base, unsigned char mask);
 extern unsigned char cia_able_irq(struct ciabase *base, unsigned char mask);
 
-#endif /* asm-m68k/amigaints.h */
+#endif /* _M68K_AMIGAINTS_H_ */
diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16/include/asm-m68k/entry.h linux-2.3.16-int/include/asm-m68k/entry.h
--- linux-2.3.16/include/asm-m68k/entry.h	Fri Sep  3 21:46:38 1999
+++ linux-2.3.16-int/include/asm-m68k/entry.h	Sat Sep  4 21:57:28 1999
@@ -34,10 +34,6 @@
  *		     the whole kernel.
  */
 
-#ifdef __ASSEMBLY__
-
-#define curptr a2
-
 /* the following macro is used when enabling interrupts */
 #if defined(MACH_ATARI_ONLY) && !defined(CONFIG_HADES)
 	/* block out HSYNC on the atari */
@@ -48,6 +44,10 @@
 #define ALLOWINT 0xf8ff
 #define	MAX_NOINT_IPL	0
 #endif /* machine compilation types */ 
+
+#ifdef __ASSEMBLY__
+
+#define curptr a2
 
 LFLUSH_I_AND_D = 0x00000808
 LSIGTRAP = 5
diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16/include/asm-m68k/hardirq.h linux-2.3.16-int/include/asm-m68k/hardirq.h
--- linux-2.3.16/include/asm-m68k/hardirq.h	Tue Aug 10 20:24:42 1999
+++ linux-2.3.16-int/include/asm-m68k/hardirq.h	Sat Sep  4 21:57:28 1999
@@ -7,7 +7,11 @@
 
 #define in_interrupt() (local_irq_count[smp_processor_id()] + local_bh_count[smp_processor_id()] != 0)
 
-#define hardirq_trylock(cpu)	(local_irq_count[cpu] == 0)
+/* the bottomhalf is already protected by softirq_trylock() and
+ * the interrupt exit guarantees already that do_bottom_half()
+ * is only called from the last interrupt
+ */
+#define hardirq_trylock(cpu)	(1)
 #define hardirq_endlock(cpu)	do { } while (0)
 
 #define hardirq_enter(cpu)	(local_irq_count[cpu]++)
diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16/include/asm-m68k/irq.h linux-2.3.16-int/include/asm-m68k/irq.h
--- linux-2.3.16/include/asm-m68k/irq.h	Fri Aug 20 20:56:31 1999
+++ linux-2.3.16-int/include/asm-m68k/irq.h	Sat Sep  4 21:57:28 1999
@@ -4,46 +4,32 @@
 #include <linux/config.h>
 
 /*
- * # of m68k interrupts
+ * # of auto and user vector m68k interrupts. This number is used for kstat, so
+ * the first 8 are always the autovector interrupts, the rest is machine
+ * specific. It can be either the # of used vector interrupts or the # of other
+ * interrupt sources. The highest value wins if compiled for several machines.
  */
 
-#define SYS_IRQS 8
+#define AUTO_IRQ_NR 8
 
-/*
- * This should be the same as the max(NUM_X_SOURCES) for all the
- * different m68k hosts compiled into the kernel.
- * Currently the Atari has 72 and the Amiga 24, but if both are
- * supported in the kernel it is better to make room for 72.
- */
 #if defined(CONFIG_ATARI)
-#define NR_IRQS (72+SYS_IRQS)
+#define USER_IRQ_NR 72
+#elif defined(CONFIG_AMIGA)
+#define USER_IRQ_NR 24
+#elif defined(CONFIG_APOLLO)
+#define USER_IRQ_NR 16
 #else
-#define NR_IRQS (24+SYS_IRQS)
+#define USER_IRQ_NR 0
 #endif
 
 /*
- * Interrupt source definitions
- * General interrupt sources are the level 1-7.
- * Adding an interrupt service routine for one of these sources
- * results in the addition of that routine to a chain of routines.
- * Each one is called in succession.  Each individual interrupt
- * service routine should determine if the device associated with
- * that routine requires service.
- */
-
-#define IRQ1		(1)	/* level 1 interrupt */
-#define IRQ2		(2)	/* level 2 interrupt */
-#define IRQ3		(3)	/* level 3 interrupt */
-#define IRQ4		(4)	/* level 4 interrupt */
-#define IRQ5		(5)	/* level 5 interrupt */
-#define IRQ6		(6)	/* level 6 interrupt */
-#define IRQ7		(7)	/* level 7 interrupt (non-maskable) */
-
-/*
- * "Generic" interrupt sources
+ * This should be the same as the max(NUM_X_SOURCES) for all the
+ * different m68k hosts compiled into the kernel.
  */
 
-#define IRQ_SCHED_TIMER	(8)    /* interrupt source for scheduling timer */
+#define NR_IRQS (AUTO_IRQ_NR+USER_IRQ_NR)
+
+#ifndef __ASSEMBLY__
 
 static __inline__ int irq_cannonicalize(int irq)
 {
@@ -83,12 +69,20 @@
  * mechanism like all other architectures - SA_INTERRUPT and SA_SHIRQ
  * are your friends.
  */
-#ifndef CONFIG_AMIGA
 #define IRQ_FLG_LOCK	(0x0001)	/* handler is not replaceable	*/
 #define IRQ_FLG_REPLACE	(0x0002)	/* replace existing handler	*/
 #define IRQ_FLG_FAST	(0x0004)
 #define IRQ_FLG_SLOW	(0x0008)
-#define IRQ_FLG_STD	(0x8000)	/* internally used		*/
+#define IRQ_FLG_LIST	(0x0010)
+#define IRQ_FLG_REALTIME (0x0020)
+
+/* only used by the interrupt management! depending on the config option
+ * IRQ_FLG_FASTQUEUE decides about on which queue a handler is put on.
+ */
+#ifdef CONFIG_RT_INTERRUPT
+#define IRQ_FLG_FASTQUEUE IRQ_FLG_REALTIME
+#else
+#define IRQ_FLG_FASTQUEUE IRQ_FLG_FAST
 #endif
 
 /*
@@ -103,22 +97,38 @@
 	struct irq_node *next;
 } irq_node_t;
 
-/*
- * This structure has only 4 elements for speed reasons
- */
-typedef struct irq_handler {
-	void		(*handler)(int, void *, struct pt_regs *);
-	unsigned long	flags;
-	void		*dev_id;
-	const char	*devname;
-} irq_handler_t;
+extern int sys_request_irq(unsigned int, void (*)(int, void *, struct pt_regs *), 
+                           unsigned long, const char *, void *);
+extern int sys_request_listirq(unsigned int, void (*)(int, void *, struct pt_regs *), 
+                               unsigned long, const char *, void *);
+extern void sys_free_irq(unsigned int, void *);
+
+extern irq_node_t *autoirq_list[];
+extern irq_node_t *userirq_list[];
+extern irq_node_t *autoirq_slowlist[];
+extern irq_node_t *userirq_slowlist[];
+extern volatile int slowirq_busycnt;
 
 /* count of spurious interrupts */
 extern volatile unsigned int num_spurious;
 
+extern volatile int slowirq_request;
+#define set_slowirq_request(mask)				\
+	asm volatile ("orl %2,%1" : "=m" (slowirq_request)	\
+	              : "0" (slowirq_request), "id" (mask))
+
+/* standard interrupt handlers */
+asmlinkage void autoirq_handler(void);
+asmlinkage void autoirq_listhandler(void);
+asmlinkage void userirq_handler(void);
+asmlinkage void bad_interrupt(void);
+
 /*
  * This function returns a new irq_node_t
  */
 extern irq_node_t *new_irq_node(void);
+extern void free_irq_node(irq_node_t *);
+
+#endif /* __ASSEMBLY__ */
 
 #endif /* _M68K_IRQ_H_ */
diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16/include/asm-m68k/machdep.h linux-2.3.16-int/include/asm-m68k/machdep.h
--- linux-2.3.16/include/asm-m68k/machdep.h	Fri Sep  3 21:46:48 1999
+++ linux-2.3.16-int/include/asm-m68k/machdep.h	Sat Sep  4 21:57:28 1999
@@ -15,14 +15,12 @@
 extern void (*mach_kbd_leds) (unsigned int);
 /* machine dependent irq functions */
 extern void (*mach_init_IRQ) (void);
-extern void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *);
 extern int (*mach_request_irq) (unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
                                 unsigned long flags, const char *devname, void *dev_id);
 extern void (*mach_free_irq) (unsigned int irq, void *dev_id);
 extern void (*mach_get_model) (char *model);
 extern int (*mach_get_hardware_list) (char *buffer);
 extern int (*mach_get_irq_list) (char *buf);
-extern void (*mach_process_int) (int irq, struct pt_regs *fp);
 /* machine dependent timer functions */
 extern unsigned long (*mach_gettimeoffset)(void);
 extern void (*mach_gettod)(int *year, int *mon, int *day, int *hour,
diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16/include/asm-m68k/system.h linux-2.3.16-int/include/asm-m68k/system.h
--- linux-2.3.16/include/asm-m68k/system.h	Tue Aug 10 20:24:53 1999
+++ linux-2.3.16-int/include/asm-m68k/system.h	Sat Sep  4 21:57:28 1999
@@ -4,6 +4,8 @@
 #include <linux/config.h> /* get configuration macros */
 #include <linux/linkage.h>
 #include <asm/segment.h>
+#include <asm/hardirq.h>
+#include <asm/entry.h>
 
 #define prepare_to_switch()	do { } while(0)
 
@@ -44,35 +46,34 @@
   (last) = _last; \
 }
 
+#define __sti() ({							\
+	if (local_irq_count[smp_processor_id()] <= 1)			\
+		asm volatile ("andiw %0,%%sr":				\
+			      : "i" (ALLOWINT) : "memory");		\
+})
+#define __cli() asm volatile ("oriw  #0x0700,%%sr": : : "memory")
+
+#define __save_flags(x)							\
+	asm volatile ("movew %%sr,%0":"=d" (x) : :"memory")
+#define __restore_flags(x)						\
+	asm volatile ("movew %0,%%sr": :"d" (x) : "memory")
+
+#define cli()			__cli()
+#define sti()			__sti()
+#define save_flags(x)		__save_flags(x)
+#define restore_flags(x)	__restore_flags(x)
+#define save_and_cli(flags)	({ save_flags(flags); cli(); })
+
+#define nop()	__asm__ __volatile__ ("nop": :)
+#define mb()	__asm__ __volatile__ (""   : : :"memory")
+#define rmb()	__asm__ __volatile__ (""   : : :"memory")
+#define wmb()	__asm__ __volatile__ (""   : : :"memory")
+
 #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
 #define tas(ptr) (xchg((ptr),1))
 
 struct __xchg_dummy { unsigned long a[100]; };
 #define __xg(x) ((volatile struct __xchg_dummy *)(x))
-
-#if defined(MACH_ATARI_ONLY) && !defined(CONFIG_HADES)
-/* block out HSYNC on the atari */
-#define __sti() __asm__ __volatile__ ("andiw #0xfbff,%/sr": : : "memory")
-#else /* portable version */
-#define __sti() __asm__ __volatile__ ("andiw #0xf8ff,%/sr": : : "memory")
-#endif /* machine compilation types */ 
-#define __cli() __asm__ __volatile__ ("oriw  #0x0700,%/sr": : : "memory")
-#define nop() __asm__ __volatile__ ("nop"::)
-#define mb()  __asm__ __volatile__ (""   : : :"memory")
-#define rmb()  __asm__ __volatile__ (""   : : :"memory")
-#define wmb()  __asm__ __volatile__ (""   : : :"memory")
-
-#define __save_flags(x) \
-__asm__ __volatile__("movew %/sr,%0":"=d" (x) : /* no input */ :"memory")
-
-#define __restore_flags(x) \
-__asm__ __volatile__("movew %0,%/sr": /* no outputs */ :"d" (x) : "memory")
-
-#define cli() __cli()
-#define sti() __sti()
-#define save_flags(x) __save_flags(x)
-#define restore_flags(x) __restore_flags(x)
-#define save_and_cli(flags)   do { save_flags(flags); cli(); } while(0)
 
 #ifndef CONFIG_RMW_INSNS
 static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)

diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16-int/arch/m68k/kernel/entry.S linux-2.3.16-misc/arch/m68k/kernel/entry.S
--- linux-2.3.16-int/arch/m68k/kernel/entry.S	Sat Sep  4 23:53:17 1999
+++ linux-2.3.16-misc/arch/m68k/kernel/entry.S	Sat Sep  4 23:53:29 1999
@@ -44,7 +44,8 @@
 
 .globl SYMBOL_NAME(system_call), SYMBOL_NAME(buserr), SYMBOL_NAME(trap)
 .globl SYMBOL_NAME(resume), SYMBOL_NAME(ret_from_exception)
-.globl SYMBOL_NAME(ret_from_signal), SYMBOL_NAME(sys_call_table)
+.globl SYMBOL_NAME(ret_from_signal)
+.globl SYMBOL_NAME(inthandler), SYMBOL_NAME(sys_call_table)
 .globl SYMBOL_NAME(sys_fork), SYMBOL_NAME(sys_clone), SYMBOL_NAME(sys_vfork)
 
 .text
diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16-int/arch/m68k/kernel/head.S linux-2.3.16-misc/arch/m68k/kernel/head.S
--- linux-2.3.16-int/arch/m68k/kernel/head.S	Sat Sep  4 21:44:18 1999
+++ linux-2.3.16-misc/arch/m68k/kernel/head.S	Mon Sep  6 02:04:12 1999
@@ -259,7 +259,9 @@
 #include <linux/init.h>
 #include <asm/bootinfo.h>
 #include <asm/setup.h>
+#include <asm/entry.h>
 #include <asm/pgtable.h>
+#include <asm/page.h>
 #include "m68k_defs.h"
 
 #ifdef CONFIG_MAC
@@ -386,6 +388,12 @@
 #endif
 #endif
 
+/* The __INITDATA stuff is a no-op when ftrace or kgdb are turned on */
+#ifndef __INITDATA
+#define __INITDATA	.data
+#define __FINIT		.previous
+#endif
+
 /* Several macros to make the writing of subroutines easier:
  * - func_start marks the beginning of the routine which setups the frame
  *   register and saves the registers, it also defines another macro
@@ -503,18 +511,10 @@
 
 .macro	puts		string
 #if defined(CONSOLE) || defined(SERIAL_DEBUG)
-/* The __INITDATA stuff is a no-op when ftrace or kgdb are turned on */
-#if defined(CONFIG_FTRACE) || defined(CONFIG_KGDB)
-	bra 1f
-#endif
 	__INITDATA
 .Lstr\@:
 	.string	"\string"
 	__FINIT
-#if defined(CONFIG_FTRACE) || defined(CONFIG_KGDB)
-	.align 2
-1:
-#endif
 	pea	%pc@(.Lstr\@)
 	func_call	puts
 	addql	#4,%sp
@@ -843,6 +843,7 @@
 	lea	%pc@(L(phys_kernel_start)),%a0
 	lea	%pc@(SYMBOL_NAME(_stext)),%a1
 	subl	#SYMBOL_NAME(_stext),%a1
+	addl	#PAGE_OFFSET,%a1
 	movel	%a1,%a0@
 
 	putc	'B'
@@ -857,7 +858,7 @@
  *	First map the first 4 MB of kernel code & data
  */
 
-	mmu_map	#0,%pc@(L(phys_kernel_start)),#4*1024*1024,\
+	mmu_map	#PAGE_OFFSET,%pc@(L(phys_kernel_start)),#4*1024*1024,\
 		%pc@(SYMBOL_NAME(m68k_supervisor_cachemode))
 
 	putc	'C'
@@ -1161,6 +1162,7 @@
          * contains also kernel_pg_dir.
 	 */
 	movel	%pc@(L(phys_kernel_start)),%d0
+	subl	#PAGE_OFFSET,%d0
 	lea	%pc@(SYMBOL_NAME(_stext)),%a0
 	subl	%d0,%a0
 	mmu_fixup_page_mmu_cache	%a0
@@ -1352,8 +1354,8 @@
 /*
  * Setup initial stack pointer
  */
-	lea	SYMBOL_NAME(init_task_union),%a2
-	lea	0x2000(%a2),%sp
+	lea	SYMBOL_NAME(init_task_union),%curptr
+	lea	0x2000(%curptr),%sp
 
 /* jump to the kernel start */
 	putc	'\n'
@@ -2355,6 +2357,7 @@
 	.chip	68k
 
 L(mmu_engage_cleanup):
+	subl	#PAGE_OFFSET,%d2
 	subl	%d2,%a2
 	movel	%a2,L(kernel_pgdir_ptr)
 	subl	%d2,%fp
@@ -3032,7 +3035,7 @@
 #ifdef CONFIG_HP300
 func_start	set_leds,%d0/%a0
 	movel	ARG1,%d0
-	movel	%pc@(Lcustom),%a0
+	movel	%pc@(L(custom)),%a0
 	moveb	%d0,%a0@(0x1ffff)
 func_return	set_leds
 #endif
diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16-int/arch/m68k/kernel/ptrace.c linux-2.3.16-misc/arch/m68k/kernel/ptrace.c
--- linux-2.3.16-int/arch/m68k/kernel/ptrace.c	Sat Sep  4 21:44:18 1999
+++ linux-2.3.16-misc/arch/m68k/kernel/ptrace.c	Sun Sep  5 21:59:40 1999
@@ -87,210 +87,6 @@
 	return 0;
 }
 
-/*
- * This routine gets a long from any process space by following the page
- * tables. NOTE! You should check that the long isn't on a page boundary,
- * and that it is in the task area before calling this: this routine does
- * no checking.
- *
- */
-static unsigned long get_long(struct task_struct * tsk, 
-	struct vm_area_struct * vma, unsigned long addr)
-{
-	pgd_t * pgdir;
-	pmd_t * pgmiddle;
-	pte_t * pgtable;
-	unsigned long page;
-
-repeat:
-	pgdir = pgd_offset(vma->vm_mm, addr);
-	if (pgd_none(*pgdir)) {
-		handle_mm_fault(tsk, vma, addr, 0);
-		goto repeat;
-	}
-	if (pgd_bad(*pgdir)) {
-		printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
-		pgd_clear(pgdir);
-		return 0;
-	}
-	pgmiddle = pmd_offset(pgdir,addr);
-	if (pmd_none(*pgmiddle)) {
-		handle_mm_fault(tsk, vma, addr, 0);
-		goto repeat;
-	}
-	if (pmd_bad(*pgmiddle)) {
-		printk("ptrace: bad page directory %08lx\n",
-		       pmd_val(*pgmiddle));
-		pmd_clear(pgmiddle);
-		return 0;
-	}
-	pgtable = pte_offset(pgmiddle, addr);
-	if (!pte_present(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, 0);
-		goto repeat;
-	}
-	page = pte_page(*pgtable);
-/* this is a hack for non-kernel-mapped video buffers and similar */
-	if (MAP_NR(page) >= max_mapnr)
-		return 0;
-	page += addr & ~PAGE_MASK;
-	return *(unsigned long *) page;
-}
-
-/*
- * This routine puts a long into any process space by following the page
- * tables. NOTE! You should check that the long isn't on a page boundary,
- * and that it is in the task area before calling this: this routine does
- * no checking.
- *
- * Now keeps R/W state of page so that a text page stays readonly
- * even if a debugger scribbles breakpoints into it.  -M.U-
- */
-static void put_long(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long addr,
-	unsigned long data)
-{
-	pgd_t *pgdir;
-	pmd_t *pgmiddle;
-	pte_t *pgtable;
-	unsigned long page;
-		
-repeat:
-	pgdir = pgd_offset(vma->vm_mm, addr);
-	if (!pgd_present(*pgdir)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
-	}
-	if (pgd_bad(*pgdir)) {
-		printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
-		pgd_clear(pgdir);
-		return;
-	}
-	pgmiddle = pmd_offset(pgdir,addr);
-	if (pmd_none(*pgmiddle)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
-	}
-	if (pmd_bad(*pgmiddle)) {
-		printk("ptrace: bad page directory %08lx\n",
-		       pmd_val(*pgmiddle));
-		pmd_clear(pgmiddle);
-		return;
-	}
-	pgtable = pte_offset(pgmiddle, addr);
-	if (!pte_present(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
-	}
-	page = pte_page(*pgtable);
-	if (!pte_write(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
-	}
-/* this is a hack for non-kernel-mapped video buffers and similar */
-	if (MAP_NR(page) < max_mapnr) {
-		*(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
-		flush_page_to_ram (page);
-	}
-/* we're bypassing pagetables, so we have to set the dirty bit ourselves */
-/* this should also re-instate whatever read-only mode there was before */
-	*pgtable = pte_mkdirty(mk_pte(page, vma->vm_page_prot));
-	flush_tlb_all();
-}
-
-/*
- * This routine checks the page boundaries, and that the offset is
- * within the task area. It then calls get_long() to read a long.
- */
-static int read_long(struct task_struct * tsk, unsigned long addr,
-	unsigned long * result)
-{
-	struct vm_area_struct * vma = find_extend_vma(tsk, addr);
-
-	if (!vma)
-		return -EIO;
-	if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
-		unsigned long low,high;
-		struct vm_area_struct * vma_low = vma;
-
-		if (addr + sizeof(long) >= vma->vm_end) {
-			vma_low = vma->vm_next;
-			if (!vma_low || vma_low->vm_start != vma->vm_end)
-				return -EIO;
-		}
-		high = get_long(tsk, vma,addr & ~(sizeof(long)-1));
-		low = get_long(tsk, vma_low,(addr+sizeof(long)) & ~(sizeof(long)-1));
-		switch (addr & (sizeof(long)-1)) {
-			case 3:
-				low >>= 8;
-				low |= high << 24;
-				break;
-			case 2:
-				low >>= 16;
-				low |= high << 16;
-				break;
-			case 1:
-				low >>= 24;
-				low |= high << 8;
-				break;
-		}
-		*result = low;
-	} else
-		*result = get_long(tsk, vma,addr);
-	return 0;
-}
-
-/*
- * This routine checks the page boundaries, and that the offset is
- * within the task area. It then calls put_long() to write a long.
- */
-static int write_long(struct task_struct * tsk, unsigned long addr,
-	unsigned long data)
-{
-	struct vm_area_struct * vma = find_extend_vma(tsk, addr);
-
-	if (!vma)
-		return -EIO;
-	if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
-		unsigned long low,high;
-		struct vm_area_struct * vma_low = vma;
-
-		if (addr + sizeof(long) >= vma->vm_end) {
-			vma_low = vma->vm_next;
-			if (!vma_low || vma_low->vm_start != vma->vm_end)
-				return -EIO;
-		}
-		high = get_long(tsk, vma,addr & ~(sizeof(long)-1));
-		low = get_long(tsk, vma_low,(addr+sizeof(long)) & ~(sizeof(long)-1));
-		switch (addr & (sizeof(long)-1)) {
-			case 0: /* shouldn't happen, but safety first */
-				high = data;
-				break;
-			case 3:
-				low &= 0x000000ff;
-				low |= data << 8;
-				high &= ~0xff;
-				high |= data >> 24;
-				break;
-			case 2:
-				low &= 0x0000ffff;
-				low |= data << 16;
-				high &= ~0xffff;
-				high |= data >> 16;
-				break;
-			case 1:
-				low &= 0x00ffffff;
-				low |= data << 24;
-				high &= ~0xffffff;
-				high |= data >> 8;
-				break;
-		}
-		put_long(tsk, vma,addr & ~(sizeof(long)-1),high);
-		put_long(tsk, vma_low,(addr+sizeof(long)) & ~(sizeof(long)-1),low);
-	} else
-		put_long(tsk, vma,addr,data);
-	return 0;
-}
-
 asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
 {
 	struct task_struct *child;
@@ -361,12 +157,13 @@
 		case PTRACE_PEEKTEXT: /* read word at location addr. */ 
 		case PTRACE_PEEKDATA: {
 			unsigned long tmp;
+			int copied;
 
-			down(&child->mm->mmap_sem);
-			ret = read_long(child, addr, &tmp);
-			up(&child->mm->mmap_sem);
-			if (ret >= 0)
-				ret = put_user(tmp, (unsigned long *) data);
+			copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+			ret = -EIO;
+			if (copied != sizeof(tmp))
+				goto out;
+			ret = put_user(tmp,(unsigned long *) data);
 			goto out;
 		}
 
@@ -404,9 +201,10 @@
       /* when I and D space are separate, this will have to be fixed. */
 		case PTRACE_POKETEXT: /* write the word at location addr. */
 		case PTRACE_POKEDATA:
-			down(&child->mm->mmap_sem);
-			ret = write_long(child,addr,data);
-			up(&child->mm->mmap_sem);
+			ret = 0;
+			if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
+				goto out;
+			ret = -EIO;
 			goto out;
 
 		case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16-int/arch/m68k/kernel/setup.c linux-2.3.16-misc/arch/m68k/kernel/setup.c
--- linux-2.3.16-int/arch/m68k/kernel/setup.c	Sat Sep  4 22:02:13 1999
+++ linux-2.3.16-misc/arch/m68k/kernel/setup.c	Mon Sep  6 01:58:24 1999
@@ -50,6 +50,7 @@
 
 int m68k_num_memory = 0;
 int m68k_realnum_memory = 0;
+unsigned long m68k_memoffset;
 struct mem_info m68k_memory[NUM_MEMINFO];
 
 static struct mem_info m68k_ramdisk = { 0, 0 };
@@ -195,6 +196,7 @@
 	       (m68k_num_memory - 1));
 	m68k_num_memory = 1;
     }
+    m68k_memoffset = m68k_memory[0].addr-PAGE_OFFSET;
 #endif
 }
 
@@ -213,9 +215,7 @@
 	else if (CPU_IS_060)
 		m68k_is040or060 = 6;
 
-#ifndef CONFIG_SUN3
 	base_trap_init();
-#endif
 
 	/* FIXME: m68k_fputype is passed in by Penguin booter, which can
 	 * be confused by software FPU emulation. BEWARE.
@@ -340,7 +340,7 @@
 
 #ifndef CONFIG_SUN3
 	*memory_start_p = availmem;
-	*memory_end_p = 0;
+	*memory_end_p = PAGE_OFFSET;
 	for (i = 0; i < m68k_num_memory; i++)
 		*memory_end_p += m68k_memory[i].size & MASK_256K;
 #endif
diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16-int/arch/m68k/kernel/signal.c linux-2.3.16-misc/arch/m68k/kernel/signal.c
--- linux-2.3.16-int/arch/m68k/kernel/signal.c	Sat Sep  4 21:44:18 1999
+++ linux-2.3.16-misc/arch/m68k/kernel/signal.c	Sun Sep  5 22:20:00 1999
@@ -1074,7 +1074,8 @@
 				continue;
 
 			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH:
+			case SIGCONT: case SIGCHLD:
+			case SIGWINCH: case SIGURG:
 				continue;
 
 			case SIGTSTP: case SIGTTIN: case SIGTTOU:
@@ -1093,6 +1094,7 @@
 
 			case SIGQUIT: case SIGILL: case SIGTRAP:
 			case SIGIOT: case SIGFPE: case SIGSEGV:
+			case SIGBUS: case SIGXCPU: case SIGXFSZ:
 				if (do_coredump(signr, regs))
 					exit_code |= 0x80;
 				/* FALLTHRU */
diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16-int/arch/m68k/kernel/traps.c linux-2.3.16-misc/arch/m68k/kernel/traps.c
--- linux-2.3.16-int/arch/m68k/kernel/traps.c	Sat Sep  4 22:04:54 1999
+++ linux-2.3.16-misc/arch/m68k/kernel/traps.c	Sat Sep  4 21:58:10 1999
@@ -67,16 +67,14 @@
 void __init base_trap_init(void)
 {
 #ifdef CONFIG_SUN3
-	/* Keep the keyboard interrupt working with PROM for debugging. --m */
 	e_vector *old_vbr;
-	__asm__ volatile ("movec %%vbr,%1\n\t"
-			  "movec %0,%%vbr"
-			  : "=&r" (old_vbr) : "r" ((void*)vectors));
-	vectors[0x1E] = old_vbr[0x1E];	/* Copy int6 vector. */
-#else
+
+	/* Keep the keyboard interrupt working with PROM for debugging. --m */
+	__asm__ volatile ("movec %%vbr,%1" : "=r" (old_vbr));
+	vectors[VEC_INT6] = old_vbr[VEC_INT6];
+#endif
 	/* setup the exception vector table */
 	__asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)vectors));
-#endif
 
 	if (CPU_IS_040 && !FPU_IS_EMU) {
 		/* set up FPSP entry points */
@@ -144,11 +142,6 @@
 #ifdef CONFIG_M68KFPU_EMU
 	if (FPU_IS_EMU)
 		vectors[VEC_LINE11] = fpu_emu;
-#endif
-
-#ifdef CONFIG_SUN3
-	/* Moved from setup_arch() */
-	base_trap_init();
 #endif
 }
 
diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16-int/include/asm-m68k/movs.h linux-2.3.16-misc/include/asm-m68k/movs.h
--- linux-2.3.16-int/include/asm-m68k/movs.h	Sat Sep  4 22:08:13 1999
+++ linux-2.3.16-misc/include/asm-m68k/movs.h	Sat Sep  4 21:58:30 1999
@@ -10,46 +10,46 @@
 /* Set DFC register value */
 
 #define SET_DFC(x) \
-        __asm__ __volatile__ (" movec %0,%/dfc" : : "d" (x));
+        __asm__ __volatile__ ("movec %0,%%dfc" : : "r" (x))
 
 /* Get DFC register value */
 
 #define GET_DFC(x) \
-        __asm__ __volatile__ (" movec %/dfc, %0" : "=d" (x) : );
+        __asm__ __volatile__ ("movec %%dfc,%0" : "=r" (x))
 
 /* Set SFC register value */
 
 #define SET_SFC(x) \
-        __asm__ __volatile__ (" movec %0,%/sfc" : : "d" (x));
+        __asm__ __volatile__ ("movec %0,%%sfc" : : "r" (x))
 
 /* Get SFC register value */
 
 #define GET_SFC(x) \
-        __asm__ __volatile__ (" movec %/sfc, %0" : "=d" (x) : );
+        __asm__ __volatile__ ("movec %%sfc,%0" : "=r" (x))
 
 #define SET_VBR(x) \
-        __asm__ __volatile__ (" movec %0,%/vbr" : : "r" (x));
+        __asm__ __volatile__ ("movec %0,%%vbr" : : "r" (x))
 
 #define GET_VBR(x) \
-        __asm__ __volatile__ (" movec %/vbr, %0" : "=g" (x) : );
+        __asm__ __volatile__ ("movec %%vbr,%0" : "=r" (x))
 
-/* Set a byte using the "movs" instruction */
+/* Set a byte using the "moves" instruction */
 
 #define SET_CONTROL_BYTE(addr,value) \
-        __asm__ __volatile__ (" movsb %0, %1@" : : "d" (value), "a" (addr));
+        __asm__ __volatile__ ("movesb %1,%0" : "=m" (addr) : "d" (value))
 
-/* Get a byte using the "movs" instruction */
+/* Get a byte using the "moves" instruction */
 
 #define GET_CONTROL_BYTE(addr,value) \
-        __asm__ __volatile__ (" movsb %1@, %0" : "=d" (value) : "a" (addr));
+        __asm__ __volatile__ ("movesb %1,%0" : "=d" (value) : "m" (addr))
 
-/* Set a (long)word using the "movs" instruction */
+/* Set a (long)word using the "moves" instruction */
 
 #define SET_CONTROL_WORD(addr,value) \
-        __asm__ __volatile__ (" movsl %0, %1@" : : "d" (value), "a" (addr));
+        __asm__ __volatile__ ("movesl %1,%0" : "=m" (addr) : "r" (value))
 
-/* Get a (long)word using the "movs" instruction */
+/* Get a (long)word using the "moves" instruction */
 
 #define GET_CONTROL_WORD(addr,value) \
-        __asm__ __volatile__ (" movsl %1@, %0" : "=d" (value) : "a" (addr));
+        __asm__ __volatile__ ("movesl %1,%0" : "=d" (value) : "m" (addr))
 #endif
diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16-int/include/asm-m68k/page.h linux-2.3.16-misc/include/asm-m68k/page.h
--- linux-2.3.16-int/include/asm-m68k/page.h	Sat Sep  4 21:44:43 1999
+++ linux-2.3.16-misc/include/asm-m68k/page.h	Mon Sep  6 01:54:07 1999
@@ -122,31 +122,26 @@
 /* to align the pointer to the (next) page boundary */
 #define PAGE_ALIGN(addr)	(((addr)+PAGE_SIZE-1)&PAGE_MASK)
 
-/* This handles the memory map.. */
+#endif /* !__ASSEMBLY__ */
+
+#include <asm/page_offset.h>
+
+#define PAGE_OFFSET		(PAGE_OFFSET_RAW)
+
+#ifndef __ASSEMBLY__
+
 #ifndef CONFIG_SUN3
-#define PAGE_OFFSET		0
+
+#ifdef CONFIG_SINGLE_MEMORY_CHUNK
+extern unsigned long m68k_memoffset;
+
+#define __pa(vaddr)		((unsigned long)(vaddr)+m68k_memoffset)
+#define __va(paddr)		((void *)((unsigned long)(paddr)-m68k_memoffset))
 #else
-#define PAGE_OFFSET		0x0E000000
+#define __pa(vaddr)		virt_to_phys((void *)vaddr)
+#define __va(paddr)		phys_to_virt((unsigned long)paddr)
 #endif
 
-#ifndef CONFIG_SUN3
-#define __pa(x)			((unsigned long)(x)-PAGE_OFFSET)
-/*
- * A hacky workaround for the problems with mmap() of frame buffer
- * memory in the lower 16MB physical memoryspace.
- *
- * This is a short term solution, we will have to deal properly
- * with this in 2.3.x.
- */
-extern inline void *__va(unsigned long physaddr)
-{
-#ifdef CONFIG_AMIGA
-	if (MACH_IS_AMIGA && (physaddr < 16*1024*1024))
-		return (void *)0xffffffff;
-	else
-#endif
-		return (void *)(physaddr+PAGE_OFFSET);
-}
 #else	/* !CONFIG_SUN3 */
 /* This #define is a horrible hack to suppress lots of warnings. --m */
 #define __pa(x) ___pa((unsigned long)x)
@@ -172,9 +167,7 @@
 }
 #endif	/* CONFIG_SUN3 */
 
-#define MAP_NR(addr)		(__pa(addr) >> PAGE_SHIFT)
-
-#endif /* !__ASSEMBLY__ */
+#define MAP_NR(addr)		(((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT)
 
 #ifndef CONFIG_SUN3
 #define BUG() do { \
@@ -191,6 +184,8 @@
 #define PAGE_BUG(page) do { \
 	BUG(); \
 } while (0)
+
+#endif /* __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
 
diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16-int/include/asm-m68k/page_offset.h linux-2.3.16-misc/include/asm-m68k/page_offset.h
--- linux-2.3.16-int/include/asm-m68k/page_offset.h	Thu Jan  1 01:00:00 1970
+++ linux-2.3.16-misc/include/asm-m68k/page_offset.h	Mon Sep  6 01:58:24 1999
@@ -0,0 +1,9 @@
+#include <linux/config.h>
+
+/* This handles the memory map.. */
+#ifndef CONFIG_SUN3
+#define PAGE_OFFSET_RAW		0x00000000
+#else
+#define PAGE_OFFSET_RAW		0x0E000000 
+#endif
+
diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16-int/include/asm-m68k/pgtable.h linux-2.3.16-misc/include/asm-m68k/pgtable.h
--- linux-2.3.16-int/include/asm-m68k/pgtable.h	Sat Sep  4 21:44:43 1999
+++ linux-2.3.16-misc/include/asm-m68k/pgtable.h	Mon Sep  6 01:58:24 1999
@@ -122,7 +122,7 @@
 			      "cpushp %%dc,(%0)\n\t"
 			      "cinvp %%ic,(%0)\n\t"
 			      ".chip 68k"
-			      : : "a" (virt_to_phys((void *)address)));
+			      : : "a" (__pa((void *)address)));
     }
     else {
 	unsigned long _tmp;
@@ -412,7 +412,7 @@
  * and a page entry and page directory to the page they refer to.
  */
 #define mk_pte(page, pgprot) \
-({ pte_t __pte; pte_val(__pte) = virt_to_phys((void *)page) + pgprot_val(pgprot); __pte; })
+({ pte_t __pte; pte_val(__pte) = __pa((void *)page) + pgprot_val(pgprot); __pte; })
 #define mk_pte_phys(physpage, pgprot) \
 ({ pte_t __pte; pte_val(__pte) = (unsigned long)physpage + pgprot_val(pgprot); __pte; })
 
@@ -423,23 +423,23 @@
 {
 	int i;
 	unsigned long ptbl;
-	ptbl = virt_to_phys(ptep) | _PAGE_TABLE | _PAGE_ACCESSED;
+	ptbl = __pa(ptep) | _PAGE_TABLE | _PAGE_ACCESSED;
 	for (i = 0; i < 16; i++, ptbl += (sizeof(pte_t)*PTRS_PER_PTE/16))
 		pmdp->pmd[i] = ptbl;
 }
 
 extern inline void pgd_set(pgd_t * pgdp, pmd_t * pmdp)
-{ pgd_val(*pgdp) = _PAGE_TABLE | _PAGE_ACCESSED | virt_to_phys(pmdp); }
+{ pgd_val(*pgdp) = _PAGE_TABLE | _PAGE_ACCESSED | __pa(pmdp); }
 
 extern inline unsigned long pte_page(pte_t pte)
-{ return (unsigned long)phys_to_virt(pte_val(pte) & PAGE_MASK); }
+{ return (unsigned long)__va(pte_val(pte) & PAGE_MASK); }
 
 extern inline unsigned long pmd_page2(pmd_t *pmd)
-{ return (unsigned long)phys_to_virt(pmd_val(*pmd) & _TABLE_MASK); }
+{ return (unsigned long)__va(pmd_val(*pmd) & _TABLE_MASK); }
 #define pmd_page(pmd) pmd_page2(&(pmd))
 
 extern inline unsigned long pgd_page(pgd_t pgd)
-{ return (unsigned long)phys_to_virt(pgd_val(pgd) & _TABLE_MASK); }
+{ return (unsigned long)__va(pgd_val(pgd) & _TABLE_MASK); }
 
 extern inline int pte_none(pte_t pte)		{ return !pte_val(pte); }
 extern inline int pte_present(pte_t pte)	{ return pte_val(pte) & (_PAGE_PRESENT | _PAGE_FAKE_SUPER); }
diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16-int/include/asm-m68k/virtconvert.h linux-2.3.16-misc/include/asm-m68k/virtconvert.h
--- linux-2.3.16-int/include/asm-m68k/virtconvert.h	Sat Sep  4 21:44:43 1999
+++ linux-2.3.16-misc/include/asm-m68k/virtconvert.h	Mon Sep  6 02:01:10 1999
@@ -9,6 +9,7 @@
 
 #include <linux/config.h>
 #include <asm/setup.h>
+#include <asm/page.h>
 
 #ifdef CONFIG_AMIGA
 #include <asm/amigahw.h>
@@ -34,22 +35,22 @@
 #endif 
 
 #ifdef CONFIG_SINGLE_MEMORY_CHUNK
-extern inline unsigned long virt_to_phys(volatile void * address)
+extern inline unsigned long virt_to_phys(volatile void *vaddr)
 {
-	unsigned long voff = (unsigned long) address;
+	unsigned long voff = (unsigned long)vaddr - PAGE_OFFSET;
 
 	if (voff < m68k_memory[0].size)
-		return m68k_memory[0].addr + voff;
-	else
-		return mm_vtop_fallback(voff);
+		return voff + m68k_memory[0].addr;
+	return mm_vtop_fallback((unsigned long)vaddr);
 }
 
 extern inline void * phys_to_virt(unsigned long paddr)
 {
-	unsigned long base = m68k_memory[0].addr;
+	unsigned long poff = paddr - m68k_memory[0].addr;
+
+	if (poff < m68k_memory[0].size)
+		return (void *)(poff + PAGE_OFFSET);
 
-	if ((paddr >=  base) && (paddr < (base + m68k_memory[0].size)))
-		return (void *)(paddr - base);
 #ifdef CONFIG_AMIGA
 	/*
 	 * if on an amiga and address is in first 16M, move it 

diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16-misc/arch/m68k/fpsp040/skeleton.S linux-2.3.16-sysstack/arch/m68k/fpsp040/skeleton.S
--- linux-2.3.16-misc/arch/m68k/fpsp040/skeleton.S	Sat Sep  4 21:58:10 1999
+++ linux-2.3.16-sysstack/arch/m68k/fpsp040/skeleton.S	Sat Sep  4 23:49:03 1999
@@ -70,9 +70,9 @@
 	frestore	(%sp)+
 	unlk		%a6
 
-	SAVE_ALL_INT
-	GET_CURRENT(%d0)
-	movel	%sp,%sp@- 		| stack frame pointer argument
+	save_all_int
+	get_current
+	pea	%sp@			| stack frame pointer argument
 	bsrl	SYMBOL_NAME(trap_c)
 	addql	#4,%sp
 	bral	SYMBOL_NAME(ret_from_exception)
@@ -161,9 +161,9 @@
 	frestore	(%sp)+
 	unlk		%a6
 
-	SAVE_ALL_INT
-	GET_CURRENT(%d0)
-	movel	%sp,%sp@- 		| stack frame pointer argument
+	save_all_int
+	get_current
+	pea	%sp@ 			| stack frame pointer argument
 	bsrl	SYMBOL_NAME(trap_c)
 	addql	#4,%sp
 	bral	SYMBOL_NAME(ret_from_exception)
@@ -187,9 +187,9 @@
 	frestore	(%sp)+
 	unlk		%a6
 
-	SAVE_ALL_INT
-	GET_CURRENT(%d0)
-	movel	%sp,%sp@- 		| stack frame pointer argument
+	save_all_int
+	get_current
+	pea	%sp@	 		| stack frame pointer argument
 	bsrl	SYMBOL_NAME(trap_c)
 	addql	#4,%sp
 	bral	SYMBOL_NAME(ret_from_exception)
@@ -213,9 +213,9 @@
 	frestore	(%sp)+
 	unlk		%a6
 
-	SAVE_ALL_INT
-	GET_CURRENT(%d0)
-	movel	%sp,%sp@- 		| stack frame pointer argument
+	save_all_int
+	get_current
+	pea	%sp@	 		| stack frame pointer argument
 	bsrl	SYMBOL_NAME(trap_c)
 	addql	#4,%sp
 	bral	SYMBOL_NAME(ret_from_exception)
@@ -235,9 +235,9 @@
 	frestore	(%sp)+
 	unlk		%a6
 
-	SAVE_ALL_INT
-	GET_CURRENT(%d0)
-	movel	%sp,%sp@- 		| stack frame pointer argument
+	save_all_int
+	get_current
+	pea	%sp@	 		| stack frame pointer argument
 	bsrl	SYMBOL_NAME(trap_c)
 	addql	#4,%sp
 	bral	SYMBOL_NAME(ret_from_exception)
@@ -257,9 +257,9 @@
 	frestore	(%sp)+
 	unlk		%a6
 
-	SAVE_ALL_INT
-	GET_CURRENT(%d0)
-	movel	%sp,%sp@- 		| stack frame pointer argument
+	save_all_int
+	get_current
+	pea	%sp@	 		| stack frame pointer argument
 	bsrl	SYMBOL_NAME(trap_c)
 	addql	#4,%sp
 	bral	SYMBOL_NAME(ret_from_exception)
@@ -285,9 +285,9 @@
 	frestore	(%sp)+
 	unlk		%a6
 
-	SAVE_ALL_INT
-	GET_CURRENT(%d0)
-	movel	%sp,%sp@- 		| stack frame pointer argument
+	save_all_int
+	get_current
+	pea	%sp@	 		| stack frame pointer argument
 	bsrl	SYMBOL_NAME(trap_c)
 	addql	#4,%sp
 	bral	SYMBOL_NAME(ret_from_exception)
@@ -306,9 +306,9 @@
 	jmp	fpsp_fline
 real_fline:
 
-	SAVE_ALL_INT
-	GET_CURRENT(%d0)
-	movel	%sp,%sp@- 		| stack frame pointer argument
+	save_all_int
+	get_current
+	pea	%sp@	 		| stack frame pointer argument
 	bsrl	SYMBOL_NAME(trap_c)
 	addql	#4,%sp
 	bral	SYMBOL_NAME(ret_from_exception)
@@ -328,9 +328,9 @@
 	frestore	(%sp)+
 	unlk		%a6
 
-	SAVE_ALL_INT
-	GET_CURRENT(%d0)
-	movel	%sp,%sp@- 		| stack frame pointer argument
+	save_all_int
+	get_current
+	pea	%sp@	 		| stack frame pointer argument
 	bsrl	SYMBOL_NAME(trap_c)
 	addql	#4,%sp
 	bral	SYMBOL_NAME(ret_from_exception)
@@ -379,12 +379,12 @@
 	beq	.Lnotkern
 	rte
 .Lnotkern:
-	SAVE_ALL_INT
-	GET_CURRENT(%d0)
+	save_all_int
+	get_current
 	tstl	%curptr@(TASK_NEEDRESCHED)
 	jne	SYMBOL_NAME(ret_from_exception)	| deliver signals,
 						| reschedule etc..
-	RESTORE_ALL
+	restore_all
 
 |
 |	mem_write --- write to user or supervisor address space
diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16-misc/arch/m68k/ifpsp060/iskeleton.S linux-2.3.16-sysstack/arch/m68k/ifpsp060/iskeleton.S
--- linux-2.3.16-misc/arch/m68k/ifpsp060/iskeleton.S	Sat Sep  4 21:58:10 1999
+++ linux-2.3.16-sysstack/arch/m68k/ifpsp060/iskeleton.S	Sat Sep  4 23:49:53 1999
@@ -73,12 +73,12 @@
 	beq	.Lnotkern
 	rte
 .Lnotkern:
-	SAVE_ALL_INT
-	GET_CURRENT(%d0)
+	save_all_int
+	get_current
 	tstl	%curptr@(TASK_NEEDRESCHED)
 	jne	SYMBOL_NAME(ret_from_exception)	| deliver signals,
 						| reschedule etc..
-	RESTORE_ALL
+	restore_all
 
 |
 | _060_real_chk():
diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16-misc/arch/m68k/kernel/entry.S linux-2.3.16-sysstack/arch/m68k/kernel/entry.S
--- linux-2.3.16-misc/arch/m68k/kernel/entry.S	Sat Sep  4 23:53:29 1999
+++ linux-2.3.16-sysstack/arch/m68k/kernel/entry.S	Mon Sep  6 01:54:17 1999
@@ -33,7 +33,6 @@
 #include <linux/sys.h>
 #include <linux/config.h>
 #include <linux/linkage.h>
-#include <asm/entry.h>
 #include <asm/errno.h>
 #include <asm/setup.h>
 #include <asm/segment.h>
@@ -42,24 +41,24 @@
 
 #include "m68k_defs.h"
 
-.globl SYMBOL_NAME(system_call), SYMBOL_NAME(buserr), SYMBOL_NAME(trap)
-.globl SYMBOL_NAME(resume), SYMBOL_NAME(ret_from_exception)
+#include <asm/entry.h>
+
+.globl SYMBOL_NAME(ret_from_exception)
 .globl SYMBOL_NAME(ret_from_signal)
-.globl SYMBOL_NAME(inthandler), SYMBOL_NAME(sys_call_table)
-.globl SYMBOL_NAME(sys_fork), SYMBOL_NAME(sys_clone), SYMBOL_NAME(sys_vfork)
+.globl SYMBOL_NAME(sys_call_table)
 
 .text
 ENTRY(buserr)
-	SAVE_ALL_INT
-	GET_CURRENT(%d0)
+	save_all_int
+	get_current
 	movel	%sp,%sp@- 		| stack frame pointer argument
 	bsrl	SYMBOL_NAME(buserr_c)
 	addql	#4,%sp
 	jra	SYMBOL_NAME(ret_from_exception)
 
 ENTRY(trap)
-	SAVE_ALL_INT
-	GET_CURRENT(%d0)
+	save_all_int
+	get_current
 	movel	%sp,%sp@- 		| stack frame pointer argument
 	bsrl	SYMBOL_NAME(trap_c)
 	addql	#4,%sp
@@ -67,7 +66,7 @@
 
 ENTRY(reschedule)
 	| save top of frame
-	movel	%sp,%curptr@(TASK_THREAD+THREAD_ESP0)
+|	movel	%sp,%curptr@(TASK_THREAD+THREAD_ESP0)
 
 	pea	SYMBOL_NAME(ret_from_exception)
 	jmp	SYMBOL_NAME(schedule)
@@ -83,42 +82,76 @@
 	jra	SYMBOL_NAME(ret_from_exception)
 
 badsys:
-	movel	#-ENOSYS,PT_D0(%sp)
+	drop_sys_stack
+	movel	#-ENOSYS,%sp@(PT_D0)
 	jra	SYMBOL_NAME(ret_from_exception)
 
 do_trace:
-	movel	#-ENOSYS,PT_D0(%sp)	| needed for strace
+	drop_sys_stack
+	movel	#-ENOSYS,%sp@(PT_D0)	| needed for strace
 	subql	#4,%sp
-	SAVE_SWITCH_STACK
+	save_switch_stack
+	| save top of frame
+	movel	%sp,%curptr@(TASK_THREAD+THREAD_ESP0)
 	jbsr	SYMBOL_NAME(syscall_trace)
-	RESTORE_SWITCH_STACK
+	restore_switch_stack
 	addql	#4,%sp
-	jbsr	@(SYMBOL_NAME(sys_call_table),%d2:l:4)@(0)
+	rebuild_sys_stack
+	movel	%sp@(SC_SIZEOF+PT_SYSCALL),%d1
+	movel	#-ENOSYS,%d0
+	cmpl	#NR_syscalls,%d1
+	jcc	1f
+	jbsr	@(SYMBOL_NAME(sys_call_table),%d1:l:4)@(0)
+1:	drop_sys_stack
 	movel	%d0,%sp@(PT_D0)		| save the return value
 	subql	#4,%sp			| dummy return address
-	SAVE_SWITCH_STACK
+	save_switch_stack
 	jbsr	SYMBOL_NAME(syscall_trace)
 
 SYMBOL_NAME_LABEL(ret_from_signal)
-	RESTORE_SWITCH_STACK
+	restore_switch_stack
 	addql	#4,%sp
 	jra	SYMBOL_NAME(ret_from_exception)
 
 ENTRY(system_call)
-	SAVE_ALL_SYS
-	movel	%d0,%d2
-
-	GET_CURRENT(%d0)
-	| save top of frame
-	movel	%sp,%curptr@(TASK_THREAD+THREAD_ESP0)
+	save_all_sys
+	save_sys_stack
+	get_current %d1
+
+#if 0
+	.data
+1:	.string	"sc: %d"
+	.previous
+	cmpl	#142,%d0
+	jeq	2f
+	cmpl	#114,%d0
+	jeq	2f
+	movel	%d0,%sp@-
+	pea	1b
+	jsr	SYMBOL_NAME(printk)
+	addql	#4,%sp
+	movel	%sp@+,%d0
+2:
+#endif
 
-	cmpl	#NR_syscalls,%d2
-	jcc	badsys
 	btst	#PF_TRACESYS_BIT,%curptr@(TASK_FLAGS+PF_TRACESYS_OFF)
 	jne	do_trace
-	jbsr	@(SYMBOL_NAME(sys_call_table),%d2:l:4)@(0)
+	cmpl	#NR_syscalls,%d0
+	jcc	badsys
+	jsr	@(SYMBOL_NAME(sys_call_table),%d0:l:4)@(0)
+	drop_sys_stack
 	movel	%d0,%sp@(PT_D0)		| save the return value
 
+#if 0
+	.data
+1:	.string	" ->%d\n"
+	.previous
+	movel	%sp@(PT_D0),%sp@-
+	pea	1b
+	jsr	SYMBOL_NAME(printk)
+	addql	#8,%sp
+#endif
+
 SYMBOL_NAME_LABEL(ret_from_exception)
 	btst	#5,%sp@(PT_SR)		| check if returning to kernel
 	bnes	2f			| if so, skip resched, signals
@@ -136,19 +169,19 @@
 	jne	SYMBOL_NAME(reschedule)
 
 	tstl	%curptr@(TASK_SIGPENDING)
-	jne	Lsignal_return
-2:	RESTORE_ALL
+	jne	signal_return
+2:	restore_all
 
-Lsignal_return:
+signal_return:
 	subql	#4,%sp			| dummy return address
-	SAVE_SWITCH_STACK
-	pea	%sp@(SWITCH_STACK_SIZE)
+	save_switch_stack
+	pea	%sp@
 	clrl	%sp@-
 	bsrl	SYMBOL_NAME(do_signal)
 	addql	#8,%sp
-	RESTORE_SWITCH_STACK
+	restore_switch_stack
 	addql	#4,%sp
-	RESTORE_ALL
+	restore_all
 
 do_delayed_trace:
 	bclr	#7,%sp@(PT_SR)		| clear trace bit in SR
@@ -171,8 +204,8 @@
 | -> %a0 contains first int node, %d0 exception vector
 .macro	int_entry intnodes, firstvec, firststatvec=VEC_SPUR
 	addql	#1,SYMBOL_NAME(local_irq_count)
-	SAVE_ALL_INT
-	GET_CURRENT(%d0)
+	save_all_int
+	get_current
 
 | extract exception vector, do some statistic and get (first) int node
 	bfextu	%sp@(PT_VECTOR){#4,#12},%d0
@@ -339,58 +372,50 @@
 	rte
 
 ENTRY(sys_fork)
-	SAVE_SWITCH_STACK	
-	pea	%sp@(SWITCH_STACK_SIZE)
+	changeto_switch_stack
 	jbsr	SYMBOL_NAME(m68k_fork)
-	addql	#4,%sp
-	RESTORE_SWITCH_STACK
+	changeto_sys_stack
 	rts
 
 ENTRY(sys_clone)
-	SAVE_SWITCH_STACK
-	pea	%sp@(SWITCH_STACK_SIZE)
+	changeto_switch_stack
 	jbsr	SYMBOL_NAME(m68k_clone)
-	addql	#4,%sp
-	RESTORE_SWITCH_STACK
+	changeto_sys_stack
 	rts
 
 ENTRY(sys_vfork)
-	SAVE_SWITCH_STACK	
-	pea	%sp@(SWITCH_STACK_SIZE)
+	changeto_switch_stack
 	jbsr	SYMBOL_NAME(m68k_vfork)
-	addql	#4,%sp
-	RESTORE_SWITCH_STACK
+	changeto_sys_stack
 	rts
 
 ENTRY(sys_sigsuspend)
-	SAVE_SWITCH_STACK
-	pea	%sp@(SWITCH_STACK_SIZE)
+	changeto_switch_stack
 	jbsr	SYMBOL_NAME(do_sigsuspend)
-	addql	#4,%sp
-	RESTORE_SWITCH_STACK
+	changeto_sys_stack
 	rts
 
 ENTRY(sys_rt_sigsuspend)
-	SAVE_SWITCH_STACK
-	pea	%sp@(SWITCH_STACK_SIZE)
+	changeto_switch_stack
+	pea	%sp@(SW_SIZEOF)
 	jbsr	SYMBOL_NAME(do_rt_sigsuspend)
 	addql	#4,%sp
-	RESTORE_SWITCH_STACK
+	changeto_sys_stack
 	rts
 
 ENTRY(sys_sigreturn)
-	SAVE_SWITCH_STACK
+	changeto_switch_stack
 	jbsr	SYMBOL_NAME(do_sigreturn)
-	RESTORE_SWITCH_STACK
+	changeto_sys_stack nodrop=1
 	rts
 
 ENTRY(sys_rt_sigreturn)
-	SAVE_SWITCH_STACK
+	changeto_switch_stack
 	jbsr	SYMBOL_NAME(do_rt_sigreturn)
-	RESTORE_SWITCH_STACK
+	changeto_sys_stack nodrop=1
 	rts
 
-SYMBOL_NAME_LABEL(resume)
+ENTRY(resume)
 	/*
 	 * Beware - when entering resume, prev (the current task) is
 	 * in a0, next (the new task) is in a1,so don't change these
@@ -410,7 +435,7 @@
 	movel	%d0,%a0@(TASK_THREAD+THREAD_USP)
 
 	/* save non-scratch registers on stack */
-	SAVE_SWITCH_STACK
+	save_switch_stack
 
 	/* save current kernel stack pointer */
 	movel	%sp,%a0@(TASK_THREAD+THREAD_KSP)
@@ -481,7 +506,7 @@
 	movel	%a1@(TASK_THREAD+THREAD_KSP),%sp
 
 	/* restore non-scratch registers */
-	RESTORE_SWITCH_STACK
+	restore_switch_stack
 
 	/* restore user stack pointer */
 	movel	%a1@(TASK_THREAD+THREAD_USP),%a0
diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16-misc/arch/m68k/kernel/m68k_defs.c linux-2.3.16-sysstack/arch/m68k/kernel/m68k_defs.c
--- linux-2.3.16-misc/arch/m68k/kernel/m68k_defs.c	Sat Sep  4 21:58:10 1999
+++ linux-2.3.16-sysstack/arch/m68k/kernel/m68k_defs.c	Sun Sep  5 00:10:47 1999
@@ -43,19 +43,19 @@
 
 	/* offsets into the pt_regs */
 	DEFINE(PT_D0, offsetof(struct pt_regs, d0));
-	DEFINE(PT_ORIG_D0, offsetof(struct pt_regs, orig_d0));
 	DEFINE(PT_D1, offsetof(struct pt_regs, d1));
-	DEFINE(PT_D2, offsetof(struct pt_regs, d2));
-	DEFINE(PT_D3, offsetof(struct pt_regs, d3));
-	DEFINE(PT_D4, offsetof(struct pt_regs, d4));
-	DEFINE(PT_D5, offsetof(struct pt_regs, d5));
 	DEFINE(PT_A0, offsetof(struct pt_regs, a0));
 	DEFINE(PT_A1, offsetof(struct pt_regs, a1));
 	DEFINE(PT_A2, offsetof(struct pt_regs, a2));
+	DEFINE(PT_SYSCALL, offsetof(struct pt_regs, syscall));
 	DEFINE(PT_PC, offsetof(struct pt_regs, pc));
 	DEFINE(PT_SR, offsetof(struct pt_regs, sr));
 	/* bitfields are a bit difficult */
 	DEFINE(PT_VECTOR, offsetof(struct pt_regs, pc) + 4);
+
+	/* size of switchstack and syscall stack */
+	DEFINE(SW_SIZEOF, sizeof(struct switch_stack));
+	DEFINE(SC_SIZEOF, sizeof(struct syscall_stack));
 
 	/* offsets into the irq_handler struct */
 	DEFINE(IRQ_HANDLER, offsetof(struct irq_node, handler));
diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16-misc/arch/m68k/kernel/process.c linux-2.3.16-sysstack/arch/m68k/kernel/process.c
--- linux-2.3.16-misc/arch/m68k/kernel/process.c	Sat Sep  4 21:58:10 1999
+++ linux-2.3.16-sysstack/arch/m68k/kernel/process.c	Sun Sep  5 21:46:31 1999
@@ -116,14 +116,12 @@
 	printk("\n");
 	printk("Format %02x  Vector: %04x  PC: %08lx  Status: %04x\n",
 	       regs->format, regs->vector, regs->pc, regs->sr);
-	printk("ORIG_D0: %08lx  D0: %08lx  A2: %08lx  A1: %08lx\n",
-	       regs->orig_d0, regs->d0, regs->a2, regs->a1);
-	printk("A0: %08lx  D5: %08lx  D4: %08lx\n",
-	       regs->a0, regs->d5, regs->d4);
-	printk("D3: %08lx  D2: %08lx  D1: %08lx\n",
-	       regs->d3, regs->d2, regs->d1);
+	printk("A0: %08lx  A1: %08lx  A2: %08lx  SYS: %08lx\n",
+	       regs->a0, regs->a1, regs->a2, regs->syscall);
+	printk("D0: %08lx  D1: %08lx", regs->d0, regs->d1);
 	if (!(regs->sr & PS_S))
-		printk("USP: %08lx\n", rdusp());
+		printk("  USP: %08lx", rdusp());
+	printk("\n");
 }
 
 /*
@@ -183,48 +181,48 @@
  * also copy_thread)
  */
 
-asmlinkage int m68k_fork(struct pt_regs *regs)
+asmlinkage int m68k_fork(unsigned long __unused)
 {
-	return do_fork(SIGCHLD, rdusp(), regs);
+	struct full_stack *fs = (struct full_stack *)&__unused;
+
+	return do_fork(SIGCHLD, rdusp(), &fs->pt_regs);
 }
 
-asmlinkage int m68k_vfork(struct pt_regs *regs)
+asmlinkage int m68k_vfork(unsigned long __unused)
 {
-	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs);
+	struct full_stack *fs = (struct full_stack *)&__unused;
+
+	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), &fs->pt_regs);
 }
 
-asmlinkage int m68k_clone(struct pt_regs *regs)
+asmlinkage int m68k_clone(unsigned long __unused)
 {
+	struct full_stack *fs = (struct full_stack *)&__unused;
 	unsigned long clone_flags;
 	unsigned long newsp;
 
 	/* syscall2 puts clone_flags in d1 and usp in d2 */
-	clone_flags = regs->d1;
-	newsp = regs->d2;
+	clone_flags = fs->pt_regs.d1;
+	newsp = fs->sw_regs.d2;
 	if (!newsp)
 		newsp = rdusp();
-	return do_fork(clone_flags, newsp, regs);
+	return do_fork(clone_flags, newsp, &fs->pt_regs);
 }
 
 int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
 		 struct task_struct * p, struct pt_regs * regs)
 {
-	struct pt_regs * childregs;
-	struct switch_stack * childstack, *stack;
-	unsigned long stack_offset, *retp;
-
-	stack_offset = KTHREAD_SIZE - sizeof(struct pt_regs);
-	childregs = (struct pt_regs *) ((unsigned long) p + stack_offset);
+	struct full_stack *childstack, *stack;
+	unsigned long stack_offset;
 
-	*childregs = *regs;
-	childregs->d0 = 0;
+	stack = (struct full_stack *)(regs + 1) - 1;
 
-	retp = ((unsigned long *) regs);
-	stack = ((struct switch_stack *) retp) - 1;
+	stack_offset = KTHREAD_SIZE - sizeof(struct full_stack);
+	childstack = (struct full_stack *)((unsigned long)p + stack_offset);
 
-	childstack = ((struct switch_stack *) childregs) - 1;
 	*childstack = *stack;
-	childstack->retpc = (unsigned long)ret_from_fork;
+	childstack->pt_regs.d0 = 0;
+	childstack->sw_regs.retpc = (unsigned long)ret_from_fork;
 
 	p->thread.usp = usp;
 	p->thread.ksp = (unsigned long)childstack;
@@ -307,10 +305,10 @@
 	dump->u_ar0 = (struct user_regs_struct *)((int)&dump->regs - (int)dump);
 	sw = ((struct switch_stack *)regs) - 1;
 	dump->regs.d1 = regs->d1;
-	dump->regs.d2 = regs->d2;
-	dump->regs.d3 = regs->d3;
-	dump->regs.d4 = regs->d4;
-	dump->regs.d5 = regs->d5;
+	dump->regs.d2 = sw->d2;
+	dump->regs.d3 = sw->d3;
+	dump->regs.d4 = sw->d4;
+	dump->regs.d5 = sw->d5;
 	dump->regs.d6 = sw->d6;
 	dump->regs.d7 = sw->d7;
 	dump->regs.a0 = regs->a0;
@@ -321,7 +319,7 @@
 	dump->regs.a5 = sw->a5;
 	dump->regs.a6 = sw->a6;
 	dump->regs.d0 = regs->d0;
-	dump->regs.orig_d0 = regs->orig_d0;
+	dump->regs.orig_d0 = regs->syscall;
 	dump->regs.stkadj = regs->stkadj;
 	dump->regs.sr = regs->sr;
 	dump->regs.pc = regs->pc;
@@ -337,7 +335,7 @@
 {
 	int error;
 	char * filename;
-	struct pt_regs *regs = (struct pt_regs *) &name;
+	struct pt_regs *regs = (struct pt_regs *)((struct syscall_stack *)&name + 1);
 
 	lock_kernel();
 	filename = getname(name);
diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16-misc/arch/m68k/kernel/ptrace.c linux-2.3.16-sysstack/arch/m68k/kernel/ptrace.c
--- linux-2.3.16-misc/arch/m68k/kernel/ptrace.c	Sun Sep  5 21:59:40 1999
+++ linux-2.3.16-sysstack/arch/m68k/kernel/ptrace.c	Sun Sep  5 20:36:17 1999
@@ -39,18 +39,17 @@
 #define TRACE_BITS 0x8000
 
 /* Find the stack offset for a register, relative to thread.esp0. */
-#define PT_REG(reg)	((long)&((struct pt_regs *)0)->reg)
-#define SW_REG(reg)	((long)&((struct switch_stack *)0)->reg \
-			 - sizeof(struct switch_stack))
+#define PT_REG(reg)	((long)&((struct full_stack *)0)->pt_regs.reg)
+#define SW_REG(reg)	((long)&((struct full_stack *)0)->sw_regs.reg)
 /* Mapping from PT_xxx to the stack offset at which the register is
    saved.  Notice that usp has no stack-slot and needs to be treated
    specially (see get_reg/put_reg below). */
 static int regoff[] = {
-	PT_REG(d1), PT_REG(d2), PT_REG(d3), PT_REG(d4),
-	PT_REG(d5), SW_REG(d6), SW_REG(d7), PT_REG(a0),
+	PT_REG(d1), SW_REG(d2), SW_REG(d3), SW_REG(d4),
+	SW_REG(d5), SW_REG(d6), SW_REG(d7), PT_REG(a0),
 	PT_REG(a1), PT_REG(a2), SW_REG(a3), SW_REG(a4),
 	SW_REG(a5), SW_REG(a6), PT_REG(d0), -1,
-	PT_REG(orig_d0), PT_REG(sr), PT_REG(pc),
+	PT_REG(syscall), PT_REG(sr), PT_REG(pc),
 };
 
 /*
diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16-misc/arch/m68k/kernel/signal.c linux-2.3.16-sysstack/arch/m68k/kernel/signal.c
--- linux-2.3.16-misc/arch/m68k/kernel/signal.c	Sun Sep  5 22:20:00 1999
+++ linux-2.3.16-sysstack/arch/m68k/kernel/signal.c	Sun Sep  5 22:19:26 1999
@@ -48,7 +48,7 @@
 
 asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr,
 			 int options, unsigned long *ru);
-asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs);
+asmlinkage int do_signal(sigset_t *oldset, struct full_stack *fs);
 
 const int frame_extra_sizes[16] = {
   0,
@@ -72,9 +72,10 @@
 /*
  * Atomically swap in the new signal mask, and wait for a signal.
  */
-asmlinkage int do_sigsuspend(struct pt_regs *regs)
+asmlinkage int do_sigsuspend(unsigned long __unused)
 {
-	old_sigset_t mask = regs->d3;
+	struct full_stack *fs = (struct full_stack *)&__unused;
+	old_sigset_t mask = fs->sw_regs.d3;
 	sigset_t saveset;
 
 	mask &= _BLOCKABLE;
@@ -82,20 +83,21 @@
 	siginitset(&current->blocked, mask);
 	recalc_sigpending(current);
 
-	regs->d0 = -EINTR;
+	fs->pt_regs.d0 = -EINTR;
 	while (1) {
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
-		if (do_signal(&saveset, regs))
+		if (do_signal(&saveset, fs))
 			return -EINTR;
 	}
 }
 
 asmlinkage int
-do_rt_sigsuspend(struct pt_regs *regs)
+do_rt_sigsuspend(unsigned long __unused)
 {
-	sigset_t *unewset = (sigset_t *)regs->d1;
-	size_t sigsetsize = (size_t)regs->d2;
+	struct full_stack *fs = (struct full_stack *)&__unused;
+	sigset_t *unewset = (sigset_t *)fs->pt_regs.d1;
+	size_t sigsetsize = (size_t)fs->sw_regs.d2;
 	sigset_t saveset, newset;
 
 	/* XXX: Don't preclude handling different sized sigset_t's.  */
@@ -110,11 +112,11 @@
 	current->blocked = newset;
 	recalc_sigpending(current);
 
-	regs->d0 = -EINTR;
+	fs->pt_regs.d0 = -EINTR;
 	while (1) {
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
-		if (do_signal(&saveset, regs))
+		if (do_signal(&saveset, fs))
 			return -EINTR;
 	}
 }
@@ -317,7 +319,7 @@
 }
 
 static inline int
-restore_sigcontext(struct pt_regs *regs, struct sigcontext *usc, void *fp,
+restore_sigcontext(struct full_stack *fs, struct sigcontext *usc, void *fp,
 		   int *pd0)
 {
 	int fsize, formatvec;
@@ -329,20 +331,20 @@
 		goto badframe;
 	
 	/* restore passed registers */
-	regs->d1 = context.sc_d1;
-	regs->a0 = context.sc_a0;
-	regs->a1 = context.sc_a1;
-	regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff);
-	regs->pc = context.sc_pc;
-	regs->orig_d0 = -1;		/* disable syscall checks */
+	fs->pt_regs.d1 = context.sc_d1;
+	fs->pt_regs.a0 = context.sc_a0;
+	fs->pt_regs.a1 = context.sc_a1;
+	fs->pt_regs.sr = (fs->pt_regs.sr & 0xff00) | (context.sc_sr & 0xff);
+	fs->pt_regs.pc = context.sc_pc;
+	fs->pt_regs.syscall = -1;		/* disable syscall checks */
 	wrusp(context.sc_usp);
 	formatvec = context.sc_formatvec;
-	regs->format = formatvec >> 12;
-	regs->vector = formatvec & 0xfff;
+	fs->pt_regs.format = formatvec >> 12;
+	fs->pt_regs.vector = formatvec & 0xfff;
 
 	err = restore_fpu_state(&context);
 
-	fsize = frame_extra_sizes[regs->format];
+	fsize = frame_extra_sizes[fs->pt_regs.format];
 	if (fsize < 0) {
 		/*
 		 * user process trying to return with weird frame format
@@ -358,9 +360,7 @@
 	 */
 
 	if (fsize) {
-		struct switch_stack *sw = (struct switch_stack *)regs - 1;
-		regs->d0 = context.sc_d0;
-#define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack))
+		fs->pt_regs.d0 = context.sc_d0;
 		__asm__ __volatile__
 			("   movel %0,%/a0\n\t"
 			 "   subl %1,%/a0\n\t"     /* make room on stack */
@@ -382,10 +382,9 @@
 			 "   .long 3b,4b\n"
 			 ".previous"
 			 : /* no outputs, it doesn't ever return */
-			 : "a" (sw), "d" (fsize), "d" (frame_offset/4-1),
-			   "n" (frame_offset), "a" (fp)
+			 : "a" (fs), "d" (fsize), "d" (sizeof(*fs)/4-1),
+			   "n" (sizeof(*fs)), "a" (fp)
 			 : "a0");
-#undef frame_offset
 		/*
 		 * If we ever get here an exception occurred while
 		 * building the above stack-frame.
@@ -401,8 +400,7 @@
 }
 
 static inline int
-rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw,
-		    struct ucontext *uc, int *pd0)
+rt_restore_ucontext(struct full_stack *fs, struct ucontext *uc, int *pd0)
 {
 	int fsize, temp;
 	greg_t *gregs = uc->uc_mcontext.gregs;
@@ -413,37 +411,37 @@
 	if (temp != MCONTEXT_VERSION)
 		goto badframe;
 	/* restore passed registers */
-	err |= __get_user(regs->d0, &gregs[0]);
-	err |= __get_user(regs->d1, &gregs[1]);
-	err |= __get_user(regs->d2, &gregs[2]);
-	err |= __get_user(regs->d3, &gregs[3]);
-	err |= __get_user(regs->d4, &gregs[4]);
-	err |= __get_user(regs->d5, &gregs[5]);
-	err |= __get_user(sw->d6, &gregs[6]);
-	err |= __get_user(sw->d7, &gregs[7]);
-	err |= __get_user(regs->a0, &gregs[8]);
-	err |= __get_user(regs->a1, &gregs[9]);
-	err |= __get_user(regs->a2, &gregs[10]);
-	err |= __get_user(sw->a3, &gregs[11]);
-	err |= __get_user(sw->a4, &gregs[12]);
-	err |= __get_user(sw->a5, &gregs[13]);
-	err |= __get_user(sw->a6, &gregs[14]);
+	err |= __get_user(fs->pt_regs.d0, &gregs[0]);
+	err |= __get_user(fs->pt_regs.d1, &gregs[1]);
+	err |= __get_user(fs->sw_regs.d2, &gregs[2]);
+	err |= __get_user(fs->sw_regs.d3, &gregs[3]);
+	err |= __get_user(fs->sw_regs.d4, &gregs[4]);
+	err |= __get_user(fs->sw_regs.d5, &gregs[5]);
+	err |= __get_user(fs->sw_regs.d6, &gregs[6]);
+	err |= __get_user(fs->sw_regs.d7, &gregs[7]);
+	err |= __get_user(fs->pt_regs.a0, &gregs[8]);
+	err |= __get_user(fs->pt_regs.a1, &gregs[9]);
+	err |= __get_user(fs->pt_regs.a2, &gregs[10]);
+	err |= __get_user(fs->sw_regs.a3, &gregs[11]);
+	err |= __get_user(fs->sw_regs.a4, &gregs[12]);
+	err |= __get_user(fs->sw_regs.a5, &gregs[13]);
+	err |= __get_user(fs->sw_regs.a6, &gregs[14]);
 	err |= __get_user(usp, &gregs[15]);
 	wrusp(usp);
-	err |= __get_user(regs->pc, &gregs[16]);
+	err |= __get_user(fs->pt_regs.pc, &gregs[16]);
 	err |= __get_user(temp, &gregs[17]);
-	regs->sr = (regs->sr & 0xff00) | (temp & 0xff);
-	regs->orig_d0 = -1;		/* disable syscall checks */
+	fs->pt_regs.sr = (fs->pt_regs.sr & 0xff00) | (temp & 0xff);
+	fs->pt_regs.syscall = -1;		/* disable syscall checks */
 	err |= __get_user(temp, &uc->uc_formatvec);
-	regs->format = temp >> 12;
-	regs->vector = temp & 0xfff;
+	fs->pt_regs.format = temp >> 12;
+	fs->pt_regs.vector = temp & 0xfff;
 
 	err |= rt_restore_fpu_state(uc);
 
 	if (do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT)
 		goto badframe;
 
-	fsize = frame_extra_sizes[regs->format];
+	fsize = frame_extra_sizes[fs->pt_regs.format];
 	if (fsize < 0) {
 		/*
 		 * user process trying to return with weird frame format
@@ -459,7 +457,6 @@
 	 */
 
 	if (fsize) {
-#define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack))
 		__asm__ __volatile__
 			("   movel %0,%/a0\n\t"
 			 "   subl %1,%/a0\n\t"     /* make room on stack */
@@ -481,10 +478,9 @@
 			 "   .long 3b,4b\n"
 			 ".previous"
 			 : /* no outputs, it doesn't ever return */
-			 : "a" (sw), "d" (fsize), "d" (frame_offset/4-1),
-			   "n" (frame_offset), "a" (&uc->uc_extra)
+			 : "a" (fs), "d" (fsize), "d" (sizeof(*fs)/4-1),
+			   "n" (sizeof(*fs)), "a" (&uc->uc_extra)
 			 : "a0");
-#undef frame_offset
 		/*
 		 * If we ever get here an exception occurred while
 		 * building the above stack-frame.
@@ -492,7 +488,7 @@
 		goto badframe;
 	}
 
-	*pd0 = regs->d0;
+	*pd0 = fs->pt_regs.d0;
 	return err;
 
 badframe:
@@ -501,8 +497,7 @@
 
 asmlinkage int do_sigreturn(unsigned long __unused)
 {
-	struct switch_stack *sw = (struct switch_stack *) &__unused;
-	struct pt_regs *regs = (struct pt_regs *) (sw + 1);
+	struct full_stack *fs = (struct full_stack *)&__unused;
 	unsigned long usp = rdusp();
 	struct sigframe *frame = (struct sigframe *)(usp - 4);
 	sigset_t set;
@@ -520,7 +515,7 @@
 	current->blocked = set;
 	recalc_sigpending(current);
 	
-	if (restore_sigcontext(regs, &frame->sc, frame + 1, &d0))
+	if (restore_sigcontext(fs, &frame->sc, frame + 1, &d0))
 		goto badframe;
 	return d0;
 
@@ -531,8 +526,7 @@
 
 asmlinkage int do_rt_sigreturn(unsigned long __unused)
 {
-	struct switch_stack *sw = (struct switch_stack *) &__unused;
-	struct pt_regs *regs = (struct pt_regs *) (sw + 1);
+	struct full_stack *fs = (struct full_stack *)&__unused;
 	unsigned long usp = rdusp();
 	struct rt_sigframe *frame = (struct rt_sigframe *)(usp - 4);
 	sigset_t set;
@@ -547,7 +541,7 @@
 	current->blocked = set;
 	recalc_sigpending(current);
 	
-	if (rt_restore_ucontext(regs, sw, &frame->uc, &d0))
+	if (rt_restore_ucontext(fs, &frame->uc, &d0))
 		goto badframe;
 	return d0;
 
@@ -560,7 +554,7 @@
  * Set up a signal frame.
  */
 
-static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs)
+static inline void save_fpu_state(struct sigcontext *sc, struct full_stack *fs)
 {
 	if (FPU_IS_EMU) {
 		/* save registers */
@@ -577,8 +571,8 @@
 	if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) {
 		fpu_version = sc->sc_fpstate[0];
 		if (CPU_IS_020_OR_030 &&
-		    regs->vector >= (VEC_FPBRUC * 4) &&
-		    regs->vector <= (VEC_FPNAN * 4)) {
+		    fs->pt_regs.vector >= (VEC_FPBRUC * 4) &&
+		    fs->pt_regs.vector <= (VEC_FPNAN * 4)) {
 			/* Clear pending exception in 68882 idle frame */
 			if (*(unsigned short *) sc->sc_fpstate == 0x1f38)
 				sc->sc_fpstate[0x38] |= 1 << 3;
@@ -594,7 +588,7 @@
 	}
 }
 
-static inline int rt_save_fpu_state(struct ucontext *uc, struct pt_regs *regs)
+static inline int rt_save_fpu_state(struct ucontext *uc, struct full_stack *fs)
 {
 	unsigned char fpstate[FPCONTEXT_SIZE];
 	int context_size = CPU_IS_060 ? 8 : 0;
@@ -622,8 +616,8 @@
 			context_size = fpstate[1];
 		fpu_version = fpstate[0];
 		if (CPU_IS_020_OR_030 &&
-		    regs->vector >= (VEC_FPBRUC * 4) &&
-		    regs->vector <= (VEC_FPNAN * 4)) {
+		    fs->pt_regs.vector >= (VEC_FPBRUC * 4) &&
+		    fs->pt_regs.vector <= (VEC_FPNAN * 4)) {
 			/* Clear pending exception in 68882 idle frame */
 			if (*(unsigned short *) fpstate == 0x1f38)
 				fpstate[0x38] |= 1 << 3;
@@ -645,48 +639,47 @@
 	return err;
 }
 
-static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
+static void setup_sigcontext(struct sigcontext *sc, struct full_stack *fs,
 			     unsigned long mask)
 {
 	sc->sc_mask = mask;
 	sc->sc_usp = rdusp();
-	sc->sc_d0 = regs->d0;
-	sc->sc_d1 = regs->d1;
-	sc->sc_a0 = regs->a0;
-	sc->sc_a1 = regs->a1;
-	sc->sc_sr = regs->sr;
-	sc->sc_pc = regs->pc;
-	sc->sc_formatvec = regs->format << 12 | regs->vector;
-	save_fpu_state(sc, regs);
+	sc->sc_d0 = fs->pt_regs.d0;
+	sc->sc_d1 = fs->pt_regs.d1;
+	sc->sc_a0 = fs->pt_regs.a0;
+	sc->sc_a1 = fs->pt_regs.a1;
+	sc->sc_sr = fs->pt_regs.sr;
+	sc->sc_pc = fs->pt_regs.pc;
+	sc->sc_formatvec = fs->pt_regs.format << 12 | fs->pt_regs.vector;
+	save_fpu_state(sc, fs);
 }
 
-static inline int rt_setup_ucontext(struct ucontext *uc, struct pt_regs *regs)
+static inline int rt_setup_ucontext(struct ucontext *uc, struct full_stack *fs)
 {
-	struct switch_stack *sw = (struct switch_stack *)regs - 1;
 	greg_t *gregs = uc->uc_mcontext.gregs;
 	int err = 0;
 
 	err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version);
-	err |= __put_user(regs->d0, &gregs[0]);
-	err |= __put_user(regs->d1, &gregs[1]);
-	err |= __put_user(regs->d2, &gregs[2]);
-	err |= __put_user(regs->d3, &gregs[3]);
-	err |= __put_user(regs->d4, &gregs[4]);
-	err |= __put_user(regs->d5, &gregs[5]);
-	err |= __put_user(sw->d6, &gregs[6]);
-	err |= __put_user(sw->d7, &gregs[7]);
-	err |= __put_user(regs->a0, &gregs[8]);
-	err |= __put_user(regs->a1, &gregs[9]);
-	err |= __put_user(regs->a2, &gregs[10]);
-	err |= __put_user(sw->a3, &gregs[11]);
-	err |= __put_user(sw->a4, &gregs[12]);
-	err |= __put_user(sw->a5, &gregs[13]);
-	err |= __put_user(sw->a6, &gregs[14]);
+	err |= __put_user(fs->pt_regs.d0, &gregs[0]);
+	err |= __put_user(fs->pt_regs.d1, &gregs[1]);
+	err |= __put_user(fs->sw_regs.d2, &gregs[2]);
+	err |= __put_user(fs->sw_regs.d3, &gregs[3]);
+	err |= __put_user(fs->sw_regs.d4, &gregs[4]);
+	err |= __put_user(fs->sw_regs.d5, &gregs[5]);
+	err |= __put_user(fs->sw_regs.d6, &gregs[6]);
+	err |= __put_user(fs->sw_regs.d7, &gregs[7]);
+	err |= __put_user(fs->pt_regs.a0, &gregs[8]);
+	err |= __put_user(fs->pt_regs.a1, &gregs[9]);
+	err |= __put_user(fs->pt_regs.a2, &gregs[10]);
+	err |= __put_user(fs->sw_regs.a3, &gregs[11]);
+	err |= __put_user(fs->sw_regs.a4, &gregs[12]);
+	err |= __put_user(fs->sw_regs.a5, &gregs[13]);
+	err |= __put_user(fs->sw_regs.a6, &gregs[14]);
 	err |= __put_user(rdusp(), &gregs[15]);
-	err |= __put_user(regs->pc, &gregs[16]);
-	err |= __put_user(regs->sr, &gregs[17]);
-	err |= __put_user((regs->format << 12) | regs->vector, &uc->uc_formatvec);
-	err |= rt_save_fpu_state(uc, regs);
+	err |= __put_user(fs->pt_regs.pc, &gregs[16]);
+	err |= __put_user(fs->pt_regs.sr, &gregs[17]);
+	err |= __put_user((fs->pt_regs.format << 12) | fs->pt_regs.vector, &uc->uc_formatvec);
+	err |= rt_save_fpu_state(uc, fs);
 	return err;
 }
 
@@ -752,7 +745,7 @@
 }
 
 static inline void *
-get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
+get_sigframe(struct k_sigaction *ka, size_t frame_size)
 {
 	unsigned long usp;
 
@@ -768,10 +761,10 @@
 }
 
 static void setup_frame (int sig, struct k_sigaction *ka,
-			 sigset_t *set, struct pt_regs *regs)
+			 sigset_t *set, struct full_stack *fs)
 {
 	struct sigframe *frame;
-	int fsize = frame_extra_sizes[regs->format];
+	int fsize = frame_extra_sizes[fs->pt_regs.format];
 	struct sigcontext context;
 	int err = 0;
 
@@ -783,11 +776,11 @@
 		goto give_sigsegv;
 	}
 
-	frame = get_sigframe(ka, regs, sizeof(*frame) + fsize);
+	frame = get_sigframe(ka, sizeof(*frame) + fsize);
 
 	if (fsize) {
-		err |= copy_to_user (frame + 1, regs + 1, fsize);
-		regs->stkadj = fsize;
+		err |= copy_to_user (frame + 1, fs + 1, fsize);
+		fs->pt_regs.stkadj = fsize;
 	}
 
 	err |= __put_user((current->exec_domain
@@ -797,14 +790,14 @@
 			   : sig),
 			  &frame->sig);
 
-	err |= __put_user(regs->vector, &frame->code);
+	err |= __put_user(fs->pt_regs.vector, &frame->code);
 	err |= __put_user(&frame->sc, &frame->psc);
 
 	if (_NSIG_WORDS > 1)
 		err |= copy_to_user(frame->extramask, &set->sig[1],
 				    sizeof(frame->extramask));
 
-	setup_sigcontext(&context, regs, set->sig[0]);
+	setup_sigcontext(&context, fs, set->sig[0]);
 	err |= copy_to_user (&frame->sc, &context, sizeof(context));
 
 	/* Set up to return from userspace.  */
@@ -820,13 +813,13 @@
 
 	/* Set up registers for signal handler */
 	wrusp ((unsigned long) frame);
-	regs->pc = (unsigned long) ka->sa.sa_handler;
+	fs->pt_regs.pc = (unsigned long) ka->sa.sa_handler;
 
 adjust_stack:
 	/* Prepare to skip over the extra stuff in the exception frame.  */
-	if (regs->stkadj) {
+	if (fs->pt_regs.stkadj) {
 		struct pt_regs *tregs =
-			(struct pt_regs *)((ulong)regs + regs->stkadj);
+			(struct pt_regs *)((ulong)&fs->pt_regs + fs->pt_regs.stkadj);
 #if DEBUG
 		printk("Performing stackadjust=%04x\n", regs->stkadj);
 #endif
@@ -834,8 +827,8 @@
                    handle overlaps.  */
 		tregs->vector = 0;
 		tregs->format = 0;
-		tregs->pc = regs->pc;
-		tregs->sr = regs->sr;
+		tregs->pc = fs->pt_regs.pc;
+		tregs->sr = fs->pt_regs.sr;
 	}
 	return;
 
@@ -847,10 +840,10 @@
 }
 
 static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
-			    sigset_t *set, struct pt_regs *regs)
+			    sigset_t *set, struct full_stack *fs)
 {
 	struct rt_sigframe *frame;
-	int fsize = frame_extra_sizes[regs->format];
+	int fsize = frame_extra_sizes[fs->pt_regs.format];
 	int err = 0;
 
 	if (fsize < 0) {
@@ -861,11 +854,11 @@
 		goto give_sigsegv;
 	}
 
-	frame = get_sigframe(ka, regs, sizeof(*frame));
+	frame = get_sigframe(ka, sizeof(*frame));
 
 	if (fsize) {
-		err |= copy_to_user (&frame->uc.uc_extra, regs + 1, fsize);
-		regs->stkadj = fsize;
+		err |= copy_to_user (&frame->uc.uc_extra, fs + 1, fsize);
+		fs->pt_regs.stkadj = fsize;
 	}
 
 	err |= __put_user((current->exec_domain
@@ -886,7 +879,7 @@
 	err |= __put_user(sas_ss_flags(rdusp()),
 			  &frame->uc.uc_stack.ss_flags);
 	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
-	err |= rt_setup_ucontext(&frame->uc, regs);
+	err |= rt_setup_ucontext(&frame->uc, fs);
 	err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set));
 
 	/* Set up to return from userspace.  */
@@ -903,13 +896,13 @@
 
 	/* Set up registers for signal handler */
 	wrusp ((unsigned long) frame);
-	regs->pc = (unsigned long) ka->sa.sa_handler;
+	fs->pt_regs.pc = (unsigned long) ka->sa.sa_handler;
 
 adjust_stack:
 	/* Prepare to skip over the extra stuff in the exception frame.  */
-	if (regs->stkadj) {
+	if (fs->pt_regs.stkadj) {
 		struct pt_regs *tregs =
-			(struct pt_regs *)((ulong)regs + regs->stkadj);
+			(struct pt_regs *)((ulong)&fs->pt_regs + fs->pt_regs.stkadj);
 #if DEBUG
 		printk("Performing stackadjust=%04x\n", regs->stkadj);
 #endif
@@ -917,8 +910,8 @@
                    handle overlaps.  */
 		tregs->vector = 0;
 		tregs->format = 0;
-		tregs->pc = regs->pc;
-		tregs->sr = regs->sr;
+		tregs->pc = fs->pt_regs.pc;
+		tregs->sr = fs->pt_regs.sr;
 	}
 	return;
 
@@ -930,25 +923,25 @@
 }
 
 static inline void
-handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
+handle_restart(struct full_stack *fs, struct k_sigaction *ka, int has_handler)
 {
-	switch (regs->d0) {
+	switch (fs->pt_regs.d0) {
 	case -ERESTARTNOHAND:
 		if (!has_handler)
 			goto do_restart;
-		regs->d0 = -EINTR;
+		fs->pt_regs.d0 = -EINTR;
 		break;
 
 	case -ERESTARTSYS:
 		if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) {
-			regs->d0 = -EINTR;
+			fs->pt_regs.d0 = -EINTR;
 			break;
 		}
 	/* fallthrough */
 	case -ERESTARTNOINTR:
 	do_restart:
-		regs->d0 = regs->orig_d0;
-		regs->pc -= 2;
+		fs->pt_regs.d0 = fs->pt_regs.syscall;
+		fs->pt_regs.pc -= 2;
 		break;
 	}
 }
@@ -958,18 +951,18 @@
  */
 static void
 handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
-	      sigset_t *oldset, struct pt_regs *regs)
+	      sigset_t *oldset, struct full_stack *fs)
 {
 	/* are we from a system call? */
-	if (regs->orig_d0 >= 0)
+	if (fs->pt_regs.syscall >= 0)
 		/* If so, check system call restarting.. */
-		handle_restart(regs, ka, 1);
+		handle_restart(fs, ka, 1);
 
 	/* set up the stack frame */
 	if (ka->sa.sa_flags & SA_SIGINFO)
-		setup_rt_frame(sig, ka, info, oldset, regs);
+		setup_rt_frame(sig, ka, info, oldset, fs);
 	else
-		setup_frame(sig, ka, oldset, regs);
+		setup_frame(sig, ka, oldset, fs);
 
 	if (ka->sa.sa_flags & SA_ONESHOT)
 		ka->sa.sa_handler = SIG_DFL;
@@ -989,12 +982,12 @@
  * that the kernel can handle, and then we build all the user-level signal
  * handling stack-frames in one go after that.
  */
-asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
+asmlinkage int do_signal(sigset_t *oldset, struct full_stack *fs)
 {
 	siginfo_t info;
 	struct k_sigaction *ka;
 
-	current->thread.esp0 = (unsigned long) regs;
+	current->thread.esp0 = (unsigned long)fs;
 
 	if (!oldset)
 		oldset = &current->blocked;
@@ -1010,10 +1003,10 @@
 		if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
 			current->exit_code = signr;
 			current->state = TASK_STOPPED;
-			regs->sr &= ~PS_T;
+			fs->pt_regs.sr &= ~PS_T;
 
 			/* Did we come from a system call? */
-			if (regs->orig_d0 >= 0) {
+			if (fs->pt_regs.syscall >= 0) {
 				/* Restart the system call the same way as
 				   if the process were not traced.  */
 				struct k_sigaction *ka =
@@ -1021,7 +1014,7 @@
 				int has_handler =
 					(ka->sa.sa_handler != SIG_IGN &&
 					 ka->sa.sa_handler != SIG_DFL);
-				handle_restart(regs, ka, has_handler);
+				handle_restart(fs, ka, has_handler);
 			}
 			notify_parent(current, SIGCHLD);
 			schedule();
@@ -1031,8 +1024,8 @@
 			discard_frame:
 			    /* Make sure that a faulted bus cycle isn't
 			       restarted (only needed on the 680[23]0).  */
-			    if (regs->format == 10 || regs->format == 11)
-				regs->stkadj = frame_extra_sizes[regs->format];
+			    if (fs->pt_regs.format == 10 || fs->pt_regs.format == 11)
+				fs->pt_regs.stkadj = frame_extra_sizes[fs->pt_regs.format];
 			    continue;
 			}
 			current->exit_code = 0;
@@ -1095,7 +1088,7 @@
 			case SIGQUIT: case SIGILL: case SIGTRAP:
 			case SIGIOT: case SIGFPE: case SIGSEGV:
 			case SIGBUS: case SIGXCPU: case SIGXFSZ:
-				if (do_coredump(signr, regs))
+				if (do_coredump(signr, &fs->pt_regs))
 					exit_code |= 0x80;
 				/* FALLTHRU */
 
@@ -1109,27 +1102,27 @@
 		}
 
 		/* Whee!  Actually deliver the signal.  */
-		handle_signal(signr, ka, &info, oldset, regs);
+		handle_signal(signr, ka, &info, oldset, fs);
 		return 1;
 	}
 
 	/* Did we come from a system call? */
-	if (regs->orig_d0 >= 0)
+	if (fs->pt_regs.syscall >= 0)
 		/* Restart the system call - no handlers present */
-		handle_restart(regs, NULL, 0);
+		handle_restart(fs, NULL, 0);
 
 	/* If we are about to discard some frame stuff we must copy
 	   over the remaining frame. */
-	if (regs->stkadj) {
+	if (fs->pt_regs.stkadj) {
 		struct pt_regs *tregs =
-		  (struct pt_regs *) ((ulong) regs + regs->stkadj);
+		  (struct pt_regs *)((ulong)&fs->pt_regs + fs->pt_regs.stkadj);
 
 		/* This must be copied with decreasing addresses to
 		   handle overlaps.  */
 		tregs->vector = 0;
 		tregs->format = 0;
-		tregs->pc = regs->pc;
-		tregs->sr = regs->sr;
+		tregs->pc = fs->pt_regs.pc;
+		tregs->sr = fs->pt_regs.sr;
 	}
 	return 0;
 }
diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16-misc/arch/m68k/kernel/traps.c linux-2.3.16-sysstack/arch/m68k/kernel/traps.c
--- linux-2.3.16-misc/arch/m68k/kernel/traps.c	Sat Sep  4 21:58:10 1999
+++ linux-2.3.16-sysstack/arch/m68k/kernel/traps.c	Sun Sep  5 20:35:05 1999
@@ -715,9 +715,11 @@
 
 asmlinkage void buserr_c(struct frame *fp)
 {
+#if 0
 	/* Only set esp0 if coming from user mode */
 	if (user_mode(&fp->ptregs))
 		current->thread.esp0 = (unsigned long) fp;
+#endif
 
 #if DEBUG
 	printk ("*** Bus Error *** Format is %x\n", fp->ptregs.format);
@@ -1037,10 +1039,8 @@
 	printk("%s: %08x\n",str,nr);
 	printk("PC: [<%08lx>]\nSR: %04x  SP: %p  a2: %08lx\n",
 	       fp->pc, fp->sr, fp, fp->a2);
-	printk("d0: %08lx    d1: %08lx    d2: %08lx    d3: %08lx\n",
-	       fp->d0, fp->d1, fp->d2, fp->d3);
-	printk("d4: %08lx    d5: %08lx    a0: %08lx    a1: %08lx\n",
-	       fp->d4, fp->d5, fp->a0, fp->a1);
+	printk("d0: %08lx  d1: %08lx  a0: %08lx  a1: %08lx\n",
+	       fp->d0, fp->d1, fp->a0, fp->a1);
 
 	printk("Process %s (pid: %d, stackpage=%08lx)\n",
 		current->comm, current->pid, PAGE_SIZE+(unsigned long)current);
diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16-misc/arch/m68k/math-emu/fp_entry.S linux-2.3.16-sysstack/arch/m68k/math-emu/fp_entry.S
--- linux-2.3.16-misc/arch/m68k/math-emu/fp_entry.S	Sat Sep  4 21:58:10 1999
+++ linux-2.3.16-sysstack/arch/m68k/math-emu/fp_entry.S	Sun Sep  5 20:14:18 1999
@@ -46,8 +46,8 @@
 
 	.text
 SYMBOL_NAME_LABEL(fpu_emu)
-	SAVE_ALL_INT
-	GET_CURRENT(%d0)
+	save_all_int
+	get_current
 
 #if defined(CPU_M68020_OR_M68030) && defined(CPU_M68040_OR_M68060)
         tst.l	SYMBOL_NAME(m68k_is040or060)
@@ -57,9 +57,16 @@
 	move.l	(FPS_PC2,%sp),(FPS_PC,%sp)
 #endif
 1:
+	| save %d2 too, it's used by the instruction decoder
+	| and is no longer on the int stack
+	movel	%d2,(%sp)-
+
 	| emulate the instruction
 	jsr	fp_scan
 
+	| restore %d2 from stack
+	movel	+(sp),%d2
+
 #if defined(CONFIG_M68060)
 #if !defined(CPU_M68060_ONLY)
 	btst	#3,SYMBOL_NAME(m68k_cputype)+3
@@ -81,7 +88,7 @@
 	| user space, we correct stackpointer and send a SIGSEGV to
 	| the user process
 fp_err_ua2:
-	addq.l	#4,%sp
+	addq.l	#8,%sp
 fp_err_ua1:
 	addq.l	#4,%sp
 	move.l	%a0,-(%sp)
@@ -106,6 +113,8 @@
 	.globl	fp_get_data_reg, fp_put_data_reg
 	.globl	fp_get_addr_reg, fp_put_addr_reg
 
+#define STKOFF	12
+
 	| Entry points to get/put a register. Some of them can be get/put
 	| directly, others are on the stack, as we read/write the stack
 	| directly here, these function may only be called from within
@@ -122,17 +131,17 @@
 	.long	fp_get_d6, fp_get_d7
 
 fp_get_d0:
-	move.l	(PT_D0+8,%sp),%d0
+	move.l	(STKOFF+PT_D0,%sp),%d0
 	printf	PREGISTER,"{d0->%08x}",1,%d0
 	rts
 
 fp_get_d1:
-	move.l	(PT_D1+8,%sp),%d0
+	move.l	(STKOFF+PT_D1,%sp),%d0
 	printf	PREGISTER,"{d1->%08x}",1,%d0
 	rts
 
 fp_get_d2:
-	move.l	(PT_D2+8,%sp),%d0
+	move.l	(STKOFF-4,%sp),%d0
 	printf	PREGISTER,"{d2->%08x}",1,%d0
 	rts
 
@@ -173,35 +182,32 @@
 
 fp_put_d0:
 	printf	PREGISTER,"{d0<-%08x}",1,%d0
-	move.l	%d0,(PT_D0+8,%sp)
+	move.l	%d0,(STKOFF+PT_D0,%sp)
 	rts
 
 fp_put_d1:
 	printf	PREGISTER,"{d1<-%08x}",1,%d0
-	move.l	%d0,(PT_D1+8,%sp)
+	move.l	%d0,(STKOFF+PT_D1,%sp)
 	rts
 
 fp_put_d2:
 	printf	PREGISTER,"{d2<-%08x}",1,%d0
-	move.l	%d0,(PT_D2+8,%sp)
+	move.l	%d0,(STKOFF-4,%sp)
 	rts
 
 fp_put_d3:
 	printf	PREGISTER,"{d3<-%08x}",1,%d0
-|	move.l	%d0,%d3
-	move.l	%d0,(PT_D3+8,%sp)
+	move.l	%d0,%d3
 	rts
 
 fp_put_d4:
 	printf	PREGISTER,"{d4<-%08x}",1,%d0
-|	move.l	%d0,%d4
-	move.l	%d0,(PT_D4+8,%sp)
+	move.l	%d0,%d4
 	rts
 
 fp_put_d5:
 	printf	PREGISTER,"{d5<-%08x}",1,%d0
-|	move.l	%d0,%d5
-	move.l	%d0,(PT_D5+8,%sp)
+	move.l	%d0,%d5
 	rts
 
 fp_put_d6:
@@ -225,17 +231,17 @@
 	.long	fp_get_a6, fp_get_a7
 
 fp_get_a0:
-	move.l	(PT_A0+8,%sp),%a0
+	move.l	(STKOFF+PT_A0,%sp),%a0
 	printf	PREGISTER,"{a0->%08x}",1,%a0
 	rts
 
 fp_get_a1:
-	move.l	(PT_A1+8,%sp),%a0
+	move.l	(STKOFF+PT_A1,%sp),%a0
 	printf	PREGISTER,"{a1->%08x}",1,%a0
 	rts
 
 fp_get_a2:
-	move.l	(PT_A2+8,%sp),%a0
+	move.l	(STKOFF+PT_A2,%sp),%a0
 	printf	PREGISTER,"{a2->%08x}",1,%a0
 	rts
 
@@ -276,17 +282,17 @@
 
 fp_put_a0:
 	printf	PREGISTER,"{a0<-%08x}",1,%a0
-	move.l	%a0,(PT_A0+8,%sp)
+	move.l	%a0,(STKOFF+PT_A0,%sp)
 	rts
 
 fp_put_a1:
 	printf	PREGISTER,"{a1<-%08x}",1,%a0
-	move.l	%a0,(PT_A1+8,%sp)
+	move.l	%a0,(STKOFF+PT_A1,%sp)
 	rts
 
 fp_put_a2:
 	printf	PREGISTER,"{a2<-%08x}",1,%a0
-	move.l	%a0,(PT_A2+8,%sp)
+	move.l	%a0,(STKOFF+PT_A2,%sp)
 	rts
 
 fp_put_a3:
diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16-misc/include/asm-m68k/elf.h linux-2.3.16-sysstack/include/asm-m68k/elf.h
--- linux-2.3.16-misc/include/asm-m68k/elf.h	Sat Sep  4 21:58:30 1999
+++ linux-2.3.16-sysstack/include/asm-m68k/elf.h	Mon Sep  6 01:58:05 1999
@@ -51,30 +51,29 @@
 #endif
 
 #define ELF_CORE_COPY_REGS(pr_reg, regs)				\
-	/* Bleech. */							\
-	pr_reg[0] = regs->d1;						\
-	pr_reg[1] = regs->d2;						\
-	pr_reg[2] = regs->d3;						\
-	pr_reg[3] = regs->d4;						\
-	pr_reg[4] = regs->d5;						\
-	pr_reg[7] = regs->a0;						\
-	pr_reg[8] = regs->a1;						\
-	pr_reg[9] = regs->a2;						\
-	pr_reg[14] = regs->d0;						\
-	pr_reg[15] = rdusp();						\
-	pr_reg[16] = regs->orig_d0;					\
-	pr_reg[17] = regs->sr;						\
-	pr_reg[18] = regs->pc;						\
-	pr_reg[19] = (regs->format << 12) | regs->vector;		\
-	{								\
-	  struct switch_stack *sw = ((struct switch_stack *)regs) - 1;	\
-	  pr_reg[5] = sw->d6;						\
-	  pr_reg[6] = sw->d7;						\
-	  pr_reg[10] = sw->a3;						\
-	  pr_reg[11] = sw->a4;						\
-	  pr_reg[12] = sw->a5;						\
-	  pr_reg[13] = sw->a6;						\
-	}
+{									\
+	struct full_stack *fs = (struct full_stack *)(regs + 1) - 1;	\
+	pr_reg[PT_D0] = fs->pt_regs.d0;					\
+	pr_reg[PT_D1] = fs->pt_regs.d1;					\
+	pr_reg[PT_D2] = fs->sw_regs.d2;					\
+	pr_reg[PT_D3] = fs->sw_regs.d3;					\
+	pr_reg[PT_D4] = fs->sw_regs.d4;					\
+	pr_reg[PT_D5] = fs->sw_regs.d5;					\
+	pr_reg[PT_D6] = fs->sw_regs.d6;					\
+	pr_reg[PT_D7] = fs->sw_regs.d7;					\
+	pr_reg[PT_A0] = fs->pt_regs.a0;					\
+	pr_reg[PT_A1] = fs->pt_regs.a1;					\
+	pr_reg[PT_A2] = fs->pt_regs.a2;					\
+	pr_reg[PT_A3] = fs->sw_regs.a3;					\
+	pr_reg[PT_A4] = fs->sw_regs.a4;					\
+	pr_reg[PT_A5] = fs->sw_regs.a5;					\
+	pr_reg[PT_A6] = fs->sw_regs.a6;					\
+	pr_reg[PT_USP] = rdusp();					\
+	pr_reg[PT_ORIG_D0] = fs->pt_regs.syscall;			\
+	pr_reg[PT_SR] = fs->pt_regs.sr;					\
+	pr_reg[PT_PC] = fs->pt_regs.pc;					\
+	pr_reg[PT_VEC] = (fs->pt_regs.format << 12) | fs->pt_regs.vector;\
+}
 
 /* This yields a mask that user programs can use to figure out what
    instruction set this cpu supports.  */
diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16-misc/include/asm-m68k/entry.h linux-2.3.16-sysstack/include/asm-m68k/entry.h
--- linux-2.3.16-misc/include/asm-m68k/entry.h	Sat Sep  4 21:58:30 1999
+++ linux-2.3.16-sysstack/include/asm-m68k/entry.h	Mon Sep  6 01:54:20 1999
@@ -60,78 +60,84 @@
 PF_DTRACE_OFF = 1
 PF_DTRACE_BIT = 5
 
-#define SAVE_ALL_INT save_all_int
-#define SAVE_ALL_SYS save_all_sys
-#define RESTORE_ALL restore_all
 /*
  * This defines the normal kernel pt-regs layout.
  *
- * regs a3-a6 and d6-d7 are preserved by C code
+ * regs a3-a6 and d2-d7 are preserved by C code
  * the kernel doesn't mess with usp unless it needs to
  */
-#ifndef CONFIG_KGDB
 /*
- * a -1 in the orig_d0 field signifies
+ * a -1 in the syscall field signifies
  * that the stack frame is NOT for syscall
  */
 .macro	save_all_int
 	clrl	%sp@-		| stk_adj
-	pea	-1:w		| orig d0
-	movel	%d0,%sp@-	| d0
-	moveml	%d1-%d5/%a0-%a1/%curptr,%sp@-
-.endm
-
-.macro	save_all_sys
-	clrl	%sp@-		| stk_adj
-	movel	%d0,%sp@-	| orig d0
-	movel	%d0,%sp@-	| d0
-	moveml	%d1-%d5/%a0-%a1/%curptr,%sp@-
-.endm
-#else
-/* Need to save the "missing" registers for kgdb...
- */
-.macro	save_all_int
-	clrl	%sp@-		| stk_adj
-	pea	-1:w		| orig d0
-	movel	%d0,%sp@-	| d0
-	moveml	%d1-%d5/%a0-%a1/%curptr,%sp@-
-	moveml	%d6-%d7,kgdb_registers+GDBOFFA_D6
+	pea	-1:w		| syscall
+	moveml	%d0/%d1/%a0/%a1/%curptr,%sp@-
+#ifdef CONFIG_KGDB
+/* Need to save the "missing" registers for kgdb... */
+	moveml	%d2-%d7,kgdb_registers+GDBOFFA_D2
 	moveml	%a3-%a6,kgdb_registers+GDBOFFA_A3
+#endif
 .endm
 
 .macro	save_all_sys
 	clrl	%sp@-		| stk_adj
-	movel	%d0,%sp@-	| orig d0
-	movel	%d0,%sp@-	| d0
-	moveml	%d1-%d5/%a0-%a1/%curptr,%sp@-
-	moveml	%d6-%d7,kgdb_registers+GDBOFFA_D6
+	movel	%d0,%sp@-	| syscall
+	moveml	%d0/%d1/%a0/%a1/%curptr,%sp@-
+#ifdef CONFIG_KGDB
+	moveml	%d2-%d7,kgdb_registers+GDBOFFA_D2
 	moveml	%a3-%a6,kgdb_registers+GDBOFFA_A3
-.endm
 #endif
+.endm
 
-.macro	restore_all
-	moveml	%sp@+,%a0-%a1/%curptr/%d1-%d5
-	movel	%sp@+,%d0
-	addql	#4,%sp		| orig d0
-	addl	%sp@+,%sp	| stk adj
-	rte
+.macro	save_sys_stack
+	moveml	%d1-%d5,%sp@-
 .endm
 
-#define SWITCH_STACK_SIZE (6*4+4)	/* includes return address */
+.macro	rebuild_sys_stack
+	movel	%sp@(PT_D1),%d1
+	moveml	%d1-%d5,%sp@-
+.endm
 
-#define SAVE_SWITCH_STACK save_switch_stack
-#define RESTORE_SWITCH_STACK restore_switch_stack
-#define GET_CURRENT(tmp) get_current tmp
+.macro	drop_sys_stack
+	lea	%sp@(20),%sp
+.endm
 
 .macro	save_switch_stack
-	moveml	%a3-%a6/%d6-%d7,%sp@-
+	moveml	%d2-%d7/%a3-%a6,%sp@-
 .endm
 
 .macro	restore_switch_stack
-	moveml	%sp@+,%a3-%a6/%d6-%d7
+	moveml	%sp@+,%d2-%d7/%a3-%a6
+.endm
+
+.macro	changeto_switch_stack
+	movel	%sp@+,%d1
+	drop_sys_stack
+	movel	%d1,%sp@-
+	save_switch_stack
+.endm
+
+.macro	changeto_sys_stack	nodrop=0
+	.if	\nodrop
+	restore_switch_stack
+	.else
+	lea	%sp@(SW_SIZEOF-4),%sp
+	.endif
+	movel	%sp@+,%d1
+	lea	%sp@(-SC_SIZEOF),%sp
+	movel	%d1,%sp@-
+.endm
+
+.macro	restore_all
+	moveml	%sp@+,%d0/%d1/%a0/%a1/%curptr
+	addql	#4,%sp		| syscall
+	addl	%sp@+,%sp	| stk_adj
+	rte
 .endm
 
-.macro	get_current reg=%d0
+.macro	get_current reg=%d1
 	movel	%sp,\reg
 	andw	#-KTHREAD_SIZE,\reg
 	movel	\reg,%curptr
diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16-misc/include/asm-m68k/ptrace.h linux-2.3.16-sysstack/include/asm-m68k/ptrace.h
--- linux-2.3.16-misc/include/asm-m68k/ptrace.h	Sat Sep  4 21:58:30 1999
+++ linux-2.3.16-sysstack/include/asm-m68k/ptrace.h	Sun Sep  5 17:01:06 1999
@@ -20,28 +20,25 @@
 #define PT_ORIG_D0 16
 #define PT_SR	   17
 #define PT_PC	   18
+#define PT_VEC	   19
 
 #ifndef __ASSEMBLY__
 
 /* this struct defines the way the registers are stored on the
-   stack during a system call. */
+   stack during an exception. */
 
 struct pt_regs {
-  long     d1;
-  long     d2;
-  long     d3;
-  long     d4;
-  long     d5;
-  long     a0;
-  long     a1;
-  long     a2;
-  long     d0;
-  long     orig_d0;
-  long     stkadj;
-  unsigned short sr;
-  unsigned long  pc;
-  unsigned format :  4; /* frame format specifier */
-  unsigned vector : 12; /* vector offset */
+	unsigned long  d0;
+	unsigned long  d1;
+	unsigned long  a0;
+	unsigned long  a1;
+	unsigned long  a2;
+	unsigned long  syscall;
+	unsigned long  stkadj;
+	unsigned short sr;
+	unsigned long  pc;
+	unsigned format :  4; /* frame format specifier */
+	unsigned vector : 12; /* vector offset */
 };
 
 /*
@@ -49,6 +46,10 @@
  * switcher: it's pushed after the normal "struct pt_regs".
  */
 struct switch_stack {
+	unsigned long  d2;
+	unsigned long  d3;
+	unsigned long  d4;
+	unsigned long  d5;
 	unsigned long  d6;
 	unsigned long  d7;
 	unsigned long  a3;
@@ -56,6 +57,22 @@
 	unsigned long  a5;
 	unsigned long  a6;
 	unsigned long  retpc;
+};
+
+struct full_stack {
+	struct switch_stack sw_regs;
+	struct pt_regs pt_regs;
+};
+
+/*
+ * This is the stack used during system calls for the arguments
+ */
+struct syscall_stack {
+	unsigned long  d1;
+	unsigned long  d2;
+	unsigned long  d3;
+	unsigned long  d4;
+	unsigned long  d5;
 };
 
 /* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
diff -Nur -X /opt/home/roman/src/m68k_nodiff linux-2.3.16-misc/include/asm-m68k/system.h linux-2.3.16-sysstack/include/asm-m68k/system.h
--- linux-2.3.16-misc/include/asm-m68k/system.h	Sat Sep  4 21:58:31 1999
+++ linux-2.3.16-sysstack/include/asm-m68k/system.h	Mon Sep  6 01:54:20 1999
@@ -42,7 +42,7 @@
   register void *_last __asm__ ("d1"); \
   __asm__ __volatile__("jbsr " SYMBOL_NAME_STR(resume) \
 		       : "=d" (_last) : "a" (_prev), "a" (_next) \
-		       : "d0", "d1", "d2", "d3", "d4", "d5", "a0", "a1"); \
+		       : "d0", "d1", "a0", "a1"); \
   (last) = _last; \
 }
 

