sparc: prepare kernel/ for unification
authorSam Ravnborg <sam@ravnborg.org>
Wed, 3 Dec 2008 11:08:37 +0000 (03:08 -0800)
committerDavid S. Miller <davem@davemloft.net>
Thu, 4 Dec 2008 17:17:20 +0000 (09:17 -0800)
o sparc32 files with identical names to sparc64 renamed to <name>_32.S
o introduced a few Kconfig helpers to simplify Makefile logic
o refactored Makefile to prepare for unification
  - use obj-$(CONFIG_SPARC32) for sparc32 specific files
  - use <name>_$(BITS) for files where sparc64 has a _64 variant
  - sparc64 directly include a few files where sparc32 builds them,
    refer to these files directly (no BITS)
  - sneaked in -Werror as used by sparc64
o modified sparc/Makefile to use the new names for head/init_task

Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
53 files changed:
arch/sparc/Kconfig
arch/sparc/Makefile
arch/sparc/kernel/Makefile
arch/sparc/kernel/auxio.c [deleted file]
arch/sparc/kernel/auxio_32.c [new file with mode: 0644]
arch/sparc/kernel/cpu.c [deleted file]
arch/sparc/kernel/cpu_32.c [new file with mode: 0644]
arch/sparc/kernel/etrap.S [deleted file]
arch/sparc/kernel/etrap_32.S [new file with mode: 0644]
arch/sparc/kernel/head.S [deleted file]
arch/sparc/kernel/head_32.S [new file with mode: 0644]
arch/sparc/kernel/idprom.c [deleted file]
arch/sparc/kernel/idprom_32.c [new file with mode: 0644]
arch/sparc/kernel/init_task.c [deleted file]
arch/sparc/kernel/init_task_32.c [new file with mode: 0644]
arch/sparc/kernel/irq.c [deleted file]
arch/sparc/kernel/irq_32.c [new file with mode: 0644]
arch/sparc/kernel/kgdb.c [deleted file]
arch/sparc/kernel/kgdb_32.c [new file with mode: 0644]
arch/sparc/kernel/module.c [deleted file]
arch/sparc/kernel/module_32.c [new file with mode: 0644]
arch/sparc/kernel/of_device.c [deleted file]
arch/sparc/kernel/of_device_32.c [new file with mode: 0644]
arch/sparc/kernel/process.c [deleted file]
arch/sparc/kernel/process_32.c [new file with mode: 0644]
arch/sparc/kernel/prom.c [deleted file]
arch/sparc/kernel/prom_32.c [new file with mode: 0644]
arch/sparc/kernel/ptrace.c [deleted file]
arch/sparc/kernel/ptrace_32.c [new file with mode: 0644]
arch/sparc/kernel/rtrap.S [deleted file]
arch/sparc/kernel/rtrap_32.S [new file with mode: 0644]
arch/sparc/kernel/setup.c [deleted file]
arch/sparc/kernel/setup_32.c [new file with mode: 0644]
arch/sparc/kernel/signal.c [deleted file]
arch/sparc/kernel/signal_32.c [new file with mode: 0644]
arch/sparc/kernel/smp.c [deleted file]
arch/sparc/kernel/smp_32.c [new file with mode: 0644]
arch/sparc/kernel/sparc_ksyms.c [deleted file]
arch/sparc/kernel/sparc_ksyms_32.c [new file with mode: 0644]
arch/sparc/kernel/sys_sparc.c [deleted file]
arch/sparc/kernel/sys_sparc_32.c [new file with mode: 0644]
arch/sparc/kernel/systbls.S [deleted file]
arch/sparc/kernel/systbls_32.S [new file with mode: 0644]
arch/sparc/kernel/time.c [deleted file]
arch/sparc/kernel/time_32.c [new file with mode: 0644]
arch/sparc/kernel/trampoline.S [deleted file]
arch/sparc/kernel/trampoline_32.S [new file with mode: 0644]
arch/sparc/kernel/traps.c [deleted file]
arch/sparc/kernel/traps_32.c [new file with mode: 0644]
arch/sparc/kernel/una_asm.S [deleted file]
arch/sparc/kernel/una_asm_32.S [new file with mode: 0644]
arch/sparc/kernel/unaligned.c [deleted file]
arch/sparc/kernel/unaligned_32.c [new file with mode: 0644]

index 26ddeedb51669df0d54a91410232098359f8eba4..7cfe557db23da6cb5e4e47265496a87dba674f8f 100644 (file)
@@ -198,6 +198,17 @@ config EMULATED_CMPXCHG
          Sparc32 does not have a CAS instruction like sparc64. cmpxchg()
          is emulated, and therefore it is not completely atomic.
 
+# Makefile helpers
+config SPARC32_SMP
+       bool
+       default y
+       depends on SPARC32 && SMP
+
+config SPARC64_SMP
+       bool
+       default y
+       depends on SPARC64 && SMP
+
 choice
        prompt "Kernel page size" if SPARC64
        default SPARC64_PAGE_SIZE_8KB
@@ -505,6 +516,16 @@ config SUN_OPENPROMFS
          Only choose N if you know in advance that you will not need to modify
          OpenPROM settings on the running system.
 
+# Makefile helpers
+config SPARC32_PCI
+       bool
+       default y
+       depends on SPARC32 && PCI
+
+config SPARC64_PCI
+       bool
+       default y
+       depends on SPARC64 && PCI
 
 endmenu
 
index b1d691489ed4145e2cbd3e79436718bc2d73cccb..f061d0ada158606d213cb9084cd33af77bfa8496 100644 (file)
@@ -67,8 +67,8 @@ endif
 
 endif
 
-head-$(CONFIG_SPARC32) := arch/sparc/kernel/head.o
-head-$(CONFIG_SPARC32) += arch/sparc/kernel/init_task.o
+head-$(CONFIG_SPARC32) := arch/sparc/kernel/head_$(BITS).o
+head-$(CONFIG_SPARC32) += arch/sparc/kernel/init_task_$(BITS).o
 head-$(CONFIG_SPARC64) := arch/sparc64/kernel/head.o
 head-$(CONFIG_SPARC64) += arch/sparc64/kernel/init_task.o
 
index 2d658209509943ce5d29fd0d6ebd2553097d4d76..6558eea5f0bc7711f16457231da1a7bc408468ab 100644 (file)
@@ -2,25 +2,57 @@
 # Makefile for the linux kernel.
 #
 
-extra-y                := head.o init_task.o vmlinux.lds
-
-EXTRA_AFLAGS   := -ansi
-
-IRQ_OBJS := irq.o sun4m_irq.o sun4c_irq.o sun4d_irq.o
-obj-y    := entry.o wof.o wuf.o etrap.o rtrap.o traps.o $(IRQ_OBJS) \
-           process.o signal.o ioport.o setup.o idprom.o \
-           sys_sparc.o systbls.o \
-           time.o windows.o cpu.o devices.o \
-           tadpole.o tick14.o ptrace.o \
-           unaligned.o una_asm.o muldiv.o \
-           prom.o of_device.o devres.o dma.o
-
-devres-y = ../../../kernel/irq/devres.o
-
-obj-$(CONFIG_PCI) += pcic.o
-obj-$(CONFIG_SMP) += trampoline.o smp.o sun4m_smp.o sun4d_smp.o
-obj-$(CONFIG_SUN_AUXIO) += auxio.o
-obj-$(CONFIG_SUN_PM) += apc.o pmc.o
-obj-$(CONFIG_MODULES) += module.o sparc_ksyms.o
-obj-$(CONFIG_SPARC_LED) += led.o
-obj-$(CONFIG_KGDB) += kgdb.o
+asflags-y := -ansi
+ccflags-y := -Werror
+
+extra-y     := head_$(BITS).o
+extra-y     += init_task_$(BITS).o
+extra-y     += vmlinux.lds
+
+obj-$(CONFIG_SPARC32)   += entry.o wof.o wuf.o
+obj-$(CONFIG_SPARC32)   += etrap_32.o
+obj-$(CONFIG_SPARC32)   += rtrap_32.o
+obj-y                   += traps_$(BITS).o
+
+# IRQ
+obj-y                   += irq_$(BITS).o
+obj-$(CONFIG_SPARC32)   += sun4m_irq.o sun4c_irq.o sun4d_irq.o
+
+obj-y                   += process_$(BITS).o
+obj-y                   += signal_$(BITS).o
+obj-$(CONFIG_SPARC32)   += ioport.o
+obj-y                   += setup_$(BITS).o
+obj-y                   += idprom_$(BITS).o
+obj-y                   += sys_sparc_$(BITS).o
+obj-$(CONFIG_SPARC32)   += systbls_32.o
+obj-y                   += time_$(BITS).o
+obj-$(CONFIG_SPARC32)   += windows.o
+obj-y                   += cpu_$(BITS).o
+obj-$(CONFIG_SPARC32)   += devices.o
+obj-$(CONFIG_SPARC32)   += tadpole.o
+obj-$(CONFIG_SPARC32)   += tick14.o
+obj-y                   += ptrace_$(BITS).o
+obj-y                   += unaligned_$(BITS).o
+obj-y                   += una_asm_$(BITS).o
+obj-$(CONFIG_SPARC32)   += muldiv.o
+obj-y                   += prom_$(BITS).o
+obj-y                   += of_device_$(BITS).o
+
+# sparc32 do not use GENERIC_HARDIRQS but uses the generic devres implementation
+obj-$(CONFIG_SPARC32)     += devres.o
+devres-y                  := ../../../kernel/irq/devres.o
+
+obj-$(CONFIG_SPARC32)     += dma.o
+
+obj-$(CONFIG_SPARC32_PCI) += pcic.o
+
+obj-$(CONFIG_SMP)         += trampoline_$(BITS).o smp_$(BITS).o
+obj-$(CONFIG_SPARC32_SMP) += sun4m_smp.o sun4d_smp.o
+
+obj-y                     += auxio_$(BITS).o
+obj-$(CONFIG_SUN_PM)      += apc.o pmc.o
+
+obj-$(CONFIG_MODULES)     += module_$(BITS).o
+obj-$(CONFIG_MODULES)     += sparc_ksyms_$(BITS).o
+obj-$(CONFIG_SPARC_LED)   += led.o
+obj-$(CONFIG_KGDB)        += kgdb_$(BITS).o
diff --git a/arch/sparc/kernel/auxio.c b/arch/sparc/kernel/auxio.c
deleted file mode 100644 (file)
index 09c8572..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-/* auxio.c: Probing for the Sparc AUXIO register at boot time.
- *
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <linux/stddef.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <asm/oplib.h>
-#include <asm/io.h>
-#include <asm/auxio.h>
-#include <asm/string.h>                /* memset(), Linux has no bzero() */
-
-/* Probe and map in the Auxiliary I/O register */
-
-/* auxio_register is not static because it is referenced 
- * in entry.S::floppy_tdone
- */
-void __iomem *auxio_register = NULL;
-static DEFINE_SPINLOCK(auxio_lock);
-
-void __init auxio_probe(void)
-{
-       int node, auxio_nd;
-       struct linux_prom_registers auxregs[1];
-       struct resource r;
-
-       switch (sparc_cpu_model) {
-       case sun4d:
-       case sun4:
-               return;
-       default:
-               break;
-       }
-       node = prom_getchild(prom_root_node);
-       auxio_nd = prom_searchsiblings(node, "auxiliary-io");
-       if(!auxio_nd) {
-               node = prom_searchsiblings(node, "obio");
-               node = prom_getchild(node);
-               auxio_nd = prom_searchsiblings(node, "auxio");
-               if(!auxio_nd) {
-#ifdef CONFIG_PCI
-                       /* There may be auxio on Ebus */
-                       return;
-#else
-                       if(prom_searchsiblings(node, "leds")) {
-                               /* VME chassis sun4m machine, no auxio exists. */
-                               return;
-                       }
-                       prom_printf("Cannot find auxio node, cannot continue...\n");
-                       prom_halt();
-#endif
-               }
-       }
-       if(prom_getproperty(auxio_nd, "reg", (char *) auxregs, sizeof(auxregs)) <= 0)
-               return;
-       prom_apply_obio_ranges(auxregs, 0x1);
-       /* Map the register both read and write */
-       r.flags = auxregs[0].which_io & 0xF;
-       r.start = auxregs[0].phys_addr;
-       r.end = auxregs[0].phys_addr + auxregs[0].reg_size - 1;
-       auxio_register = of_ioremap(&r, 0, auxregs[0].reg_size, "auxio");
-       /* Fix the address on sun4m and sun4c. */
-       if((((unsigned long) auxregs[0].phys_addr) & 3) == 3 ||
-          sparc_cpu_model == sun4c)
-               auxio_register += (3 - ((unsigned long)auxio_register & 3));
-
-       set_auxio(AUXIO_LED, 0);
-}
-
-unsigned char get_auxio(void)
-{
-       if(auxio_register) 
-               return sbus_readb(auxio_register);
-       return 0;
-}
-
-void set_auxio(unsigned char bits_on, unsigned char bits_off)
-{
-       unsigned char regval;
-       unsigned long flags;
-       spin_lock_irqsave(&auxio_lock, flags);
-       switch(sparc_cpu_model) {
-       case sun4c:
-               regval = sbus_readb(auxio_register);
-               sbus_writeb(((regval | bits_on) & ~bits_off) | AUXIO_ORMEIN,
-                       auxio_register);
-               break;
-       case sun4m:
-               if(!auxio_register)
-                       break;     /* VME chassis sun4m, no auxio. */
-               regval = sbus_readb(auxio_register);
-               sbus_writeb(((regval | bits_on) & ~bits_off) | AUXIO_ORMEIN4M,
-                       auxio_register);
-               break;
-       case sun4d:
-               break;
-       default:
-               panic("Can't set AUXIO register on this machine.");
-       };
-       spin_unlock_irqrestore(&auxio_lock, flags);
-}
-
-
-/* sun4m power control register (AUXIO2) */
-
-volatile unsigned char * auxio_power_register = NULL;
-
-void __init auxio_power_probe(void)
-{
-       struct linux_prom_registers regs;
-       int node;
-       struct resource r;
-
-       /* Attempt to find the sun4m power control node. */
-       node = prom_getchild(prom_root_node);
-       node = prom_searchsiblings(node, "obio");
-       node = prom_getchild(node);
-       node = prom_searchsiblings(node, "power");
-       if (node == 0 || node == -1)
-               return;
-
-       /* Map the power control register. */
-       if (prom_getproperty(node, "reg", (char *)&regs, sizeof(regs)) <= 0)
-               return;
-       prom_apply_obio_ranges(&regs, 1);
-       memset(&r, 0, sizeof(r));
-       r.flags = regs.which_io & 0xF;
-       r.start = regs.phys_addr;
-       r.end = regs.phys_addr + regs.reg_size - 1;
-       auxio_power_register = (unsigned char *) of_ioremap(&r, 0,
-           regs.reg_size, "auxpower");
-
-       /* Display a quick message on the console. */
-       if (auxio_power_register)
-               printk(KERN_INFO "Power off control detected.\n");
-}
diff --git a/arch/sparc/kernel/auxio_32.c b/arch/sparc/kernel/auxio_32.c
new file mode 100644 (file)
index 0000000..09c8572
--- /dev/null
@@ -0,0 +1,139 @@
+/* auxio.c: Probing for the Sparc AUXIO register at boot time.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <asm/oplib.h>
+#include <asm/io.h>
+#include <asm/auxio.h>
+#include <asm/string.h>                /* memset(), Linux has no bzero() */
+
+/* Probe and map in the Auxiliary I/O register */
+
+/* auxio_register is not static because it is referenced 
+ * in entry.S::floppy_tdone
+ */
+void __iomem *auxio_register = NULL;
+static DEFINE_SPINLOCK(auxio_lock);
+
+void __init auxio_probe(void)
+{
+       int node, auxio_nd;
+       struct linux_prom_registers auxregs[1];
+       struct resource r;
+
+       switch (sparc_cpu_model) {
+       case sun4d:
+       case sun4:
+               return;
+       default:
+               break;
+       }
+       node = prom_getchild(prom_root_node);
+       auxio_nd = prom_searchsiblings(node, "auxiliary-io");
+       if(!auxio_nd) {
+               node = prom_searchsiblings(node, "obio");
+               node = prom_getchild(node);
+               auxio_nd = prom_searchsiblings(node, "auxio");
+               if(!auxio_nd) {
+#ifdef CONFIG_PCI
+                       /* There may be auxio on Ebus */
+                       return;
+#else
+                       if(prom_searchsiblings(node, "leds")) {
+                               /* VME chassis sun4m machine, no auxio exists. */
+                               return;
+                       }
+                       prom_printf("Cannot find auxio node, cannot continue...\n");
+                       prom_halt();
+#endif
+               }
+       }
+       if(prom_getproperty(auxio_nd, "reg", (char *) auxregs, sizeof(auxregs)) <= 0)
+               return;
+       prom_apply_obio_ranges(auxregs, 0x1);
+       /* Map the register both read and write */
+       r.flags = auxregs[0].which_io & 0xF;
+       r.start = auxregs[0].phys_addr;
+       r.end = auxregs[0].phys_addr + auxregs[0].reg_size - 1;
+       auxio_register = of_ioremap(&r, 0, auxregs[0].reg_size, "auxio");
+       /* Fix the address on sun4m and sun4c. */
+       if((((unsigned long) auxregs[0].phys_addr) & 3) == 3 ||
+          sparc_cpu_model == sun4c)
+               auxio_register += (3 - ((unsigned long)auxio_register & 3));
+
+       set_auxio(AUXIO_LED, 0);
+}
+
+unsigned char get_auxio(void)
+{
+       if(auxio_register) 
+               return sbus_readb(auxio_register);
+       return 0;
+}
+
+void set_auxio(unsigned char bits_on, unsigned char bits_off)
+{
+       unsigned char regval;
+       unsigned long flags;
+       spin_lock_irqsave(&auxio_lock, flags);
+       switch(sparc_cpu_model) {
+       case sun4c:
+               regval = sbus_readb(auxio_register);
+               sbus_writeb(((regval | bits_on) & ~bits_off) | AUXIO_ORMEIN,
+                       auxio_register);
+               break;
+       case sun4m:
+               if(!auxio_register)
+                       break;     /* VME chassis sun4m, no auxio. */
+               regval = sbus_readb(auxio_register);
+               sbus_writeb(((regval | bits_on) & ~bits_off) | AUXIO_ORMEIN4M,
+                       auxio_register);
+               break;
+       case sun4d:
+               break;
+       default:
+               panic("Can't set AUXIO register on this machine.");
+       };
+       spin_unlock_irqrestore(&auxio_lock, flags);
+}
+
+
+/* sun4m power control register (AUXIO2) */
+
+volatile unsigned char * auxio_power_register = NULL;
+
+void __init auxio_power_probe(void)
+{
+       struct linux_prom_registers regs;
+       int node;
+       struct resource r;
+
+       /* Attempt to find the sun4m power control node. */
+       node = prom_getchild(prom_root_node);
+       node = prom_searchsiblings(node, "obio");
+       node = prom_getchild(node);
+       node = prom_searchsiblings(node, "power");
+       if (node == 0 || node == -1)
+               return;
+
+       /* Map the power control register. */
+       if (prom_getproperty(node, "reg", (char *)&regs, sizeof(regs)) <= 0)
+               return;
+       prom_apply_obio_ranges(&regs, 1);
+       memset(&r, 0, sizeof(r));
+       r.flags = regs.which_io & 0xF;
+       r.start = regs.phys_addr;
+       r.end = regs.phys_addr + regs.reg_size - 1;
+       auxio_power_register = (unsigned char *) of_ioremap(&r, 0,
+           regs.reg_size, "auxpower");
+
+       /* Display a quick message on the console. */
+       if (auxio_power_register)
+               printk(KERN_INFO "Power off control detected.\n");
+}
diff --git a/arch/sparc/kernel/cpu.c b/arch/sparc/kernel/cpu.c
deleted file mode 100644 (file)
index 1fc17f5..0000000
+++ /dev/null
@@ -1,167 +0,0 @@
-/* cpu.c: Dinky routines to look for the kind of Sparc cpu
- *        we are on.
- *
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/threads.h>
-#include <asm/oplib.h>
-#include <asm/page.h>
-#include <asm/head.h>
-#include <asm/psr.h>
-#include <asm/mbus.h>
-#include <asm/cpudata.h>
-
-DEFINE_PER_CPU(cpuinfo_sparc, __cpu_data) = { 0 };
-
-struct cpu_iu_info {
-  int psr_impl;
-  int psr_vers;
-  char* cpu_name;   /* should be enough I hope... */
-};
-
-struct cpu_fp_info {
-  int psr_impl;
-  int fp_vers;
-  char* fp_name;
-};
-
-/* In order to get the fpu type correct, you need to take the IDPROM's
- * machine type value into consideration too.  I will fix this.
- */
-static struct cpu_fp_info linux_sparc_fpu[] = {
-  { 0, 0, "Fujitsu MB86910 or Weitek WTL1164/5"},
-  { 0, 1, "Fujitsu MB86911 or Weitek WTL1164/5 or LSI L64831"},
-  { 0, 2, "LSI Logic L64802 or Texas Instruments ACT8847"},
-  /* SparcStation SLC, SparcStation1 */
-  { 0, 3, "Weitek WTL3170/2"},
-  /* SPARCstation-5 */
-  { 0, 4, "Lsi Logic/Meiko L64804 or compatible"},
-  { 0, 5, "reserved"},
-  { 0, 6, "reserved"},
-  { 0, 7, "No FPU"},
-  { 1, 0, "ROSS HyperSparc combined IU/FPU"},
-  { 1, 1, "Lsi Logic L64814"},
-  { 1, 2, "Texas Instruments TMS390-C602A"},
-  { 1, 3, "Cypress CY7C602 FPU"},
-  { 1, 4, "reserved"},
-  { 1, 5, "reserved"},
-  { 1, 6, "reserved"},
-  { 1, 7, "No FPU"},
-  { 2, 0, "BIT B5010 or B5110/20 or B5210"},
-  { 2, 1, "reserved"},
-  { 2, 2, "reserved"},
-  { 2, 3, "reserved"},
-  { 2, 4, "reserved"},
-  { 2, 5, "reserved"},
-  { 2, 6, "reserved"},
-  { 2, 7, "No FPU"},
-  /* SuperSparc 50 module */
-  { 4, 0, "SuperSparc on-chip FPU"},
-  /* SparcClassic */
-  { 4, 4, "TI MicroSparc on chip FPU"},
-  { 5, 0, "Matsushita MN10501"},
-  { 5, 1, "reserved"},
-  { 5, 2, "reserved"},
-  { 5, 3, "reserved"},
-  { 5, 4, "reserved"},
-  { 5, 5, "reserved"},
-  { 5, 6, "reserved"},
-  { 5, 7, "No FPU"},
-  { 9, 3, "Fujitsu or Weitek on-chip FPU"},
-};
-
-#define NSPARCFPU  ARRAY_SIZE(linux_sparc_fpu)
-
-static struct cpu_iu_info linux_sparc_chips[] = {
-  /* Sun4/100, 4/200, SLC */
-  { 0, 0, "Fujitsu  MB86900/1A or LSI L64831 SparcKIT-40"},
-  /* borned STP1012PGA */
-  { 0, 4, "Fujitsu  MB86904"},
-  { 0, 5, "Fujitsu TurboSparc MB86907"},
-  /* SparcStation2, SparcServer 490 & 690 */
-  { 1, 0, "LSI Logic Corporation - L64811"},
-  /* SparcStation2 */
-  { 1, 1, "Cypress/ROSS CY7C601"},
-  /* Embedded controller */
-  { 1, 3, "Cypress/ROSS CY7C611"},
-  /* Ross Technologies HyperSparc */
-  { 1, 0xf, "ROSS HyperSparc RT620"},
-  { 1, 0xe, "ROSS HyperSparc RT625 or RT626"},
-  /* ECL Implementation, CRAY S-MP Supercomputer... AIEEE! */
-  /* Someone please write the code to support this beast! ;) */
-  { 2, 0, "Bipolar Integrated Technology - B5010"},
-  { 3, 0, "LSI Logic Corporation - unknown-type"},
-  { 4, 0, "Texas Instruments, Inc. - SuperSparc-(II)"},
-  /* SparcClassic  --  borned STP1010TAB-50*/
-  { 4, 1, "Texas Instruments, Inc. - MicroSparc"},
-  { 4, 2, "Texas Instruments, Inc. - MicroSparc II"},
-  { 4, 3, "Texas Instruments, Inc. - SuperSparc 51"},
-  { 4, 4, "Texas Instruments, Inc. - SuperSparc 61"},
-  { 4, 5, "Texas Instruments, Inc. - unknown"},
-  { 5, 0, "Matsushita - MN10501"},
-  { 6, 0, "Philips Corporation - unknown"},
-  { 7, 0, "Harvest VLSI Design Center, Inc. - unknown"},
-  /* Gallium arsenide 200MHz, BOOOOGOOOOMIPS!!! */
-  { 8, 0, "Systems and Processes Engineering Corporation (SPEC)"},
-  { 9, 0, "Fujitsu or Weitek Power-UP"},
-  { 9, 1, "Fujitsu or Weitek Power-UP"},
-  { 9, 2, "Fujitsu or Weitek Power-UP"},
-  { 9, 3, "Fujitsu or Weitek Power-UP"},
-  { 0xa, 0, "UNKNOWN CPU-VENDOR/TYPE"},
-  { 0xb, 0, "UNKNOWN CPU-VENDOR/TYPE"},
-  { 0xc, 0, "UNKNOWN CPU-VENDOR/TYPE"},
-  { 0xd, 0, "UNKNOWN CPU-VENDOR/TYPE"},
-  { 0xe, 0, "UNKNOWN CPU-VENDOR/TYPE"},
-  { 0xf, 0, "UNKNOWN CPU-VENDOR/TYPE"},
-};
-
-#define NSPARCCHIPS  ARRAY_SIZE(linux_sparc_chips)
-
-char *sparc_cpu_type;
-char *sparc_fpu_type;
-
-unsigned int fsr_storage;
-
-void __cpuinit cpu_probe(void)
-{
-       int psr_impl, psr_vers, fpu_vers;
-       int i, psr;
-
-       psr_impl = ((get_psr()>>28)&0xf);
-       psr_vers = ((get_psr()>>24)&0xf);
-
-       psr = get_psr();
-       put_psr(psr | PSR_EF);
-       fpu_vers = ((get_fsr()>>17)&0x7);
-       put_psr(psr);
-
-       for(i = 0; i<NSPARCCHIPS; i++) {
-               if(linux_sparc_chips[i].psr_impl == psr_impl)
-                       if(linux_sparc_chips[i].psr_vers == psr_vers) {
-                               sparc_cpu_type = linux_sparc_chips[i].cpu_name;
-                               break;
-                       }
-       }
-
-       if(i==NSPARCCHIPS)
-               printk("DEBUG: psr.impl = 0x%x   psr.vers = 0x%x\n", psr_impl, 
-                           psr_vers);
-
-       for(i = 0; i<NSPARCFPU; i++) {
-               if(linux_sparc_fpu[i].psr_impl == psr_impl)
-                       if(linux_sparc_fpu[i].fp_vers == fpu_vers) {
-                               sparc_fpu_type = linux_sparc_fpu[i].fp_name;
-                               break;
-                       }
-       }
-
-       if(i == NSPARCFPU) {
-               printk("DEBUG: psr.impl = 0x%x  fsr.vers = 0x%x\n", psr_impl,
-                           fpu_vers);
-               sparc_fpu_type = linux_sparc_fpu[31].fp_name;
-       }
-}
diff --git a/arch/sparc/kernel/cpu_32.c b/arch/sparc/kernel/cpu_32.c
new file mode 100644 (file)
index 0000000..1fc17f5
--- /dev/null
@@ -0,0 +1,167 @@
+/* cpu.c: Dinky routines to look for the kind of Sparc cpu
+ *        we are on.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/threads.h>
+#include <asm/oplib.h>
+#include <asm/page.h>
+#include <asm/head.h>
+#include <asm/psr.h>
+#include <asm/mbus.h>
+#include <asm/cpudata.h>
+
+DEFINE_PER_CPU(cpuinfo_sparc, __cpu_data) = { 0 };
+
+struct cpu_iu_info {
+  int psr_impl;
+  int psr_vers;
+  char* cpu_name;   /* should be enough I hope... */
+};
+
+struct cpu_fp_info {
+  int psr_impl;
+  int fp_vers;
+  char* fp_name;
+};
+
+/* In order to get the fpu type correct, you need to take the IDPROM's
+ * machine type value into consideration too.  I will fix this.
+ */
+static struct cpu_fp_info linux_sparc_fpu[] = {
+  { 0, 0, "Fujitsu MB86910 or Weitek WTL1164/5"},
+  { 0, 1, "Fujitsu MB86911 or Weitek WTL1164/5 or LSI L64831"},
+  { 0, 2, "LSI Logic L64802 or Texas Instruments ACT8847"},
+  /* SparcStation SLC, SparcStation1 */
+  { 0, 3, "Weitek WTL3170/2"},
+  /* SPARCstation-5 */
+  { 0, 4, "Lsi Logic/Meiko L64804 or compatible"},
+  { 0, 5, "reserved"},
+  { 0, 6, "reserved"},
+  { 0, 7, "No FPU"},
+  { 1, 0, "ROSS HyperSparc combined IU/FPU"},
+  { 1, 1, "Lsi Logic L64814"},
+  { 1, 2, "Texas Instruments TMS390-C602A"},
+  { 1, 3, "Cypress CY7C602 FPU"},
+  { 1, 4, "reserved"},
+  { 1, 5, "reserved"},
+  { 1, 6, "reserved"},
+  { 1, 7, "No FPU"},
+  { 2, 0, "BIT B5010 or B5110/20 or B5210"},
+  { 2, 1, "reserved"},
+  { 2, 2, "reserved"},
+  { 2, 3, "reserved"},
+  { 2, 4, "reserved"},
+  { 2, 5, "reserved"},
+  { 2, 6, "reserved"},
+  { 2, 7, "No FPU"},
+  /* SuperSparc 50 module */
+  { 4, 0, "SuperSparc on-chip FPU"},
+  /* SparcClassic */
+  { 4, 4, "TI MicroSparc on chip FPU"},
+  { 5, 0, "Matsushita MN10501"},
+  { 5, 1, "reserved"},
+  { 5, 2, "reserved"},
+  { 5, 3, "reserved"},
+  { 5, 4, "reserved"},
+  { 5, 5, "reserved"},
+  { 5, 6, "reserved"},
+  { 5, 7, "No FPU"},
+  { 9, 3, "Fujitsu or Weitek on-chip FPU"},
+};
+
+#define NSPARCFPU  ARRAY_SIZE(linux_sparc_fpu)
+
+static struct cpu_iu_info linux_sparc_chips[] = {
+  /* Sun4/100, 4/200, SLC */
+  { 0, 0, "Fujitsu  MB86900/1A or LSI L64831 SparcKIT-40"},
+  /* borned STP1012PGA */
+  { 0, 4, "Fujitsu  MB86904"},
+  { 0, 5, "Fujitsu TurboSparc MB86907"},
+  /* SparcStation2, SparcServer 490 & 690 */
+  { 1, 0, "LSI Logic Corporation - L64811"},
+  /* SparcStation2 */
+  { 1, 1, "Cypress/ROSS CY7C601"},
+  /* Embedded controller */
+  { 1, 3, "Cypress/ROSS CY7C611"},
+  /* Ross Technologies HyperSparc */
+  { 1, 0xf, "ROSS HyperSparc RT620"},
+  { 1, 0xe, "ROSS HyperSparc RT625 or RT626"},
+  /* ECL Implementation, CRAY S-MP Supercomputer... AIEEE! */
+  /* Someone please write the code to support this beast! ;) */
+  { 2, 0, "Bipolar Integrated Technology - B5010"},
+  { 3, 0, "LSI Logic Corporation - unknown-type"},
+  { 4, 0, "Texas Instruments, Inc. - SuperSparc-(II)"},
+  /* SparcClassic  --  borned STP1010TAB-50*/
+  { 4, 1, "Texas Instruments, Inc. - MicroSparc"},
+  { 4, 2, "Texas Instruments, Inc. - MicroSparc II"},
+  { 4, 3, "Texas Instruments, Inc. - SuperSparc 51"},
+  { 4, 4, "Texas Instruments, Inc. - SuperSparc 61"},
+  { 4, 5, "Texas Instruments, Inc. - unknown"},
+  { 5, 0, "Matsushita - MN10501"},
+  { 6, 0, "Philips Corporation - unknown"},
+  { 7, 0, "Harvest VLSI Design Center, Inc. - unknown"},
+  /* Gallium arsenide 200MHz, BOOOOGOOOOMIPS!!! */
+  { 8, 0, "Systems and Processes Engineering Corporation (SPEC)"},
+  { 9, 0, "Fujitsu or Weitek Power-UP"},
+  { 9, 1, "Fujitsu or Weitek Power-UP"},
+  { 9, 2, "Fujitsu or Weitek Power-UP"},
+  { 9, 3, "Fujitsu or Weitek Power-UP"},
+  { 0xa, 0, "UNKNOWN CPU-VENDOR/TYPE"},
+  { 0xb, 0, "UNKNOWN CPU-VENDOR/TYPE"},
+  { 0xc, 0, "UNKNOWN CPU-VENDOR/TYPE"},
+  { 0xd, 0, "UNKNOWN CPU-VENDOR/TYPE"},
+  { 0xe, 0, "UNKNOWN CPU-VENDOR/TYPE"},
+  { 0xf, 0, "UNKNOWN CPU-VENDOR/TYPE"},
+};
+
+#define NSPARCCHIPS  ARRAY_SIZE(linux_sparc_chips)
+
+char *sparc_cpu_type;
+char *sparc_fpu_type;
+
+unsigned int fsr_storage;
+
+void __cpuinit cpu_probe(void)
+{
+       int psr_impl, psr_vers, fpu_vers;
+       int i, psr;
+
+       psr_impl = ((get_psr()>>28)&0xf);
+       psr_vers = ((get_psr()>>24)&0xf);
+
+       psr = get_psr();
+       put_psr(psr | PSR_EF);
+       fpu_vers = ((get_fsr()>>17)&0x7);
+       put_psr(psr);
+
+       for(i = 0; i<NSPARCCHIPS; i++) {
+               if(linux_sparc_chips[i].psr_impl == psr_impl)
+                       if(linux_sparc_chips[i].psr_vers == psr_vers) {
+                               sparc_cpu_type = linux_sparc_chips[i].cpu_name;
+                               break;
+                       }
+       }
+
+       if(i==NSPARCCHIPS)
+               printk("DEBUG: psr.impl = 0x%x   psr.vers = 0x%x\n", psr_impl, 
+                           psr_vers);
+
+       for(i = 0; i<NSPARCFPU; i++) {
+               if(linux_sparc_fpu[i].psr_impl == psr_impl)
+                       if(linux_sparc_fpu[i].fp_vers == fpu_vers) {
+                               sparc_fpu_type = linux_sparc_fpu[i].fp_name;
+                               break;
+                       }
+       }
+
+       if(i == NSPARCFPU) {
+               printk("DEBUG: psr.impl = 0x%x  fsr.vers = 0x%x\n", psr_impl,
+                           fpu_vers);
+               sparc_fpu_type = linux_sparc_fpu[31].fp_name;
+       }
+}
diff --git a/arch/sparc/kernel/etrap.S b/arch/sparc/kernel/etrap.S
deleted file mode 100644 (file)
index e806fcd..0000000
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- * etrap.S: Sparc trap window preparation for entry into the
- *          Linux kernel.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <asm/head.h>
-#include <asm/asi.h>
-#include <asm/contregs.h>
-#include <asm/page.h>
-#include <asm/psr.h>
-#include <asm/ptrace.h>
-#include <asm/winmacro.h>
-#include <asm/asmmacro.h>
-#include <asm/thread_info.h>
-
-/* Registers to not touch at all. */
-#define t_psr        l0 /* Set by caller */
-#define t_pc         l1 /* Set by caller */
-#define t_npc        l2 /* Set by caller */
-#define t_wim        l3 /* Set by caller */
-#define t_twinmask   l4 /* Set at beginning of this entry routine. */
-#define t_kstack     l5 /* Set right before pt_regs frame is built */
-#define t_retpc      l6 /* If you change this, change winmacro.h header file */
-#define t_systable   l7 /* Never touch this, could be the syscall table ptr. */
-#define curptr       g6 /* Set after pt_regs frame is built */
-
-       .text
-       .align 4
-
-       /* SEVEN WINDOW PATCH INSTRUCTIONS */
-       .globl  tsetup_7win_patch1, tsetup_7win_patch2
-       .globl  tsetup_7win_patch3, tsetup_7win_patch4
-       .globl  tsetup_7win_patch5, tsetup_7win_patch6
-tsetup_7win_patch1:    sll     %t_wim, 0x6, %t_wim
-tsetup_7win_patch2:    and     %g2, 0x7f, %g2
-tsetup_7win_patch3:    and     %g2, 0x7f, %g2
-tsetup_7win_patch4:    and     %g1, 0x7f, %g1
-tsetup_7win_patch5:    sll     %t_wim, 0x6, %t_wim
-tsetup_7win_patch6:    and     %g2, 0x7f, %g2
-       /* END OF PATCH INSTRUCTIONS */
-
-       /* At trap time, interrupts and all generic traps do the
-        * following:
-        *
-        * rd   %psr, %l0
-        * b    some_handler
-        * rd   %wim, %l3
-        * nop
-        *
-        * Then 'some_handler' if it needs a trap frame (ie. it has
-        * to call c-code and the trap cannot be handled in-window)
-        * then it does the SAVE_ALL macro in entry.S which does
-        *
-        * sethi        %hi(trap_setup), %l4
-        * jmpl         %l4 + %lo(trap_setup), %l6
-        * nop
-        */
-
-       /* 2 3 4  window number
-        * -----
-        * O T S  mnemonic
-        *
-        * O == Current window before trap
-        * T == Window entered when trap occurred
-        * S == Window we will need to save if (1<<T) == %wim
-        *
-        * Before execution gets here, it must be guaranteed that
-        * %l0 contains trap time %psr, %l1 and %l2 contain the
-        * trap pc and npc, and %l3 contains the trap time %wim.
-        */
-
-       .globl  trap_setup, tsetup_patch1, tsetup_patch2
-       .globl  tsetup_patch3, tsetup_patch4
-       .globl  tsetup_patch5, tsetup_patch6
-trap_setup:
-       /* Calculate mask of trap window.  See if from user
-        * or kernel and branch conditionally.
-        */
-       mov     1, %t_twinmask
-       andcc   %t_psr, PSR_PS, %g0              ! fromsupv_p = (psr & PSR_PS)
-       be      trap_setup_from_user             ! nope, from user mode
-        sll    %t_twinmask, %t_psr, %t_twinmask ! t_twinmask = (1 << psr)
-
-       /* From kernel, allocate more kernel stack and
-        * build a pt_regs trap frame.
-        */
-       sub     %fp, (STACKFRAME_SZ + TRACEREG_SZ), %t_kstack
-       STORE_PT_ALL(t_kstack, t_psr, t_pc, t_npc, g2)
-
-       /* See if we are in the trap window. */
-       andcc   %t_twinmask, %t_wim, %g0
-       bne     trap_setup_kernel_spill         ! in trap window, clean up
-        nop
-
-       /* Trap from kernel with a window available.
-        * Just do it...
-        */
-       jmpl    %t_retpc + 0x8, %g0     ! return to caller
-        mov    %t_kstack, %sp          ! jump onto new stack
-
-trap_setup_kernel_spill:
-       ld      [%curptr + TI_UWINMASK], %g1
-       orcc    %g0, %g1, %g0
-       bne     trap_setup_user_spill   ! there are some user windows, yuck
-       /* Spill from kernel, but only kernel windows, adjust
-        * %wim and go.
-        */
-        srl    %t_wim, 0x1, %g2        ! begin computation of new %wim
-tsetup_patch1:
-       sll     %t_wim, 0x7, %t_wim     ! patched on 7 window Sparcs
-       or      %t_wim, %g2, %g2
-tsetup_patch2:
-       and     %g2, 0xff, %g2          ! patched on 7 window Sparcs
-
-       save    %g0, %g0, %g0
-
-       /* Set new %wim value */
-       wr      %g2, 0x0, %wim
-
-       /* Save the kernel window onto the corresponding stack. */
-       STORE_WINDOW(sp)
-
-       restore %g0, %g0, %g0
-
-       jmpl    %t_retpc + 0x8, %g0     ! return to caller
-        mov    %t_kstack, %sp          ! and onto new kernel stack
-
-#define STACK_OFFSET (THREAD_SIZE - TRACEREG_SZ - STACKFRAME_SZ)
-
-trap_setup_from_user:
-       /* We can't use %curptr yet. */
-       LOAD_CURRENT(t_kstack, t_twinmask)
-
-       sethi   %hi(STACK_OFFSET), %t_twinmask
-       or      %t_twinmask, %lo(STACK_OFFSET), %t_twinmask
-       add     %t_kstack, %t_twinmask, %t_kstack
-
-       mov     1, %t_twinmask
-       sll     %t_twinmask, %t_psr, %t_twinmask ! t_twinmask = (1 << psr)
-
-       /* Build pt_regs frame. */
-       STORE_PT_ALL(t_kstack, t_psr, t_pc, t_npc, g2)
-
-#if 0
-       /* If we're sure every task_struct is THREAD_SIZE aligned,
-          we can speed this up. */
-       sethi   %hi(STACK_OFFSET), %curptr
-       or      %curptr, %lo(STACK_OFFSET), %curptr
-       sub     %t_kstack, %curptr, %curptr
-#else
-       sethi   %hi(~(THREAD_SIZE - 1)), %curptr
-       and     %t_kstack, %curptr, %curptr
-#endif
-
-       /* Clear current_thread_info->w_saved */
-       st      %g0, [%curptr + TI_W_SAVED]
-
-       /* See if we are in the trap window. */
-       andcc   %t_twinmask, %t_wim, %g0
-       bne     trap_setup_user_spill           ! yep we are
-        orn    %g0, %t_twinmask, %g1           ! negate trap win mask into %g1
-
-       /* Trap from user, but not into the invalid window.
-        * Calculate new umask.  The way this works is,
-        * any window from the %wim at trap time until
-        * the window right before the one we are in now,
-        * is a user window.  A diagram:
-        *
-        *      7 6 5 4 3 2 1 0    window number
-        *      ---------------
-        *        I     L T        mnemonic
-        *
-        * Window 'I' is the invalid window in our example,
-        * window 'L' is the window the user was in when
-        * the trap occurred, window T is the trap window
-        * we are in now.  So therefore, windows 5, 4 and
-        * 3 are user windows.  The following sequence
-        * computes the user winmask to represent this.
-        */
-       subcc   %t_wim, %t_twinmask, %g2
-       bneg,a  1f
-        sub    %g2, 0x1, %g2
-1:
-       andn    %g2, %t_twinmask, %g2
-tsetup_patch3:
-       and     %g2, 0xff, %g2                  ! patched on 7win Sparcs
-       st      %g2, [%curptr + TI_UWINMASK]    ! store new umask
-
-       jmpl    %t_retpc + 0x8, %g0             ! return to caller
-        mov    %t_kstack, %sp                  ! and onto kernel stack
-
-trap_setup_user_spill:
-       /* A spill occurred from either kernel or user mode
-        * and there exist some user windows to deal with.
-        * A mask of the currently valid user windows
-        * is in %g1 upon entry to here.
-        */
-
-tsetup_patch4:
-       and     %g1, 0xff, %g1          ! patched on 7win Sparcs, mask
-       srl     %t_wim, 0x1, %g2        ! compute new %wim
-tsetup_patch5:
-       sll     %t_wim, 0x7, %t_wim     ! patched on 7win Sparcs
-       or      %t_wim, %g2, %g2        ! %g2 is new %wim
-tsetup_patch6:
-       and     %g2, 0xff, %g2          ! patched on 7win Sparcs
-       andn    %g1, %g2, %g1           ! clear this bit in %g1
-       st      %g1, [%curptr + TI_UWINMASK]
-
-       save    %g0, %g0, %g0
-
-       wr      %g2, 0x0, %wim
-
-       /* Call MMU-architecture dependent stack checking
-        * routine.
-        */
-       .globl  tsetup_mmu_patchme
-tsetup_mmu_patchme:
-       b       tsetup_sun4c_stackchk
-        andcc  %sp, 0x7, %g0
-
-       /* Architecture specific stack checking routines.  When either
-        * of these routines are called, the globals are free to use
-        * as they have been safely stashed on the new kernel stack
-        * pointer.  Thus the definition below for simplicity.
-        */
-#define glob_tmp     g1
-
-tsetup_sun4c_stackchk:
-       /* Done by caller: andcc %sp, 0x7, %g0 */
-       bne     trap_setup_user_stack_is_bolixed
-        sra    %sp, 29, %glob_tmp
-
-       add     %glob_tmp, 0x1, %glob_tmp
-       andncc  %glob_tmp, 0x1, %g0
-       bne     trap_setup_user_stack_is_bolixed
-        and    %sp, 0xfff, %glob_tmp           ! delay slot
-
-       /* See if our dump area will be on more than one
-        * page.
-        */
-       add     %glob_tmp, 0x38, %glob_tmp
-       andncc  %glob_tmp, 0xff8, %g0
-       be      tsetup_sun4c_onepage            ! only one page to check
-        lda    [%sp] ASI_PTE, %glob_tmp        ! have to check first page anyways
-
-tsetup_sun4c_twopages:
-       /* Is first page ok permission wise? */
-       srl     %glob_tmp, 29, %glob_tmp
-       cmp     %glob_tmp, 0x6
-       bne     trap_setup_user_stack_is_bolixed
-        add    %sp, 0x38, %glob_tmp            /* Is second page in vma hole? */
-
-       sra     %glob_tmp, 29, %glob_tmp
-       add     %glob_tmp, 0x1, %glob_tmp
-       andncc  %glob_tmp, 0x1, %g0
-       bne     trap_setup_user_stack_is_bolixed
-        add    %sp, 0x38, %glob_tmp
-
-       lda     [%glob_tmp] ASI_PTE, %glob_tmp
-
-tsetup_sun4c_onepage:
-       srl     %glob_tmp, 29, %glob_tmp
-       cmp     %glob_tmp, 0x6                          ! can user write to it?
-       bne     trap_setup_user_stack_is_bolixed        ! failure
-        nop
-
-       STORE_WINDOW(sp)
-
-       restore %g0, %g0, %g0
-
-       jmpl    %t_retpc + 0x8, %g0
-        mov    %t_kstack, %sp
-
-       .globl  tsetup_srmmu_stackchk
-tsetup_srmmu_stackchk:
-       /* Check results of callers andcc %sp, 0x7, %g0 */
-       bne     trap_setup_user_stack_is_bolixed
-        sethi   %hi(PAGE_OFFSET), %glob_tmp
-
-       cmp     %glob_tmp, %sp
-       bleu,a  1f
-        lda    [%g0] ASI_M_MMUREGS, %glob_tmp          ! read MMU control
-
-trap_setup_user_stack_is_bolixed:
-       /* From user/kernel into invalid window w/bad user
-        * stack. Save bad user stack, and return to caller.
-        */
-       SAVE_BOLIXED_USER_STACK(curptr, g3)
-       restore %g0, %g0, %g0
-
-       jmpl    %t_retpc + 0x8, %g0
-        mov    %t_kstack, %sp
-
-1:
-       /* Clear the fault status and turn on the no_fault bit. */
-       or      %glob_tmp, 0x2, %glob_tmp               ! or in no_fault bit
-       sta     %glob_tmp, [%g0] ASI_M_MMUREGS          ! set it
-
-       /* Dump the registers and cross fingers. */
-       STORE_WINDOW(sp)
-
-       /* Clear the no_fault bit and check the status. */
-       andn    %glob_tmp, 0x2, %glob_tmp
-       sta     %glob_tmp, [%g0] ASI_M_MMUREGS
-       mov     AC_M_SFAR, %glob_tmp
-       lda     [%glob_tmp] ASI_M_MMUREGS, %g0
-       mov     AC_M_SFSR, %glob_tmp
-       lda     [%glob_tmp] ASI_M_MMUREGS, %glob_tmp    ! save away status of winstore
-       andcc   %glob_tmp, 0x2, %g0                     ! did we fault?
-       bne     trap_setup_user_stack_is_bolixed        ! failure
-        nop
-
-       restore %g0, %g0, %g0
-
-       jmpl    %t_retpc + 0x8, %g0
-        mov    %t_kstack, %sp
-
diff --git a/arch/sparc/kernel/etrap_32.S b/arch/sparc/kernel/etrap_32.S
new file mode 100644 (file)
index 0000000..e806fcd
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ * etrap.S: Sparc trap window preparation for entry into the
+ *          Linux kernel.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/head.h>
+#include <asm/asi.h>
+#include <asm/contregs.h>
+#include <asm/page.h>
+#include <asm/psr.h>
+#include <asm/ptrace.h>
+#include <asm/winmacro.h>
+#include <asm/asmmacro.h>
+#include <asm/thread_info.h>
+
+/* Registers to not touch at all. */
+#define t_psr        l0 /* Set by caller */
+#define t_pc         l1 /* Set by caller */
+#define t_npc        l2 /* Set by caller */
+#define t_wim        l3 /* Set by caller */
+#define t_twinmask   l4 /* Set at beginning of this entry routine. */
+#define t_kstack     l5 /* Set right before pt_regs frame is built */
+#define t_retpc      l6 /* If you change this, change winmacro.h header file */
+#define t_systable   l7 /* Never touch this, could be the syscall table ptr. */
+#define curptr       g6 /* Set after pt_regs frame is built */
+
+       .text
+       .align 4
+
+       /* SEVEN WINDOW PATCH INSTRUCTIONS */
+       .globl  tsetup_7win_patch1, tsetup_7win_patch2
+       .globl  tsetup_7win_patch3, tsetup_7win_patch4
+       .globl  tsetup_7win_patch5, tsetup_7win_patch6
+tsetup_7win_patch1:    sll     %t_wim, 0x6, %t_wim
+tsetup_7win_patch2:    and     %g2, 0x7f, %g2
+tsetup_7win_patch3:    and     %g2, 0x7f, %g2
+tsetup_7win_patch4:    and     %g1, 0x7f, %g1
+tsetup_7win_patch5:    sll     %t_wim, 0x6, %t_wim
+tsetup_7win_patch6:    and     %g2, 0x7f, %g2
+       /* END OF PATCH INSTRUCTIONS */
+
+       /* At trap time, interrupts and all generic traps do the
+        * following:
+        *
+        * rd   %psr, %l0
+        * b    some_handler
+        * rd   %wim, %l3
+        * nop
+        *
+        * Then 'some_handler' if it needs a trap frame (ie. it has
+        * to call c-code and the trap cannot be handled in-window)
+        * then it does the SAVE_ALL macro in entry.S which does
+        *
+        * sethi        %hi(trap_setup), %l4
+        * jmpl         %l4 + %lo(trap_setup), %l6
+        * nop
+        */
+
+       /* 2 3 4  window number
+        * -----
+        * O T S  mnemonic
+        *
+        * O == Current window before trap
+        * T == Window entered when trap occurred
+        * S == Window we will need to save if (1<<T) == %wim
+        *
+        * Before execution gets here, it must be guaranteed that
+        * %l0 contains trap time %psr, %l1 and %l2 contain the
+        * trap pc and npc, and %l3 contains the trap time %wim.
+        */
+
+       .globl  trap_setup, tsetup_patch1, tsetup_patch2
+       .globl  tsetup_patch3, tsetup_patch4
+       .globl  tsetup_patch5, tsetup_patch6
+trap_setup:
+       /* Calculate mask of trap window.  See if from user
+        * or kernel and branch conditionally.
+        */
+       mov     1, %t_twinmask
+       andcc   %t_psr, PSR_PS, %g0              ! fromsupv_p = (psr & PSR_PS)
+       be      trap_setup_from_user             ! nope, from user mode
+        sll    %t_twinmask, %t_psr, %t_twinmask ! t_twinmask = (1 << psr)
+
+       /* From kernel, allocate more kernel stack and
+        * build a pt_regs trap frame.
+        */
+       sub     %fp, (STACKFRAME_SZ + TRACEREG_SZ), %t_kstack
+       STORE_PT_ALL(t_kstack, t_psr, t_pc, t_npc, g2)
+
+       /* See if we are in the trap window. */
+       andcc   %t_twinmask, %t_wim, %g0
+       bne     trap_setup_kernel_spill         ! in trap window, clean up
+        nop
+
+       /* Trap from kernel with a window available.
+        * Just do it...
+        */
+       jmpl    %t_retpc + 0x8, %g0     ! return to caller
+        mov    %t_kstack, %sp          ! jump onto new stack
+
+trap_setup_kernel_spill:
+       ld      [%curptr + TI_UWINMASK], %g1
+       orcc    %g0, %g1, %g0
+       bne     trap_setup_user_spill   ! there are some user windows, yuck
+       /* Spill from kernel, but only kernel windows, adjust
+        * %wim and go.
+        */
+        srl    %t_wim, 0x1, %g2        ! begin computation of new %wim
+tsetup_patch1:
+       sll     %t_wim, 0x7, %t_wim     ! patched on 7 window Sparcs
+       or      %t_wim, %g2, %g2
+tsetup_patch2:
+       and     %g2, 0xff, %g2          ! patched on 7 window Sparcs
+
+       save    %g0, %g0, %g0
+
+       /* Set new %wim value */
+       wr      %g2, 0x0, %wim
+
+       /* Save the kernel window onto the corresponding stack. */
+       STORE_WINDOW(sp)
+
+       restore %g0, %g0, %g0
+
+       jmpl    %t_retpc + 0x8, %g0     ! return to caller
+        mov    %t_kstack, %sp          ! and onto new kernel stack
+
+#define STACK_OFFSET (THREAD_SIZE - TRACEREG_SZ - STACKFRAME_SZ)
+
+trap_setup_from_user:
+       /* We can't use %curptr yet. */
+       LOAD_CURRENT(t_kstack, t_twinmask)
+
+       sethi   %hi(STACK_OFFSET), %t_twinmask
+       or      %t_twinmask, %lo(STACK_OFFSET), %t_twinmask
+       add     %t_kstack, %t_twinmask, %t_kstack
+
+       mov     1, %t_twinmask
+       sll     %t_twinmask, %t_psr, %t_twinmask ! t_twinmask = (1 << psr)
+
+       /* Build pt_regs frame. */
+       STORE_PT_ALL(t_kstack, t_psr, t_pc, t_npc, g2)
+
+#if 0
+       /* If we're sure every task_struct is THREAD_SIZE aligned,
+          we can speed this up. */
+       sethi   %hi(STACK_OFFSET), %curptr
+       or      %curptr, %lo(STACK_OFFSET), %curptr
+       sub     %t_kstack, %curptr, %curptr
+#else
+       sethi   %hi(~(THREAD_SIZE - 1)), %curptr
+       and     %t_kstack, %curptr, %curptr
+#endif
+
+       /* Clear current_thread_info->w_saved */
+       st      %g0, [%curptr + TI_W_SAVED]
+
+       /* See if we are in the trap window. */
+       andcc   %t_twinmask, %t_wim, %g0
+       bne     trap_setup_user_spill           ! yep we are
+        orn    %g0, %t_twinmask, %g1           ! negate trap win mask into %g1
+
+       /* Trap from user, but not into the invalid window.
+        * Calculate new umask.  The way this works is,
+        * any window from the %wim at trap time until
+        * the window right before the one we are in now,
+        * is a user window.  A diagram:
+        *
+        *      7 6 5 4 3 2 1 0    window number
+        *      ---------------
+        *        I     L T        mnemonic
+        *
+        * Window 'I' is the invalid window in our example,
+        * window 'L' is the window the user was in when
+        * the trap occurred, window T is the trap window
+        * we are in now.  So therefore, windows 5, 4 and
+        * 3 are user windows.  The following sequence
+        * computes the user winmask to represent this.
+        */
+       subcc   %t_wim, %t_twinmask, %g2
+       bneg,a  1f
+        sub    %g2, 0x1, %g2
+1:
+       andn    %g2, %t_twinmask, %g2
+tsetup_patch3:
+       and     %g2, 0xff, %g2                  ! patched on 7win Sparcs
+       st      %g2, [%curptr + TI_UWINMASK]    ! store new umask
+
+       jmpl    %t_retpc + 0x8, %g0             ! return to caller
+        mov    %t_kstack, %sp                  ! and onto kernel stack
+
+trap_setup_user_spill:
+       /* A spill occurred from either kernel or user mode
+        * and there exist some user windows to deal with.
+        * A mask of the currently valid user windows
+        * is in %g1 upon entry to here.
+        */
+
+tsetup_patch4:
+       and     %g1, 0xff, %g1          ! patched on 7win Sparcs, mask
+       srl     %t_wim, 0x1, %g2        ! compute new %wim
+tsetup_patch5:
+       sll     %t_wim, 0x7, %t_wim     ! patched on 7win Sparcs
+       or      %t_wim, %g2, %g2        ! %g2 is new %wim
+tsetup_patch6:
+       and     %g2, 0xff, %g2          ! patched on 7win Sparcs
+       andn    %g1, %g2, %g1           ! clear this bit in %g1
+       st      %g1, [%curptr + TI_UWINMASK]
+
+       save    %g0, %g0, %g0
+
+       wr      %g2, 0x0, %wim
+
+       /* Call MMU-architecture dependent stack checking
+        * routine.
+        */
+       .globl  tsetup_mmu_patchme
+tsetup_mmu_patchme:
+       b       tsetup_sun4c_stackchk
+        andcc  %sp, 0x7, %g0
+
+       /* Architecture specific stack checking routines.  When either
+        * of these routines are called, the globals are free to use
+        * as they have been safely stashed on the new kernel stack
+        * pointer.  Thus the definition below for simplicity.
+        */
+#define glob_tmp     g1
+
+tsetup_sun4c_stackchk:
+       /* Done by caller: andcc %sp, 0x7, %g0 */
+       bne     trap_setup_user_stack_is_bolixed
+        sra    %sp, 29, %glob_tmp
+
+       add     %glob_tmp, 0x1, %glob_tmp
+       andncc  %glob_tmp, 0x1, %g0
+       bne     trap_setup_user_stack_is_bolixed
+        and    %sp, 0xfff, %glob_tmp           ! delay slot
+
+       /* See if our dump area will be on more than one
+        * page.
+        */
+       add     %glob_tmp, 0x38, %glob_tmp
+       andncc  %glob_tmp, 0xff8, %g0
+       be      tsetup_sun4c_onepage            ! only one page to check
+        lda    [%sp] ASI_PTE, %glob_tmp        ! have to check first page anyways
+
+tsetup_sun4c_twopages:
+       /* Is first page ok permission wise? */
+       srl     %glob_tmp, 29, %glob_tmp
+       cmp     %glob_tmp, 0x6
+       bne     trap_setup_user_stack_is_bolixed
+        add    %sp, 0x38, %glob_tmp            /* Is second page in vma hole? */
+
+       sra     %glob_tmp, 29, %glob_tmp
+       add     %glob_tmp, 0x1, %glob_tmp
+       andncc  %glob_tmp, 0x1, %g0
+       bne     trap_setup_user_stack_is_bolixed
+        add    %sp, 0x38, %glob_tmp
+
+       lda     [%glob_tmp] ASI_PTE, %glob_tmp
+
+tsetup_sun4c_onepage:
+       srl     %glob_tmp, 29, %glob_tmp
+       cmp     %glob_tmp, 0x6                          ! can user write to it?
+       bne     trap_setup_user_stack_is_bolixed        ! failure
+        nop
+
+       STORE_WINDOW(sp)
+
+       restore %g0, %g0, %g0
+
+       jmpl    %t_retpc + 0x8, %g0
+        mov    %t_kstack, %sp
+
+       .globl  tsetup_srmmu_stackchk
+tsetup_srmmu_stackchk:
+       /* Check results of callers andcc %sp, 0x7, %g0 */
+       bne     trap_setup_user_stack_is_bolixed
+        sethi   %hi(PAGE_OFFSET), %glob_tmp
+
+       cmp     %glob_tmp, %sp
+       bleu,a  1f
+        lda    [%g0] ASI_M_MMUREGS, %glob_tmp          ! read MMU control
+
+trap_setup_user_stack_is_bolixed:
+       /* From user/kernel into invalid window w/bad user
+        * stack. Save bad user stack, and return to caller.
+        */
+       SAVE_BOLIXED_USER_STACK(curptr, g3)
+       restore %g0, %g0, %g0
+
+       jmpl    %t_retpc + 0x8, %g0
+        mov    %t_kstack, %sp
+
+1:
+       /* Clear the fault status and turn on the no_fault bit. */
+       or      %glob_tmp, 0x2, %glob_tmp               ! or in no_fault bit
+       sta     %glob_tmp, [%g0] ASI_M_MMUREGS          ! set it
+
+       /* Dump the registers and cross fingers. */
+       STORE_WINDOW(sp)
+
+       /* Clear the no_fault bit and check the status. */
+       andn    %glob_tmp, 0x2, %glob_tmp
+       sta     %glob_tmp, [%g0] ASI_M_MMUREGS
+       mov     AC_M_SFAR, %glob_tmp
+       lda     [%glob_tmp] ASI_M_MMUREGS, %g0
+       mov     AC_M_SFSR, %glob_tmp
+       lda     [%glob_tmp] ASI_M_MMUREGS, %glob_tmp    ! save away status of winstore
+       andcc   %glob_tmp, 0x2, %g0                     ! did we fault?
+       bne     trap_setup_user_stack_is_bolixed        ! failure
+        nop
+
+       restore %g0, %g0, %g0
+
+       jmpl    %t_retpc + 0x8, %g0
+        mov    %t_kstack, %sp
+
diff --git a/arch/sparc/kernel/head.S b/arch/sparc/kernel/head.S
deleted file mode 100644 (file)
index 51b4042..0000000
+++ /dev/null
@@ -1,1295 +0,0 @@
-/*
- * head.S: The initial boot code for the Sparc port of Linux.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1995,1999 Pete Zaitcev   (zaitcev@yahoo.com)
- * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
- * Copyright (C) 1997 Jakub Jelinek   (jj@sunsite.mff.cuni.cz)
- * Copyright (C) 1997 Michael A. Griffith (grif@acm.org)
- *
- * CompactPCI platform by Eric Brower, 1999.
- */
-
-#include <linux/version.h>
-#include <linux/init.h>
-
-#include <asm/head.h>
-#include <asm/asi.h>
-#include <asm/contregs.h>
-#include <asm/ptrace.h>
-#include <asm/psr.h>
-#include <asm/page.h>
-#include <asm/kdebug.h>
-#include <asm/winmacro.h>
-#include <asm/thread_info.h>   /* TI_UWINMASK */
-#include <asm/errno.h>
-#include <asm/pgtsrmmu.h>      /* SRMMU_PGDIR_SHIFT */
-
-       .data
-/* 
- * The following are used with the prom_vector node-ops to figure out
- * the cpu-type 
- */
-
-       .align 4
-cputyp:
-        .word   1
-
-       .align 4
-       .globl cputypval
-cputypval:
-       .asciz "sun4c"
-       .ascii "     "
-
-cputypvalend:
-cputypvallen = cputypvar - cputypval
-
-       .align 4
-/*
- * Sun people can't spell worth damn. "compatability" indeed.
- * At least we *know* we can't spell, and use a spell-checker.
- */
-
-/* Uh, actually Linus it is I who cannot spell. Too much murky
- * Sparc assembly will do this to ya.
- */
-cputypvar:
-       .asciz "compatability"
-
-/* Tested on SS-5, SS-10. Probably someone at Sun applied a spell-checker. */
-       .align 4
-cputypvar_sun4m:
-       .asciz "compatible"
-
-       .align 4
-
-sun4_notsup:
-       .asciz  "Sparc-Linux sun4 support does no longer exist.\n\n"
-       .align 4
-
-sun4e_notsup:
-        .asciz  "Sparc-Linux sun4e support does not exist\n\n"
-       .align 4
-
-       /* The Sparc trap table, bootloader gives us control at _start. */
-       .section .text.head,"ax"
-       .globl  start, _stext, _start, __stext
-       .globl  trapbase
-_start:   /* danger danger */
-__stext:
-_stext:
-start:
-trapbase:
-#ifdef CONFIG_SMP
-trapbase_cpu0:
-#endif
-/* We get control passed to us here at t_zero. */
-t_zero:        b gokernel; nop; nop; nop;
-t_tflt:        SPARC_TFAULT                        /* Inst. Access Exception        */
-t_bins:        TRAP_ENTRY(0x2, bad_instruction)    /* Illegal Instruction           */
-t_pins:        TRAP_ENTRY(0x3, priv_instruction)   /* Privileged Instruction        */
-t_fpd: TRAP_ENTRY(0x4, fpd_trap_handler)   /* Floating Point Disabled       */
-t_wovf:        WINDOW_SPILL                        /* Window Overflow               */
-t_wunf:        WINDOW_FILL                         /* Window Underflow              */
-t_mna: TRAP_ENTRY(0x7, mna_handler)        /* Memory Address Not Aligned    */
-t_fpe: TRAP_ENTRY(0x8, fpe_trap_handler)   /* Floating Point Exception      */
-t_dflt:        SPARC_DFAULT                        /* Data Miss Exception           */
-t_tio: TRAP_ENTRY(0xa, do_tag_overflow)    /* Tagged Instruction Ovrflw     */
-t_wpt: TRAP_ENTRY(0xb, do_watchpoint)      /* Watchpoint Detected           */
-t_badc:        BAD_TRAP(0xc) BAD_TRAP(0xd) BAD_TRAP(0xe) BAD_TRAP(0xf) BAD_TRAP(0x10)
-t_irq1:        TRAP_ENTRY_INTERRUPT(1)             /* IRQ Software/SBUS Level 1     */
-t_irq2:        TRAP_ENTRY_INTERRUPT(2)             /* IRQ SBUS Level 2              */
-t_irq3:        TRAP_ENTRY_INTERRUPT(3)             /* IRQ SCSI/DMA/SBUS Level 3     */
-t_irq4:        TRAP_ENTRY_INTERRUPT(4)             /* IRQ Software Level 4          */
-t_irq5:        TRAP_ENTRY_INTERRUPT(5)             /* IRQ SBUS/Ethernet Level 5     */
-t_irq6:        TRAP_ENTRY_INTERRUPT(6)             /* IRQ Software Level 6          */
-t_irq7:        TRAP_ENTRY_INTERRUPT(7)             /* IRQ Video/SBUS Level 5        */
-t_irq8:        TRAP_ENTRY_INTERRUPT(8)             /* IRQ SBUS Level 6              */
-t_irq9:        TRAP_ENTRY_INTERRUPT(9)             /* IRQ SBUS Level 7              */
-t_irq10:TRAP_ENTRY_INTERRUPT(10)            /* IRQ Timer #1 (one we use)     */
-t_irq11:TRAP_ENTRY_INTERRUPT(11)            /* IRQ Floppy Intr.              */
-t_irq12:TRAP_ENTRY_INTERRUPT(12)            /* IRQ Zilog serial chip         */
-t_irq13:TRAP_ENTRY_INTERRUPT(13)            /* IRQ Audio Intr.               */
-t_irq14:TRAP_ENTRY_INTERRUPT(14)            /* IRQ Timer #2                  */
-       .globl  t_nmi
-#ifndef CONFIG_SMP
-t_nmi: NMI_TRAP                            /* Level 15 (NMI)                */
-#else
-t_nmi: TRAP_ENTRY(0x1f, linux_trap_ipi15_sun4m)
-#endif
-t_racc:        TRAP_ENTRY(0x20, do_reg_access)     /* General Register Access Error */
-t_iacce:BAD_TRAP(0x21)                      /* Instr Access Error            */
-t_bad22:BAD_TRAP(0x22) BAD_TRAP(0x23)
-t_cpdis:TRAP_ENTRY(0x24, do_cp_disabled)    /* Co-Processor Disabled         */
-t_uflsh:SKIP_TRAP(0x25, unimp_flush)        /* Unimplemented FLUSH inst.     */
-t_bad26:BAD_TRAP(0x26) BAD_TRAP(0x27)
-t_cpexc:TRAP_ENTRY(0x28, do_cp_exception)   /* Co-Processor Exception        */
-t_dacce:SPARC_DFAULT                        /* Data Access Error             */
-t_hwdz:        TRAP_ENTRY(0x2a, do_hw_divzero)     /* Division by zero, you lose... */
-t_dserr:BAD_TRAP(0x2b)                      /* Data Store Error              */
-t_daccm:BAD_TRAP(0x2c)                      /* Data Access MMU-Miss          */
-t_bad2d:BAD_TRAP(0x2d) BAD_TRAP(0x2e) BAD_TRAP(0x2f) BAD_TRAP(0x30) BAD_TRAP(0x31)
-t_bad32:BAD_TRAP(0x32) BAD_TRAP(0x33) BAD_TRAP(0x34) BAD_TRAP(0x35) BAD_TRAP(0x36)
-t_bad37:BAD_TRAP(0x37) BAD_TRAP(0x38) BAD_TRAP(0x39) BAD_TRAP(0x3a) BAD_TRAP(0x3b)
-t_iaccm:BAD_TRAP(0x3c)                      /* Instr Access MMU-Miss         */
-t_bad3d:BAD_TRAP(0x3d) BAD_TRAP(0x3e) BAD_TRAP(0x3f) BAD_TRAP(0x40) BAD_TRAP(0x41)
-t_bad42:BAD_TRAP(0x42) BAD_TRAP(0x43) BAD_TRAP(0x44) BAD_TRAP(0x45) BAD_TRAP(0x46)
-t_bad47:BAD_TRAP(0x47) BAD_TRAP(0x48) BAD_TRAP(0x49) BAD_TRAP(0x4a) BAD_TRAP(0x4b)
-t_bad4c:BAD_TRAP(0x4c) BAD_TRAP(0x4d) BAD_TRAP(0x4e) BAD_TRAP(0x4f) BAD_TRAP(0x50)
-t_bad51:BAD_TRAP(0x51) BAD_TRAP(0x52) BAD_TRAP(0x53) BAD_TRAP(0x54) BAD_TRAP(0x55)
-t_bad56:BAD_TRAP(0x56) BAD_TRAP(0x57) BAD_TRAP(0x58) BAD_TRAP(0x59) BAD_TRAP(0x5a)
-t_bad5b:BAD_TRAP(0x5b) BAD_TRAP(0x5c) BAD_TRAP(0x5d) BAD_TRAP(0x5e) BAD_TRAP(0x5f)
-t_bad60:BAD_TRAP(0x60) BAD_TRAP(0x61) BAD_TRAP(0x62) BAD_TRAP(0x63) BAD_TRAP(0x64)
-t_bad65:BAD_TRAP(0x65) BAD_TRAP(0x66) BAD_TRAP(0x67) BAD_TRAP(0x68) BAD_TRAP(0x69)
-t_bad6a:BAD_TRAP(0x6a) BAD_TRAP(0x6b) BAD_TRAP(0x6c) BAD_TRAP(0x6d) BAD_TRAP(0x6e)
-t_bad6f:BAD_TRAP(0x6f) BAD_TRAP(0x70) BAD_TRAP(0x71) BAD_TRAP(0x72) BAD_TRAP(0x73)
-t_bad74:BAD_TRAP(0x74) BAD_TRAP(0x75) BAD_TRAP(0x76) BAD_TRAP(0x77) BAD_TRAP(0x78)
-t_bad79:BAD_TRAP(0x79) BAD_TRAP(0x7a) BAD_TRAP(0x7b) BAD_TRAP(0x7c) BAD_TRAP(0x7d)
-t_bad7e:BAD_TRAP(0x7e) BAD_TRAP(0x7f)
-t_bad80:BAD_TRAP(0x80)                      /* SunOS System Call             */
-t_sbkpt:BREAKPOINT_TRAP                     /* Software Breakpoint/KGDB      */
-t_divz:        TRAP_ENTRY(0x82, do_hw_divzero)     /* Divide by zero trap           */
-t_flwin:TRAP_ENTRY(0x83, do_flush_windows)  /* Flush Windows Trap            */
-t_clwin:BAD_TRAP(0x84)                      /* Clean Windows Trap            */
-t_rchk:        BAD_TRAP(0x85)                      /* Range Check                   */
-t_funal:BAD_TRAP(0x86)                      /* Fix Unaligned Access Trap     */
-t_iovf:        BAD_TRAP(0x87)                      /* Integer Overflow Trap         */
-t_bad88:BAD_TRAP(0x88)                      /* Slowaris System Call          */
-t_bad89:BAD_TRAP(0x89)                      /* Net-B.S. System Call          */
-t_bad8a:BAD_TRAP(0x8a) BAD_TRAP(0x8b) BAD_TRAP(0x8c) BAD_TRAP(0x8d) BAD_TRAP(0x8e)
-t_bad8f:BAD_TRAP(0x8f)
-t_linux:LINUX_SYSCALL_TRAP                  /* Linux System Call             */
-t_bad91:BAD_TRAP(0x91) BAD_TRAP(0x92) BAD_TRAP(0x93) BAD_TRAP(0x94) BAD_TRAP(0x95)
-t_bad96:BAD_TRAP(0x96) BAD_TRAP(0x97) BAD_TRAP(0x98) BAD_TRAP(0x99) BAD_TRAP(0x9a)
-t_bad9b:BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e) BAD_TRAP(0x9f)
-t_getcc:GETCC_TRAP                          /* Get Condition Codes           */
-t_setcc:SETCC_TRAP                          /* Set Condition Codes           */
-t_getpsr:GETPSR_TRAP                        /* Get PSR Register              */
-t_bada3:BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6)
-t_bada7:BAD_TRAP(0xa7)
-t_bada8:BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab)
-t_badac:BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf) BAD_TRAP(0xb0)
-t_badb1:BAD_TRAP(0xb1) BAD_TRAP(0xb2) BAD_TRAP(0xb3) BAD_TRAP(0xb4) BAD_TRAP(0xb5)
-t_badb6:BAD_TRAP(0xb6) BAD_TRAP(0xb7) BAD_TRAP(0xb8) BAD_TRAP(0xb9) BAD_TRAP(0xba)
-t_badbb:BAD_TRAP(0xbb) BAD_TRAP(0xbc) BAD_TRAP(0xbd) BAD_TRAP(0xbe) BAD_TRAP(0xbf)
-t_badc0:BAD_TRAP(0xc0) BAD_TRAP(0xc1) BAD_TRAP(0xc2) BAD_TRAP(0xc3) BAD_TRAP(0xc4)
-t_badc5:BAD_TRAP(0xc5) BAD_TRAP(0xc6) BAD_TRAP(0xc7) BAD_TRAP(0xc8) BAD_TRAP(0xc9)
-t_badca:BAD_TRAP(0xca) BAD_TRAP(0xcb) BAD_TRAP(0xcc) BAD_TRAP(0xcd) BAD_TRAP(0xce)
-t_badcf:BAD_TRAP(0xcf) BAD_TRAP(0xd0) BAD_TRAP(0xd1) BAD_TRAP(0xd2) BAD_TRAP(0xd3)
-t_badd4:BAD_TRAP(0xd4) BAD_TRAP(0xd5) BAD_TRAP(0xd6) BAD_TRAP(0xd7) BAD_TRAP(0xd8)
-t_badd9:BAD_TRAP(0xd9) BAD_TRAP(0xda) BAD_TRAP(0xdb) BAD_TRAP(0xdc) BAD_TRAP(0xdd)
-t_badde:BAD_TRAP(0xde) BAD_TRAP(0xdf) BAD_TRAP(0xe0) BAD_TRAP(0xe1) BAD_TRAP(0xe2)
-t_bade3:BAD_TRAP(0xe3) BAD_TRAP(0xe4) BAD_TRAP(0xe5) BAD_TRAP(0xe6) BAD_TRAP(0xe7)
-t_bade8:BAD_TRAP(0xe8) BAD_TRAP(0xe9) BAD_TRAP(0xea) BAD_TRAP(0xeb) BAD_TRAP(0xec)
-t_baded:BAD_TRAP(0xed) BAD_TRAP(0xee) BAD_TRAP(0xef) BAD_TRAP(0xf0) BAD_TRAP(0xf1)
-t_badf2:BAD_TRAP(0xf2) BAD_TRAP(0xf3) BAD_TRAP(0xf4) BAD_TRAP(0xf5) BAD_TRAP(0xf6)
-t_badf7:BAD_TRAP(0xf7) BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb)
-t_badfc:BAD_TRAP(0xfc)
-t_kgdb:        KGDB_TRAP(0xfd)
-dbtrap:        BAD_TRAP(0xfe)                      /* Debugger/PROM breakpoint #1   */
-dbtrap2:BAD_TRAP(0xff)                      /* Debugger/PROM breakpoint #2   */        
-
-       .globl  end_traptable
-end_traptable:
-
-#ifdef CONFIG_SMP
-       /* Trap tables for the other cpus. */
-       .globl  trapbase_cpu1, trapbase_cpu2, trapbase_cpu3
-trapbase_cpu1:
-       BAD_TRAP(0x0) SRMMU_TFAULT TRAP_ENTRY(0x2, bad_instruction)
-       TRAP_ENTRY(0x3, priv_instruction) TRAP_ENTRY(0x4, fpd_trap_handler)
-       WINDOW_SPILL WINDOW_FILL TRAP_ENTRY(0x7, mna_handler)
-       TRAP_ENTRY(0x8, fpe_trap_handler) SRMMU_DFAULT
-       TRAP_ENTRY(0xa, do_tag_overflow) TRAP_ENTRY(0xb, do_watchpoint)
-       BAD_TRAP(0xc) BAD_TRAP(0xd) BAD_TRAP(0xe) BAD_TRAP(0xf) BAD_TRAP(0x10)
-       TRAP_ENTRY_INTERRUPT(1) TRAP_ENTRY_INTERRUPT(2)
-       TRAP_ENTRY_INTERRUPT(3) TRAP_ENTRY_INTERRUPT(4)
-       TRAP_ENTRY_INTERRUPT(5) TRAP_ENTRY_INTERRUPT(6)
-       TRAP_ENTRY_INTERRUPT(7) TRAP_ENTRY_INTERRUPT(8)
-       TRAP_ENTRY_INTERRUPT(9) TRAP_ENTRY_INTERRUPT(10)
-       TRAP_ENTRY_INTERRUPT(11) TRAP_ENTRY_INTERRUPT(12)
-       TRAP_ENTRY_INTERRUPT(13) TRAP_ENTRY_INTERRUPT(14)
-       TRAP_ENTRY(0x1f, linux_trap_ipi15_sun4m)
-       TRAP_ENTRY(0x20, do_reg_access) BAD_TRAP(0x21) BAD_TRAP(0x22)
-       BAD_TRAP(0x23) TRAP_ENTRY(0x24, do_cp_disabled) SKIP_TRAP(0x25, unimp_flush)
-       BAD_TRAP(0x26) BAD_TRAP(0x27) TRAP_ENTRY(0x28, do_cp_exception)
-       SRMMU_DFAULT TRAP_ENTRY(0x2a, do_hw_divzero) BAD_TRAP(0x2b) BAD_TRAP(0x2c)
-       BAD_TRAP(0x2d) BAD_TRAP(0x2e) BAD_TRAP(0x2f) BAD_TRAP(0x30) BAD_TRAP(0x31)
-       BAD_TRAP(0x32) BAD_TRAP(0x33) BAD_TRAP(0x34) BAD_TRAP(0x35) BAD_TRAP(0x36)
-       BAD_TRAP(0x37) BAD_TRAP(0x38) BAD_TRAP(0x39) BAD_TRAP(0x3a) BAD_TRAP(0x3b)
-       BAD_TRAP(0x3c) BAD_TRAP(0x3d) BAD_TRAP(0x3e) BAD_TRAP(0x3f) BAD_TRAP(0x40)
-       BAD_TRAP(0x41) BAD_TRAP(0x42) BAD_TRAP(0x43) BAD_TRAP(0x44) BAD_TRAP(0x45)
-       BAD_TRAP(0x46) BAD_TRAP(0x47) BAD_TRAP(0x48) BAD_TRAP(0x49) BAD_TRAP(0x4a)
-       BAD_TRAP(0x4b) BAD_TRAP(0x4c) BAD_TRAP(0x4d) BAD_TRAP(0x4e) BAD_TRAP(0x4f)
-       BAD_TRAP(0x50)
-       BAD_TRAP(0x51) BAD_TRAP(0x52) BAD_TRAP(0x53) BAD_TRAP(0x54) BAD_TRAP(0x55)
-       BAD_TRAP(0x56) BAD_TRAP(0x57) BAD_TRAP(0x58) BAD_TRAP(0x59) BAD_TRAP(0x5a)
-       BAD_TRAP(0x5b) BAD_TRAP(0x5c) BAD_TRAP(0x5d) BAD_TRAP(0x5e) BAD_TRAP(0x5f)
-       BAD_TRAP(0x60) BAD_TRAP(0x61) BAD_TRAP(0x62) BAD_TRAP(0x63) BAD_TRAP(0x64)
-       BAD_TRAP(0x65) BAD_TRAP(0x66) BAD_TRAP(0x67) BAD_TRAP(0x68) BAD_TRAP(0x69)
-       BAD_TRAP(0x6a) BAD_TRAP(0x6b) BAD_TRAP(0x6c) BAD_TRAP(0x6d) BAD_TRAP(0x6e)
-       BAD_TRAP(0x6f) BAD_TRAP(0x70) BAD_TRAP(0x71) BAD_TRAP(0x72) BAD_TRAP(0x73)
-       BAD_TRAP(0x74) BAD_TRAP(0x75) BAD_TRAP(0x76) BAD_TRAP(0x77) BAD_TRAP(0x78)
-       BAD_TRAP(0x79) BAD_TRAP(0x7a) BAD_TRAP(0x7b) BAD_TRAP(0x7c) BAD_TRAP(0x7d)
-       BAD_TRAP(0x7e) BAD_TRAP(0x7f)
-       BAD_TRAP(0x80)
-       BREAKPOINT_TRAP
-       TRAP_ENTRY(0x82, do_hw_divzero)
-       TRAP_ENTRY(0x83, do_flush_windows) BAD_TRAP(0x84) BAD_TRAP(0x85)
-       BAD_TRAP(0x86) BAD_TRAP(0x87) BAD_TRAP(0x88)
-       BAD_TRAP(0x89) BAD_TRAP(0x8a) BAD_TRAP(0x8b) BAD_TRAP(0x8c)
-       BAD_TRAP(0x8d) BAD_TRAP(0x8e) BAD_TRAP(0x8f)
-       LINUX_SYSCALL_TRAP BAD_TRAP(0x91) BAD_TRAP(0x92) BAD_TRAP(0x93) BAD_TRAP(0x94)
-       BAD_TRAP(0x95) BAD_TRAP(0x96) BAD_TRAP(0x97) BAD_TRAP(0x98) BAD_TRAP(0x99)
-       BAD_TRAP(0x9a) BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e)
-       BAD_TRAP(0x9f) GETCC_TRAP SETCC_TRAP GETPSR_TRAP
-       BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6)
-       BAD_TRAP(0xa7) BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab)
-       BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf) BAD_TRAP(0xb0)
-       BAD_TRAP(0xb1) BAD_TRAP(0xb2) BAD_TRAP(0xb3) BAD_TRAP(0xb4) BAD_TRAP(0xb5)
-       BAD_TRAP(0xb6) BAD_TRAP(0xb7) BAD_TRAP(0xb8) BAD_TRAP(0xb9) BAD_TRAP(0xba)
-       BAD_TRAP(0xbb) BAD_TRAP(0xbc) BAD_TRAP(0xbd) BAD_TRAP(0xbe) BAD_TRAP(0xbf)
-       BAD_TRAP(0xc0) BAD_TRAP(0xc1) BAD_TRAP(0xc2) BAD_TRAP(0xc3) BAD_TRAP(0xc4)
-       BAD_TRAP(0xc5) BAD_TRAP(0xc6) BAD_TRAP(0xc7) BAD_TRAP(0xc8) BAD_TRAP(0xc9)
-       BAD_TRAP(0xca) BAD_TRAP(0xcb) BAD_TRAP(0xcc) BAD_TRAP(0xcd) BAD_TRAP(0xce)
-       BAD_TRAP(0xcf) BAD_TRAP(0xd0) BAD_TRAP(0xd1) BAD_TRAP(0xd2) BAD_TRAP(0xd3)
-       BAD_TRAP(0xd4) BAD_TRAP(0xd5) BAD_TRAP(0xd6) BAD_TRAP(0xd7) BAD_TRAP(0xd8)
-       BAD_TRAP(0xd9) BAD_TRAP(0xda) BAD_TRAP(0xdb) BAD_TRAP(0xdc) BAD_TRAP(0xdd)
-       BAD_TRAP(0xde) BAD_TRAP(0xdf) BAD_TRAP(0xe0) BAD_TRAP(0xe1) BAD_TRAP(0xe2)
-       BAD_TRAP(0xe3) BAD_TRAP(0xe4) BAD_TRAP(0xe5) BAD_TRAP(0xe6) BAD_TRAP(0xe7)
-       BAD_TRAP(0xe8) BAD_TRAP(0xe9) BAD_TRAP(0xea) BAD_TRAP(0xeb) BAD_TRAP(0xec)
-       BAD_TRAP(0xed) BAD_TRAP(0xee) BAD_TRAP(0xef) BAD_TRAP(0xf0) BAD_TRAP(0xf1)
-       BAD_TRAP(0xf2) BAD_TRAP(0xf3) BAD_TRAP(0xf4) BAD_TRAP(0xf5) BAD_TRAP(0xf6)
-       BAD_TRAP(0xf7) BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb)
-       BAD_TRAP(0xfc) KGDB_TRAP(0xfd) BAD_TRAP(0xfe) BAD_TRAP(0xff)
-
-trapbase_cpu2:
-       BAD_TRAP(0x0) SRMMU_TFAULT TRAP_ENTRY(0x2, bad_instruction)
-       TRAP_ENTRY(0x3, priv_instruction) TRAP_ENTRY(0x4, fpd_trap_handler)
-       WINDOW_SPILL WINDOW_FILL TRAP_ENTRY(0x7, mna_handler)
-       TRAP_ENTRY(0x8, fpe_trap_handler) SRMMU_DFAULT
-       TRAP_ENTRY(0xa, do_tag_overflow) TRAP_ENTRY(0xb, do_watchpoint)
-       BAD_TRAP(0xc) BAD_TRAP(0xd) BAD_TRAP(0xe) BAD_TRAP(0xf) BAD_TRAP(0x10)
-       TRAP_ENTRY_INTERRUPT(1) TRAP_ENTRY_INTERRUPT(2)
-       TRAP_ENTRY_INTERRUPT(3) TRAP_ENTRY_INTERRUPT(4)
-       TRAP_ENTRY_INTERRUPT(5) TRAP_ENTRY_INTERRUPT(6)
-       TRAP_ENTRY_INTERRUPT(7) TRAP_ENTRY_INTERRUPT(8)
-       TRAP_ENTRY_INTERRUPT(9) TRAP_ENTRY_INTERRUPT(10)
-       TRAP_ENTRY_INTERRUPT(11) TRAP_ENTRY_INTERRUPT(12)
-       TRAP_ENTRY_INTERRUPT(13) TRAP_ENTRY_INTERRUPT(14)
-       TRAP_ENTRY(0x1f, linux_trap_ipi15_sun4m)
-       TRAP_ENTRY(0x20, do_reg_access) BAD_TRAP(0x21) BAD_TRAP(0x22)
-       BAD_TRAP(0x23) TRAP_ENTRY(0x24, do_cp_disabled) SKIP_TRAP(0x25, unimp_flush)
-       BAD_TRAP(0x26) BAD_TRAP(0x27) TRAP_ENTRY(0x28, do_cp_exception)
-       SRMMU_DFAULT TRAP_ENTRY(0x2a, do_hw_divzero) BAD_TRAP(0x2b) BAD_TRAP(0x2c)
-       BAD_TRAP(0x2d) BAD_TRAP(0x2e) BAD_TRAP(0x2f) BAD_TRAP(0x30) BAD_TRAP(0x31)
-       BAD_TRAP(0x32) BAD_TRAP(0x33) BAD_TRAP(0x34) BAD_TRAP(0x35) BAD_TRAP(0x36)
-       BAD_TRAP(0x37) BAD_TRAP(0x38) BAD_TRAP(0x39) BAD_TRAP(0x3a) BAD_TRAP(0x3b)
-       BAD_TRAP(0x3c) BAD_TRAP(0x3d) BAD_TRAP(0x3e) BAD_TRAP(0x3f) BAD_TRAP(0x40)
-       BAD_TRAP(0x41) BAD_TRAP(0x42) BAD_TRAP(0x43) BAD_TRAP(0x44) BAD_TRAP(0x45)
-       BAD_TRAP(0x46) BAD_TRAP(0x47) BAD_TRAP(0x48) BAD_TRAP(0x49) BAD_TRAP(0x4a)
-       BAD_TRAP(0x4b) BAD_TRAP(0x4c) BAD_TRAP(0x4d) BAD_TRAP(0x4e) BAD_TRAP(0x4f)
-       BAD_TRAP(0x50)
-       BAD_TRAP(0x51) BAD_TRAP(0x52) BAD_TRAP(0x53) BAD_TRAP(0x54) BAD_TRAP(0x55)
-       BAD_TRAP(0x56) BAD_TRAP(0x57) BAD_TRAP(0x58) BAD_TRAP(0x59) BAD_TRAP(0x5a)
-       BAD_TRAP(0x5b) BAD_TRAP(0x5c) BAD_TRAP(0x5d) BAD_TRAP(0x5e) BAD_TRAP(0x5f)
-       BAD_TRAP(0x60) BAD_TRAP(0x61) BAD_TRAP(0x62) BAD_TRAP(0x63) BAD_TRAP(0x64)
-       BAD_TRAP(0x65) BAD_TRAP(0x66) BAD_TRAP(0x67) BAD_TRAP(0x68) BAD_TRAP(0x69)
-       BAD_TRAP(0x6a) BAD_TRAP(0x6b) BAD_TRAP(0x6c) BAD_TRAP(0x6d) BAD_TRAP(0x6e)
-       BAD_TRAP(0x6f) BAD_TRAP(0x70) BAD_TRAP(0x71) BAD_TRAP(0x72) BAD_TRAP(0x73)
-       BAD_TRAP(0x74) BAD_TRAP(0x75) BAD_TRAP(0x76) BAD_TRAP(0x77) BAD_TRAP(0x78)
-       BAD_TRAP(0x79) BAD_TRAP(0x7a) BAD_TRAP(0x7b) BAD_TRAP(0x7c) BAD_TRAP(0x7d)
-       BAD_TRAP(0x7e) BAD_TRAP(0x7f)
-       BAD_TRAP(0x80)
-       BREAKPOINT_TRAP
-       TRAP_ENTRY(0x82, do_hw_divzero)
-       TRAP_ENTRY(0x83, do_flush_windows) BAD_TRAP(0x84) BAD_TRAP(0x85)
-       BAD_TRAP(0x86) BAD_TRAP(0x87) BAD_TRAP(0x88)
-       BAD_TRAP(0x89) BAD_TRAP(0x8a) BAD_TRAP(0x8b) BAD_TRAP(0x8c)
-       BAD_TRAP(0x8d) BAD_TRAP(0x8e) BAD_TRAP(0x8f)
-       LINUX_SYSCALL_TRAP BAD_TRAP(0x91) BAD_TRAP(0x92) BAD_TRAP(0x93) BAD_TRAP(0x94)
-       BAD_TRAP(0x95) BAD_TRAP(0x96) BAD_TRAP(0x97) BAD_TRAP(0x98) BAD_TRAP(0x99)
-       BAD_TRAP(0x9a) BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e)
-       BAD_TRAP(0x9f) GETCC_TRAP SETCC_TRAP GETPSR_TRAP
-       BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6)
-       BAD_TRAP(0xa7) BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab)
-       BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf) BAD_TRAP(0xb0)
-       BAD_TRAP(0xb1) BAD_TRAP(0xb2) BAD_TRAP(0xb3) BAD_TRAP(0xb4) BAD_TRAP(0xb5)
-       BAD_TRAP(0xb6) BAD_TRAP(0xb7) BAD_TRAP(0xb8) BAD_TRAP(0xb9) BAD_TRAP(0xba)
-       BAD_TRAP(0xbb) BAD_TRAP(0xbc) BAD_TRAP(0xbd) BAD_TRAP(0xbe) BAD_TRAP(0xbf)
-       BAD_TRAP(0xc0) BAD_TRAP(0xc1) BAD_TRAP(0xc2) BAD_TRAP(0xc3) BAD_TRAP(0xc4)
-       BAD_TRAP(0xc5) BAD_TRAP(0xc6) BAD_TRAP(0xc7) BAD_TRAP(0xc8) BAD_TRAP(0xc9)
-       BAD_TRAP(0xca) BAD_TRAP(0xcb) BAD_TRAP(0xcc) BAD_TRAP(0xcd) BAD_TRAP(0xce)
-       BAD_TRAP(0xcf) BAD_TRAP(0xd0) BAD_TRAP(0xd1) BAD_TRAP(0xd2) BAD_TRAP(0xd3)
-       BAD_TRAP(0xd4) BAD_TRAP(0xd5) BAD_TRAP(0xd6) BAD_TRAP(0xd7) BAD_TRAP(0xd8)
-       BAD_TRAP(0xd9) BAD_TRAP(0xda) BAD_TRAP(0xdb) BAD_TRAP(0xdc) BAD_TRAP(0xdd)
-       BAD_TRAP(0xde) BAD_TRAP(0xdf) BAD_TRAP(0xe0) BAD_TRAP(0xe1) BAD_TRAP(0xe2)
-       BAD_TRAP(0xe3) BAD_TRAP(0xe4) BAD_TRAP(0xe5) BAD_TRAP(0xe6) BAD_TRAP(0xe7)
-       BAD_TRAP(0xe8) BAD_TRAP(0xe9) BAD_TRAP(0xea) BAD_TRAP(0xeb) BAD_TRAP(0xec)
-       BAD_TRAP(0xed) BAD_TRAP(0xee) BAD_TRAP(0xef) BAD_TRAP(0xf0) BAD_TRAP(0xf1)
-       BAD_TRAP(0xf2) BAD_TRAP(0xf3) BAD_TRAP(0xf4) BAD_TRAP(0xf5) BAD_TRAP(0xf6)
-       BAD_TRAP(0xf7) BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb)
-       BAD_TRAP(0xfc) KGDB_TRAP(0xfd) BAD_TRAP(0xfe) BAD_TRAP(0xff)
-
-trapbase_cpu3:
-       BAD_TRAP(0x0) SRMMU_TFAULT TRAP_ENTRY(0x2, bad_instruction)
-       TRAP_ENTRY(0x3, priv_instruction) TRAP_ENTRY(0x4, fpd_trap_handler)
-       WINDOW_SPILL WINDOW_FILL TRAP_ENTRY(0x7, mna_handler)
-       TRAP_ENTRY(0x8, fpe_trap_handler) SRMMU_DFAULT
-       TRAP_ENTRY(0xa, do_tag_overflow) TRAP_ENTRY(0xb, do_watchpoint)
-       BAD_TRAP(0xc) BAD_TRAP(0xd) BAD_TRAP(0xe) BAD_TRAP(0xf) BAD_TRAP(0x10)
-       TRAP_ENTRY_INTERRUPT(1) TRAP_ENTRY_INTERRUPT(2)
-       TRAP_ENTRY_INTERRUPT(3) TRAP_ENTRY_INTERRUPT(4)
-       TRAP_ENTRY_INTERRUPT(5) TRAP_ENTRY_INTERRUPT(6)
-       TRAP_ENTRY_INTERRUPT(7) TRAP_ENTRY_INTERRUPT(8)
-       TRAP_ENTRY_INTERRUPT(9) TRAP_ENTRY_INTERRUPT(10)
-       TRAP_ENTRY_INTERRUPT(11) TRAP_ENTRY_INTERRUPT(12)
-       TRAP_ENTRY_INTERRUPT(13) TRAP_ENTRY_INTERRUPT(14)
-       TRAP_ENTRY(0x1f, linux_trap_ipi15_sun4m)
-       TRAP_ENTRY(0x20, do_reg_access) BAD_TRAP(0x21) BAD_TRAP(0x22)
-       BAD_TRAP(0x23) TRAP_ENTRY(0x24, do_cp_disabled) SKIP_TRAP(0x25, unimp_flush)
-       BAD_TRAP(0x26) BAD_TRAP(0x27) TRAP_ENTRY(0x28, do_cp_exception)
-       SRMMU_DFAULT TRAP_ENTRY(0x2a, do_hw_divzero) BAD_TRAP(0x2b) BAD_TRAP(0x2c)
-       BAD_TRAP(0x2d) BAD_TRAP(0x2e) BAD_TRAP(0x2f) BAD_TRAP(0x30) BAD_TRAP(0x31)
-       BAD_TRAP(0x32) BAD_TRAP(0x33) BAD_TRAP(0x34) BAD_TRAP(0x35) BAD_TRAP(0x36)
-       BAD_TRAP(0x37) BAD_TRAP(0x38) BAD_TRAP(0x39) BAD_TRAP(0x3a) BAD_TRAP(0x3b)
-       BAD_TRAP(0x3c) BAD_TRAP(0x3d) BAD_TRAP(0x3e) BAD_TRAP(0x3f) BAD_TRAP(0x40)
-       BAD_TRAP(0x41) BAD_TRAP(0x42) BAD_TRAP(0x43) BAD_TRAP(0x44) BAD_TRAP(0x45)
-       BAD_TRAP(0x46) BAD_TRAP(0x47) BAD_TRAP(0x48) BAD_TRAP(0x49) BAD_TRAP(0x4a)
-       BAD_TRAP(0x4b) BAD_TRAP(0x4c) BAD_TRAP(0x4d) BAD_TRAP(0x4e) BAD_TRAP(0x4f)
-       BAD_TRAP(0x50)
-       BAD_TRAP(0x51) BAD_TRAP(0x52) BAD_TRAP(0x53) BAD_TRAP(0x54) BAD_TRAP(0x55)
-       BAD_TRAP(0x56) BAD_TRAP(0x57) BAD_TRAP(0x58) BAD_TRAP(0x59) BAD_TRAP(0x5a)
-       BAD_TRAP(0x5b) BAD_TRAP(0x5c) BAD_TRAP(0x5d) BAD_TRAP(0x5e) BAD_TRAP(0x5f)
-       BAD_TRAP(0x60) BAD_TRAP(0x61) BAD_TRAP(0x62) BAD_TRAP(0x63) BAD_TRAP(0x64)
-       BAD_TRAP(0x65) BAD_TRAP(0x66) BAD_TRAP(0x67) BAD_TRAP(0x68) BAD_TRAP(0x69)
-       BAD_TRAP(0x6a) BAD_TRAP(0x6b) BAD_TRAP(0x6c) BAD_TRAP(0x6d) BAD_TRAP(0x6e)
-       BAD_TRAP(0x6f) BAD_TRAP(0x70) BAD_TRAP(0x71) BAD_TRAP(0x72) BAD_TRAP(0x73)
-       BAD_TRAP(0x74) BAD_TRAP(0x75) BAD_TRAP(0x76) BAD_TRAP(0x77) BAD_TRAP(0x78)
-       BAD_TRAP(0x79) BAD_TRAP(0x7a) BAD_TRAP(0x7b) BAD_TRAP(0x7c) BAD_TRAP(0x7d)
-       BAD_TRAP(0x7e) BAD_TRAP(0x7f)
-       BAD_TRAP(0x80)
-       BREAKPOINT_TRAP
-       TRAP_ENTRY(0x82, do_hw_divzero)
-       TRAP_ENTRY(0x83, do_flush_windows) BAD_TRAP(0x84) BAD_TRAP(0x85)
-       BAD_TRAP(0x86) BAD_TRAP(0x87) BAD_TRAP(0x88)
-       BAD_TRAP(0x89) BAD_TRAP(0x8a) BAD_TRAP(0x8b) BAD_TRAP(0x8c)
-       BAD_TRAP(0x8d) BAD_TRAP(0x8e) BAD_TRAP(0x8f)
-       LINUX_SYSCALL_TRAP BAD_TRAP(0x91) BAD_TRAP(0x92) BAD_TRAP(0x93) BAD_TRAP(0x94)
-       BAD_TRAP(0x95) BAD_TRAP(0x96) BAD_TRAP(0x97) BAD_TRAP(0x98) BAD_TRAP(0x99)
-       BAD_TRAP(0x9a) BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e)
-       BAD_TRAP(0x9f) GETCC_TRAP SETCC_TRAP GETPSR_TRAP
-       BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6)
-       BAD_TRAP(0xa7) BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab)
-       BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf) BAD_TRAP(0xb0)
-       BAD_TRAP(0xb1) BAD_TRAP(0xb2) BAD_TRAP(0xb3) BAD_TRAP(0xb4) BAD_TRAP(0xb5)
-       BAD_TRAP(0xb6) BAD_TRAP(0xb7) BAD_TRAP(0xb8) BAD_TRAP(0xb9) BAD_TRAP(0xba)
-       BAD_TRAP(0xbb) BAD_TRAP(0xbc) BAD_TRAP(0xbd) BAD_TRAP(0xbe) BAD_TRAP(0xbf)
-       BAD_TRAP(0xc0) BAD_TRAP(0xc1) BAD_TRAP(0xc2) BAD_TRAP(0xc3) BAD_TRAP(0xc4)
-       BAD_TRAP(0xc5) BAD_TRAP(0xc6) BAD_TRAP(0xc7) BAD_TRAP(0xc8) BAD_TRAP(0xc9)
-       BAD_TRAP(0xca) BAD_TRAP(0xcb) BAD_TRAP(0xcc) BAD_TRAP(0xcd) BAD_TRAP(0xce)
-       BAD_TRAP(0xcf) BAD_TRAP(0xd0) BAD_TRAP(0xd1) BAD_TRAP(0xd2) BAD_TRAP(0xd3)
-       BAD_TRAP(0xd4) BAD_TRAP(0xd5) BAD_TRAP(0xd6) BAD_TRAP(0xd7) BAD_TRAP(0xd8)
-       BAD_TRAP(0xd9) BAD_TRAP(0xda) BAD_TRAP(0xdb) BAD_TRAP(0xdc) BAD_TRAP(0xdd)
-       BAD_TRAP(0xde) BAD_TRAP(0xdf) BAD_TRAP(0xe0) BAD_TRAP(0xe1) BAD_TRAP(0xe2)
-       BAD_TRAP(0xe3) BAD_TRAP(0xe4) BAD_TRAP(0xe5) BAD_TRAP(0xe6) BAD_TRAP(0xe7)
-       BAD_TRAP(0xe8) BAD_TRAP(0xe9) BAD_TRAP(0xea) BAD_TRAP(0xeb) BAD_TRAP(0xec)
-       BAD_TRAP(0xed) BAD_TRAP(0xee) BAD_TRAP(0xef) BAD_TRAP(0xf0) BAD_TRAP(0xf1)
-       BAD_TRAP(0xf2) BAD_TRAP(0xf3) BAD_TRAP(0xf4) BAD_TRAP(0xf5) BAD_TRAP(0xf6)
-       BAD_TRAP(0xf7) BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb)
-       BAD_TRAP(0xfc) KGDB_TRAP(0xfd) BAD_TRAP(0xfe) BAD_TRAP(0xff)
-
-#endif
-       .align PAGE_SIZE
-
-/* This was the only reasonable way I could think of to properly align
- * these page-table data structures.
- */
-       .globl pg0, pg1, pg2, pg3
-       .globl empty_bad_page
-       .globl empty_bad_page_table
-       .globl empty_zero_page
-       .globl swapper_pg_dir
-swapper_pg_dir:                .skip PAGE_SIZE
-pg0:                   .skip PAGE_SIZE
-pg1:                   .skip PAGE_SIZE
-pg2:                   .skip PAGE_SIZE
-pg3:                   .skip PAGE_SIZE
-empty_bad_page:                .skip PAGE_SIZE
-empty_bad_page_table:  .skip PAGE_SIZE
-empty_zero_page:       .skip PAGE_SIZE
-
-       .global root_flags
-       .global ram_flags
-       .global root_dev
-       .global sparc_ramdisk_image
-       .global sparc_ramdisk_size
-
-/* This stuff has to be in sync with SILO and other potential boot loaders
- * Fields should be kept upward compatible and whenever any change is made,
- * HdrS version should be incremented.
- */
-       .ascii  "HdrS"
-       .word   LINUX_VERSION_CODE
-       .half   0x0203          /* HdrS version */
-root_flags:
-       .half   1
-root_dev:
-       .half   0
-ram_flags:
-       .half   0
-sparc_ramdisk_image:
-       .word   0
-sparc_ramdisk_size:
-       .word   0
-       .word   reboot_command
-       .word   0, 0, 0
-       .word   _end
-
-/* Cool, here we go. Pick up the romvec pointer in %o0 and stash it in
- * %g7 and at prom_vector_p. And also quickly check whether we are on
- * a v0, v2, or v3 prom.
- */
-gokernel:
-               /* Ok, it's nice to know, as early as possible, if we
-                * are already mapped where we expect to be in virtual
-                * memory.  The Solaris /boot elf format bootloader
-                * will peek into our elf header and load us where
-                * we want to be, otherwise we have to re-map.
-                *
-                * Some boot loaders don't place the jmp'rs address
-                * in %o7, so we do a pc-relative call to a local
-                * label, then see what %o7 has.
-                */
-
-               mov     %o7, %g4                ! Save %o7
-
-               /* Jump to it, and pray... */
-current_pc:
-               call    1f
-                nop
-
-1:
-               mov     %o7, %g3
-
-               tst     %o0
-               be      no_sun4u_here
-                mov    %g4, %o7                /* Previous %o7. */
-       
-               mov     %o0, %l0                ! stash away romvec
-               mov     %o0, %g7                ! put it here too
-               mov     %o1, %l1                ! stash away debug_vec too
-
-               /* Ok, let's check out our run time program counter. */
-               set     current_pc, %g5
-               cmp     %g3, %g5
-               be      already_mapped
-                nop 
-
-               /* %l6 will hold the offset we have to subtract
-                * from absolute symbols in order to access areas
-                * in our own image.  If already mapped this is
-                * just plain zero, else it is KERNBASE.
-                */
-               set     KERNBASE, %l6
-               b       copy_prom_lvl14
-                nop
-
-already_mapped:
-               mov     0, %l6
-
-               /* Copy over the Prom's level 14 clock handler. */
-copy_prom_lvl14:
-#if 1
-               /* DJHR
-                * preserve our linked/calculated instructions
-                */
-               set     lvl14_save, %g1
-               set     t_irq14, %g3
-               sub     %g1, %l6, %g1           ! translate to physical
-               sub     %g3, %l6, %g3           ! translate to physical
-               ldd     [%g3], %g4
-               std     %g4, [%g1]
-               ldd     [%g3+8], %g4
-               std     %g4, [%g1+8]
-#endif
-               rd      %tbr, %g1
-               andn    %g1, 0xfff, %g1         ! proms trap table base
-               or      %g0, (0x1e<<4), %g2     ! offset to lvl14 intr
-               or      %g1, %g2, %g2
-               set     t_irq14, %g3
-               sub     %g3, %l6, %g3
-               ldd     [%g2], %g4
-               std     %g4, [%g3]
-               ldd     [%g2 + 0x8], %g4
-               std     %g4, [%g3 + 0x8]        ! Copy proms handler
-
-/* Must determine whether we are on a sun4c MMU, SRMMU, or SUN4/400 MUTANT
- * MMU so we can remap ourselves properly.  DON'T TOUCH %l0 thru %l5 in these
- * remapping routines, we need their values afterwards!
- */
-               /* Now check whether we are already mapped, if we
-                * are we can skip all this garbage coming up.
-                */
-copy_prom_done:
-               cmp     %l6, 0
-               be      go_to_highmem           ! this will be a nop then
-                nop
-
-               set     LOAD_ADDR, %g6
-               cmp     %g7, %g6
-               bne     remap_not_a_sun4        ! This is not a Sun4
-                nop
-
-               or      %g0, 0x1, %g1
-               lduba   [%g1] ASI_CONTROL, %g1  ! Only safe to try on Sun4.
-               subcc   %g1, 0x24, %g0          ! Is this a mutant Sun4/400???
-               be      sun4_mutant_remap       ! Ugh, it is...
-                nop
-
-               b       sun4_normal_remap       ! regular sun4, 2 level mmu
-                nop
-
-remap_not_a_sun4:
-               lda     [%g0] ASI_M_MMUREGS, %g1 ! same as ASI_PTE on sun4c
-               and     %g1, 0x1, %g1           ! Test SRMMU Enable bit ;-)
-               cmp     %g1, 0x0
-               be      sun4c_remap             ! A sun4c MMU or normal Sun4
-                nop
-srmmu_remap:
-               /* First, check for a viking (TI) module. */
-               set     0x40000000, %g2
-               rd      %psr, %g3
-               and     %g2, %g3, %g3
-               subcc   %g3, 0x0, %g0
-               bz      srmmu_nviking
-                nop
-
-               /* Figure out what kind of viking we are on.
-                * We need to know if we have to play with the
-                * AC bit and disable traps or not.
-                */
-
-               /* I've only seen MicroSparc's on SparcClassics with this
-                * bit set.
-                */
-               set     0x800, %g2
-               lda     [%g0] ASI_M_MMUREGS, %g3        ! peek in the control reg
-               and     %g2, %g3, %g3
-               subcc   %g3, 0x0, %g0
-               bnz     srmmu_nviking                   ! is in mbus mode
-                nop
-               
-               rd      %psr, %g3                       ! DO NOT TOUCH %g3
-               andn    %g3, PSR_ET, %g2
-               wr      %g2, 0x0, %psr
-               WRITE_PAUSE
-               
-               /* Get context table pointer, then convert to
-                * a physical address, which is 36 bits.
-                */
-               set     AC_M_CTPR, %g4
-               lda     [%g4] ASI_M_MMUREGS, %g4
-               sll     %g4, 0x4, %g4                   ! We use this below
-                                                       ! DO NOT TOUCH %g4
-
-               /* Set the AC bit in the Viking's MMU control reg. */
-               lda     [%g0] ASI_M_MMUREGS, %g5        ! DO NOT TOUCH %g5
-               set     0x8000, %g6                     ! AC bit mask
-               or      %g5, %g6, %g6                   ! Or it in...
-               sta     %g6, [%g0] ASI_M_MMUREGS        ! Close your eyes...
-
-               /* Grrr, why does it seem like every other load/store
-                * on the sun4m is in some ASI space...
-                * Fine with me, let's get the pointer to the level 1
-                * page table directory and fetch its entry.
-                */
-               lda     [%g4] ASI_M_BYPASS, %o1         ! This is a level 1 ptr
-               srl     %o1, 0x4, %o1                   ! Clear low 4 bits
-               sll     %o1, 0x8, %o1                   ! Make physical
-               
-               /* Ok, pull in the PTD. */
-               lda     [%o1] ASI_M_BYPASS, %o2         ! This is the 0x0 16MB pgd
-
-               /* Calculate to KERNBASE entry. */
-               add     %o1, KERNBASE >> (SRMMU_PGDIR_SHIFT - 2), %o3           
-
-               /* Poke the entry into the calculated address. */
-               sta     %o2, [%o3] ASI_M_BYPASS
-
-               /* I don't get it Sun, if you engineered all these
-                * boot loaders and the PROM (thank you for the debugging
-                * features btw) why did you not have them load kernel
-                * images up in high address space, since this is necessary
-                * for ABI compliance anyways?  Does this low-mapping provide
-                * enhanced interoperability?
-                *
-                * "The PROM is the computer."
-                */
-
-               /* Ok, restore the MMU control register we saved in %g5 */
-               sta     %g5, [%g0] ASI_M_MMUREGS        ! POW... ouch
-
-               /* Turn traps back on.  We saved it in %g3 earlier. */
-               wr      %g3, 0x0, %psr                  ! tick tock, tick tock
-
-               /* Now we burn precious CPU cycles due to bad engineering. */
-               WRITE_PAUSE
-
-               /* Wow, all that just to move a 32-bit value from one
-                * place to another...  Jump to high memory.
-                */
-               b       go_to_highmem
-                nop
-
-               /* This works on viking's in Mbus mode and all
-                * other MBUS modules.  It is virtually the same as
-                * the above madness sans turning traps off and flipping
-                * the AC bit.
-                */
-srmmu_nviking:
-               set     AC_M_CTPR, %g1
-               lda     [%g1] ASI_M_MMUREGS, %g1        ! get ctx table ptr
-               sll     %g1, 0x4, %g1                   ! make physical addr
-               lda     [%g1] ASI_M_BYPASS, %g1         ! ptr to level 1 pg_table
-               srl     %g1, 0x4, %g1
-               sll     %g1, 0x8, %g1                   ! make phys addr for l1 tbl
-
-               lda     [%g1] ASI_M_BYPASS, %g2         ! get level1 entry for 0x0
-               add     %g1, KERNBASE >> (SRMMU_PGDIR_SHIFT - 2), %g3
-               sta     %g2, [%g3] ASI_M_BYPASS         ! place at KERNBASE entry
-               b       go_to_highmem
-                nop                                    ! wheee....
-
-               /* This remaps the kernel on Sun4/4xx machines
-                * that have the Sun Mutant Three Level MMU.
-                * It's like a platypus, Sun didn't have the
-                * SRMMU in conception so they kludged the three
-                * level logic in the regular Sun4 MMU probably.
-                *
-                * Basically, you take each entry in the top level
-                * directory that maps the low 3MB starting at
-                * address zero and put the mapping in the KERNBASE
-                * slots.  These top level pgd's are called regmaps.
-                */
-sun4_mutant_remap:
-               or      %g0, %g0, %g3           ! source base
-               sethi   %hi(KERNBASE), %g4      ! destination base
-               or      %g4, %lo(KERNBASE), %g4
-               sethi   %hi(0x300000), %g5
-               or      %g5, %lo(0x300000), %g5 ! upper bound 3MB
-               or      %g0, 0x1, %l6
-               sll     %l6, 24, %l6            ! Regmap mapping size
-               add     %g3, 0x2, %g3           ! Base magic
-               add     %g4, 0x2, %g4           ! Base magic
-
-               /* Main remapping loop on Sun4-Mutant-MMU.
-                * "I am not an animal..." -Famous Mutant Person
-                */
-sun4_mutant_loop:
-               lduha   [%g3] ASI_REGMAP, %g2   ! Get lower entry
-               stha    %g2, [%g4] ASI_REGMAP   ! Store in high entry
-               add     %g4, %l6, %g4           ! Move up high memory ptr
-               subcc   %g3, %g5, %g0           ! Reached our limit?
-               blu     sun4_mutant_loop        ! Nope, loop again
-                add    %g3, %l6, %g3           ! delay, Move up low ptr
-               b       go_to_highmem           ! Jump to high memory.
-                nop
-
-               /* The following is for non-4/4xx sun4 MMU's. */
-sun4_normal_remap:
-               mov     0, %g3                  ! source base
-               set     KERNBASE, %g4           ! destination base
-               set     0x300000, %g5           ! upper bound 3MB
-               mov     1, %l6
-               sll     %l6, 18, %l6            ! sun4 mmu segmap size
-sun4_normal_loop:
-               lduha   [%g3] ASI_SEGMAP, %g6   ! load phys_seg
-               stha    %g6, [%g4] ASI_SEGMAP   ! stort new virt mapping
-               add     %g3, %l6, %g3           ! increment source pointer
-               subcc   %g3, %g5, %g0           ! reached limit?
-               blu     sun4_normal_loop        ! nope, loop again
-                add    %g4, %l6, %g4           ! delay, increment dest ptr
-               b       go_to_highmem
-                nop
-
-               /* The following works for Sun4c MMU's */
-sun4c_remap:
-               mov     0, %g3                  ! source base
-               set     KERNBASE, %g4           ! destination base
-               set     0x300000, %g5           ! upper bound 3MB
-               mov     1, %l6
-               sll     %l6, 18, %l6            ! sun4c mmu segmap size
-sun4c_remap_loop:
-               lda     [%g3] ASI_SEGMAP, %g6   ! load phys_seg
-               sta     %g6, [%g4] ASI_SEGMAP   ! store new virt mapping
-               add     %g3, %l6, %g3           ! Increment source ptr
-               subcc   %g3, %g5, %g0           ! Reached limit?
-               bl      sun4c_remap_loop        ! Nope, loop again
-                add    %g4, %l6, %g4           ! delay, Increment dest ptr
-
-/* Now do a non-relative jump so that PC is in high-memory */
-go_to_highmem:
-               set     execute_in_high_mem, %g1
-               jmpl    %g1, %g0
-                nop
-
-/* The code above should be at beginning and we have to take care about
- * short jumps, as branching to .text.init section from .text is usually
- * impossible */
-               __INIT
-/* Acquire boot time privileged register values, this will help debugging.
- * I figure out and store nwindows and nwindowsm1 later on.
- */
-execute_in_high_mem:
-               mov     %l0, %o0                ! put back romvec
-               mov     %l1, %o1                ! and debug_vec
-
-               sethi   %hi(prom_vector_p), %g1
-               st      %o0, [%g1 + %lo(prom_vector_p)]
-
-               sethi   %hi(linux_dbvec), %g1
-               st      %o1, [%g1 + %lo(linux_dbvec)]
-
-               ld      [%o0 + 0x4], %o3
-               and     %o3, 0x3, %o5                   ! get the version
-
-               cmp     %o3, 0x2                        ! a v2 prom?
-               be      found_version
-                nop
-
-               /* paul@sfe.com.au */
-               cmp     %o3, 0x3                        ! a v3 prom?
-               be      found_version
-                nop
-
-/* Old sun4's pass our load address into %o0 instead of the prom
- * pointer. On sun4's you have to hard code the romvec pointer into
- * your code. Sun probably still does that because they don't even
- * trust their own "OpenBoot" specifications.
- */
-               set     LOAD_ADDR, %g6
-               cmp     %o0, %g6                ! an old sun4?
-               be      sun4_init
-                nop
-
-found_version:
-/* Get the machine type via the mysterious romvec node operations. */
-
-               add     %g7, 0x1c, %l1          
-               ld      [%l1], %l0
-               ld      [%l0], %l0
-               call    %l0
-                or     %g0, %g0, %o0           ! next_node(0) = first_node
-               or      %o0, %g0, %g6
-
-               sethi   %hi(cputypvar), %o1     ! First node has cpu-arch
-               or      %o1, %lo(cputypvar), %o1
-               sethi   %hi(cputypval), %o2     ! information, the string
-               or      %o2, %lo(cputypval), %o2
-               ld      [%l1], %l0              ! 'compatibility' tells
-               ld      [%l0 + 0xc], %l0        ! that we want 'sun4x' where
-               call    %l0                     ! x is one of '', 'c', 'm',
-                nop                            ! 'd' or 'e'. %o2 holds pointer
-                                               ! to a buf where above string
-                                               ! will get stored by the prom.
-
-               subcc   %o0, %g0, %g0
-               bpos    got_prop                ! Got the property
-                nop
-
-               or      %g6, %g0, %o0
-               sethi   %hi(cputypvar_sun4m), %o1
-               or      %o1, %lo(cputypvar_sun4m), %o1
-               sethi   %hi(cputypval), %o2
-               or      %o2, %lo(cputypval), %o2
-               ld      [%l1], %l0
-               ld      [%l0 + 0xc], %l0
-               call    %l0
-                nop
-
-got_prop:
-               set     cputypval, %o2
-               ldub    [%o2 + 0x4], %l1
-
-               cmp     %l1, ' '
-               be      1f
-                cmp    %l1, 'c'
-               be      1f
-                cmp    %l1, 'm'
-               be      1f
-                cmp    %l1, 's'
-               be      1f
-                cmp    %l1, 'd'
-               be      1f
-                cmp    %l1, 'e'
-               be      no_sun4e_here           ! Could be a sun4e.
-                nop
-               b       no_sun4u_here           ! AIEEE, a V9 sun4u... Get our BIG BROTHER kernel :))
-                nop
-
-1:             set     cputypval, %l1
-               ldub    [%l1 + 0x4], %l1
-               cmp     %l1, 'm'                ! Test for sun4d, sun4e ?
-               be      sun4m_init
-                cmp    %l1, 's'                ! Treat sun4s as sun4m
-               be      sun4m_init
-                cmp    %l1, 'd'                ! Let us see how the beast will die
-               be      sun4d_init
-                nop
-
-               /* Jump into mmu context zero. */
-               set     AC_CONTEXT, %g1
-               stba    %g0, [%g1] ASI_CONTROL
-
-               b       sun4c_continue_boot
-                nop
-
-/* CPUID in bootbus can be found at PA 0xff0140000 */
-#define SUN4D_BOOTBUS_CPUID     0xf0140000
-
-sun4d_init:
-       /* Need to patch call to handler_irq */
-       set     patch_handler_irq, %g4
-       set     sun4d_handler_irq, %g5
-       sethi   %hi(0x40000000), %g3            ! call
-       sub     %g5, %g4, %g5
-       srl     %g5, 2, %g5
-       or      %g5, %g3, %g5
-       st      %g5, [%g4]
-
-#ifdef CONFIG_SMP
-       /* Get our CPU id out of bootbus */
-       set     SUN4D_BOOTBUS_CPUID, %g3
-       lduba   [%g3] ASI_M_CTL, %g3
-       and     %g3, 0xf8, %g3
-       srl     %g3, 3, %g4
-       sta     %g4, [%g0] ASI_M_VIKING_TMP1
-       sethi   %hi(boot_cpu_id), %g5
-       stb     %g4, [%g5 + %lo(boot_cpu_id)]
-       sll     %g4, 2, %g4
-       sethi   %hi(boot_cpu_id4), %g5
-       stb     %g4, [%g5 + %lo(boot_cpu_id4)]
-#endif
-
-       /* Fall through to sun4m_init */
-
-sun4m_init:
-       /* XXX Fucking Cypress... */
-       lda     [%g0] ASI_M_MMUREGS, %g5
-       srl     %g5, 28, %g4
-
-       cmp     %g4, 1
-       bne     1f
-        srl    %g5, 24, %g4
-
-       and     %g4, 0xf, %g4
-       cmp     %g4, 7          /* This would be a HyperSparc. */
-
-       bne     2f
-        nop
-
-1:
-
-#define PATCH_IT(dst, src)     \
-       set     (dst), %g5;     \
-       set     (src), %g4;     \
-       ld      [%g4], %g3;     \
-       st      %g3, [%g5];     \
-       ld      [%g4+0x4], %g3; \
-       st      %g3, [%g5+0x4];
-
-       /* Signed multiply. */
-       PATCH_IT(.mul, .mul_patch)
-       PATCH_IT(.mul+0x08, .mul_patch+0x08)
-
-       /* Signed remainder. */
-       PATCH_IT(.rem, .rem_patch)
-       PATCH_IT(.rem+0x08, .rem_patch+0x08)
-       PATCH_IT(.rem+0x10, .rem_patch+0x10)
-       PATCH_IT(.rem+0x18, .rem_patch+0x18)
-       PATCH_IT(.rem+0x20, .rem_patch+0x20)
-       PATCH_IT(.rem+0x28, .rem_patch+0x28)
-
-       /* Signed division. */
-       PATCH_IT(.div, .div_patch)
-       PATCH_IT(.div+0x08, .div_patch+0x08)
-       PATCH_IT(.div+0x10, .div_patch+0x10)
-       PATCH_IT(.div+0x18, .div_patch+0x18)
-       PATCH_IT(.div+0x20, .div_patch+0x20)
-
-       /* Unsigned multiply. */
-       PATCH_IT(.umul, .umul_patch)
-       PATCH_IT(.umul+0x08, .umul_patch+0x08)
-
-       /* Unsigned remainder. */
-       PATCH_IT(.urem, .urem_patch)
-       PATCH_IT(.urem+0x08, .urem_patch+0x08)
-       PATCH_IT(.urem+0x10, .urem_patch+0x10)
-       PATCH_IT(.urem+0x18, .urem_patch+0x18)
-
-       /* Unsigned division. */
-       PATCH_IT(.udiv, .udiv_patch)
-       PATCH_IT(.udiv+0x08, .udiv_patch+0x08)
-       PATCH_IT(.udiv+0x10, .udiv_patch+0x10)
-
-#undef PATCH_IT
-
-/* Ok, the PROM could have done funny things and apple cider could still
- * be sitting in the fault status/address registers.  Read them all to
- * clear them so we don't get magic faults later on.
- */
-/* This sucks, apparently this makes Vikings call prom panic, will fix later */
-2:
-               rd      %psr, %o1
-               srl     %o1, 28, %o1            ! Get a type of the CPU
-
-               subcc   %o1, 4, %g0             ! TI: Viking or MicroSPARC
-               be      sun4c_continue_boot
-                nop
-
-               set     AC_M_SFSR, %o0
-               lda     [%o0] ASI_M_MMUREGS, %g0
-               set     AC_M_SFAR, %o0
-               lda     [%o0] ASI_M_MMUREGS, %g0
-
-               /* Fujitsu MicroSPARC-II has no asynchronous flavors of FARs */
-               subcc   %o1, 0, %g0
-               be      sun4c_continue_boot
-                nop
-
-               set     AC_M_AFSR, %o0
-               lda     [%o0] ASI_M_MMUREGS, %g0
-               set     AC_M_AFAR, %o0
-               lda     [%o0] ASI_M_MMUREGS, %g0
-                nop
-
-
-sun4c_continue_boot:
-
-
-/* Aieee, now set PC and nPC, enable traps, give ourselves a stack and it's
- * show-time!
- */
-
-               sethi   %hi(cputyp), %o0
-               st      %g4, [%o0 + %lo(cputyp)]
-
-               /* Turn on Supervisor, EnableFloating, and all the PIL bits.
-                * Also puts us in register window zero with traps off.
-                */
-               set     (PSR_PS | PSR_S | PSR_PIL | PSR_EF), %g2
-               wr      %g2, 0x0, %psr
-               WRITE_PAUSE
-
-               /* I want a kernel stack NOW! */
-               set     init_thread_union, %g1
-               set     (THREAD_SIZE - STACKFRAME_SZ), %g2
-               add     %g1, %g2, %sp
-               mov     0, %fp                  /* And for good luck */
-
-               /* Zero out our BSS section. */
-               set     __bss_start , %o0       ! First address of BSS
-               set     end , %o1               ! Last address of BSS
-               add     %o0, 0x1, %o0
-1:     
-               stb     %g0, [%o0]
-               subcc   %o0, %o1, %g0
-               bl      1b
-                add    %o0, 0x1, %o0
-
-               /* Initialize the uwinmask value for init task just in case.
-                * But first make current_set[boot_cpu_id] point to something useful.
-                */
-               set     init_thread_union, %g6
-               set     current_set, %g2
-#ifdef CONFIG_SMP
-               sethi   %hi(boot_cpu_id4), %g3
-               ldub    [%g3 + %lo(boot_cpu_id4)], %g3
-               st      %g6, [%g2]
-               add     %g2, %g3, %g2
-#endif
-               st      %g6, [%g2]
-
-               st      %g0, [%g6 + TI_UWINMASK]
-
-/* Compute NWINDOWS and stash it away. Now uses %wim trick explained
- * in the V8 manual. Ok, this method seems to work, Sparc is cool...
- * No, it doesn't work, have to play the save/readCWP/restore trick.
- */
-
-               wr      %g0, 0x0, %wim                  ! so we do not get a trap
-               WRITE_PAUSE
-
-               save
-
-               rd      %psr, %g3
-
-               restore
-
-               and     %g3, 0x1f, %g3
-               add     %g3, 0x1, %g3
-
-               mov     2, %g1
-               wr      %g1, 0x0, %wim                  ! make window 1 invalid
-               WRITE_PAUSE
-
-               cmp     %g3, 0x7
-               bne     2f
-                nop
-
-               /* Adjust our window handling routines to
-                * do things correctly on 7 window Sparcs.
-                */
-
-#define                PATCH_INSN(src, dest) \
-               set     src, %g5; \
-               set     dest, %g2; \
-               ld      [%g5], %g4; \
-               st      %g4, [%g2];
-       
-               /* Patch for window spills... */
-               PATCH_INSN(spnwin_patch1_7win, spnwin_patch1)
-               PATCH_INSN(spnwin_patch2_7win, spnwin_patch2)
-               PATCH_INSN(spnwin_patch3_7win, spnwin_patch3)
-
-               /* Patch for window fills... */
-               PATCH_INSN(fnwin_patch1_7win, fnwin_patch1)
-               PATCH_INSN(fnwin_patch2_7win, fnwin_patch2)
-
-               /* Patch for trap entry setup... */
-               PATCH_INSN(tsetup_7win_patch1, tsetup_patch1)
-               PATCH_INSN(tsetup_7win_patch2, tsetup_patch2)
-               PATCH_INSN(tsetup_7win_patch3, tsetup_patch3)
-               PATCH_INSN(tsetup_7win_patch4, tsetup_patch4)
-               PATCH_INSN(tsetup_7win_patch5, tsetup_patch5)
-               PATCH_INSN(tsetup_7win_patch6, tsetup_patch6)
-
-               /* Patch for returning from traps... */
-               PATCH_INSN(rtrap_7win_patch1, rtrap_patch1)
-               PATCH_INSN(rtrap_7win_patch2, rtrap_patch2)
-               PATCH_INSN(rtrap_7win_patch3, rtrap_patch3)
-               PATCH_INSN(rtrap_7win_patch4, rtrap_patch4)
-               PATCH_INSN(rtrap_7win_patch5, rtrap_patch5)
-
-               /* Patch for killing user windows from the register file. */
-               PATCH_INSN(kuw_patch1_7win, kuw_patch1)
-
-               /* Now patch the kernel window flush sequences.
-                * This saves 2 traps on every switch and fork.
-                */
-               set     0x01000000, %g4
-               set     flush_patch_one, %g5
-               st      %g4, [%g5 + 0x18]
-               st      %g4, [%g5 + 0x1c]
-               set     flush_patch_two, %g5
-               st      %g4, [%g5 + 0x18]
-               st      %g4, [%g5 + 0x1c]
-               set     flush_patch_three, %g5
-               st      %g4, [%g5 + 0x18]
-               st      %g4, [%g5 + 0x1c]
-               set     flush_patch_four, %g5
-               st      %g4, [%g5 + 0x18]
-               st      %g4, [%g5 + 0x1c]
-               set     flush_patch_exception, %g5
-               st      %g4, [%g5 + 0x18]
-               st      %g4, [%g5 + 0x1c]
-               set     flush_patch_switch, %g5
-               st      %g4, [%g5 + 0x18]
-               st      %g4, [%g5 + 0x1c]
-
-2:             
-               sethi   %hi(nwindows), %g4
-               st      %g3, [%g4 + %lo(nwindows)]      ! store final value
-               sub     %g3, 0x1, %g3
-               sethi   %hi(nwindowsm1), %g4
-               st      %g3, [%g4 + %lo(nwindowsm1)]
-
-               /* Here we go, start using Linux's trap table... */
-               set     trapbase, %g3
-               wr      %g3, 0x0, %tbr
-               WRITE_PAUSE
-
-               /* Finally, turn on traps so that we can call c-code. */
-               rd      %psr, %g3
-               wr      %g3, 0x0, %psr
-               WRITE_PAUSE
-
-               wr      %g3, PSR_ET, %psr
-               WRITE_PAUSE
-
-               /* First we call prom_init() to set up PROMLIB, then
-                * off to start_kernel().
-                */
-
-               sethi   %hi(prom_vector_p), %g5
-               ld      [%g5 + %lo(prom_vector_p)], %o0
-               call    prom_init
-                nop
-
-               call    start_kernel
-                nop
-       
-               /* We should not get here. */
-               call    halt_me
-                nop
-
-sun4_init:
-               sethi   %hi(SUN4_PROM_VECTOR+0x84), %o1
-               ld      [%o1 + %lo(SUN4_PROM_VECTOR+0x84)], %o1
-               set     sun4_notsup, %o0
-               call    %o1     /* printf */
-                nop
-               sethi   %hi(SUN4_PROM_VECTOR+0xc4), %o1
-               ld      [%o1 + %lo(SUN4_PROM_VECTOR+0xc4)], %o1
-               call    %o1     /* exittomon */
-                nop
-1:             ba      1b                      ! Cannot exit into KMON
-                nop
-
-no_sun4e_here:
-               ld      [%g7 + 0x68], %o1
-               set     sun4e_notsup, %o0
-               call    %o1
-                nop
-               b       halt_me
-                nop
-
-               __INITDATA
-
-sun4u_1:
-               .asciz "finddevice"
-               .align  4
-sun4u_2:
-               .asciz "/chosen"
-               .align  4
-sun4u_3:
-               .asciz "getprop"
-               .align  4
-sun4u_4:
-               .asciz "stdout"
-               .align  4
-sun4u_5:
-               .asciz "write"
-               .align  4
-sun4u_6:
-               .asciz  "\n\rOn sun4u you have to use UltraLinux (64bit) kernel\n\rand not a 32bit sun4[cdem] version\n\r\n\r"
-sun4u_6e:
-               .align  4
-sun4u_7:
-               .asciz "exit"
-               .align  8
-sun4u_a1:
-               .word   0, sun4u_1, 0, 1, 0, 1, 0, sun4u_2, 0
-sun4u_r1:
-               .word   0
-sun4u_a2:
-               .word   0, sun4u_3, 0, 4, 0, 1, 0
-sun4u_i2:
-               .word   0, 0, sun4u_4, 0, sun4u_1, 0, 8, 0
-sun4u_r2:
-               .word   0
-sun4u_a3:
-               .word   0, sun4u_5, 0, 3, 0, 1, 0
-sun4u_i3:
-               .word   0, 0, sun4u_6, 0, sun4u_6e - sun4u_6 - 1, 0
-sun4u_r3:
-               .word   0
-sun4u_a4:
-               .word   0, sun4u_7, 0, 0, 0, 0
-sun4u_r4:
-
-               __INIT
-no_sun4u_here:
-               set     sun4u_a1, %o0
-               set     current_pc, %l2
-               cmp     %l2, %g3
-               be      1f
-                mov    %o4, %l0
-               sub     %g3, %l2, %l6
-               add     %o0, %l6, %o0
-               mov     %o0, %l4
-               mov     sun4u_r4 - sun4u_a1, %l3
-               ld      [%l4], %l5
-2:
-               add     %l4, 4, %l4
-               cmp     %l5, %l2
-               add     %l5, %l6, %l5
-               bgeu,a  3f
-                st     %l5, [%l4 - 4]
-3:
-               subcc   %l3, 4, %l3
-               bne     2b
-                ld     [%l4], %l5
-1:
-               call    %l0
-                mov    %o0, %l1
-
-               ld      [%l1 + (sun4u_r1 - sun4u_a1)], %o1
-               add     %l1, (sun4u_a2 - sun4u_a1), %o0
-               call    %l0
-                st     %o1, [%o0 + (sun4u_i2 - sun4u_a2)]
-
-               ld      [%l1 + (sun4u_1 - sun4u_a1)], %o1
-               add     %l1, (sun4u_a3 - sun4u_a1), %o0
-               call    %l0
-               st      %o1, [%o0 + (sun4u_i3 - sun4u_a3)]
-
-               call    %l0
-                add    %l1, (sun4u_a4 - sun4u_a1), %o0
-
-               /* Not reached */
-halt_me:
-               ld      [%g7 + 0x74], %o0
-               call    %o0                     ! Get us out of here...
-                nop                            ! Apparently Solaris is better.
-
-/* Ok, now we continue in the .data/.text sections */
-
-       .data
-       .align 4
-
-/*
- * Fill up the prom vector, note in particular the kind first element,
- * no joke. I don't need all of them in here as the entire prom vector
- * gets initialized in c-code so all routines can use it.
- */
-
-prom_vector_p:
-               .word 0
-
-/* We calculate the following at boot time, window fills/spills and trap entry
- * code uses these to keep track of the register windows.
- */
-
-       .align 4
-       .globl  nwindows
-       .globl  nwindowsm1
-nwindows:
-       .word   8
-nwindowsm1:
-       .word   7
-
-/* Boot time debugger vector value.  We need this later on. */
-
-       .align 4
-       .globl  linux_dbvec
-linux_dbvec:
-       .word   0
-       .word   0
-
-       .align 8
-
-       .globl  lvl14_save
-lvl14_save:
-       .word   0
-       .word   0
-       .word   0
-       .word   0
-       .word   t_irq14
-
-        .section        ".fixup",#alloc,#execinstr
-        .globl  __ret_efault
-__ret_efault:
-        ret
-         restore %g0, -EFAULT, %o0
diff --git a/arch/sparc/kernel/head_32.S b/arch/sparc/kernel/head_32.S
new file mode 100644 (file)
index 0000000..51b4042
--- /dev/null
@@ -0,0 +1,1295 @@
+/*
+ * head.S: The initial boot code for the Sparc port of Linux.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995,1999 Pete Zaitcev   (zaitcev@yahoo.com)
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1997 Jakub Jelinek   (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997 Michael A. Griffith (grif@acm.org)
+ *
+ * CompactPCI platform by Eric Brower, 1999.
+ */
+
+#include <linux/version.h>
+#include <linux/init.h>
+
+#include <asm/head.h>
+#include <asm/asi.h>
+#include <asm/contregs.h>
+#include <asm/ptrace.h>
+#include <asm/psr.h>
+#include <asm/page.h>
+#include <asm/kdebug.h>
+#include <asm/winmacro.h>
+#include <asm/thread_info.h>   /* TI_UWINMASK */
+#include <asm/errno.h>
+#include <asm/pgtsrmmu.h>      /* SRMMU_PGDIR_SHIFT */
+
+       .data
+/* 
+ * The following are used with the prom_vector node-ops to figure out
+ * the cpu-type 
+ */
+
+       .align 4
+cputyp:
+        .word   1
+
+       .align 4
+       .globl cputypval
+cputypval:
+       .asciz "sun4c"
+       .ascii "     "
+
+cputypvalend:
+cputypvallen = cputypvar - cputypval
+
+       .align 4
+/*
+ * Sun people can't spell worth damn. "compatability" indeed.
+ * At least we *know* we can't spell, and use a spell-checker.
+ */
+
+/* Uh, actually Linus it is I who cannot spell. Too much murky
+ * Sparc assembly will do this to ya.
+ */
+cputypvar:
+       .asciz "compatability"
+
+/* Tested on SS-5, SS-10. Probably someone at Sun applied a spell-checker. */
+       .align 4
+cputypvar_sun4m:
+       .asciz "compatible"
+
+       .align 4
+
+sun4_notsup:
+       .asciz  "Sparc-Linux sun4 support does no longer exist.\n\n"
+       .align 4
+
+sun4e_notsup:
+        .asciz  "Sparc-Linux sun4e support does not exist\n\n"
+       .align 4
+
+       /* The Sparc trap table, bootloader gives us control at _start. */
+       .section .text.head,"ax"
+       .globl  start, _stext, _start, __stext
+       .globl  trapbase
+_start:   /* danger danger */
+__stext:
+_stext:
+start:
+trapbase:
+#ifdef CONFIG_SMP
+trapbase_cpu0:
+#endif
+/* We get control passed to us here at t_zero. */
+t_zero:        b gokernel; nop; nop; nop;
+t_tflt:        SPARC_TFAULT                        /* Inst. Access Exception        */
+t_bins:        TRAP_ENTRY(0x2, bad_instruction)    /* Illegal Instruction           */
+t_pins:        TRAP_ENTRY(0x3, priv_instruction)   /* Privileged Instruction        */
+t_fpd: TRAP_ENTRY(0x4, fpd_trap_handler)   /* Floating Point Disabled       */
+t_wovf:        WINDOW_SPILL                        /* Window Overflow               */
+t_wunf:        WINDOW_FILL                         /* Window Underflow              */
+t_mna: TRAP_ENTRY(0x7, mna_handler)        /* Memory Address Not Aligned    */
+t_fpe: TRAP_ENTRY(0x8, fpe_trap_handler)   /* Floating Point Exception      */
+t_dflt:        SPARC_DFAULT                        /* Data Miss Exception           */
+t_tio: TRAP_ENTRY(0xa, do_tag_overflow)    /* Tagged Instruction Ovrflw     */
+t_wpt: TRAP_ENTRY(0xb, do_watchpoint)      /* Watchpoint Detected           */
+t_badc:        BAD_TRAP(0xc) BAD_TRAP(0xd) BAD_TRAP(0xe) BAD_TRAP(0xf) BAD_TRAP(0x10)
+t_irq1:        TRAP_ENTRY_INTERRUPT(1)             /* IRQ Software/SBUS Level 1     */
+t_irq2:        TRAP_ENTRY_INTERRUPT(2)             /* IRQ SBUS Level 2              */
+t_irq3:        TRAP_ENTRY_INTERRUPT(3)             /* IRQ SCSI/DMA/SBUS Level 3     */
+t_irq4:        TRAP_ENTRY_INTERRUPT(4)             /* IRQ Software Level 4          */
+t_irq5:        TRAP_ENTRY_INTERRUPT(5)             /* IRQ SBUS/Ethernet Level 5     */
+t_irq6:        TRAP_ENTRY_INTERRUPT(6)             /* IRQ Software Level 6          */
+t_irq7:        TRAP_ENTRY_INTERRUPT(7)             /* IRQ Video/SBUS Level 5        */
+t_irq8:        TRAP_ENTRY_INTERRUPT(8)             /* IRQ SBUS Level 6              */
+t_irq9:        TRAP_ENTRY_INTERRUPT(9)             /* IRQ SBUS Level 7              */
+t_irq10:TRAP_ENTRY_INTERRUPT(10)            /* IRQ Timer #1 (one we use)     */
+t_irq11:TRAP_ENTRY_INTERRUPT(11)            /* IRQ Floppy Intr.              */
+t_irq12:TRAP_ENTRY_INTERRUPT(12)            /* IRQ Zilog serial chip         */
+t_irq13:TRAP_ENTRY_INTERRUPT(13)            /* IRQ Audio Intr.               */
+t_irq14:TRAP_ENTRY_INTERRUPT(14)            /* IRQ Timer #2                  */
+       .globl  t_nmi
+#ifndef CONFIG_SMP
+t_nmi: NMI_TRAP                            /* Level 15 (NMI)                */
+#else
+t_nmi: TRAP_ENTRY(0x1f, linux_trap_ipi15_sun4m)
+#endif
+t_racc:        TRAP_ENTRY(0x20, do_reg_access)     /* General Register Access Error */
+t_iacce:BAD_TRAP(0x21)                      /* Instr Access Error            */
+t_bad22:BAD_TRAP(0x22) BAD_TRAP(0x23)
+t_cpdis:TRAP_ENTRY(0x24, do_cp_disabled)    /* Co-Processor Disabled         */
+t_uflsh:SKIP_TRAP(0x25, unimp_flush)        /* Unimplemented FLUSH inst.     */
+t_bad26:BAD_TRAP(0x26) BAD_TRAP(0x27)
+t_cpexc:TRAP_ENTRY(0x28, do_cp_exception)   /* Co-Processor Exception        */
+t_dacce:SPARC_DFAULT                        /* Data Access Error             */
+t_hwdz:        TRAP_ENTRY(0x2a, do_hw_divzero)     /* Division by zero, you lose... */
+t_dserr:BAD_TRAP(0x2b)                      /* Data Store Error              */
+t_daccm:BAD_TRAP(0x2c)                      /* Data Access MMU-Miss          */
+t_bad2d:BAD_TRAP(0x2d) BAD_TRAP(0x2e) BAD_TRAP(0x2f) BAD_TRAP(0x30) BAD_TRAP(0x31)
+t_bad32:BAD_TRAP(0x32) BAD_TRAP(0x33) BAD_TRAP(0x34) BAD_TRAP(0x35) BAD_TRAP(0x36)
+t_bad37:BAD_TRAP(0x37) BAD_TRAP(0x38) BAD_TRAP(0x39) BAD_TRAP(0x3a) BAD_TRAP(0x3b)
+t_iaccm:BAD_TRAP(0x3c)                      /* Instr Access MMU-Miss         */
+t_bad3d:BAD_TRAP(0x3d) BAD_TRAP(0x3e) BAD_TRAP(0x3f) BAD_TRAP(0x40) BAD_TRAP(0x41)
+t_bad42:BAD_TRAP(0x42) BAD_TRAP(0x43) BAD_TRAP(0x44) BAD_TRAP(0x45) BAD_TRAP(0x46)
+t_bad47:BAD_TRAP(0x47) BAD_TRAP(0x48) BAD_TRAP(0x49) BAD_TRAP(0x4a) BAD_TRAP(0x4b)
+t_bad4c:BAD_TRAP(0x4c) BAD_TRAP(0x4d) BAD_TRAP(0x4e) BAD_TRAP(0x4f) BAD_TRAP(0x50)
+t_bad51:BAD_TRAP(0x51) BAD_TRAP(0x52) BAD_TRAP(0x53) BAD_TRAP(0x54) BAD_TRAP(0x55)
+t_bad56:BAD_TRAP(0x56) BAD_TRAP(0x57) BAD_TRAP(0x58) BAD_TRAP(0x59) BAD_TRAP(0x5a)
+t_bad5b:BAD_TRAP(0x5b) BAD_TRAP(0x5c) BAD_TRAP(0x5d) BAD_TRAP(0x5e) BAD_TRAP(0x5f)
+t_bad60:BAD_TRAP(0x60) BAD_TRAP(0x61) BAD_TRAP(0x62) BAD_TRAP(0x63) BAD_TRAP(0x64)
+t_bad65:BAD_TRAP(0x65) BAD_TRAP(0x66) BAD_TRAP(0x67) BAD_TRAP(0x68) BAD_TRAP(0x69)
+t_bad6a:BAD_TRAP(0x6a) BAD_TRAP(0x6b) BAD_TRAP(0x6c) BAD_TRAP(0x6d) BAD_TRAP(0x6e)
+t_bad6f:BAD_TRAP(0x6f) BAD_TRAP(0x70) BAD_TRAP(0x71) BAD_TRAP(0x72) BAD_TRAP(0x73)
+t_bad74:BAD_TRAP(0x74) BAD_TRAP(0x75) BAD_TRAP(0x76) BAD_TRAP(0x77) BAD_TRAP(0x78)
+t_bad79:BAD_TRAP(0x79) BAD_TRAP(0x7a) BAD_TRAP(0x7b) BAD_TRAP(0x7c) BAD_TRAP(0x7d)
+t_bad7e:BAD_TRAP(0x7e) BAD_TRAP(0x7f)
+t_bad80:BAD_TRAP(0x80)                      /* SunOS System Call             */
+t_sbkpt:BREAKPOINT_TRAP                     /* Software Breakpoint/KGDB      */
+t_divz:        TRAP_ENTRY(0x82, do_hw_divzero)     /* Divide by zero trap           */
+t_flwin:TRAP_ENTRY(0x83, do_flush_windows)  /* Flush Windows Trap            */
+t_clwin:BAD_TRAP(0x84)                      /* Clean Windows Trap            */
+t_rchk:        BAD_TRAP(0x85)                      /* Range Check                   */
+t_funal:BAD_TRAP(0x86)                      /* Fix Unaligned Access Trap     */
+t_iovf:        BAD_TRAP(0x87)                      /* Integer Overflow Trap         */
+t_bad88:BAD_TRAP(0x88)                      /* Slowaris System Call          */
+t_bad89:BAD_TRAP(0x89)                      /* Net-B.S. System Call          */
+t_bad8a:BAD_TRAP(0x8a) BAD_TRAP(0x8b) BAD_TRAP(0x8c) BAD_TRAP(0x8d) BAD_TRAP(0x8e)
+t_bad8f:BAD_TRAP(0x8f)
+t_linux:LINUX_SYSCALL_TRAP                  /* Linux System Call             */
+t_bad91:BAD_TRAP(0x91) BAD_TRAP(0x92) BAD_TRAP(0x93) BAD_TRAP(0x94) BAD_TRAP(0x95)
+t_bad96:BAD_TRAP(0x96) BAD_TRAP(0x97) BAD_TRAP(0x98) BAD_TRAP(0x99) BAD_TRAP(0x9a)
+t_bad9b:BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e) BAD_TRAP(0x9f)
+t_getcc:GETCC_TRAP                          /* Get Condition Codes           */
+t_setcc:SETCC_TRAP                          /* Set Condition Codes           */
+t_getpsr:GETPSR_TRAP                        /* Get PSR Register              */
+t_bada3:BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6)
+t_bada7:BAD_TRAP(0xa7)
+t_bada8:BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab)
+t_badac:BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf) BAD_TRAP(0xb0)
+t_badb1:BAD_TRAP(0xb1) BAD_TRAP(0xb2) BAD_TRAP(0xb3) BAD_TRAP(0xb4) BAD_TRAP(0xb5)
+t_badb6:BAD_TRAP(0xb6) BAD_TRAP(0xb7) BAD_TRAP(0xb8) BAD_TRAP(0xb9) BAD_TRAP(0xba)
+t_badbb:BAD_TRAP(0xbb) BAD_TRAP(0xbc) BAD_TRAP(0xbd) BAD_TRAP(0xbe) BAD_TRAP(0xbf)
+t_badc0:BAD_TRAP(0xc0) BAD_TRAP(0xc1) BAD_TRAP(0xc2) BAD_TRAP(0xc3) BAD_TRAP(0xc4)
+t_badc5:BAD_TRAP(0xc5) BAD_TRAP(0xc6) BAD_TRAP(0xc7) BAD_TRAP(0xc8) BAD_TRAP(0xc9)
+t_badca:BAD_TRAP(0xca) BAD_TRAP(0xcb) BAD_TRAP(0xcc) BAD_TRAP(0xcd) BAD_TRAP(0xce)
+t_badcf:BAD_TRAP(0xcf) BAD_TRAP(0xd0) BAD_TRAP(0xd1) BAD_TRAP(0xd2) BAD_TRAP(0xd3)
+t_badd4:BAD_TRAP(0xd4) BAD_TRAP(0xd5) BAD_TRAP(0xd6) BAD_TRAP(0xd7) BAD_TRAP(0xd8)
+t_badd9:BAD_TRAP(0xd9) BAD_TRAP(0xda) BAD_TRAP(0xdb) BAD_TRAP(0xdc) BAD_TRAP(0xdd)
+t_badde:BAD_TRAP(0xde) BAD_TRAP(0xdf) BAD_TRAP(0xe0) BAD_TRAP(0xe1) BAD_TRAP(0xe2)
+t_bade3:BAD_TRAP(0xe3) BAD_TRAP(0xe4) BAD_TRAP(0xe5) BAD_TRAP(0xe6) BAD_TRAP(0xe7)
+t_bade8:BAD_TRAP(0xe8) BAD_TRAP(0xe9) BAD_TRAP(0xea) BAD_TRAP(0xeb) BAD_TRAP(0xec)
+t_baded:BAD_TRAP(0xed) BAD_TRAP(0xee) BAD_TRAP(0xef) BAD_TRAP(0xf0) BAD_TRAP(0xf1)
+t_badf2:BAD_TRAP(0xf2) BAD_TRAP(0xf3) BAD_TRAP(0xf4) BAD_TRAP(0xf5) BAD_TRAP(0xf6)
+t_badf7:BAD_TRAP(0xf7) BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb)
+t_badfc:BAD_TRAP(0xfc)
+t_kgdb:        KGDB_TRAP(0xfd)
+dbtrap:        BAD_TRAP(0xfe)                      /* Debugger/PROM breakpoint #1   */
+dbtrap2:BAD_TRAP(0xff)                      /* Debugger/PROM breakpoint #2   */        
+
+       .globl  end_traptable
+end_traptable:
+
+#ifdef CONFIG_SMP
+       /* Trap tables for the other cpus. */
+       .globl  trapbase_cpu1, trapbase_cpu2, trapbase_cpu3
+trapbase_cpu1:
+       BAD_TRAP(0x0) SRMMU_TFAULT TRAP_ENTRY(0x2, bad_instruction)
+       TRAP_ENTRY(0x3, priv_instruction) TRAP_ENTRY(0x4, fpd_trap_handler)
+       WINDOW_SPILL WINDOW_FILL TRAP_ENTRY(0x7, mna_handler)
+       TRAP_ENTRY(0x8, fpe_trap_handler) SRMMU_DFAULT
+       TRAP_ENTRY(0xa, do_tag_overflow) TRAP_ENTRY(0xb, do_watchpoint)
+       BAD_TRAP(0xc) BAD_TRAP(0xd) BAD_TRAP(0xe) BAD_TRAP(0xf) BAD_TRAP(0x10)
+       TRAP_ENTRY_INTERRUPT(1) TRAP_ENTRY_INTERRUPT(2)
+       TRAP_ENTRY_INTERRUPT(3) TRAP_ENTRY_INTERRUPT(4)
+       TRAP_ENTRY_INTERRUPT(5) TRAP_ENTRY_INTERRUPT(6)
+       TRAP_ENTRY_INTERRUPT(7) TRAP_ENTRY_INTERRUPT(8)
+       TRAP_ENTRY_INTERRUPT(9) TRAP_ENTRY_INTERRUPT(10)
+       TRAP_ENTRY_INTERRUPT(11) TRAP_ENTRY_INTERRUPT(12)
+       TRAP_ENTRY_INTERRUPT(13) TRAP_ENTRY_INTERRUPT(14)
+       TRAP_ENTRY(0x1f, linux_trap_ipi15_sun4m)
+       TRAP_ENTRY(0x20, do_reg_access) BAD_TRAP(0x21) BAD_TRAP(0x22)
+       BAD_TRAP(0x23) TRAP_ENTRY(0x24, do_cp_disabled) SKIP_TRAP(0x25, unimp_flush)
+       BAD_TRAP(0x26) BAD_TRAP(0x27) TRAP_ENTRY(0x28, do_cp_exception)
+       SRMMU_DFAULT TRAP_ENTRY(0x2a, do_hw_divzero) BAD_TRAP(0x2b) BAD_TRAP(0x2c)
+       BAD_TRAP(0x2d) BAD_TRAP(0x2e) BAD_TRAP(0x2f) BAD_TRAP(0x30) BAD_TRAP(0x31)
+       BAD_TRAP(0x32) BAD_TRAP(0x33) BAD_TRAP(0x34) BAD_TRAP(0x35) BAD_TRAP(0x36)
+       BAD_TRAP(0x37) BAD_TRAP(0x38) BAD_TRAP(0x39) BAD_TRAP(0x3a) BAD_TRAP(0x3b)
+       BAD_TRAP(0x3c) BAD_TRAP(0x3d) BAD_TRAP(0x3e) BAD_TRAP(0x3f) BAD_TRAP(0x40)
+       BAD_TRAP(0x41) BAD_TRAP(0x42) BAD_TRAP(0x43) BAD_TRAP(0x44) BAD_TRAP(0x45)
+       BAD_TRAP(0x46) BAD_TRAP(0x47) BAD_TRAP(0x48) BAD_TRAP(0x49) BAD_TRAP(0x4a)
+       BAD_TRAP(0x4b) BAD_TRAP(0x4c) BAD_TRAP(0x4d) BAD_TRAP(0x4e) BAD_TRAP(0x4f)
+       BAD_TRAP(0x50)
+       BAD_TRAP(0x51) BAD_TRAP(0x52) BAD_TRAP(0x53) BAD_TRAP(0x54) BAD_TRAP(0x55)
+       BAD_TRAP(0x56) BAD_TRAP(0x57) BAD_TRAP(0x58) BAD_TRAP(0x59) BAD_TRAP(0x5a)
+       BAD_TRAP(0x5b) BAD_TRAP(0x5c) BAD_TRAP(0x5d) BAD_TRAP(0x5e) BAD_TRAP(0x5f)
+       BAD_TRAP(0x60) BAD_TRAP(0x61) BAD_TRAP(0x62) BAD_TRAP(0x63) BAD_TRAP(0x64)
+       BAD_TRAP(0x65) BAD_TRAP(0x66) BAD_TRAP(0x67) BAD_TRAP(0x68) BAD_TRAP(0x69)
+       BAD_TRAP(0x6a) BAD_TRAP(0x6b) BAD_TRAP(0x6c) BAD_TRAP(0x6d) BAD_TRAP(0x6e)
+       BAD_TRAP(0x6f) BAD_TRAP(0x70) BAD_TRAP(0x71) BAD_TRAP(0x72) BAD_TRAP(0x73)
+       BAD_TRAP(0x74) BAD_TRAP(0x75) BAD_TRAP(0x76) BAD_TRAP(0x77) BAD_TRAP(0x78)
+       BAD_TRAP(0x79) BAD_TRAP(0x7a) BAD_TRAP(0x7b) BAD_TRAP(0x7c) BAD_TRAP(0x7d)
+       BAD_TRAP(0x7e) BAD_TRAP(0x7f)
+       BAD_TRAP(0x80)
+       BREAKPOINT_TRAP
+       TRAP_ENTRY(0x82, do_hw_divzero)
+       TRAP_ENTRY(0x83, do_flush_windows) BAD_TRAP(0x84) BAD_TRAP(0x85)
+       BAD_TRAP(0x86) BAD_TRAP(0x87) BAD_TRAP(0x88)
+       BAD_TRAP(0x89) BAD_TRAP(0x8a) BAD_TRAP(0x8b) BAD_TRAP(0x8c)
+       BAD_TRAP(0x8d) BAD_TRAP(0x8e) BAD_TRAP(0x8f)
+       LINUX_SYSCALL_TRAP BAD_TRAP(0x91) BAD_TRAP(0x92) BAD_TRAP(0x93) BAD_TRAP(0x94)
+       BAD_TRAP(0x95) BAD_TRAP(0x96) BAD_TRAP(0x97) BAD_TRAP(0x98) BAD_TRAP(0x99)
+       BAD_TRAP(0x9a) BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e)
+       BAD_TRAP(0x9f) GETCC_TRAP SETCC_TRAP GETPSR_TRAP
+       BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6)
+       BAD_TRAP(0xa7) BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab)
+       BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf) BAD_TRAP(0xb0)
+       BAD_TRAP(0xb1) BAD_TRAP(0xb2) BAD_TRAP(0xb3) BAD_TRAP(0xb4) BAD_TRAP(0xb5)
+       BAD_TRAP(0xb6) BAD_TRAP(0xb7) BAD_TRAP(0xb8) BAD_TRAP(0xb9) BAD_TRAP(0xba)
+       BAD_TRAP(0xbb) BAD_TRAP(0xbc) BAD_TRAP(0xbd) BAD_TRAP(0xbe) BAD_TRAP(0xbf)
+       BAD_TRAP(0xc0) BAD_TRAP(0xc1) BAD_TRAP(0xc2) BAD_TRAP(0xc3) BAD_TRAP(0xc4)
+       BAD_TRAP(0xc5) BAD_TRAP(0xc6) BAD_TRAP(0xc7) BAD_TRAP(0xc8) BAD_TRAP(0xc9)
+       BAD_TRAP(0xca) BAD_TRAP(0xcb) BAD_TRAP(0xcc) BAD_TRAP(0xcd) BAD_TRAP(0xce)
+       BAD_TRAP(0xcf) BAD_TRAP(0xd0) BAD_TRAP(0xd1) BAD_TRAP(0xd2) BAD_TRAP(0xd3)
+       BAD_TRAP(0xd4) BAD_TRAP(0xd5) BAD_TRAP(0xd6) BAD_TRAP(0xd7) BAD_TRAP(0xd8)
+       BAD_TRAP(0xd9) BAD_TRAP(0xda) BAD_TRAP(0xdb) BAD_TRAP(0xdc) BAD_TRAP(0xdd)
+       BAD_TRAP(0xde) BAD_TRAP(0xdf) BAD_TRAP(0xe0) BAD_TRAP(0xe1) BAD_TRAP(0xe2)
+       BAD_TRAP(0xe3) BAD_TRAP(0xe4) BAD_TRAP(0xe5) BAD_TRAP(0xe6) BAD_TRAP(0xe7)
+       BAD_TRAP(0xe8) BAD_TRAP(0xe9) BAD_TRAP(0xea) BAD_TRAP(0xeb) BAD_TRAP(0xec)
+       BAD_TRAP(0xed) BAD_TRAP(0xee) BAD_TRAP(0xef) BAD_TRAP(0xf0) BAD_TRAP(0xf1)
+       BAD_TRAP(0xf2) BAD_TRAP(0xf3) BAD_TRAP(0xf4) BAD_TRAP(0xf5) BAD_TRAP(0xf6)
+       BAD_TRAP(0xf7) BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb)
+       BAD_TRAP(0xfc) KGDB_TRAP(0xfd) BAD_TRAP(0xfe) BAD_TRAP(0xff)
+
+trapbase_cpu2:
+       BAD_TRAP(0x0) SRMMU_TFAULT TRAP_ENTRY(0x2, bad_instruction)
+       TRAP_ENTRY(0x3, priv_instruction) TRAP_ENTRY(0x4, fpd_trap_handler)
+       WINDOW_SPILL WINDOW_FILL TRAP_ENTRY(0x7, mna_handler)
+       TRAP_ENTRY(0x8, fpe_trap_handler) SRMMU_DFAULT
+       TRAP_ENTRY(0xa, do_tag_overflow) TRAP_ENTRY(0xb, do_watchpoint)
+       BAD_TRAP(0xc) BAD_TRAP(0xd) BAD_TRAP(0xe) BAD_TRAP(0xf) BAD_TRAP(0x10)
+       TRAP_ENTRY_INTERRUPT(1) TRAP_ENTRY_INTERRUPT(2)
+       TRAP_ENTRY_INTERRUPT(3) TRAP_ENTRY_INTERRUPT(4)
+       TRAP_ENTRY_INTERRUPT(5) TRAP_ENTRY_INTERRUPT(6)
+       TRAP_ENTRY_INTERRUPT(7) TRAP_ENTRY_INTERRUPT(8)
+       TRAP_ENTRY_INTERRUPT(9) TRAP_ENTRY_INTERRUPT(10)
+       TRAP_ENTRY_INTERRUPT(11) TRAP_ENTRY_INTERRUPT(12)
+       TRAP_ENTRY_INTERRUPT(13) TRAP_ENTRY_INTERRUPT(14)
+       TRAP_ENTRY(0x1f, linux_trap_ipi15_sun4m)
+       TRAP_ENTRY(0x20, do_reg_access) BAD_TRAP(0x21) BAD_TRAP(0x22)
+       BAD_TRAP(0x23) TRAP_ENTRY(0x24, do_cp_disabled) SKIP_TRAP(0x25, unimp_flush)
+       BAD_TRAP(0x26) BAD_TRAP(0x27) TRAP_ENTRY(0x28, do_cp_exception)
+       SRMMU_DFAULT TRAP_ENTRY(0x2a, do_hw_divzero) BAD_TRAP(0x2b) BAD_TRAP(0x2c)
+       BAD_TRAP(0x2d) BAD_TRAP(0x2e) BAD_TRAP(0x2f) BAD_TRAP(0x30) BAD_TRAP(0x31)
+       BAD_TRAP(0x32) BAD_TRAP(0x33) BAD_TRAP(0x34) BAD_TRAP(0x35) BAD_TRAP(0x36)
+       BAD_TRAP(0x37) BAD_TRAP(0x38) BAD_TRAP(0x39) BAD_TRAP(0x3a) BAD_TRAP(0x3b)
+       BAD_TRAP(0x3c) BAD_TRAP(0x3d) BAD_TRAP(0x3e) BAD_TRAP(0x3f) BAD_TRAP(0x40)
+       BAD_TRAP(0x41) BAD_TRAP(0x42) BAD_TRAP(0x43) BAD_TRAP(0x44) BAD_TRAP(0x45)
+       BAD_TRAP(0x46) BAD_TRAP(0x47) BAD_TRAP(0x48) BAD_TRAP(0x49) BAD_TRAP(0x4a)
+       BAD_TRAP(0x4b) BAD_TRAP(0x4c) BAD_TRAP(0x4d) BAD_TRAP(0x4e) BAD_TRAP(0x4f)
+       BAD_TRAP(0x50)
+       BAD_TRAP(0x51) BAD_TRAP(0x52) BAD_TRAP(0x53) BAD_TRAP(0x54) BAD_TRAP(0x55)
+       BAD_TRAP(0x56) BAD_TRAP(0x57) BAD_TRAP(0x58) BAD_TRAP(0x59) BAD_TRAP(0x5a)
+       BAD_TRAP(0x5b) BAD_TRAP(0x5c) BAD_TRAP(0x5d) BAD_TRAP(0x5e) BAD_TRAP(0x5f)
+       BAD_TRAP(0x60) BAD_TRAP(0x61) BAD_TRAP(0x62) BAD_TRAP(0x63) BAD_TRAP(0x64)
+       BAD_TRAP(0x65) BAD_TRAP(0x66) BAD_TRAP(0x67) BAD_TRAP(0x68) BAD_TRAP(0x69)
+       BAD_TRAP(0x6a) BAD_TRAP(0x6b) BAD_TRAP(0x6c) BAD_TRAP(0x6d) BAD_TRAP(0x6e)
+       BAD_TRAP(0x6f) BAD_TRAP(0x70) BAD_TRAP(0x71) BAD_TRAP(0x72) BAD_TRAP(0x73)
+       BAD_TRAP(0x74) BAD_TRAP(0x75) BAD_TRAP(0x76) BAD_TRAP(0x77) BAD_TRAP(0x78)
+       BAD_TRAP(0x79) BAD_TRAP(0x7a) BAD_TRAP(0x7b) BAD_TRAP(0x7c) BAD_TRAP(0x7d)
+       BAD_TRAP(0x7e) BAD_TRAP(0x7f)
+       BAD_TRAP(0x80)
+       BREAKPOINT_TRAP
+       TRAP_ENTRY(0x82, do_hw_divzero)
+       TRAP_ENTRY(0x83, do_flush_windows) BAD_TRAP(0x84) BAD_TRAP(0x85)
+       BAD_TRAP(0x86) BAD_TRAP(0x87) BAD_TRAP(0x88)
+       BAD_TRAP(0x89) BAD_TRAP(0x8a) BAD_TRAP(0x8b) BAD_TRAP(0x8c)
+       BAD_TRAP(0x8d) BAD_TRAP(0x8e) BAD_TRAP(0x8f)
+       LINUX_SYSCALL_TRAP BAD_TRAP(0x91) BAD_TRAP(0x92) BAD_TRAP(0x93) BAD_TRAP(0x94)
+       BAD_TRAP(0x95) BAD_TRAP(0x96) BAD_TRAP(0x97) BAD_TRAP(0x98) BAD_TRAP(0x99)
+       BAD_TRAP(0x9a) BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e)
+       BAD_TRAP(0x9f) GETCC_TRAP SETCC_TRAP GETPSR_TRAP
+       BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6)
+       BAD_TRAP(0xa7) BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab)
+       BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf) BAD_TRAP(0xb0)
+       BAD_TRAP(0xb1) BAD_TRAP(0xb2) BAD_TRAP(0xb3) BAD_TRAP(0xb4) BAD_TRAP(0xb5)
+       BAD_TRAP(0xb6) BAD_TRAP(0xb7) BAD_TRAP(0xb8) BAD_TRAP(0xb9) BAD_TRAP(0xba)
+       BAD_TRAP(0xbb) BAD_TRAP(0xbc) BAD_TRAP(0xbd) BAD_TRAP(0xbe) BAD_TRAP(0xbf)
+       BAD_TRAP(0xc0) BAD_TRAP(0xc1) BAD_TRAP(0xc2) BAD_TRAP(0xc3) BAD_TRAP(0xc4)
+       BAD_TRAP(0xc5) BAD_TRAP(0xc6) BAD_TRAP(0xc7) BAD_TRAP(0xc8) BAD_TRAP(0xc9)
+       BAD_TRAP(0xca) BAD_TRAP(0xcb) BAD_TRAP(0xcc) BAD_TRAP(0xcd) BAD_TRAP(0xce)
+       BAD_TRAP(0xcf) BAD_TRAP(0xd0) BAD_TRAP(0xd1) BAD_TRAP(0xd2) BAD_TRAP(0xd3)
+       BAD_TRAP(0xd4) BAD_TRAP(0xd5) BAD_TRAP(0xd6) BAD_TRAP(0xd7) BAD_TRAP(0xd8)
+       BAD_TRAP(0xd9) BAD_TRAP(0xda) BAD_TRAP(0xdb) BAD_TRAP(0xdc) BAD_TRAP(0xdd)
+       BAD_TRAP(0xde) BAD_TRAP(0xdf) BAD_TRAP(0xe0) BAD_TRAP(0xe1) BAD_TRAP(0xe2)
+       BAD_TRAP(0xe3) BAD_TRAP(0xe4) BAD_TRAP(0xe5) BAD_TRAP(0xe6) BAD_TRAP(0xe7)
+       BAD_TRAP(0xe8) BAD_TRAP(0xe9) BAD_TRAP(0xea) BAD_TRAP(0xeb) BAD_TRAP(0xec)
+       BAD_TRAP(0xed) BAD_TRAP(0xee) BAD_TRAP(0xef) BAD_TRAP(0xf0) BAD_TRAP(0xf1)
+       BAD_TRAP(0xf2) BAD_TRAP(0xf3) BAD_TRAP(0xf4) BAD_TRAP(0xf5) BAD_TRAP(0xf6)
+       BAD_TRAP(0xf7) BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb)
+       BAD_TRAP(0xfc) KGDB_TRAP(0xfd) BAD_TRAP(0xfe) BAD_TRAP(0xff)
+
+trapbase_cpu3:
+       BAD_TRAP(0x0) SRMMU_TFAULT TRAP_ENTRY(0x2, bad_instruction)
+       TRAP_ENTRY(0x3, priv_instruction) TRAP_ENTRY(0x4, fpd_trap_handler)
+       WINDOW_SPILL WINDOW_FILL TRAP_ENTRY(0x7, mna_handler)
+       TRAP_ENTRY(0x8, fpe_trap_handler) SRMMU_DFAULT
+       TRAP_ENTRY(0xa, do_tag_overflow) TRAP_ENTRY(0xb, do_watchpoint)
+       BAD_TRAP(0xc) BAD_TRAP(0xd) BAD_TRAP(0xe) BAD_TRAP(0xf) BAD_TRAP(0x10)
+       TRAP_ENTRY_INTERRUPT(1) TRAP_ENTRY_INTERRUPT(2)
+       TRAP_ENTRY_INTERRUPT(3) TRAP_ENTRY_INTERRUPT(4)
+       TRAP_ENTRY_INTERRUPT(5) TRAP_ENTRY_INTERRUPT(6)
+       TRAP_ENTRY_INTERRUPT(7) TRAP_ENTRY_INTERRUPT(8)
+       TRAP_ENTRY_INTERRUPT(9) TRAP_ENTRY_INTERRUPT(10)
+       TRAP_ENTRY_INTERRUPT(11) TRAP_ENTRY_INTERRUPT(12)
+       TRAP_ENTRY_INTERRUPT(13) TRAP_ENTRY_INTERRUPT(14)
+       TRAP_ENTRY(0x1f, linux_trap_ipi15_sun4m)
+       TRAP_ENTRY(0x20, do_reg_access) BAD_TRAP(0x21) BAD_TRAP(0x22)
+       BAD_TRAP(0x23) TRAP_ENTRY(0x24, do_cp_disabled) SKIP_TRAP(0x25, unimp_flush)
+       BAD_TRAP(0x26) BAD_TRAP(0x27) TRAP_ENTRY(0x28, do_cp_exception)
+       SRMMU_DFAULT TRAP_ENTRY(0x2a, do_hw_divzero) BAD_TRAP(0x2b) BAD_TRAP(0x2c)
+       BAD_TRAP(0x2d) BAD_TRAP(0x2e) BAD_TRAP(0x2f) BAD_TRAP(0x30) BAD_TRAP(0x31)
+       BAD_TRAP(0x32) BAD_TRAP(0x33) BAD_TRAP(0x34) BAD_TRAP(0x35) BAD_TRAP(0x36)
+       BAD_TRAP(0x37) BAD_TRAP(0x38) BAD_TRAP(0x39) BAD_TRAP(0x3a) BAD_TRAP(0x3b)
+       BAD_TRAP(0x3c) BAD_TRAP(0x3d) BAD_TRAP(0x3e) BAD_TRAP(0x3f) BAD_TRAP(0x40)
+       BAD_TRAP(0x41) BAD_TRAP(0x42) BAD_TRAP(0x43) BAD_TRAP(0x44) BAD_TRAP(0x45)
+       BAD_TRAP(0x46) BAD_TRAP(0x47) BAD_TRAP(0x48) BAD_TRAP(0x49) BAD_TRAP(0x4a)
+       BAD_TRAP(0x4b) BAD_TRAP(0x4c) BAD_TRAP(0x4d) BAD_TRAP(0x4e) BAD_TRAP(0x4f)
+       BAD_TRAP(0x50)
+       BAD_TRAP(0x51) BAD_TRAP(0x52) BAD_TRAP(0x53) BAD_TRAP(0x54) BAD_TRAP(0x55)
+       BAD_TRAP(0x56) BAD_TRAP(0x57) BAD_TRAP(0x58) BAD_TRAP(0x59) BAD_TRAP(0x5a)
+       BAD_TRAP(0x5b) BAD_TRAP(0x5c) BAD_TRAP(0x5d) BAD_TRAP(0x5e) BAD_TRAP(0x5f)
+       BAD_TRAP(0x60) BAD_TRAP(0x61) BAD_TRAP(0x62) BAD_TRAP(0x63) BAD_TRAP(0x64)
+       BAD_TRAP(0x65) BAD_TRAP(0x66) BAD_TRAP(0x67) BAD_TRAP(0x68) BAD_TRAP(0x69)
+       BAD_TRAP(0x6a) BAD_TRAP(0x6b) BAD_TRAP(0x6c) BAD_TRAP(0x6d) BAD_TRAP(0x6e)
+       BAD_TRAP(0x6f) BAD_TRAP(0x70) BAD_TRAP(0x71) BAD_TRAP(0x72) BAD_TRAP(0x73)
+       BAD_TRAP(0x74) BAD_TRAP(0x75) BAD_TRAP(0x76) BAD_TRAP(0x77) BAD_TRAP(0x78)
+       BAD_TRAP(0x79) BAD_TRAP(0x7a) BAD_TRAP(0x7b) BAD_TRAP(0x7c) BAD_TRAP(0x7d)
+       BAD_TRAP(0x7e) BAD_TRAP(0x7f)
+       BAD_TRAP(0x80)
+       BREAKPOINT_TRAP
+       TRAP_ENTRY(0x82, do_hw_divzero)
+       TRAP_ENTRY(0x83, do_flush_windows) BAD_TRAP(0x84) BAD_TRAP(0x85)
+       BAD_TRAP(0x86) BAD_TRAP(0x87) BAD_TRAP(0x88)
+       BAD_TRAP(0x89) BAD_TRAP(0x8a) BAD_TRAP(0x8b) BAD_TRAP(0x8c)
+       BAD_TRAP(0x8d) BAD_TRAP(0x8e) BAD_TRAP(0x8f)
+       LINUX_SYSCALL_TRAP BAD_TRAP(0x91) BAD_TRAP(0x92) BAD_TRAP(0x93) BAD_TRAP(0x94)
+       BAD_TRAP(0x95) BAD_TRAP(0x96) BAD_TRAP(0x97) BAD_TRAP(0x98) BAD_TRAP(0x99)
+       BAD_TRAP(0x9a) BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e)
+       BAD_TRAP(0x9f) GETCC_TRAP SETCC_TRAP GETPSR_TRAP
+       BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6)
+       BAD_TRAP(0xa7) BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab)
+       BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf) BAD_TRAP(0xb0)
+       BAD_TRAP(0xb1) BAD_TRAP(0xb2) BAD_TRAP(0xb3) BAD_TRAP(0xb4) BAD_TRAP(0xb5)
+       BAD_TRAP(0xb6) BAD_TRAP(0xb7) BAD_TRAP(0xb8) BAD_TRAP(0xb9) BAD_TRAP(0xba)
+       BAD_TRAP(0xbb) BAD_TRAP(0xbc) BAD_TRAP(0xbd) BAD_TRAP(0xbe) BAD_TRAP(0xbf)
+       BAD_TRAP(0xc0) BAD_TRAP(0xc1) BAD_TRAP(0xc2) BAD_TRAP(0xc3) BAD_TRAP(0xc4)
+       BAD_TRAP(0xc5) BAD_TRAP(0xc6) BAD_TRAP(0xc7) BAD_TRAP(0xc8) BAD_TRAP(0xc9)
+       BAD_TRAP(0xca) BAD_TRAP(0xcb) BAD_TRAP(0xcc) BAD_TRAP(0xcd) BAD_TRAP(0xce)
+       BAD_TRAP(0xcf) BAD_TRAP(0xd0) BAD_TRAP(0xd1) BAD_TRAP(0xd2) BAD_TRAP(0xd3)
+       BAD_TRAP(0xd4) BAD_TRAP(0xd5) BAD_TRAP(0xd6) BAD_TRAP(0xd7) BAD_TRAP(0xd8)
+       BAD_TRAP(0xd9) BAD_TRAP(0xda) BAD_TRAP(0xdb) BAD_TRAP(0xdc) BAD_TRAP(0xdd)
+       BAD_TRAP(0xde) BAD_TRAP(0xdf) BAD_TRAP(0xe0) BAD_TRAP(0xe1) BAD_TRAP(0xe2)
+       BAD_TRAP(0xe3) BAD_TRAP(0xe4) BAD_TRAP(0xe5) BAD_TRAP(0xe6) BAD_TRAP(0xe7)
+       BAD_TRAP(0xe8) BAD_TRAP(0xe9) BAD_TRAP(0xea) BAD_TRAP(0xeb) BAD_TRAP(0xec)
+       BAD_TRAP(0xed) BAD_TRAP(0xee) BAD_TRAP(0xef) BAD_TRAP(0xf0) BAD_TRAP(0xf1)
+       BAD_TRAP(0xf2) BAD_TRAP(0xf3) BAD_TRAP(0xf4) BAD_TRAP(0xf5) BAD_TRAP(0xf6)
+       BAD_TRAP(0xf7) BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb)
+       BAD_TRAP(0xfc) KGDB_TRAP(0xfd) BAD_TRAP(0xfe) BAD_TRAP(0xff)
+
+#endif
+       .align PAGE_SIZE
+
+/* This was the only reasonable way I could think of to properly align
+ * these page-table data structures.
+ */
+       .globl pg0, pg1, pg2, pg3
+       .globl empty_bad_page
+       .globl empty_bad_page_table
+       .globl empty_zero_page
+       .globl swapper_pg_dir
+swapper_pg_dir:                .skip PAGE_SIZE
+pg0:                   .skip PAGE_SIZE
+pg1:                   .skip PAGE_SIZE
+pg2:                   .skip PAGE_SIZE
+pg3:                   .skip PAGE_SIZE
+empty_bad_page:                .skip PAGE_SIZE
+empty_bad_page_table:  .skip PAGE_SIZE
+empty_zero_page:       .skip PAGE_SIZE
+
+       .global root_flags
+       .global ram_flags
+       .global root_dev
+       .global sparc_ramdisk_image
+       .global sparc_ramdisk_size
+
+/* This stuff has to be in sync with SILO and other potential boot loaders
+ * Fields should be kept upward compatible and whenever any change is made,
+ * HdrS version should be incremented.
+ */
+       .ascii  "HdrS"
+       .word   LINUX_VERSION_CODE
+       .half   0x0203          /* HdrS version */
+root_flags:
+       .half   1
+root_dev:
+       .half   0
+ram_flags:
+       .half   0
+sparc_ramdisk_image:
+       .word   0
+sparc_ramdisk_size:
+       .word   0
+       .word   reboot_command
+       .word   0, 0, 0
+       .word   _end
+
+/* Cool, here we go. Pick up the romvec pointer in %o0 and stash it in
+ * %g7 and at prom_vector_p. And also quickly check whether we are on
+ * a v0, v2, or v3 prom.
+ */
+gokernel:
+               /* Ok, it's nice to know, as early as possible, if we
+                * are already mapped where we expect to be in virtual
+                * memory.  The Solaris /boot elf format bootloader
+                * will peek into our elf header and load us where
+                * we want to be, otherwise we have to re-map.
+                *
+                * Some boot loaders don't place the jmp'rs address
+                * in %o7, so we do a pc-relative call to a local
+                * label, then see what %o7 has.
+                */
+
+               mov     %o7, %g4                ! Save %o7
+
+               /* Jump to it, and pray... */
+current_pc:
+               call    1f
+                nop
+
+1:
+               mov     %o7, %g3
+
+               tst     %o0
+               be      no_sun4u_here
+                mov    %g4, %o7                /* Previous %o7. */
+       
+               mov     %o0, %l0                ! stash away romvec
+               mov     %o0, %g7                ! put it here too
+               mov     %o1, %l1                ! stash away debug_vec too
+
+               /* Ok, let's check out our run time program counter. */
+               set     current_pc, %g5
+               cmp     %g3, %g5
+               be      already_mapped
+                nop 
+
+               /* %l6 will hold the offset we have to subtract
+                * from absolute symbols in order to access areas
+                * in our own image.  If already mapped this is
+                * just plain zero, else it is KERNBASE.
+                */
+               set     KERNBASE, %l6
+               b       copy_prom_lvl14
+                nop
+
+already_mapped:
+               mov     0, %l6
+
+               /* Copy over the Prom's level 14 clock handler. */
+copy_prom_lvl14:
+#if 1
+               /* DJHR
+                * preserve our linked/calculated instructions
+                */
+               set     lvl14_save, %g1
+               set     t_irq14, %g3
+               sub     %g1, %l6, %g1           ! translate to physical
+               sub     %g3, %l6, %g3           ! translate to physical
+               ldd     [%g3], %g4
+               std     %g4, [%g1]
+               ldd     [%g3+8], %g4
+               std     %g4, [%g1+8]
+#endif
+               rd      %tbr, %g1
+               andn    %g1, 0xfff, %g1         ! proms trap table base
+               or      %g0, (0x1e<<4), %g2     ! offset to lvl14 intr
+               or      %g1, %g2, %g2
+               set     t_irq14, %g3
+               sub     %g3, %l6, %g3
+               ldd     [%g2], %g4
+               std     %g4, [%g3]
+               ldd     [%g2 + 0x8], %g4
+               std     %g4, [%g3 + 0x8]        ! Copy proms handler
+
+/* Must determine whether we are on a sun4c MMU, SRMMU, or SUN4/400 MUTANT
+ * MMU so we can remap ourselves properly.  DON'T TOUCH %l0 thru %l5 in these
+ * remapping routines, we need their values afterwards!
+ */
+               /* Now check whether we are already mapped, if we
+                * are we can skip all this garbage coming up.
+                */
+copy_prom_done:
+               cmp     %l6, 0
+               be      go_to_highmem           ! this will be a nop then
+                nop
+
+               set     LOAD_ADDR, %g6
+               cmp     %g7, %g6
+               bne     remap_not_a_sun4        ! This is not a Sun4
+                nop
+
+               or      %g0, 0x1, %g1
+               lduba   [%g1] ASI_CONTROL, %g1  ! Only safe to try on Sun4.
+               subcc   %g1, 0x24, %g0          ! Is this a mutant Sun4/400???
+               be      sun4_mutant_remap       ! Ugh, it is...
+                nop
+
+               b       sun4_normal_remap       ! regular sun4, 2 level mmu
+                nop
+
+remap_not_a_sun4:
+               lda     [%g0] ASI_M_MMUREGS, %g1 ! same as ASI_PTE on sun4c
+               and     %g1, 0x1, %g1           ! Test SRMMU Enable bit ;-)
+               cmp     %g1, 0x0
+               be      sun4c_remap             ! A sun4c MMU or normal Sun4
+                nop
+srmmu_remap:
+               /* First, check for a viking (TI) module. */
+               set     0x40000000, %g2
+               rd      %psr, %g3
+               and     %g2, %g3, %g3
+               subcc   %g3, 0x0, %g0
+               bz      srmmu_nviking
+                nop
+
+               /* Figure out what kind of viking we are on.
+                * We need to know if we have to play with the
+                * AC bit and disable traps or not.
+                */
+
+               /* I've only seen MicroSparc's on SparcClassics with this
+                * bit set.
+                */
+               set     0x800, %g2
+               lda     [%g0] ASI_M_MMUREGS, %g3        ! peek in the control reg
+               and     %g2, %g3, %g3
+               subcc   %g3, 0x0, %g0
+               bnz     srmmu_nviking                   ! is in mbus mode
+                nop
+               
+               rd      %psr, %g3                       ! DO NOT TOUCH %g3
+               andn    %g3, PSR_ET, %g2
+               wr      %g2, 0x0, %psr
+               WRITE_PAUSE
+               
+               /* Get context table pointer, then convert to
+                * a physical address, which is 36 bits.
+                */
+               set     AC_M_CTPR, %g4
+               lda     [%g4] ASI_M_MMUREGS, %g4
+               sll     %g4, 0x4, %g4                   ! We use this below
+                                                       ! DO NOT TOUCH %g4
+
+               /* Set the AC bit in the Viking's MMU control reg. */
+               lda     [%g0] ASI_M_MMUREGS, %g5        ! DO NOT TOUCH %g5
+               set     0x8000, %g6                     ! AC bit mask
+               or      %g5, %g6, %g6                   ! Or it in...
+               sta     %g6, [%g0] ASI_M_MMUREGS        ! Close your eyes...
+
+               /* Grrr, why does it seem like every other load/store
+                * on the sun4m is in some ASI space...
+                * Fine with me, let's get the pointer to the level 1
+                * page table directory and fetch its entry.
+                */
+               lda     [%g4] ASI_M_BYPASS, %o1         ! This is a level 1 ptr
+               srl     %o1, 0x4, %o1                   ! Clear low 4 bits
+               sll     %o1, 0x8, %o1                   ! Make physical
+               
+               /* Ok, pull in the PTD. */
+               lda     [%o1] ASI_M_BYPASS, %o2         ! This is the 0x0 16MB pgd
+
+               /* Calculate to KERNBASE entry. */
+               add     %o1, KERNBASE >> (SRMMU_PGDIR_SHIFT - 2), %o3           
+
+               /* Poke the entry into the calculated address. */
+               sta     %o2, [%o3] ASI_M_BYPASS
+
+               /* I don't get it Sun, if you engineered all these
+                * boot loaders and the PROM (thank you for the debugging
+                * features btw) why did you not have them load kernel
+                * images up in high address space, since this is necessary
+                * for ABI compliance anyways?  Does this low-mapping provide
+                * enhanced interoperability?
+                *
+                * "The PROM is the computer."
+                */
+
+               /* Ok, restore the MMU control register we saved in %g5 */
+               sta     %g5, [%g0] ASI_M_MMUREGS        ! POW... ouch
+
+               /* Turn traps back on.  We saved it in %g3 earlier. */
+               wr      %g3, 0x0, %psr                  ! tick tock, tick tock
+
+               /* Now we burn precious CPU cycles due to bad engineering. */
+               WRITE_PAUSE
+
+               /* Wow, all that just to move a 32-bit value from one
+                * place to another...  Jump to high memory.
+                */
+               b       go_to_highmem
+                nop
+
+               /* This works on viking's in Mbus mode and all
+                * other MBUS modules.  It is virtually the same as
+                * the above madness sans turning traps off and flipping
+                * the AC bit.
+                */
+srmmu_nviking:
+               set     AC_M_CTPR, %g1
+               lda     [%g1] ASI_M_MMUREGS, %g1        ! get ctx table ptr
+               sll     %g1, 0x4, %g1                   ! make physical addr
+               lda     [%g1] ASI_M_BYPASS, %g1         ! ptr to level 1 pg_table
+               srl     %g1, 0x4, %g1
+               sll     %g1, 0x8, %g1                   ! make phys addr for l1 tbl
+
+               lda     [%g1] ASI_M_BYPASS, %g2         ! get level1 entry for 0x0
+               add     %g1, KERNBASE >> (SRMMU_PGDIR_SHIFT - 2), %g3
+               sta     %g2, [%g3] ASI_M_BYPASS         ! place at KERNBASE entry
+               b       go_to_highmem
+                nop                                    ! wheee....
+
+               /* This remaps the kernel on Sun4/4xx machines
+                * that have the Sun Mutant Three Level MMU.
+                * It's like a platypus, Sun didn't have the
+                * SRMMU in conception so they kludged the three
+                * level logic in the regular Sun4 MMU probably.
+                *
+                * Basically, you take each entry in the top level
+                * directory that maps the low 3MB starting at
+                * address zero and put the mapping in the KERNBASE
+                * slots.  These top level pgd's are called regmaps.
+                */
+sun4_mutant_remap:
+               or      %g0, %g0, %g3           ! source base
+               sethi   %hi(KERNBASE), %g4      ! destination base
+               or      %g4, %lo(KERNBASE), %g4
+               sethi   %hi(0x300000), %g5
+               or      %g5, %lo(0x300000), %g5 ! upper bound 3MB
+               or      %g0, 0x1, %l6
+               sll     %l6, 24, %l6            ! Regmap mapping size
+               add     %g3, 0x2, %g3           ! Base magic
+               add     %g4, 0x2, %g4           ! Base magic
+
+               /* Main remapping loop on Sun4-Mutant-MMU.
+                * "I am not an animal..." -Famous Mutant Person
+                */
+sun4_mutant_loop:
+               lduha   [%g3] ASI_REGMAP, %g2   ! Get lower entry
+               stha    %g2, [%g4] ASI_REGMAP   ! Store in high entry
+               add     %g4, %l6, %g4           ! Move up high memory ptr
+               subcc   %g3, %g5, %g0           ! Reached our limit?
+               blu     sun4_mutant_loop        ! Nope, loop again
+                add    %g3, %l6, %g3           ! delay, Move up low ptr
+               b       go_to_highmem           ! Jump to high memory.
+                nop
+
+               /* The following is for non-4/4xx sun4 MMU's. */
+sun4_normal_remap:
+               mov     0, %g3                  ! source base
+               set     KERNBASE, %g4           ! destination base
+               set     0x300000, %g5           ! upper bound 3MB
+               mov     1, %l6
+               sll     %l6, 18, %l6            ! sun4 mmu segmap size
+sun4_normal_loop:
+               lduha   [%g3] ASI_SEGMAP, %g6   ! load phys_seg
+               stha    %g6, [%g4] ASI_SEGMAP   ! stort new virt mapping
+               add     %g3, %l6, %g3           ! increment source pointer
+               subcc   %g3, %g5, %g0           ! reached limit?
+               blu     sun4_normal_loop        ! nope, loop again
+                add    %g4, %l6, %g4           ! delay, increment dest ptr
+               b       go_to_highmem
+                nop
+
+               /* The following works for Sun4c MMU's */
+sun4c_remap:
+               mov     0, %g3                  ! source base
+               set     KERNBASE, %g4           ! destination base
+               set     0x300000, %g5           ! upper bound 3MB
+               mov     1, %l6
+               sll     %l6, 18, %l6            ! sun4c mmu segmap size
+sun4c_remap_loop:
+               lda     [%g3] ASI_SEGMAP, %g6   ! load phys_seg
+               sta     %g6, [%g4] ASI_SEGMAP   ! store new virt mapping
+               add     %g3, %l6, %g3           ! Increment source ptr
+               subcc   %g3, %g5, %g0           ! Reached limit?
+               bl      sun4c_remap_loop        ! Nope, loop again
+                add    %g4, %l6, %g4           ! delay, Increment dest ptr
+
+/* Now do a non-relative jump so that PC is in high-memory */
+go_to_highmem:
+               set     execute_in_high_mem, %g1
+               jmpl    %g1, %g0
+                nop
+
+/* The code above should be at beginning and we have to take care about
+ * short jumps, as branching to .text.init section from .text is usually
+ * impossible */
+               __INIT
+/* Acquire boot time privileged register values, this will help debugging.
+ * I figure out and store nwindows and nwindowsm1 later on.
+ */
+execute_in_high_mem:
+               mov     %l0, %o0                ! put back romvec
+               mov     %l1, %o1                ! and debug_vec
+
+               sethi   %hi(prom_vector_p), %g1
+               st      %o0, [%g1 + %lo(prom_vector_p)]
+
+               sethi   %hi(linux_dbvec), %g1
+               st      %o1, [%g1 + %lo(linux_dbvec)]
+
+               ld      [%o0 + 0x4], %o3
+               and     %o3, 0x3, %o5                   ! get the version
+
+               cmp     %o3, 0x2                        ! a v2 prom?
+               be      found_version
+                nop
+
+               /* paul@sfe.com.au */
+               cmp     %o3, 0x3                        ! a v3 prom?
+               be      found_version
+                nop
+
+/* Old sun4's pass our load address into %o0 instead of the prom
+ * pointer. On sun4's you have to hard code the romvec pointer into
+ * your code. Sun probably still does that because they don't even
+ * trust their own "OpenBoot" specifications.
+ */
+               set     LOAD_ADDR, %g6
+               cmp     %o0, %g6                ! an old sun4?
+               be      sun4_init
+                nop
+
+found_version:
+/* Get the machine type via the mysterious romvec node operations. */
+
+               add     %g7, 0x1c, %l1          
+               ld      [%l1], %l0
+               ld      [%l0], %l0
+               call    %l0
+                or     %g0, %g0, %o0           ! next_node(0) = first_node
+               or      %o0, %g0, %g6
+
+               sethi   %hi(cputypvar), %o1     ! First node has cpu-arch
+               or      %o1, %lo(cputypvar), %o1
+               sethi   %hi(cputypval), %o2     ! information, the string
+               or      %o2, %lo(cputypval), %o2
+               ld      [%l1], %l0              ! 'compatibility' tells
+               ld      [%l0 + 0xc], %l0        ! that we want 'sun4x' where
+               call    %l0                     ! x is one of '', 'c', 'm',
+                nop                            ! 'd' or 'e'. %o2 holds pointer
+                                               ! to a buf where above string
+                                               ! will get stored by the prom.
+
+               subcc   %o0, %g0, %g0
+               bpos    got_prop                ! Got the property
+                nop
+
+               or      %g6, %g0, %o0
+               sethi   %hi(cputypvar_sun4m), %o1
+               or      %o1, %lo(cputypvar_sun4m), %o1
+               sethi   %hi(cputypval), %o2
+               or      %o2, %lo(cputypval), %o2
+               ld      [%l1], %l0
+               ld      [%l0 + 0xc], %l0
+               call    %l0
+                nop
+
+got_prop:
+               set     cputypval, %o2
+               ldub    [%o2 + 0x4], %l1
+
+               cmp     %l1, ' '
+               be      1f
+                cmp    %l1, 'c'
+               be      1f
+                cmp    %l1, 'm'
+               be      1f
+                cmp    %l1, 's'
+               be      1f
+                cmp    %l1, 'd'
+               be      1f
+                cmp    %l1, 'e'
+               be      no_sun4e_here           ! Could be a sun4e.
+                nop
+               b       no_sun4u_here           ! AIEEE, a V9 sun4u... Get our BIG BROTHER kernel :))
+                nop
+
+1:             set     cputypval, %l1
+               ldub    [%l1 + 0x4], %l1
+               cmp     %l1, 'm'                ! Test for sun4d, sun4e ?
+               be      sun4m_init
+                cmp    %l1, 's'                ! Treat sun4s as sun4m
+               be      sun4m_init
+                cmp    %l1, 'd'                ! Let us see how the beast will die
+               be      sun4d_init
+                nop
+
+               /* Jump into mmu context zero. */
+               set     AC_CONTEXT, %g1
+               stba    %g0, [%g1] ASI_CONTROL
+
+               b       sun4c_continue_boot
+                nop
+
+/* CPUID in bootbus can be found at PA 0xff0140000 */
+#define SUN4D_BOOTBUS_CPUID     0xf0140000
+
+sun4d_init:
+       /* Need to patch call to handler_irq */
+       set     patch_handler_irq, %g4
+       set     sun4d_handler_irq, %g5
+       sethi   %hi(0x40000000), %g3            ! call
+       sub     %g5, %g4, %g5
+       srl     %g5, 2, %g5
+       or      %g5, %g3, %g5
+       st      %g5, [%g4]
+
+#ifdef CONFIG_SMP
+       /* Get our CPU id out of bootbus */
+       set     SUN4D_BOOTBUS_CPUID, %g3
+       lduba   [%g3] ASI_M_CTL, %g3
+       and     %g3, 0xf8, %g3
+       srl     %g3, 3, %g4
+       sta     %g4, [%g0] ASI_M_VIKING_TMP1
+       sethi   %hi(boot_cpu_id), %g5
+       stb     %g4, [%g5 + %lo(boot_cpu_id)]
+       sll     %g4, 2, %g4
+       sethi   %hi(boot_cpu_id4), %g5
+       stb     %g4, [%g5 + %lo(boot_cpu_id4)]
+#endif
+
+       /* Fall through to sun4m_init */
+
+sun4m_init:
+       /* XXX Fucking Cypress... */
+       lda     [%g0] ASI_M_MMUREGS, %g5
+       srl     %g5, 28, %g4
+
+       cmp     %g4, 1
+       bne     1f
+        srl    %g5, 24, %g4
+
+       and     %g4, 0xf, %g4
+       cmp     %g4, 7          /* This would be a HyperSparc. */
+
+       bne     2f
+        nop
+
+1:
+
+#define PATCH_IT(dst, src)     \
+       set     (dst), %g5;     \
+       set     (src), %g4;     \
+       ld      [%g4], %g3;     \
+       st      %g3, [%g5];     \
+       ld      [%g4+0x4], %g3; \
+       st      %g3, [%g5+0x4];
+
+       /* Signed multiply. */
+       PATCH_IT(.mul, .mul_patch)
+       PATCH_IT(.mul+0x08, .mul_patch+0x08)
+
+       /* Signed remainder. */
+       PATCH_IT(.rem, .rem_patch)
+       PATCH_IT(.rem+0x08, .rem_patch+0x08)
+       PATCH_IT(.rem+0x10, .rem_patch+0x10)
+       PATCH_IT(.rem+0x18, .rem_patch+0x18)
+       PATCH_IT(.rem+0x20, .rem_patch+0x20)
+       PATCH_IT(.rem+0x28, .rem_patch+0x28)
+
+       /* Signed division. */
+       PATCH_IT(.div, .div_patch)
+       PATCH_IT(.div+0x08, .div_patch+0x08)
+       PATCH_IT(.div+0x10, .div_patch+0x10)
+       PATCH_IT(.div+0x18, .div_patch+0x18)
+       PATCH_IT(.div+0x20, .div_patch+0x20)
+
+       /* Unsigned multiply. */
+       PATCH_IT(.umul, .umul_patch)
+       PATCH_IT(.umul+0x08, .umul_patch+0x08)
+
+       /* Unsigned remainder. */
+       PATCH_IT(.urem, .urem_patch)
+       PATCH_IT(.urem+0x08, .urem_patch+0x08)
+       PATCH_IT(.urem+0x10, .urem_patch+0x10)
+       PATCH_IT(.urem+0x18, .urem_patch+0x18)
+
+       /* Unsigned division. */
+       PATCH_IT(.udiv, .udiv_patch)
+       PATCH_IT(.udiv+0x08, .udiv_patch+0x08)
+       PATCH_IT(.udiv+0x10, .udiv_patch+0x10)
+
+#undef PATCH_IT
+
+/* Ok, the PROM could have done funny things and apple cider could still
+ * be sitting in the fault status/address registers.  Read them all to
+ * clear them so we don't get magic faults later on.
+ */
+/* This sucks, apparently this makes Vikings call prom panic, will fix later */
+2:
+               rd      %psr, %o1
+               srl     %o1, 28, %o1            ! Get a type of the CPU
+
+               subcc   %o1, 4, %g0             ! TI: Viking or MicroSPARC
+               be      sun4c_continue_boot
+                nop
+
+               set     AC_M_SFSR, %o0
+               lda     [%o0] ASI_M_MMUREGS, %g0
+               set     AC_M_SFAR, %o0
+               lda     [%o0] ASI_M_MMUREGS, %g0
+
+               /* Fujitsu MicroSPARC-II has no asynchronous flavors of FARs */
+               subcc   %o1, 0, %g0
+               be      sun4c_continue_boot
+                nop
+
+               set     AC_M_AFSR, %o0
+               lda     [%o0] ASI_M_MMUREGS, %g0
+               set     AC_M_AFAR, %o0
+               lda     [%o0] ASI_M_MMUREGS, %g0
+                nop
+
+
+sun4c_continue_boot:
+
+
+/* Aieee, now set PC and nPC, enable traps, give ourselves a stack and it's
+ * show-time!
+ */
+
+               sethi   %hi(cputyp), %o0
+               st      %g4, [%o0 + %lo(cputyp)]
+
+               /* Turn on Supervisor, EnableFloating, and all the PIL bits.
+                * Also puts us in register window zero with traps off.
+                */
+               set     (PSR_PS | PSR_S | PSR_PIL | PSR_EF), %g2
+               wr      %g2, 0x0, %psr
+               WRITE_PAUSE
+
+               /* I want a kernel stack NOW! */
+               set     init_thread_union, %g1
+               set     (THREAD_SIZE - STACKFRAME_SZ), %g2
+               add     %g1, %g2, %sp
+               mov     0, %fp                  /* And for good luck */
+
+               /* Zero out our BSS section. */
+               set     __bss_start , %o0       ! First address of BSS
+               set     end , %o1               ! Last address of BSS
+               add     %o0, 0x1, %o0
+1:     
+               stb     %g0, [%o0]
+               subcc   %o0, %o1, %g0
+               bl      1b
+                add    %o0, 0x1, %o0
+
+               /* Initialize the uwinmask value for init task just in case.
+                * But first make current_set[boot_cpu_id] point to something useful.
+                */
+               set     init_thread_union, %g6
+               set     current_set, %g2
+#ifdef CONFIG_SMP
+               sethi   %hi(boot_cpu_id4), %g3
+               ldub    [%g3 + %lo(boot_cpu_id4)], %g3
+               st      %g6, [%g2]
+               add     %g2, %g3, %g2
+#endif
+               st      %g6, [%g2]
+
+               st      %g0, [%g6 + TI_UWINMASK]
+
+/* Compute NWINDOWS and stash it away. Now uses %wim trick explained
+ * in the V8 manual. Ok, this method seems to work, Sparc is cool...
+ * No, it doesn't work, have to play the save/readCWP/restore trick.
+ */
+
+               wr      %g0, 0x0, %wim                  ! so we do not get a trap
+               WRITE_PAUSE
+
+               save
+
+               rd      %psr, %g3
+
+               restore
+
+               and     %g3, 0x1f, %g3
+               add     %g3, 0x1, %g3
+
+               mov     2, %g1
+               wr      %g1, 0x0, %wim                  ! make window 1 invalid
+               WRITE_PAUSE
+
+               cmp     %g3, 0x7
+               bne     2f
+                nop
+
+               /* Adjust our window handling routines to
+                * do things correctly on 7 window Sparcs.
+                */
+
+#define                PATCH_INSN(src, dest) \
+               set     src, %g5; \
+               set     dest, %g2; \
+               ld      [%g5], %g4; \
+               st      %g4, [%g2];
+       
+               /* Patch for window spills... */
+               PATCH_INSN(spnwin_patch1_7win, spnwin_patch1)
+               PATCH_INSN(spnwin_patch2_7win, spnwin_patch2)
+               PATCH_INSN(spnwin_patch3_7win, spnwin_patch3)
+
+               /* Patch for window fills... */
+               PATCH_INSN(fnwin_patch1_7win, fnwin_patch1)
+               PATCH_INSN(fnwin_patch2_7win, fnwin_patch2)
+
+               /* Patch for trap entry setup... */
+               PATCH_INSN(tsetup_7win_patch1, tsetup_patch1)
+               PATCH_INSN(tsetup_7win_patch2, tsetup_patch2)
+               PATCH_INSN(tsetup_7win_patch3, tsetup_patch3)
+               PATCH_INSN(tsetup_7win_patch4, tsetup_patch4)
+               PATCH_INSN(tsetup_7win_patch5, tsetup_patch5)
+               PATCH_INSN(tsetup_7win_patch6, tsetup_patch6)
+
+               /* Patch for returning from traps... */
+               PATCH_INSN(rtrap_7win_patch1, rtrap_patch1)
+               PATCH_INSN(rtrap_7win_patch2, rtrap_patch2)
+               PATCH_INSN(rtrap_7win_patch3, rtrap_patch3)
+               PATCH_INSN(rtrap_7win_patch4, rtrap_patch4)
+               PATCH_INSN(rtrap_7win_patch5, rtrap_patch5)
+
+               /* Patch for killing user windows from the register file. */
+               PATCH_INSN(kuw_patch1_7win, kuw_patch1)
+
+               /* Now patch the kernel window flush sequences.
+                * This saves 2 traps on every switch and fork.
+                */
+               set     0x01000000, %g4
+               set     flush_patch_one, %g5
+               st      %g4, [%g5 + 0x18]
+               st      %g4, [%g5 + 0x1c]
+               set     flush_patch_two, %g5
+               st      %g4, [%g5 + 0x18]
+               st      %g4, [%g5 + 0x1c]
+               set     flush_patch_three, %g5
+               st      %g4, [%g5 + 0x18]
+               st      %g4, [%g5 + 0x1c]
+               set     flush_patch_four, %g5
+               st      %g4, [%g5 + 0x18]
+               st      %g4, [%g5 + 0x1c]
+               set     flush_patch_exception, %g5
+               st      %g4, [%g5 + 0x18]
+               st      %g4, [%g5 + 0x1c]
+               set     flush_patch_switch, %g5
+               st      %g4, [%g5 + 0x18]
+               st      %g4, [%g5 + 0x1c]
+
+2:             
+               sethi   %hi(nwindows), %g4
+               st      %g3, [%g4 + %lo(nwindows)]      ! store final value
+               sub     %g3, 0x1, %g3
+               sethi   %hi(nwindowsm1), %g4
+               st      %g3, [%g4 + %lo(nwindowsm1)]
+
+               /* Here we go, start using Linux's trap table... */
+               set     trapbase, %g3
+               wr      %g3, 0x0, %tbr
+               WRITE_PAUSE
+
+               /* Finally, turn on traps so that we can call c-code. */
+               rd      %psr, %g3
+               wr      %g3, 0x0, %psr
+               WRITE_PAUSE
+
+               wr      %g3, PSR_ET, %psr
+               WRITE_PAUSE
+
+               /* First we call prom_init() to set up PROMLIB, then
+                * off to start_kernel().
+                */
+
+               sethi   %hi(prom_vector_p), %g5
+               ld      [%g5 + %lo(prom_vector_p)], %o0
+               call    prom_init
+                nop
+
+               call    start_kernel
+                nop
+       
+               /* We should not get here. */
+               call    halt_me
+                nop
+
+sun4_init:
+               sethi   %hi(SUN4_PROM_VECTOR+0x84), %o1
+               ld      [%o1 + %lo(SUN4_PROM_VECTOR+0x84)], %o1
+               set     sun4_notsup, %o0
+               call    %o1     /* printf */
+                nop
+               sethi   %hi(SUN4_PROM_VECTOR+0xc4), %o1
+               ld      [%o1 + %lo(SUN4_PROM_VECTOR+0xc4)], %o1
+               call    %o1     /* exittomon */
+                nop
+1:             ba      1b                      ! Cannot exit into KMON
+                nop
+
+no_sun4e_here:
+               ld      [%g7 + 0x68], %o1
+               set     sun4e_notsup, %o0
+               call    %o1
+                nop
+               b       halt_me
+                nop
+
+               __INITDATA
+
+sun4u_1:
+               .asciz "finddevice"
+               .align  4
+sun4u_2:
+               .asciz "/chosen"
+               .align  4
+sun4u_3:
+               .asciz "getprop"
+               .align  4
+sun4u_4:
+               .asciz "stdout"
+               .align  4
+sun4u_5:
+               .asciz "write"
+               .align  4
+sun4u_6:
+               .asciz  "\n\rOn sun4u you have to use UltraLinux (64bit) kernel\n\rand not a 32bit sun4[cdem] version\n\r\n\r"
+sun4u_6e:
+               .align  4
+sun4u_7:
+               .asciz "exit"
+               .align  8
+sun4u_a1:
+               .word   0, sun4u_1, 0, 1, 0, 1, 0, sun4u_2, 0
+sun4u_r1:
+               .word   0
+sun4u_a2:
+               .word   0, sun4u_3, 0, 4, 0, 1, 0
+sun4u_i2:
+               .word   0, 0, sun4u_4, 0, sun4u_1, 0, 8, 0
+sun4u_r2:
+               .word   0
+sun4u_a3:
+               .word   0, sun4u_5, 0, 3, 0, 1, 0
+sun4u_i3:
+               .word   0, 0, sun4u_6, 0, sun4u_6e - sun4u_6 - 1, 0
+sun4u_r3:
+               .word   0
+sun4u_a4:
+               .word   0, sun4u_7, 0, 0, 0, 0
+sun4u_r4:
+
+               __INIT
+no_sun4u_here:
+               set     sun4u_a1, %o0
+               set     current_pc, %l2
+               cmp     %l2, %g3
+               be      1f
+                mov    %o4, %l0
+               sub     %g3, %l2, %l6
+               add     %o0, %l6, %o0
+               mov     %o0, %l4
+               mov     sun4u_r4 - sun4u_a1, %l3
+               ld      [%l4], %l5
+2:
+               add     %l4, 4, %l4
+               cmp     %l5, %l2
+               add     %l5, %l6, %l5
+               bgeu,a  3f
+                st     %l5, [%l4 - 4]
+3:
+               subcc   %l3, 4, %l3
+               bne     2b
+                ld     [%l4], %l5
+1:
+               call    %l0
+                mov    %o0, %l1
+
+               ld      [%l1 + (sun4u_r1 - sun4u_a1)], %o1
+               add     %l1, (sun4u_a2 - sun4u_a1), %o0
+               call    %l0
+                st     %o1, [%o0 + (sun4u_i2 - sun4u_a2)]
+
+               ld      [%l1 + (sun4u_1 - sun4u_a1)], %o1
+               add     %l1, (sun4u_a3 - sun4u_a1), %o0
+               call    %l0
+               st      %o1, [%o0 + (sun4u_i3 - sun4u_a3)]
+
+               call    %l0
+                add    %l1, (sun4u_a4 - sun4u_a1), %o0
+
+               /* Not reached */
+halt_me:
+               ld      [%g7 + 0x74], %o0
+               call    %o0                     ! Get us out of here...
+                nop                            ! Apparently Solaris is better.
+
+/* Ok, now we continue in the .data/.text sections */
+
+       .data
+       .align 4
+
+/*
+ * Fill up the prom vector, note in particular the kind first element,
+ * no joke. I don't need all of them in here as the entire prom vector
+ * gets initialized in c-code so all routines can use it.
+ */
+
+prom_vector_p:
+               .word 0
+
+/* We calculate the following at boot time, window fills/spills and trap entry
+ * code uses these to keep track of the register windows.
+ */
+
+       .align 4
+       .globl  nwindows
+       .globl  nwindowsm1
+nwindows:
+       .word   8
+nwindowsm1:
+       .word   7
+
+/* Boot time debugger vector value.  We need this later on. */
+
+       .align 4
+       .globl  linux_dbvec
+linux_dbvec:
+       .word   0
+       .word   0
+
+       .align 8
+
+       .globl  lvl14_save
+lvl14_save:
+       .word   0
+       .word   0
+       .word   0
+       .word   0
+       .word   t_irq14
+
+        .section        ".fixup",#alloc,#execinstr
+        .globl  __ret_efault
+__ret_efault:
+        ret
+         restore %g0, -EFAULT, %o0
diff --git a/arch/sparc/kernel/idprom.c b/arch/sparc/kernel/idprom.c
deleted file mode 100644 (file)
index 223a658..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * idprom.c: Routines to load the idprom into kernel addresses and
- *           interpret the data contained within.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-
-#include <asm/oplib.h>
-#include <asm/idprom.h>
-#include <asm/machines.h>  /* Fun with Sun released architectures. */
-
-struct idprom *idprom;
-static struct idprom idprom_buffer;
-
-/* Here is the master table of Sun machines which use some implementation
- * of the Sparc CPU and have a meaningful IDPROM machtype value that we
- * know about.  See asm-sparc/machines.h for empirical constants.
- */
-static struct Sun_Machine_Models Sun_Machines[NUM_SUN_MACHINES] = {
-/* First, Sun4's */
-{ "Sun 4/100 Series", (SM_SUN4 | SM_4_110) },
-{ "Sun 4/200 Series", (SM_SUN4 | SM_4_260) },
-{ "Sun 4/300 Series", (SM_SUN4 | SM_4_330) },
-{ "Sun 4/400 Series", (SM_SUN4 | SM_4_470) },
-/* Now, Sun4c's */
-{ "Sun4c SparcStation 1", (SM_SUN4C | SM_4C_SS1) },
-{ "Sun4c SparcStation IPC", (SM_SUN4C | SM_4C_IPC) },
-{ "Sun4c SparcStation 1+", (SM_SUN4C | SM_4C_SS1PLUS) },
-{ "Sun4c SparcStation SLC", (SM_SUN4C | SM_4C_SLC) },
-{ "Sun4c SparcStation 2", (SM_SUN4C | SM_4C_SS2) },
-{ "Sun4c SparcStation ELC", (SM_SUN4C | SM_4C_ELC) },
-{ "Sun4c SparcStation IPX", (SM_SUN4C | SM_4C_IPX) },
-/* Finally, early Sun4m's */
-{ "Sun4m SparcSystem600", (SM_SUN4M | SM_4M_SS60) },
-{ "Sun4m SparcStation10/20", (SM_SUN4M | SM_4M_SS50) },
-{ "Sun4m SparcStation5", (SM_SUN4M | SM_4M_SS40) },
-/* One entry for the OBP arch's which are sun4d, sun4e, and newer sun4m's */
-{ "Sun4M OBP based system", (SM_SUN4M_OBP | 0x0) } };
-
-static void __init display_system_type(unsigned char machtype)
-{
-       char sysname[128];
-       register int i;
-
-       for (i = 0; i < NUM_SUN_MACHINES; i++) {
-               if(Sun_Machines[i].id_machtype == machtype) {
-                       if (machtype != (SM_SUN4M_OBP | 0x00) ||
-                           prom_getproperty(prom_root_node, "banner-name",
-                                            sysname, sizeof(sysname)) <= 0)
-                               printk("TYPE: %s\n", Sun_Machines[i].name);
-                       else
-                               printk("TYPE: %s\n", sysname);
-                       return;
-               }
-       }
-
-       prom_printf("IDPROM: Bogus id_machtype value, 0x%x\n", machtype);
-       prom_halt();
-}
-
-/* Calculate the IDPROM checksum (xor of the data bytes). */
-static unsigned char __init calc_idprom_cksum(struct idprom *idprom)
-{
-       unsigned char cksum, i, *ptr = (unsigned char *)idprom;
-
-       for (i = cksum = 0; i <= 0x0E; i++)
-               cksum ^= *ptr++;
-
-       return cksum;
-}
-
-/* Create a local IDPROM copy, verify integrity, and display information. */
-void __init idprom_init(void)
-{
-       prom_get_idprom((char *) &idprom_buffer, sizeof(idprom_buffer));
-
-       idprom = &idprom_buffer;
-
-       if (idprom->id_format != 0x01)  {
-               prom_printf("IDPROM: Unknown format type!\n");
-               prom_halt();
-       }
-
-       if (idprom->id_cksum != calc_idprom_cksum(idprom)) {
-               prom_printf("IDPROM: Checksum failure (nvram=%x, calc=%x)!\n",
-                           idprom->id_cksum, calc_idprom_cksum(idprom));
-               prom_halt();
-       }
-
-       display_system_type(idprom->id_machtype);
-
-       printk("Ethernet address: %x:%x:%x:%x:%x:%x\n",
-                   idprom->id_ethaddr[0], idprom->id_ethaddr[1],
-                   idprom->id_ethaddr[2], idprom->id_ethaddr[3],
-                   idprom->id_ethaddr[4], idprom->id_ethaddr[5]);
-}
diff --git a/arch/sparc/kernel/idprom_32.c b/arch/sparc/kernel/idprom_32.c
new file mode 100644 (file)
index 0000000..223a658
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * idprom.c: Routines to load the idprom into kernel addresses and
+ *           interpret the data contained within.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+
+#include <asm/oplib.h>
+#include <asm/idprom.h>
+#include <asm/machines.h>  /* Fun with Sun released architectures. */
+
+struct idprom *idprom;
+static struct idprom idprom_buffer;
+
+/* Here is the master table of Sun machines which use some implementation
+ * of the Sparc CPU and have a meaningful IDPROM machtype value that we
+ * know about.  See asm-sparc/machines.h for empirical constants.
+ */
+static struct Sun_Machine_Models Sun_Machines[NUM_SUN_MACHINES] = {
+/* First, Sun4's */
+{ "Sun 4/100 Series", (SM_SUN4 | SM_4_110) },
+{ "Sun 4/200 Series", (SM_SUN4 | SM_4_260) },
+{ "Sun 4/300 Series", (SM_SUN4 | SM_4_330) },
+{ "Sun 4/400 Series", (SM_SUN4 | SM_4_470) },
+/* Now, Sun4c's */
+{ "Sun4c SparcStation 1", (SM_SUN4C | SM_4C_SS1) },
+{ "Sun4c SparcStation IPC", (SM_SUN4C | SM_4C_IPC) },
+{ "Sun4c SparcStation 1+", (SM_SUN4C | SM_4C_SS1PLUS) },
+{ "Sun4c SparcStation SLC", (SM_SUN4C | SM_4C_SLC) },
+{ "Sun4c SparcStation 2", (SM_SUN4C | SM_4C_SS2) },
+{ "Sun4c SparcStation ELC", (SM_SUN4C | SM_4C_ELC) },
+{ "Sun4c SparcStation IPX", (SM_SUN4C | SM_4C_IPX) },
+/* Finally, early Sun4m's */
+{ "Sun4m SparcSystem600", (SM_SUN4M | SM_4M_SS60) },
+{ "Sun4m SparcStation10/20", (SM_SUN4M | SM_4M_SS50) },
+{ "Sun4m SparcStation5", (SM_SUN4M | SM_4M_SS40) },
+/* One entry for the OBP arch's which are sun4d, sun4e, and newer sun4m's */
+{ "Sun4M OBP based system", (SM_SUN4M_OBP | 0x0) } };
+
+static void __init display_system_type(unsigned char machtype)
+{
+       char sysname[128];
+       register int i;
+
+       for (i = 0; i < NUM_SUN_MACHINES; i++) {
+               if(Sun_Machines[i].id_machtype == machtype) {
+                       if (machtype != (SM_SUN4M_OBP | 0x00) ||
+                           prom_getproperty(prom_root_node, "banner-name",
+                                            sysname, sizeof(sysname)) <= 0)
+                               printk("TYPE: %s\n", Sun_Machines[i].name);
+                       else
+                               printk("TYPE: %s\n", sysname);
+                       return;
+               }
+       }
+
+       prom_printf("IDPROM: Bogus id_machtype value, 0x%x\n", machtype);
+       prom_halt();
+}
+
+/* Calculate the IDPROM checksum (xor of the data bytes). */
+static unsigned char __init calc_idprom_cksum(struct idprom *idprom)
+{
+       unsigned char cksum, i, *ptr = (unsigned char *)idprom;
+
+       for (i = cksum = 0; i <= 0x0E; i++)
+               cksum ^= *ptr++;
+
+       return cksum;
+}
+
+/* Create a local IDPROM copy, verify integrity, and display information. */
+void __init idprom_init(void)
+{
+       prom_get_idprom((char *) &idprom_buffer, sizeof(idprom_buffer));
+
+       idprom = &idprom_buffer;
+
+       if (idprom->id_format != 0x01)  {
+               prom_printf("IDPROM: Unknown format type!\n");
+               prom_halt();
+       }
+
+       if (idprom->id_cksum != calc_idprom_cksum(idprom)) {
+               prom_printf("IDPROM: Checksum failure (nvram=%x, calc=%x)!\n",
+                           idprom->id_cksum, calc_idprom_cksum(idprom));
+               prom_halt();
+       }
+
+       display_system_type(idprom->id_machtype);
+
+       printk("Ethernet address: %x:%x:%x:%x:%x:%x\n",
+                   idprom->id_ethaddr[0], idprom->id_ethaddr[1],
+                   idprom->id_ethaddr[2], idprom->id_ethaddr[3],
+                   idprom->id_ethaddr[4], idprom->id_ethaddr[5]);
+}
diff --git a/arch/sparc/kernel/init_task.c b/arch/sparc/kernel/init_task.c
deleted file mode 100644 (file)
index 8e64ebc..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/init_task.h>
-#include <linux/mqueue.h>
-
-#include <asm/pgtable.h>
-#include <asm/uaccess.h>
-
-static struct fs_struct init_fs = INIT_FS;
-static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
-static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
-struct mm_struct init_mm = INIT_MM(init_mm);
-struct task_struct init_task = INIT_TASK(init_task);
-
-EXPORT_SYMBOL(init_mm);
-EXPORT_SYMBOL(init_task);
-
-/* .text section in head.S is aligned at 8k boundary and this gets linked
- * right after that so that the init_thread_union is aligned properly as well.
- * If this is not aligned on a 8k boundry, then you should change code
- * in etrap.S which assumes it.
- */
-union thread_union init_thread_union
-       __attribute__((section (".text\"\n\t#")))
-       __attribute__((aligned (THREAD_SIZE)))
-       = { INIT_THREAD_INFO(init_task) };
diff --git a/arch/sparc/kernel/init_task_32.c b/arch/sparc/kernel/init_task_32.c
new file mode 100644 (file)
index 0000000..8e64ebc
--- /dev/null
@@ -0,0 +1,28 @@
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init_task.h>
+#include <linux/mqueue.h>
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+
+static struct fs_struct init_fs = INIT_FS;
+static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
+static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
+struct mm_struct init_mm = INIT_MM(init_mm);
+struct task_struct init_task = INIT_TASK(init_task);
+
+EXPORT_SYMBOL(init_mm);
+EXPORT_SYMBOL(init_task);
+
+/* .text section in head.S is aligned at 8k boundary and this gets linked
+ * right after that so that the init_thread_union is aligned properly as well.
+ * If this is not aligned on a 8k boundry, then you should change code
+ * in etrap.S which assumes it.
+ */
+union thread_union init_thread_union
+       __attribute__((section (".text\"\n\t#")))
+       __attribute__((aligned (THREAD_SIZE)))
+       = { INIT_THREAD_INFO(init_task) };
diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c
deleted file mode 100644 (file)
index 93e1d1c..0000000
+++ /dev/null
@@ -1,674 +0,0 @@
-/*
- *  arch/sparc/kernel/irq.c:  Interrupt request handling routines. On the
- *                            Sparc the IRQs are basically 'cast in stone'
- *                            and you are supposed to probe the prom's device
- *                            node trees to find out who's got which IRQ.
- *
- *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- *  Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
- *  Copyright (C) 1995,2002 Pete A. Zaitcev (zaitcev@yahoo.com)
- *  Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk)
- *  Copyright (C) 1998-2000 Anton Blanchard (anton@samba.org)
- */
-
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/ptrace.h>
-#include <linux/errno.h>
-#include <linux/linkage.h>
-#include <linux/kernel_stat.h>
-#include <linux/signal.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/delay.h>
-#include <linux/threads.h>
-#include <linux/spinlock.h>
-#include <linux/seq_file.h>
-
-#include <asm/ptrace.h>
-#include <asm/processor.h>
-#include <asm/system.h>
-#include <asm/psr.h>
-#include <asm/smp.h>
-#include <asm/vaddrs.h>
-#include <asm/timer.h>
-#include <asm/openprom.h>
-#include <asm/oplib.h>
-#include <asm/traps.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/pgalloc.h>
-#include <asm/pgtable.h>
-#include <asm/pcic.h>
-#include <asm/cacheflush.h>
-#include <asm/irq_regs.h>
-
-#include "irq.h"
-
-#ifdef CONFIG_SMP
-#define SMP_NOP2 "nop; nop;\n\t"
-#define SMP_NOP3 "nop; nop; nop;\n\t"
-#else
-#define SMP_NOP2
-#define SMP_NOP3
-#endif /* SMP */
-unsigned long __raw_local_irq_save(void)
-{
-       unsigned long retval;
-       unsigned long tmp;
-
-       __asm__ __volatile__(
-               "rd     %%psr, %0\n\t"
-               SMP_NOP3        /* Sun4m + Cypress + SMP bug */
-               "or     %0, %2, %1\n\t"
-               "wr     %1, 0, %%psr\n\t"
-               "nop; nop; nop\n"
-               : "=&r" (retval), "=r" (tmp)
-               : "i" (PSR_PIL)
-               : "memory");
-
-       return retval;
-}
-
-void raw_local_irq_enable(void)
-{
-       unsigned long tmp;
-
-       __asm__ __volatile__(
-               "rd     %%psr, %0\n\t"
-               SMP_NOP3        /* Sun4m + Cypress + SMP bug */
-               "andn   %0, %1, %0\n\t"
-               "wr     %0, 0, %%psr\n\t"
-               "nop; nop; nop\n"
-               : "=&r" (tmp)
-               : "i" (PSR_PIL)
-               : "memory");
-}
-
-void raw_local_irq_restore(unsigned long old_psr)
-{
-       unsigned long tmp;
-
-       __asm__ __volatile__(
-               "rd     %%psr, %0\n\t"
-               "and    %2, %1, %2\n\t"
-               SMP_NOP2        /* Sun4m + Cypress + SMP bug */
-               "andn   %0, %1, %0\n\t"
-               "wr     %0, %2, %%psr\n\t"
-               "nop; nop; nop\n"
-               : "=&r" (tmp)
-               : "i" (PSR_PIL), "r" (old_psr)
-               : "memory");
-}
-
-EXPORT_SYMBOL(__raw_local_irq_save);
-EXPORT_SYMBOL(raw_local_irq_enable);
-EXPORT_SYMBOL(raw_local_irq_restore);
-
-/*
- * Dave Redman (djhr@tadpole.co.uk)
- *
- * IRQ numbers.. These are no longer restricted to 15..
- *
- * this is done to enable SBUS cards and onboard IO to be masked
- * correctly. using the interrupt level isn't good enough.
- *
- * For example:
- *   A device interrupting at sbus level6 and the Floppy both come in
- *   at IRQ11, but enabling and disabling them requires writing to
- *   different bits in the SLAVIO/SEC.
- *
- * As a result of these changes sun4m machines could now support
- * directed CPU interrupts using the existing enable/disable irq code
- * with tweaks.
- *
- */
-
-static void irq_panic(void)
-{
-    extern char *cputypval;
-    prom_printf("machine: %s doesn't have irq handlers defined!\n",cputypval);
-    prom_halt();
-}
-
-void (*sparc_init_timers)(irq_handler_t ) =
-    (void (*)(irq_handler_t )) irq_panic;
-
-/*
- * Dave Redman (djhr@tadpole.co.uk)
- *
- * There used to be extern calls and hard coded values here.. very sucky!
- * instead, because some of the devices attach very early, I do something
- * equally sucky but at least we'll never try to free statically allocated
- * space or call kmalloc before kmalloc_init :(.
- * 
- * In fact it's the timer10 that attaches first.. then timer14
- * then kmalloc_init is called.. then the tty interrupts attach.
- * hmmm....
- *
- */
-#define MAX_STATIC_ALLOC       4
-struct irqaction static_irqaction[MAX_STATIC_ALLOC];
-int static_irq_count;
-
-static struct {
-       struct irqaction *action;
-       int flags;
-} sparc_irq[NR_IRQS];
-#define SPARC_IRQ_INPROGRESS 1
-
-/* Used to protect the IRQ action lists */
-DEFINE_SPINLOCK(irq_action_lock);
-
-int show_interrupts(struct seq_file *p, void *v)
-{
-       int i = *(loff_t *) v;
-       struct irqaction * action;
-       unsigned long flags;
-#ifdef CONFIG_SMP
-       int j;
-#endif
-
-       if (sparc_cpu_model == sun4d) {
-               extern int show_sun4d_interrupts(struct seq_file *, void *);
-               
-               return show_sun4d_interrupts(p, v);
-       }
-       spin_lock_irqsave(&irq_action_lock, flags);
-       if (i < NR_IRQS) {
-               action = sparc_irq[i].action;
-               if (!action) 
-                       goto out_unlock;
-               seq_printf(p, "%3d: ", i);
-#ifndef CONFIG_SMP
-               seq_printf(p, "%10u ", kstat_irqs(i));
-#else
-               for_each_online_cpu(j) {
-                       seq_printf(p, "%10u ",
-                                   kstat_cpu(j).irqs[i]);
-               }
-#endif
-               seq_printf(p, " %c %s",
-                       (action->flags & IRQF_DISABLED) ? '+' : ' ',
-                       action->name);
-               for (action=action->next; action; action = action->next) {
-                       seq_printf(p, ",%s %s",
-                               (action->flags & IRQF_DISABLED) ? " +" : "",
-                               action->name);
-               }
-               seq_putc(p, '\n');
-       }
-out_unlock:
-       spin_unlock_irqrestore(&irq_action_lock, flags);
-       return 0;
-}
-
-void free_irq(unsigned int irq, void *dev_id)
-{
-       struct irqaction * action;
-       struct irqaction **actionp;
-        unsigned long flags;
-       unsigned int cpu_irq;
-       
-       if (sparc_cpu_model == sun4d) {
-               extern void sun4d_free_irq(unsigned int, void *);
-               
-               sun4d_free_irq(irq, dev_id);
-               return;
-       }
-       cpu_irq = irq & (NR_IRQS - 1);
-        if (cpu_irq > 14) {  /* 14 irq levels on the sparc */
-                printk("Trying to free bogus IRQ %d\n", irq);
-                return;
-        }
-
-       spin_lock_irqsave(&irq_action_lock, flags);
-
-       actionp = &sparc_irq[cpu_irq].action;
-       action = *actionp;
-
-       if (!action->handler) {
-               printk("Trying to free free IRQ%d\n",irq);
-               goto out_unlock;
-       }
-       if (dev_id) {
-               for (; action; action = action->next) {
-                       if (action->dev_id == dev_id)
-                               break;
-                       actionp = &action->next;
-               }
-               if (!action) {
-                       printk("Trying to free free shared IRQ%d\n",irq);
-                       goto out_unlock;
-               }
-       } else if (action->flags & IRQF_SHARED) {
-               printk("Trying to free shared IRQ%d with NULL device ID\n", irq);
-               goto out_unlock;
-       }
-       if (action->flags & SA_STATIC_ALLOC)
-       {
-               /* This interrupt is marked as specially allocated
-                * so it is a bad idea to free it.
-                */
-               printk("Attempt to free statically allocated IRQ%d (%s)\n",
-                      irq, action->name);
-               goto out_unlock;
-       }
-
-       *actionp = action->next;
-
-       spin_unlock_irqrestore(&irq_action_lock, flags);
-
-       synchronize_irq(irq);
-
-       spin_lock_irqsave(&irq_action_lock, flags);
-
-       kfree(action);
-
-       if (!sparc_irq[cpu_irq].action)
-               __disable_irq(irq);
-
-out_unlock:
-       spin_unlock_irqrestore(&irq_action_lock, flags);
-}
-
-EXPORT_SYMBOL(free_irq);
-
-/*
- * This is called when we want to synchronize with
- * interrupts. We may for example tell a device to
- * stop sending interrupts: but to make sure there
- * are no interrupts that are executing on another
- * CPU we need to call this function.
- */
-#ifdef CONFIG_SMP
-void synchronize_irq(unsigned int irq)
-{
-       unsigned int cpu_irq;
-
-       cpu_irq = irq & (NR_IRQS - 1);
-       while (sparc_irq[cpu_irq].flags & SPARC_IRQ_INPROGRESS)
-               cpu_relax();
-}
-#endif /* SMP */
-
-void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs)
-{
-        int i;
-       struct irqaction * action;
-       unsigned int cpu_irq;
-       
-       cpu_irq = irq & (NR_IRQS - 1);
-       action = sparc_irq[cpu_irq].action;
-
-        printk("IO device interrupt, irq = %d\n", irq);
-        printk("PC = %08lx NPC = %08lx FP=%08lx\n", regs->pc, 
-                   regs->npc, regs->u_regs[14]);
-       if (action) {
-               printk("Expecting: ");
-               for (i = 0; i < 16; i++)
-                       if (action->handler)
-                               printk("[%s:%d:0x%x] ", action->name,
-                                      (int) i, (unsigned int) action->handler);
-       }
-        printk("AIEEE\n");
-       panic("bogus interrupt received");
-}
-
-void handler_irq(int irq, struct pt_regs * regs)
-{
-       struct pt_regs *old_regs;
-       struct irqaction * action;
-       int cpu = smp_processor_id();
-#ifdef CONFIG_SMP
-       extern void smp4m_irq_rotate(int cpu);
-#endif
-
-       old_regs = set_irq_regs(regs);
-       irq_enter();
-       disable_pil_irq(irq);
-#ifdef CONFIG_SMP
-       /* Only rotate on lower priority IRQs (scsi, ethernet, etc.). */
-       if((sparc_cpu_model==sun4m) && (irq < 10))
-               smp4m_irq_rotate(cpu);
-#endif
-       action = sparc_irq[irq].action;
-       sparc_irq[irq].flags |= SPARC_IRQ_INPROGRESS;
-       kstat_cpu(cpu).irqs[irq]++;
-       do {
-               if (!action || !action->handler)
-                       unexpected_irq(irq, NULL, regs);
-               action->handler(irq, action->dev_id);
-               action = action->next;
-       } while (action);
-       sparc_irq[irq].flags &= ~SPARC_IRQ_INPROGRESS;
-       enable_pil_irq(irq);
-       irq_exit();
-       set_irq_regs(old_regs);
-}
-
-#if defined(CONFIG_BLK_DEV_FD) || defined(CONFIG_BLK_DEV_FD_MODULE)
-
-/* Fast IRQs on the Sparc can only have one routine attached to them,
- * thus no sharing possible.
- */
-static int request_fast_irq(unsigned int irq,
-                           void (*handler)(void),
-                           unsigned long irqflags, const char *devname)
-{
-       struct irqaction *action;
-       unsigned long flags;
-       unsigned int cpu_irq;
-       int ret;
-#ifdef CONFIG_SMP
-       struct tt_entry *trap_table;
-       extern struct tt_entry trapbase_cpu1, trapbase_cpu2, trapbase_cpu3;
-#endif
-       
-       cpu_irq = irq & (NR_IRQS - 1);
-       if(cpu_irq > 14) {
-               ret = -EINVAL;
-               goto out;
-       }
-       if(!handler) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       spin_lock_irqsave(&irq_action_lock, flags);
-
-       action = sparc_irq[cpu_irq].action;
-       if(action) {
-               if(action->flags & IRQF_SHARED)
-                       panic("Trying to register fast irq when already shared.\n");
-               if(irqflags & IRQF_SHARED)
-                       panic("Trying to register fast irq as shared.\n");
-
-               /* Anyway, someone already owns it so cannot be made fast. */
-               printk("request_fast_irq: Trying to register yet already owned.\n");
-               ret = -EBUSY;
-               goto out_unlock;
-       }
-
-       /* If this is flagged as statically allocated then we use our
-        * private struct which is never freed.
-        */
-       if (irqflags & SA_STATIC_ALLOC) {
-           if (static_irq_count < MAX_STATIC_ALLOC)
-               action = &static_irqaction[static_irq_count++];
-           else
-               printk("Fast IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n",
-                      irq, devname);
-       }
-       
-       if (action == NULL)
-           action = kmalloc(sizeof(struct irqaction),
-                                                GFP_ATOMIC);
-       
-       if (!action) { 
-               ret = -ENOMEM;
-               goto out_unlock;
-       }
-
-       /* Dork with trap table if we get this far. */
-#define INSTANTIATE(table) \
-       table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_one = SPARC_RD_PSR_L0; \
-       table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_two = \
-               SPARC_BRANCH((unsigned long) handler, \
-                            (unsigned long) &table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_two);\
-       table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_three = SPARC_RD_WIM_L3; \
-       table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_four = SPARC_NOP;
-
-       INSTANTIATE(sparc_ttable)
-#ifdef CONFIG_SMP
-       trap_table = &trapbase_cpu1; INSTANTIATE(trap_table)
-       trap_table = &trapbase_cpu2; INSTANTIATE(trap_table)
-       trap_table = &trapbase_cpu3; INSTANTIATE(trap_table)
-#endif
-#undef INSTANTIATE
-       /*
-        * XXX Correct thing whould be to flush only I- and D-cache lines
-        * which contain the handler in question. But as of time of the
-        * writing we have no CPU-neutral interface to fine-grained flushes.
-        */
-       flush_cache_all();
-
-       action->flags = irqflags;
-       cpus_clear(action->mask);
-       action->name = devname;
-       action->dev_id = NULL;
-       action->next = NULL;
-
-       sparc_irq[cpu_irq].action = action;
-
-       __enable_irq(irq);
-
-       ret = 0;
-out_unlock:
-       spin_unlock_irqrestore(&irq_action_lock, flags);
-out:
-       return ret;
-}
-
-/* These variables are used to access state from the assembler
- * interrupt handler, floppy_hardint, so we cannot put these in
- * the floppy driver image because that would not work in the
- * modular case.
- */
-volatile unsigned char *fdc_status;
-EXPORT_SYMBOL(fdc_status);
-
-char *pdma_vaddr;
-EXPORT_SYMBOL(pdma_vaddr);
-
-unsigned long pdma_size;
-EXPORT_SYMBOL(pdma_size);
-
-volatile int doing_pdma;
-EXPORT_SYMBOL(doing_pdma);
-
-char *pdma_base;
-EXPORT_SYMBOL(pdma_base);
-
-unsigned long pdma_areasize;
-EXPORT_SYMBOL(pdma_areasize);
-
-extern void floppy_hardint(void);
-
-static irq_handler_t floppy_irq_handler;
-
-void sparc_floppy_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
-       struct pt_regs *old_regs;
-       int cpu = smp_processor_id();
-
-       old_regs = set_irq_regs(regs);
-       disable_pil_irq(irq);
-       irq_enter();
-       kstat_cpu(cpu).irqs[irq]++;
-       floppy_irq_handler(irq, dev_id);
-       irq_exit();
-       enable_pil_irq(irq);
-       set_irq_regs(old_regs);
-       // XXX Eek, it's totally changed with preempt_count() and such
-       // if (softirq_pending(cpu))
-       //      do_softirq();
-}
-
-int sparc_floppy_request_irq(int irq, unsigned long flags,
-                            irq_handler_t irq_handler)
-{
-       floppy_irq_handler = irq_handler;
-       return request_fast_irq(irq, floppy_hardint, flags, "floppy");
-}
-EXPORT_SYMBOL(sparc_floppy_request_irq);
-
-#endif
-
-int request_irq(unsigned int irq,
-               irq_handler_t handler,
-               unsigned long irqflags, const char * devname, void *dev_id)
-{
-       struct irqaction * action, **actionp;
-       unsigned long flags;
-       unsigned int cpu_irq;
-       int ret;
-       
-       if (sparc_cpu_model == sun4d) {
-               extern int sun4d_request_irq(unsigned int, 
-                                            irq_handler_t ,
-                                            unsigned long, const char *, void *);
-               return sun4d_request_irq(irq, handler, irqflags, devname, dev_id);
-       }
-       cpu_irq = irq & (NR_IRQS - 1);
-       if(cpu_irq > 14) {
-               ret = -EINVAL;
-               goto out;
-       }
-       if (!handler) {
-               ret = -EINVAL;
-               goto out;
-       }
-           
-       spin_lock_irqsave(&irq_action_lock, flags);
-
-       actionp = &sparc_irq[cpu_irq].action;
-       action = *actionp;
-       if (action) {
-               if (!(action->flags & IRQF_SHARED) || !(irqflags & IRQF_SHARED)) {
-                       ret = -EBUSY;
-                       goto out_unlock;
-               }
-               if ((action->flags & IRQF_DISABLED) != (irqflags & IRQF_DISABLED)) {
-                       printk("Attempt to mix fast and slow interrupts on IRQ%d denied\n", irq);
-                       ret = -EBUSY;
-                       goto out_unlock;
-               }
-               for ( ; action; action = *actionp)
-                       actionp = &action->next;
-       }
-
-       /* If this is flagged as statically allocated then we use our
-        * private struct which is never freed.
-        */
-       if (irqflags & SA_STATIC_ALLOC) {
-               if (static_irq_count < MAX_STATIC_ALLOC)
-                       action = &static_irqaction[static_irq_count++];
-               else
-                       printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n", irq, devname);
-       }
-       
-       if (action == NULL)
-               action = kmalloc(sizeof(struct irqaction),
-                                                    GFP_ATOMIC);
-       
-       if (!action) { 
-               ret = -ENOMEM;
-               goto out_unlock;
-       }
-
-       action->handler = handler;
-       action->flags = irqflags;
-       cpus_clear(action->mask);
-       action->name = devname;
-       action->next = NULL;
-       action->dev_id = dev_id;
-
-       *actionp = action;
-
-       __enable_irq(irq);
-
-       ret = 0;
-out_unlock:
-       spin_unlock_irqrestore(&irq_action_lock, flags);
-out:
-       return ret;
-}
-
-EXPORT_SYMBOL(request_irq);
-
-void disable_irq_nosync(unsigned int irq)
-{
-       return __disable_irq(irq);
-}
-EXPORT_SYMBOL(disable_irq_nosync);
-
-void disable_irq(unsigned int irq)
-{
-       return __disable_irq(irq);
-}
-EXPORT_SYMBOL(disable_irq);
-
-void enable_irq(unsigned int irq)
-{
-       return __enable_irq(irq);
-}
-
-EXPORT_SYMBOL(enable_irq);
-
-/* We really don't need these at all on the Sparc.  We only have
- * stubs here because they are exported to modules.
- */
-unsigned long probe_irq_on(void)
-{
-       return 0;
-}
-
-EXPORT_SYMBOL(probe_irq_on);
-
-int probe_irq_off(unsigned long mask)
-{
-       return 0;
-}
-
-EXPORT_SYMBOL(probe_irq_off);
-
-/* djhr
- * This could probably be made indirect too and assigned in the CPU
- * bits of the code. That would be much nicer I think and would also
- * fit in with the idea of being able to tune your kernel for your machine
- * by removing unrequired machine and device support.
- *
- */
-
-void __init init_IRQ(void)
-{
-       extern void sun4c_init_IRQ( void );
-       extern void sun4m_init_IRQ( void );
-       extern void sun4d_init_IRQ( void );
-
-       switch(sparc_cpu_model) {
-       case sun4c:
-       case sun4:
-               sun4c_init_IRQ();
-               break;
-
-       case sun4m:
-#ifdef CONFIG_PCI
-               pcic_probe();
-               if (pcic_present()) {
-                       sun4m_pci_init_IRQ();
-                       break;
-               }
-#endif
-               sun4m_init_IRQ();
-               break;
-               
-       case sun4d:
-               sun4d_init_IRQ();
-               break;
-
-       default:
-               prom_printf("Cannot initialize IRQs on this Sun machine...");
-               break;
-       }
-       btfixup();
-}
-
-void init_irq_proc(void)
-{
-       /* For now, nothing... */
-}
diff --git a/arch/sparc/kernel/irq_32.c b/arch/sparc/kernel/irq_32.c
new file mode 100644 (file)
index 0000000..93e1d1c
--- /dev/null
@@ -0,0 +1,674 @@
+/*
+ *  arch/sparc/kernel/irq.c:  Interrupt request handling routines. On the
+ *                            Sparc the IRQs are basically 'cast in stone'
+ *                            and you are supposed to probe the prom's device
+ *                            node trees to find out who's got which IRQ.
+ *
+ *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ *  Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *  Copyright (C) 1995,2002 Pete A. Zaitcev (zaitcev@yahoo.com)
+ *  Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk)
+ *  Copyright (C) 1998-2000 Anton Blanchard (anton@samba.org)
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/linkage.h>
+#include <linux/kernel_stat.h>
+#include <linux/signal.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/delay.h>
+#include <linux/threads.h>
+#include <linux/spinlock.h>
+#include <linux/seq_file.h>
+
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/psr.h>
+#include <asm/smp.h>
+#include <asm/vaddrs.h>
+#include <asm/timer.h>
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+#include <asm/traps.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <asm/pcic.h>
+#include <asm/cacheflush.h>
+#include <asm/irq_regs.h>
+
+#include "irq.h"
+
+#ifdef CONFIG_SMP
+#define SMP_NOP2 "nop; nop;\n\t"
+#define SMP_NOP3 "nop; nop; nop;\n\t"
+#else
+#define SMP_NOP2
+#define SMP_NOP3
+#endif /* SMP */
+unsigned long __raw_local_irq_save(void)
+{
+       unsigned long retval;
+       unsigned long tmp;
+
+       __asm__ __volatile__(
+               "rd     %%psr, %0\n\t"
+               SMP_NOP3        /* Sun4m + Cypress + SMP bug */
+               "or     %0, %2, %1\n\t"
+               "wr     %1, 0, %%psr\n\t"
+               "nop; nop; nop\n"
+               : "=&r" (retval), "=r" (tmp)
+               : "i" (PSR_PIL)
+               : "memory");
+
+       return retval;
+}
+
+void raw_local_irq_enable(void)
+{
+       unsigned long tmp;
+
+       __asm__ __volatile__(
+               "rd     %%psr, %0\n\t"
+               SMP_NOP3        /* Sun4m + Cypress + SMP bug */
+               "andn   %0, %1, %0\n\t"
+               "wr     %0, 0, %%psr\n\t"
+               "nop; nop; nop\n"
+               : "=&r" (tmp)
+               : "i" (PSR_PIL)
+               : "memory");
+}
+
+void raw_local_irq_restore(unsigned long old_psr)
+{
+       unsigned long tmp;
+
+       __asm__ __volatile__(
+               "rd     %%psr, %0\n\t"
+               "and    %2, %1, %2\n\t"
+               SMP_NOP2        /* Sun4m + Cypress + SMP bug */
+               "andn   %0, %1, %0\n\t"
+               "wr     %0, %2, %%psr\n\t"
+               "nop; nop; nop\n"
+               : "=&r" (tmp)
+               : "i" (PSR_PIL), "r" (old_psr)
+               : "memory");
+}
+
+EXPORT_SYMBOL(__raw_local_irq_save);
+EXPORT_SYMBOL(raw_local_irq_enable);
+EXPORT_SYMBOL(raw_local_irq_restore);
+
+/*
+ * Dave Redman (djhr@tadpole.co.uk)
+ *
+ * IRQ numbers.. These are no longer restricted to 15..
+ *
+ * this is done to enable SBUS cards and onboard IO to be masked
+ * correctly. using the interrupt level isn't good enough.
+ *
+ * For example:
+ *   A device interrupting at sbus level6 and the Floppy both come in
+ *   at IRQ11, but enabling and disabling them requires writing to
+ *   different bits in the SLAVIO/SEC.
+ *
+ * As a result of these changes sun4m machines could now support
+ * directed CPU interrupts using the existing enable/disable irq code
+ * with tweaks.
+ *
+ */
+
+static void irq_panic(void)
+{
+    extern char *cputypval;
+    prom_printf("machine: %s doesn't have irq handlers defined!\n",cputypval);
+    prom_halt();
+}
+
+void (*sparc_init_timers)(irq_handler_t ) =
+    (void (*)(irq_handler_t )) irq_panic;
+
+/*
+ * Dave Redman (djhr@tadpole.co.uk)
+ *
+ * There used to be extern calls and hard coded values here.. very sucky!
+ * instead, because some of the devices attach very early, I do something
+ * equally sucky but at least we'll never try to free statically allocated
+ * space or call kmalloc before kmalloc_init :(.
+ * 
+ * In fact it's the timer10 that attaches first.. then timer14
+ * then kmalloc_init is called.. then the tty interrupts attach.
+ * hmmm....
+ *
+ */
+#define MAX_STATIC_ALLOC       4
+struct irqaction static_irqaction[MAX_STATIC_ALLOC];
+int static_irq_count;
+
+static struct {
+       struct irqaction *action;
+       int flags;
+} sparc_irq[NR_IRQS];
+#define SPARC_IRQ_INPROGRESS 1
+
+/* Used to protect the IRQ action lists */
+DEFINE_SPINLOCK(irq_action_lock);
+
+int show_interrupts(struct seq_file *p, void *v)
+{
+       int i = *(loff_t *) v;
+       struct irqaction * action;
+       unsigned long flags;
+#ifdef CONFIG_SMP
+       int j;
+#endif
+
+       if (sparc_cpu_model == sun4d) {
+               extern int show_sun4d_interrupts(struct seq_file *, void *);
+               
+               return show_sun4d_interrupts(p, v);
+       }
+       spin_lock_irqsave(&irq_action_lock, flags);
+       if (i < NR_IRQS) {
+               action = sparc_irq[i].action;
+               if (!action) 
+                       goto out_unlock;
+               seq_printf(p, "%3d: ", i);
+#ifndef CONFIG_SMP
+               seq_printf(p, "%10u ", kstat_irqs(i));
+#else
+               for_each_online_cpu(j) {
+                       seq_printf(p, "%10u ",
+                                   kstat_cpu(j).irqs[i]);
+               }
+#endif
+               seq_printf(p, " %c %s",
+                       (action->flags & IRQF_DISABLED) ? '+' : ' ',
+                       action->name);
+               for (action=action->next; action; action = action->next) {
+                       seq_printf(p, ",%s %s",
+                               (action->flags & IRQF_DISABLED) ? " +" : "",
+                               action->name);
+               }
+               seq_putc(p, '\n');
+       }
+out_unlock:
+       spin_unlock_irqrestore(&irq_action_lock, flags);
+       return 0;
+}
+
+void free_irq(unsigned int irq, void *dev_id)
+{
+       struct irqaction * action;
+       struct irqaction **actionp;
+        unsigned long flags;
+       unsigned int cpu_irq;
+       
+       if (sparc_cpu_model == sun4d) {
+               extern void sun4d_free_irq(unsigned int, void *);
+               
+               sun4d_free_irq(irq, dev_id);
+               return;
+       }
+       cpu_irq = irq & (NR_IRQS - 1);
+        if (cpu_irq > 14) {  /* 14 irq levels on the sparc */
+                printk("Trying to free bogus IRQ %d\n", irq);
+                return;
+        }
+
+       spin_lock_irqsave(&irq_action_lock, flags);
+
+       actionp = &sparc_irq[cpu_irq].action;
+       action = *actionp;
+
+       if (!action->handler) {
+               printk("Trying to free free IRQ%d\n",irq);
+               goto out_unlock;
+       }
+       if (dev_id) {
+               for (; action; action = action->next) {
+                       if (action->dev_id == dev_id)
+                               break;
+                       actionp = &action->next;
+               }
+               if (!action) {
+                       printk("Trying to free free shared IRQ%d\n",irq);
+                       goto out_unlock;
+               }
+       } else if (action->flags & IRQF_SHARED) {
+               printk("Trying to free shared IRQ%d with NULL device ID\n", irq);
+               goto out_unlock;
+       }
+       if (action->flags & SA_STATIC_ALLOC)
+       {
+               /* This interrupt is marked as specially allocated
+                * so it is a bad idea to free it.
+                */
+               printk("Attempt to free statically allocated IRQ%d (%s)\n",
+                      irq, action->name);
+               goto out_unlock;
+       }
+
+       *actionp = action->next;
+
+       spin_unlock_irqrestore(&irq_action_lock, flags);
+
+       synchronize_irq(irq);
+
+       spin_lock_irqsave(&irq_action_lock, flags);
+
+       kfree(action);
+
+       if (!sparc_irq[cpu_irq].action)
+               __disable_irq(irq);
+
+out_unlock:
+       spin_unlock_irqrestore(&irq_action_lock, flags);
+}
+
+EXPORT_SYMBOL(free_irq);
+
+/*
+ * This is called when we want to synchronize with
+ * interrupts. We may for example tell a device to
+ * stop sending interrupts: but to make sure there
+ * are no interrupts that are executing on another
+ * CPU we need to call this function.
+ */
+#ifdef CONFIG_SMP
+void synchronize_irq(unsigned int irq)
+{
+       unsigned int cpu_irq;
+
+       cpu_irq = irq & (NR_IRQS - 1);
+       while (sparc_irq[cpu_irq].flags & SPARC_IRQ_INPROGRESS)
+               cpu_relax();
+}
+#endif /* SMP */
+
+void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs)
+{
+        int i;
+       struct irqaction * action;
+       unsigned int cpu_irq;
+       
+       cpu_irq = irq & (NR_IRQS - 1);
+       action = sparc_irq[cpu_irq].action;
+
+        printk("IO device interrupt, irq = %d\n", irq);
+        printk("PC = %08lx NPC = %08lx FP=%08lx\n", regs->pc, 
+                   regs->npc, regs->u_regs[14]);
+       if (action) {
+               printk("Expecting: ");
+               for (i = 0; i < 16; i++)
+                       if (action->handler)
+                               printk("[%s:%d:0x%x] ", action->name,
+                                      (int) i, (unsigned int) action->handler);
+       }
+        printk("AIEEE\n");
+       panic("bogus interrupt received");
+}
+
+void handler_irq(int irq, struct pt_regs * regs)
+{
+       struct pt_regs *old_regs;
+       struct irqaction * action;
+       int cpu = smp_processor_id();
+#ifdef CONFIG_SMP
+       extern void smp4m_irq_rotate(int cpu);
+#endif
+
+       old_regs = set_irq_regs(regs);
+       irq_enter();
+       disable_pil_irq(irq);
+#ifdef CONFIG_SMP
+       /* Only rotate on lower priority IRQs (scsi, ethernet, etc.). */
+       if((sparc_cpu_model==sun4m) && (irq < 10))
+               smp4m_irq_rotate(cpu);
+#endif
+       action = sparc_irq[irq].action;
+       sparc_irq[irq].flags |= SPARC_IRQ_INPROGRESS;
+       kstat_cpu(cpu).irqs[irq]++;
+       do {
+               if (!action || !action->handler)
+                       unexpected_irq(irq, NULL, regs);
+               action->handler(irq, action->dev_id);
+               action = action->next;
+       } while (action);
+       sparc_irq[irq].flags &= ~SPARC_IRQ_INPROGRESS;
+       enable_pil_irq(irq);
+       irq_exit();
+       set_irq_regs(old_regs);
+}
+
+#if defined(CONFIG_BLK_DEV_FD) || defined(CONFIG_BLK_DEV_FD_MODULE)
+
+/* Fast IRQs on the Sparc can only have one routine attached to them,
+ * thus no sharing possible.
+ */
+static int request_fast_irq(unsigned int irq,
+                           void (*handler)(void),
+                           unsigned long irqflags, const char *devname)
+{
+       struct irqaction *action;
+       unsigned long flags;
+       unsigned int cpu_irq;
+       int ret;
+#ifdef CONFIG_SMP
+       struct tt_entry *trap_table;
+       extern struct tt_entry trapbase_cpu1, trapbase_cpu2, trapbase_cpu3;
+#endif
+       
+       cpu_irq = irq & (NR_IRQS - 1);
+       if(cpu_irq > 14) {
+               ret = -EINVAL;
+               goto out;
+       }
+       if(!handler) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       spin_lock_irqsave(&irq_action_lock, flags);
+
+       action = sparc_irq[cpu_irq].action;
+       if(action) {
+               if(action->flags & IRQF_SHARED)
+                       panic("Trying to register fast irq when already shared.\n");
+               if(irqflags & IRQF_SHARED)
+                       panic("Trying to register fast irq as shared.\n");
+
+               /* Anyway, someone already owns it so cannot be made fast. */
+               printk("request_fast_irq: Trying to register yet already owned.\n");
+               ret = -EBUSY;
+               goto out_unlock;
+       }
+
+       /* If this is flagged as statically allocated then we use our
+        * private struct which is never freed.
+        */
+       if (irqflags & SA_STATIC_ALLOC) {
+           if (static_irq_count < MAX_STATIC_ALLOC)
+               action = &static_irqaction[static_irq_count++];
+           else
+               printk("Fast IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n",
+                      irq, devname);
+       }
+       
+       if (action == NULL)
+           action = kmalloc(sizeof(struct irqaction),
+                                                GFP_ATOMIC);
+       
+       if (!action) { 
+               ret = -ENOMEM;
+               goto out_unlock;
+       }
+
+       /* Dork with trap table if we get this far. */
+#define INSTANTIATE(table) \
+       table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_one = SPARC_RD_PSR_L0; \
+       table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_two = \
+               SPARC_BRANCH((unsigned long) handler, \
+                            (unsigned long) &table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_two);\
+       table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_three = SPARC_RD_WIM_L3; \
+       table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_four = SPARC_NOP;
+
+       INSTANTIATE(sparc_ttable)
+#ifdef CONFIG_SMP
+       trap_table = &trapbase_cpu1; INSTANTIATE(trap_table)
+       trap_table = &trapbase_cpu2; INSTANTIATE(trap_table)
+       trap_table = &trapbase_cpu3; INSTANTIATE(trap_table)
+#endif
+#undef INSTANTIATE
+       /*
+        * XXX Correct thing whould be to flush only I- and D-cache lines
+        * which contain the handler in question. But as of time of the
+        * writing we have no CPU-neutral interface to fine-grained flushes.
+        */
+       flush_cache_all();
+
+       action->flags = irqflags;
+       cpus_clear(action->mask);
+       action->name = devname;
+       action->dev_id = NULL;
+       action->next = NULL;
+
+       sparc_irq[cpu_irq].action = action;
+
+       __enable_irq(irq);
+
+       ret = 0;
+out_unlock:
+       spin_unlock_irqrestore(&irq_action_lock, flags);
+out:
+       return ret;
+}
+
+/* These variables are used to access state from the assembler
+ * interrupt handler, floppy_hardint, so we cannot put these in
+ * the floppy driver image because that would not work in the
+ * modular case.
+ */
+volatile unsigned char *fdc_status;
+EXPORT_SYMBOL(fdc_status);
+
+char *pdma_vaddr;
+EXPORT_SYMBOL(pdma_vaddr);
+
+unsigned long pdma_size;
+EXPORT_SYMBOL(pdma_size);
+
+volatile int doing_pdma;
+EXPORT_SYMBOL(doing_pdma);
+
+char *pdma_base;
+EXPORT_SYMBOL(pdma_base);
+
+unsigned long pdma_areasize;
+EXPORT_SYMBOL(pdma_areasize);
+
+extern void floppy_hardint(void);
+
+static irq_handler_t floppy_irq_handler;
+
+void sparc_floppy_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct pt_regs *old_regs;
+       int cpu = smp_processor_id();
+
+       old_regs = set_irq_regs(regs);
+       disable_pil_irq(irq);
+       irq_enter();
+       kstat_cpu(cpu).irqs[irq]++;
+       floppy_irq_handler(irq, dev_id);
+       irq_exit();
+       enable_pil_irq(irq);
+       set_irq_regs(old_regs);
+       // XXX Eek, it's totally changed with preempt_count() and such
+       // if (softirq_pending(cpu))
+       //      do_softirq();
+}
+
+int sparc_floppy_request_irq(int irq, unsigned long flags,
+                            irq_handler_t irq_handler)
+{
+       floppy_irq_handler = irq_handler;
+       return request_fast_irq(irq, floppy_hardint, flags, "floppy");
+}
+EXPORT_SYMBOL(sparc_floppy_request_irq);
+
+#endif
+
+int request_irq(unsigned int irq,
+               irq_handler_t handler,
+               unsigned long irqflags, const char * devname, void *dev_id)
+{
+       struct irqaction * action, **actionp;
+       unsigned long flags;
+       unsigned int cpu_irq;
+       int ret;
+       
+       if (sparc_cpu_model == sun4d) {
+               extern int sun4d_request_irq(unsigned int, 
+                                            irq_handler_t ,
+                                            unsigned long, const char *, void *);
+               return sun4d_request_irq(irq, handler, irqflags, devname, dev_id);
+       }
+       cpu_irq = irq & (NR_IRQS - 1);
+       if(cpu_irq > 14) {
+               ret = -EINVAL;
+               goto out;
+       }
+       if (!handler) {
+               ret = -EINVAL;
+               goto out;
+       }
+           
+       spin_lock_irqsave(&irq_action_lock, flags);
+
+       actionp = &sparc_irq[cpu_irq].action;
+       action = *actionp;
+       if (action) {
+               if (!(action->flags & IRQF_SHARED) || !(irqflags & IRQF_SHARED)) {
+                       ret = -EBUSY;
+                       goto out_unlock;
+               }
+               if ((action->flags & IRQF_DISABLED) != (irqflags & IRQF_DISABLED)) {
+                       printk("Attempt to mix fast and slow interrupts on IRQ%d denied\n", irq);
+                       ret = -EBUSY;
+                       goto out_unlock;
+               }
+               for ( ; action; action = *actionp)
+                       actionp = &action->next;
+       }
+
+       /* If this is flagged as statically allocated then we use our
+        * private struct which is never freed.
+        */
+       if (irqflags & SA_STATIC_ALLOC) {
+               if (static_irq_count < MAX_STATIC_ALLOC)
+                       action = &static_irqaction[static_irq_count++];
+               else
+                       printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n", irq, devname);
+       }
+       
+       if (action == NULL)
+               action = kmalloc(sizeof(struct irqaction),
+                                                    GFP_ATOMIC);
+       
+       if (!action) { 
+               ret = -ENOMEM;
+               goto out_unlock;
+       }
+
+       action->handler = handler;
+       action->flags = irqflags;
+       cpus_clear(action->mask);
+       action->name = devname;
+       action->next = NULL;
+       action->dev_id = dev_id;
+
+       *actionp = action;
+
+       __enable_irq(irq);
+
+       ret = 0;
+out_unlock:
+       spin_unlock_irqrestore(&irq_action_lock, flags);
+out:
+       return ret;
+}
+
+EXPORT_SYMBOL(request_irq);
+
+void disable_irq_nosync(unsigned int irq)
+{
+       return __disable_irq(irq);
+}
+EXPORT_SYMBOL(disable_irq_nosync);
+
+void disable_irq(unsigned int irq)
+{
+       return __disable_irq(irq);
+}
+EXPORT_SYMBOL(disable_irq);
+
+void enable_irq(unsigned int irq)
+{
+       return __enable_irq(irq);
+}
+
+EXPORT_SYMBOL(enable_irq);
+
+/* We really don't need these at all on the Sparc.  We only have
+ * stubs here because they are exported to modules.
+ */
+unsigned long probe_irq_on(void)
+{
+       return 0;
+}
+
+EXPORT_SYMBOL(probe_irq_on);
+
+int probe_irq_off(unsigned long mask)
+{
+       return 0;
+}
+
+EXPORT_SYMBOL(probe_irq_off);
+
+/* djhr
+ * This could probably be made indirect too and assigned in the CPU
+ * bits of the code. That would be much nicer I think and would also
+ * fit in with the idea of being able to tune your kernel for your machine
+ * by removing unrequired machine and device support.
+ *
+ */
+
+void __init init_IRQ(void)
+{
+       extern void sun4c_init_IRQ( void );
+       extern void sun4m_init_IRQ( void );
+       extern void sun4d_init_IRQ( void );
+
+       switch(sparc_cpu_model) {
+       case sun4c:
+       case sun4:
+               sun4c_init_IRQ();
+               break;
+
+       case sun4m:
+#ifdef CONFIG_PCI
+               pcic_probe();
+               if (pcic_present()) {
+                       sun4m_pci_init_IRQ();
+                       break;
+               }
+#endif
+               sun4m_init_IRQ();
+               break;
+               
+       case sun4d:
+               sun4d_init_IRQ();
+               break;
+
+       default:
+               prom_printf("Cannot initialize IRQs on this Sun machine...");
+               break;
+       }
+       btfixup();
+}
+
+void init_irq_proc(void)
+{
+       /* For now, nothing... */
+}
diff --git a/arch/sparc/kernel/kgdb.c b/arch/sparc/kernel/kgdb.c
deleted file mode 100644 (file)
index 757805c..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-/* kgdb.c: KGDB support for 32-bit sparc.
- *
- * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
- */
-
-#include <linux/kgdb.h>
-#include <linux/kdebug.h>
-
-#include <asm/kdebug.h>
-#include <asm/ptrace.h>
-#include <asm/irq.h>
-
-extern unsigned long trapbase;
-
-void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
-{
-       struct reg_window *win;
-       int i;
-
-       gdb_regs[GDB_G0] = 0;
-       for (i = 0; i < 15; i++)
-               gdb_regs[GDB_G1 + i] = regs->u_regs[UREG_G1 + i];
-
-       win = (struct reg_window *) regs->u_regs[UREG_FP];
-       for (i = 0; i < 8; i++)
-               gdb_regs[GDB_L0 + i] = win->locals[i];
-       for (i = 0; i < 8; i++)
-               gdb_regs[GDB_I0 + i] = win->ins[i];
-
-       for (i = GDB_F0; i <= GDB_F31; i++)
-               gdb_regs[i] = 0;
-
-       gdb_regs[GDB_Y] = regs->y;
-       gdb_regs[GDB_PSR] = regs->psr;
-       gdb_regs[GDB_WIM] = 0;
-       gdb_regs[GDB_TBR] = (unsigned long) &trapbase;
-       gdb_regs[GDB_PC] = regs->pc;
-       gdb_regs[GDB_NPC] = regs->npc;
-       gdb_regs[GDB_FSR] = 0;
-       gdb_regs[GDB_CSR] = 0;
-}
-
-void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
-{
-       struct thread_info *t = task_thread_info(p);
-       struct reg_window *win;
-       int i;
-
-       for (i = GDB_G0; i < GDB_G6; i++)
-               gdb_regs[i] = 0;
-       gdb_regs[GDB_G6] = (unsigned long) t;
-       gdb_regs[GDB_G7] = 0;
-       for (i = GDB_O0; i < GDB_SP; i++)
-               gdb_regs[i] = 0;
-       gdb_regs[GDB_SP] = t->ksp;
-       gdb_regs[GDB_O7] = 0;
-
-       win = (struct reg_window *) t->ksp;
-       for (i = 0; i < 8; i++)
-               gdb_regs[GDB_L0 + i] = win->locals[i];
-       for (i = 0; i < 8; i++)
-               gdb_regs[GDB_I0 + i] = win->ins[i];
-
-       for (i = GDB_F0; i <= GDB_F31; i++)
-               gdb_regs[i] = 0;
-
-       gdb_regs[GDB_Y] = 0;
-
-       gdb_regs[GDB_PSR] = t->kpsr;
-       gdb_regs[GDB_WIM] = t->kwim;
-       gdb_regs[GDB_TBR] = (unsigned long) &trapbase;
-       gdb_regs[GDB_PC] = t->kpc;
-       gdb_regs[GDB_NPC] = t->kpc + 4;
-       gdb_regs[GDB_FSR] = 0;
-       gdb_regs[GDB_CSR] = 0;
-}
-
-void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
-{
-       struct reg_window *win;
-       int i;
-
-       for (i = 0; i < 15; i++)
-               regs->u_regs[UREG_G1 + i] = gdb_regs[GDB_G1 + i];
-
-       /* If the PSR register is changing, we have to preserve
-        * the CWP field, otherwise window save/restore explodes.
-        */
-       if (regs->psr != gdb_regs[GDB_PSR]) {
-               unsigned long cwp = regs->psr & PSR_CWP;
-
-               regs->psr = (gdb_regs[GDB_PSR] & ~PSR_CWP) | cwp;
-       }
-
-       regs->pc = gdb_regs[GDB_PC];
-       regs->npc = gdb_regs[GDB_NPC];
-       regs->y = gdb_regs[GDB_Y];
-
-       win = (struct reg_window *) regs->u_regs[UREG_FP];
-       for (i = 0; i < 8; i++)
-               win->locals[i] = gdb_regs[GDB_L0 + i];
-       for (i = 0; i < 8; i++)
-               win->ins[i] = gdb_regs[GDB_I0 + i];
-}
-
-int kgdb_arch_handle_exception(int e_vector, int signo, int err_code,
-                              char *remcomInBuffer, char *remcomOutBuffer,
-                              struct pt_regs *linux_regs)
-{
-       unsigned long addr;
-       char *ptr;
-
-       switch (remcomInBuffer[0]) {
-       case 'c':
-               /* try to read optional parameter, pc unchanged if no parm */
-               ptr = &remcomInBuffer[1];
-               if (kgdb_hex2long(&ptr, &addr)) {
-                       linux_regs->pc = addr;
-                       linux_regs->npc = addr + 4;
-               }
-               /* fallthru */
-
-       case 'D':
-       case 'k':
-               if (linux_regs->pc == (unsigned long) arch_kgdb_breakpoint) {
-                       linux_regs->pc = linux_regs->npc;
-                       linux_regs->npc += 4;
-               }
-               return 0;
-       }
-       return -1;
-}
-
-extern void do_hw_interrupt(struct pt_regs *regs, unsigned long type);
-
-asmlinkage void kgdb_trap(struct pt_regs *regs)
-{
-       unsigned long flags;
-
-       if (user_mode(regs)) {
-               do_hw_interrupt(regs, 0xfd);
-               return;
-       }
-
-       flushw_all();
-
-       local_irq_save(flags);
-       kgdb_handle_exception(0x172, SIGTRAP, 0, regs);
-       local_irq_restore(flags);
-}
-
-int kgdb_arch_init(void)
-{
-       return 0;
-}
-
-void kgdb_arch_exit(void)
-{
-}
-
-struct kgdb_arch arch_kgdb_ops = {
-       /* Breakpoint instruction: ta 0x7d */
-       .gdb_bpt_instr          = { 0x91, 0xd0, 0x20, 0x7d },
-};
diff --git a/arch/sparc/kernel/kgdb_32.c b/arch/sparc/kernel/kgdb_32.c
new file mode 100644 (file)
index 0000000..757805c
--- /dev/null
@@ -0,0 +1,164 @@
+/* kgdb.c: KGDB support for 32-bit sparc.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kgdb.h>
+#include <linux/kdebug.h>
+
+#include <asm/kdebug.h>
+#include <asm/ptrace.h>
+#include <asm/irq.h>
+
+extern unsigned long trapbase;
+
+void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+       struct reg_window *win;
+       int i;
+
+       gdb_regs[GDB_G0] = 0;
+       for (i = 0; i < 15; i++)
+               gdb_regs[GDB_G1 + i] = regs->u_regs[UREG_G1 + i];
+
+       win = (struct reg_window *) regs->u_regs[UREG_FP];
+       for (i = 0; i < 8; i++)
+               gdb_regs[GDB_L0 + i] = win->locals[i];
+       for (i = 0; i < 8; i++)
+               gdb_regs[GDB_I0 + i] = win->ins[i];
+
+       for (i = GDB_F0; i <= GDB_F31; i++)
+               gdb_regs[i] = 0;
+
+       gdb_regs[GDB_Y] = regs->y;
+       gdb_regs[GDB_PSR] = regs->psr;
+       gdb_regs[GDB_WIM] = 0;
+       gdb_regs[GDB_TBR] = (unsigned long) &trapbase;
+       gdb_regs[GDB_PC] = regs->pc;
+       gdb_regs[GDB_NPC] = regs->npc;
+       gdb_regs[GDB_FSR] = 0;
+       gdb_regs[GDB_CSR] = 0;
+}
+
+void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
+{
+       struct thread_info *t = task_thread_info(p);
+       struct reg_window *win;
+       int i;
+
+       for (i = GDB_G0; i < GDB_G6; i++)
+               gdb_regs[i] = 0;
+       gdb_regs[GDB_G6] = (unsigned long) t;
+       gdb_regs[GDB_G7] = 0;
+       for (i = GDB_O0; i < GDB_SP; i++)
+               gdb_regs[i] = 0;
+       gdb_regs[GDB_SP] = t->ksp;
+       gdb_regs[GDB_O7] = 0;
+
+       win = (struct reg_window *) t->ksp;
+       for (i = 0; i < 8; i++)
+               gdb_regs[GDB_L0 + i] = win->locals[i];
+       for (i = 0; i < 8; i++)
+               gdb_regs[GDB_I0 + i] = win->ins[i];
+
+       for (i = GDB_F0; i <= GDB_F31; i++)
+               gdb_regs[i] = 0;
+
+       gdb_regs[GDB_Y] = 0;
+
+       gdb_regs[GDB_PSR] = t->kpsr;
+       gdb_regs[GDB_WIM] = t->kwim;
+       gdb_regs[GDB_TBR] = (unsigned long) &trapbase;
+       gdb_regs[GDB_PC] = t->kpc;
+       gdb_regs[GDB_NPC] = t->kpc + 4;
+       gdb_regs[GDB_FSR] = 0;
+       gdb_regs[GDB_CSR] = 0;
+}
+
+void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+       struct reg_window *win;
+       int i;
+
+       for (i = 0; i < 15; i++)
+               regs->u_regs[UREG_G1 + i] = gdb_regs[GDB_G1 + i];
+
+       /* If the PSR register is changing, we have to preserve
+        * the CWP field, otherwise window save/restore explodes.
+        */
+       if (regs->psr != gdb_regs[GDB_PSR]) {
+               unsigned long cwp = regs->psr & PSR_CWP;
+
+               regs->psr = (gdb_regs[GDB_PSR] & ~PSR_CWP) | cwp;
+       }
+
+       regs->pc = gdb_regs[GDB_PC];
+       regs->npc = gdb_regs[GDB_NPC];
+       regs->y = gdb_regs[GDB_Y];
+
+       win = (struct reg_window *) regs->u_regs[UREG_FP];
+       for (i = 0; i < 8; i++)
+               win->locals[i] = gdb_regs[GDB_L0 + i];
+       for (i = 0; i < 8; i++)
+               win->ins[i] = gdb_regs[GDB_I0 + i];
+}
+
+int kgdb_arch_handle_exception(int e_vector, int signo, int err_code,
+                              char *remcomInBuffer, char *remcomOutBuffer,
+                              struct pt_regs *linux_regs)
+{
+       unsigned long addr;
+       char *ptr;
+
+       switch (remcomInBuffer[0]) {
+       case 'c':
+               /* try to read optional parameter, pc unchanged if no parm */
+               ptr = &remcomInBuffer[1];
+               if (kgdb_hex2long(&ptr, &addr)) {
+                       linux_regs->pc = addr;
+                       linux_regs->npc = addr + 4;
+               }
+               /* fallthru */
+
+       case 'D':
+       case 'k':
+               if (linux_regs->pc == (unsigned long) arch_kgdb_breakpoint) {
+                       linux_regs->pc = linux_regs->npc;
+                       linux_regs->npc += 4;
+               }
+               return 0;
+       }
+       return -1;
+}
+
+extern void do_hw_interrupt(struct pt_regs *regs, unsigned long type);
+
+asmlinkage void kgdb_trap(struct pt_regs *regs)
+{
+       unsigned long flags;
+
+       if (user_mode(regs)) {
+               do_hw_interrupt(regs, 0xfd);
+               return;
+       }
+
+       flushw_all();
+
+       local_irq_save(flags);
+       kgdb_handle_exception(0x172, SIGTRAP, 0, regs);
+       local_irq_restore(flags);
+}
+
+int kgdb_arch_init(void)
+{
+       return 0;
+}
+
+void kgdb_arch_exit(void)
+{
+}
+
+struct kgdb_arch arch_kgdb_ops = {
+       /* Breakpoint instruction: ta 0x7d */
+       .gdb_bpt_instr          = { 0x91, 0xd0, 0x20, 0x7d },
+};
diff --git a/arch/sparc/kernel/module.c b/arch/sparc/kernel/module.c
deleted file mode 100644 (file)
index 598682f..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-/* Kernel module help for sparc32.
- *
- * Copyright (C) 2001 Rusty Russell.
- * Copyright (C) 2002 David S. Miller.
- */
-
-#include <linux/moduleloader.h>
-#include <linux/kernel.h>
-#include <linux/elf.h>
-#include <linux/vmalloc.h>
-#include <linux/fs.h>
-#include <linux/string.h>
-#include <linux/ctype.h>
-
-void *module_alloc(unsigned long size)
-{
-       void *ret;
-
-       /* We handle the zero case fine, unlike vmalloc */
-       if (size == 0)
-               return NULL;
-
-       ret = vmalloc(size);
-       if (!ret)
-               ret = ERR_PTR(-ENOMEM);
-       else
-               memset(ret, 0, size);
-
-       return ret;
-}
-
-/* Free memory returned from module_core_alloc/module_init_alloc */
-void module_free(struct module *mod, void *module_region)
-{
-       vfree(module_region);
-       /* FIXME: If module_region == mod->init_region, trim exception
-           table entries. */
-}
-
-/* Make generic code ignore STT_REGISTER dummy undefined symbols,
- * and replace references to .func with _Func
- */
-int module_frob_arch_sections(Elf_Ehdr *hdr,
-                             Elf_Shdr *sechdrs,
-                             char *secstrings,
-                             struct module *mod)
-{
-       unsigned int symidx;
-       Elf32_Sym *sym;
-       char *strtab;
-       int i;
-
-       for (symidx = 0; sechdrs[symidx].sh_type != SHT_SYMTAB; symidx++) {
-               if (symidx == hdr->e_shnum-1) {
-                       printk("%s: no symtab found.\n", mod->name);
-                       return -ENOEXEC;
-               }
-       }
-       sym = (Elf32_Sym *)sechdrs[symidx].sh_addr;
-       strtab = (char *)sechdrs[sechdrs[symidx].sh_link].sh_addr;
-
-       for (i = 1; i < sechdrs[symidx].sh_size / sizeof(Elf_Sym); i++) {
-               if (sym[i].st_shndx == SHN_UNDEF) {
-                       if (ELF32_ST_TYPE(sym[i].st_info) == STT_REGISTER)
-                               sym[i].st_shndx = SHN_ABS;
-                       else {
-                               char *name = strtab + sym[i].st_name;
-                               if (name[0] == '.') {
-                                       name[0] = '_';
-                                       name[1] = toupper(name[1]);
-                               }
-                       }
-               }
-       }
-       return 0;
-}
-
-int apply_relocate(Elf32_Shdr *sechdrs,
-                  const char *strtab,
-                  unsigned int symindex,
-                  unsigned int relsec,
-                  struct module *me)
-{
-       printk(KERN_ERR "module %s: non-ADD RELOCATION unsupported\n",
-              me->name);
-       return -ENOEXEC;
-}
-
-int apply_relocate_add(Elf32_Shdr *sechdrs,
-                      const char *strtab,
-                      unsigned int symindex,
-                      unsigned int relsec,
-                      struct module *me)
-{
-       unsigned int i;
-       Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
-       Elf32_Sym *sym;
-       u8 *location;
-       u32 *loc32;
-
-       for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
-               Elf32_Addr v;
-
-               /* This is where to make the change */
-               location = (u8 *)sechdrs[sechdrs[relsec].sh_info].sh_addr
-                       + rel[i].r_offset;
-               loc32 = (u32 *) location;
-               /* This is the symbol it is referring to.  Note that all
-                  undefined symbols have been resolved.  */
-               sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
-                       + ELF32_R_SYM(rel[i].r_info);
-               v = sym->st_value + rel[i].r_addend;
-
-               switch (ELF32_R_TYPE(rel[i].r_info)) {
-               case R_SPARC_32:
-               case R_SPARC_UA32:
-                       location[0] = v >> 24;
-                       location[1] = v >> 16;
-                       location[2] = v >>  8;
-                       location[3] = v >>  0;
-                       break;
-
-               case R_SPARC_WDISP30:
-                       v -= (Elf32_Addr) location;
-                       *loc32 = (*loc32 & ~0x3fffffff) |
-                               ((v >> 2) & 0x3fffffff);
-                       break;
-
-               case R_SPARC_WDISP22:
-                       v -= (Elf32_Addr) location;
-                       *loc32 = (*loc32 & ~0x3fffff) |
-                               ((v >> 2) & 0x3fffff);
-                       break;
-
-               case R_SPARC_LO10:
-                       *loc32 = (*loc32 & ~0x3ff) | (v & 0x3ff);
-                       break;
-
-               case R_SPARC_HI22:
-                       *loc32 = (*loc32 & ~0x3fffff) |
-                               ((v >> 10) & 0x3fffff);
-                       break;
-
-               default:
-                       printk(KERN_ERR "module %s: Unknown relocation: %x\n",
-                              me->name,
-                              (int) (ELF32_R_TYPE(rel[i].r_info) & 0xff));
-                       return -ENOEXEC;
-               };
-       }
-       return 0;
-}
-
-int module_finalize(const Elf_Ehdr *hdr,
-                   const Elf_Shdr *sechdrs,
-                   struct module *me)
-{
-       return 0;
-}
-
-void module_arch_cleanup(struct module *mod)
-{
-}
diff --git a/arch/sparc/kernel/module_32.c b/arch/sparc/kernel/module_32.c
new file mode 100644 (file)
index 0000000..598682f
--- /dev/null
@@ -0,0 +1,163 @@
+/* Kernel module help for sparc32.
+ *
+ * Copyright (C) 2001 Rusty Russell.
+ * Copyright (C) 2002 David S. Miller.
+ */
+
+#include <linux/moduleloader.h>
+#include <linux/kernel.h>
+#include <linux/elf.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+
+void *module_alloc(unsigned long size)
+{
+       void *ret;
+
+       /* We handle the zero case fine, unlike vmalloc */
+       if (size == 0)
+               return NULL;
+
+       ret = vmalloc(size);
+       if (!ret)
+               ret = ERR_PTR(-ENOMEM);
+       else
+               memset(ret, 0, size);
+
+       return ret;
+}
+
+/* Free memory returned from module_core_alloc/module_init_alloc */
+void module_free(struct module *mod, void *module_region)
+{
+       vfree(module_region);
+       /* FIXME: If module_region == mod->init_region, trim exception
+           table entries. */
+}
+
+/* Make generic code ignore STT_REGISTER dummy undefined symbols,
+ * and replace references to .func with _Func
+ */
+int module_frob_arch_sections(Elf_Ehdr *hdr,
+                             Elf_Shdr *sechdrs,
+                             char *secstrings,
+                             struct module *mod)
+{
+       unsigned int symidx;
+       Elf32_Sym *sym;
+       char *strtab;
+       int i;
+
+       for (symidx = 0; sechdrs[symidx].sh_type != SHT_SYMTAB; symidx++) {
+               if (symidx == hdr->e_shnum-1) {
+                       printk("%s: no symtab found.\n", mod->name);
+                       return -ENOEXEC;
+               }
+       }
+       sym = (Elf32_Sym *)sechdrs[symidx].sh_addr;
+       strtab = (char *)sechdrs[sechdrs[symidx].sh_link].sh_addr;
+
+       for (i = 1; i < sechdrs[symidx].sh_size / sizeof(Elf_Sym); i++) {
+               if (sym[i].st_shndx == SHN_UNDEF) {
+                       if (ELF32_ST_TYPE(sym[i].st_info) == STT_REGISTER)
+                               sym[i].st_shndx = SHN_ABS;
+                       else {
+                               char *name = strtab + sym[i].st_name;
+                               if (name[0] == '.') {
+                                       name[0] = '_';
+                                       name[1] = toupper(name[1]);
+                               }
+                       }
+               }
+       }
+       return 0;
+}
+
+int apply_relocate(Elf32_Shdr *sechdrs,
+                  const char *strtab,
+                  unsigned int symindex,
+                  unsigned int relsec,
+                  struct module *me)
+{
+       printk(KERN_ERR "module %s: non-ADD RELOCATION unsupported\n",
+              me->name);
+       return -ENOEXEC;
+}
+
+int apply_relocate_add(Elf32_Shdr *sechdrs,
+                      const char *strtab,
+                      unsigned int symindex,
+                      unsigned int relsec,
+                      struct module *me)
+{
+       unsigned int i;
+       Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
+       Elf32_Sym *sym;
+       u8 *location;
+       u32 *loc32;
+
+       for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
+               Elf32_Addr v;
+
+               /* This is where to make the change */
+               location = (u8 *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+                       + rel[i].r_offset;
+               loc32 = (u32 *) location;
+               /* This is the symbol it is referring to.  Note that all
+                  undefined symbols have been resolved.  */
+               sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
+                       + ELF32_R_SYM(rel[i].r_info);
+               v = sym->st_value + rel[i].r_addend;
+
+               switch (ELF32_R_TYPE(rel[i].r_info)) {
+               case R_SPARC_32:
+               case R_SPARC_UA32:
+                       location[0] = v >> 24;
+                       location[1] = v >> 16;
+                       location[2] = v >>  8;
+                       location[3] = v >>  0;
+                       break;
+
+               case R_SPARC_WDISP30:
+                       v -= (Elf32_Addr) location;
+                       *loc32 = (*loc32 & ~0x3fffffff) |
+                               ((v >> 2) & 0x3fffffff);
+                       break;
+
+               case R_SPARC_WDISP22:
+                       v -= (Elf32_Addr) location;
+                       *loc32 = (*loc32 & ~0x3fffff) |
+                               ((v >> 2) & 0x3fffff);
+                       break;
+
+               case R_SPARC_LO10:
+                       *loc32 = (*loc32 & ~0x3ff) | (v & 0x3ff);
+                       break;
+
+               case R_SPARC_HI22:
+                       *loc32 = (*loc32 & ~0x3fffff) |
+                               ((v >> 10) & 0x3fffff);
+                       break;
+
+               default:
+                       printk(KERN_ERR "module %s: Unknown relocation: %x\n",
+                              me->name,
+                              (int) (ELF32_R_TYPE(rel[i].r_info) & 0xff));
+                       return -ENOEXEC;
+               };
+       }
+       return 0;
+}
+
+int module_finalize(const Elf_Ehdr *hdr,
+                   const Elf_Shdr *sechdrs,
+                   struct module *me)
+{
+       return 0;
+}
+
+void module_arch_cleanup(struct module *mod)
+{
+}
diff --git a/arch/sparc/kernel/of_device.c b/arch/sparc/kernel/of_device.c
deleted file mode 100644 (file)
index 0a83bd7..0000000
+++ /dev/null
@@ -1,627 +0,0 @@
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/of.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/mod_devicetable.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/of_device.h>
-#include <linux/of_platform.h>
-
-static int node_match(struct device *dev, void *data)
-{
-       struct of_device *op = to_of_device(dev);
-       struct device_node *dp = data;
-
-       return (op->node == dp);
-}
-
-struct of_device *of_find_device_by_node(struct device_node *dp)
-{
-       struct device *dev = bus_find_device(&of_platform_bus_type, NULL,
-                                            dp, node_match);
-
-       if (dev)
-               return to_of_device(dev);
-
-       return NULL;
-}
-EXPORT_SYMBOL(of_find_device_by_node);
-
-unsigned int irq_of_parse_and_map(struct device_node *node, int index)
-{
-       struct of_device *op = of_find_device_by_node(node);
-
-       if (!op || index >= op->num_irqs)
-               return 0;
-
-       return op->irqs[index];
-}
-EXPORT_SYMBOL(irq_of_parse_and_map);
-
-/* Take the archdata values for IOMMU, STC, and HOSTDATA found in
- * BUS and propagate to all child of_device objects.
- */
-void of_propagate_archdata(struct of_device *bus)
-{
-       struct dev_archdata *bus_sd = &bus->dev.archdata;
-       struct device_node *bus_dp = bus->node;
-       struct device_node *dp;
-
-       for (dp = bus_dp->child; dp; dp = dp->sibling) {
-               struct of_device *op = of_find_device_by_node(dp);
-
-               op->dev.archdata.iommu = bus_sd->iommu;
-               op->dev.archdata.stc = bus_sd->stc;
-               op->dev.archdata.host_controller = bus_sd->host_controller;
-               op->dev.archdata.numa_node = bus_sd->numa_node;
-
-               if (dp->child)
-                       of_propagate_archdata(op);
-       }
-}
-
-struct bus_type of_platform_bus_type;
-EXPORT_SYMBOL(of_platform_bus_type);
-
-static inline u64 of_read_addr(const u32 *cell, int size)
-{
-       u64 r = 0;
-       while (size--)
-               r = (r << 32) | *(cell++);
-       return r;
-}
-
-static void __init get_cells(struct device_node *dp,
-                            int *addrc, int *sizec)
-{
-       if (addrc)
-               *addrc = of_n_addr_cells(dp);
-       if (sizec)
-               *sizec = of_n_size_cells(dp);
-}
-
-/* Max address size we deal with */
-#define OF_MAX_ADDR_CELLS      4
-
-struct of_bus {
-       const char      *name;
-       const char      *addr_prop_name;
-       int             (*match)(struct device_node *parent);
-       void            (*count_cells)(struct device_node *child,
-                                      int *addrc, int *sizec);
-       int             (*map)(u32 *addr, const u32 *range,
-                              int na, int ns, int pna);
-       unsigned long   (*get_flags)(const u32 *addr, unsigned long);
-};
-
-/*
- * Default translator (generic bus)
- */
-
-static void of_bus_default_count_cells(struct device_node *dev,
-                                      int *addrc, int *sizec)
-{
-       get_cells(dev, addrc, sizec);
-}
-
-/* Make sure the least significant 64-bits are in-range.  Even
- * for 3 or 4 cell values it is a good enough approximation.
- */
-static int of_out_of_range(const u32 *addr, const u32 *base,
-                          const u32 *size, int na, int ns)
-{
-       u64 a = of_read_addr(addr, na);
-       u64 b = of_read_addr(base, na);
-
-       if (a < b)
-               return 1;
-
-       b += of_read_addr(size, ns);
-       if (a >= b)
-               return 1;
-
-       return 0;
-}
-
-static int of_bus_default_map(u32 *addr, const u32 *range,
-                             int na, int ns, int pna)
-{
-       u32 result[OF_MAX_ADDR_CELLS];
-       int i;
-
-       if (ns > 2) {
-               printk("of_device: Cannot handle size cells (%d) > 2.", ns);
-               return -EINVAL;
-       }
-
-       if (of_out_of_range(addr, range, range + na + pna, na, ns))
-               return -EINVAL;
-
-       /* Start with the parent range base.  */
-       memcpy(result, range + na, pna * 4);
-
-       /* Add in the child address offset.  */
-       for (i = 0; i < na; i++)
-               result[pna - 1 - i] +=
-                       (addr[na - 1 - i] -
-                        range[na - 1 - i]);
-
-       memcpy(addr, result, pna * 4);
-
-       return 0;
-}
-
-static unsigned long of_bus_default_get_flags(const u32 *addr, unsigned long flags)
-{
-       if (flags)
-               return flags;
-       return IORESOURCE_MEM;
-}
-
-/*
- * PCI bus specific translator
- */
-
-static int of_bus_pci_match(struct device_node *np)
-{
-       if (!strcmp(np->type, "pci") || !strcmp(np->type, "pciex")) {
-               /* Do not do PCI specific frobbing if the
-                * PCI bridge lacks a ranges property.  We
-                * want to pass it through up to the next
-                * parent as-is, not with the PCI translate
-                * method which chops off the top address cell.
-                */
-               if (!of_find_property(np, "ranges", NULL))
-                       return 0;
-
-               return 1;
-       }
-
-       return 0;
-}
-
-static void of_bus_pci_count_cells(struct device_node *np,
-                                  int *addrc, int *sizec)
-{
-       if (addrc)
-               *addrc = 3;
-       if (sizec)
-               *sizec = 2;
-}
-
-static int of_bus_pci_map(u32 *addr, const u32 *range,
-                         int na, int ns, int pna)
-{
-       u32 result[OF_MAX_ADDR_CELLS];
-       int i;
-
-       /* Check address type match */
-       if ((addr[0] ^ range[0]) & 0x03000000)
-               return -EINVAL;
-
-       if (of_out_of_range(addr + 1, range + 1, range + na + pna,
-                           na - 1, ns))
-               return -EINVAL;
-
-       /* Start with the parent range base.  */
-       memcpy(result, range + na, pna * 4);
-
-       /* Add in the child address offset, skipping high cell.  */
-       for (i = 0; i < na - 1; i++)
-               result[pna - 1 - i] +=
-                       (addr[na - 1 - i] -
-                        range[na - 1 - i]);
-
-       memcpy(addr, result, pna * 4);
-
-       return 0;
-}
-
-static unsigned long of_bus_pci_get_flags(const u32 *addr, unsigned long flags)
-{
-       u32 w = addr[0];
-
-       /* For PCI, we override whatever child busses may have used.  */
-       flags = 0;
-       switch((w >> 24) & 0x03) {
-       case 0x01:
-               flags |= IORESOURCE_IO;
-               break;
-
-       case 0x02: /* 32 bits */
-       case 0x03: /* 64 bits */
-               flags |= IORESOURCE_MEM;
-               break;
-       }
-       if (w & 0x40000000)
-               flags |= IORESOURCE_PREFETCH;
-       return flags;
-}
-
-/*
- * SBUS bus specific translator
- */
-
-static int of_bus_sbus_match(struct device_node *np)
-{
-       return !strcmp(np->name, "sbus") ||
-               !strcmp(np->name, "sbi");
-}
-
-static void of_bus_sbus_count_cells(struct device_node *child,
-                                  int *addrc, int *sizec)
-{
-       if (addrc)
-               *addrc = 2;
-       if (sizec)
-               *sizec = 1;
-}
-
-static int of_bus_sbus_map(u32 *addr, const u32 *range, int na, int ns, int pna)
-{
-       return of_bus_default_map(addr, range, na, ns, pna);
-}
-
-static unsigned long of_bus_sbus_get_flags(const u32 *addr, unsigned long flags)
-{
-       return IORESOURCE_MEM;
-}
-
-
-/*
- * Array of bus specific translators
- */
-
-static struct of_bus of_busses[] = {
-       /* PCI */
-       {
-               .name = "pci",
-               .addr_prop_name = "assigned-addresses",
-               .match = of_bus_pci_match,
-               .count_cells = of_bus_pci_count_cells,
-               .map = of_bus_pci_map,
-               .get_flags = of_bus_pci_get_flags,
-       },
-       /* SBUS */
-       {
-               .name = "sbus",
-               .addr_prop_name = "reg",
-               .match = of_bus_sbus_match,
-               .count_cells = of_bus_sbus_count_cells,
-               .map = of_bus_sbus_map,
-               .get_flags = of_bus_sbus_get_flags,
-       },
-       /* Default */
-       {
-               .name = "default",
-               .addr_prop_name = "reg",
-               .match = NULL,
-               .count_cells = of_bus_default_count_cells,
-               .map = of_bus_default_map,
-               .get_flags = of_bus_default_get_flags,
-       },
-};
-
-static struct of_bus *of_match_bus(struct device_node *np)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(of_busses); i ++)
-               if (!of_busses[i].match || of_busses[i].match(np))
-                       return &of_busses[i];
-       BUG();
-       return NULL;
-}
-
-static int __init build_one_resource(struct device_node *parent,
-                                    struct of_bus *bus,
-                                    struct of_bus *pbus,
-                                    u32 *addr,
-                                    int na, int ns, int pna)
-{
-       const u32 *ranges;
-       unsigned int rlen;
-       int rone;
-
-       ranges = of_get_property(parent, "ranges", &rlen);
-       if (ranges == NULL || rlen == 0) {
-               u32 result[OF_MAX_ADDR_CELLS];
-               int i;
-
-               memset(result, 0, pna * 4);
-               for (i = 0; i < na; i++)
-                       result[pna - 1 - i] =
-                               addr[na - 1 - i];
-
-               memcpy(addr, result, pna * 4);
-               return 0;
-       }
-
-       /* Now walk through the ranges */
-       rlen /= 4;
-       rone = na + pna + ns;
-       for (; rlen >= rone; rlen -= rone, ranges += rone) {
-               if (!bus->map(addr, ranges, na, ns, pna))
-                       return 0;
-       }
-
-       return 1;
-}
-
-static int __init use_1to1_mapping(struct device_node *pp)
-{
-       /* If we have a ranges property in the parent, use it.  */
-       if (of_find_property(pp, "ranges", NULL) != NULL)
-               return 0;
-
-       /* Some SBUS devices use intermediate nodes to express
-        * hierarchy within the device itself.  These aren't
-        * real bus nodes, and don't have a 'ranges' property.
-        * But, we should still pass the translation work up
-        * to the SBUS itself.
-        */
-       if (!strcmp(pp->name, "dma") ||
-           !strcmp(pp->name, "espdma") ||
-           !strcmp(pp->name, "ledma") ||
-           !strcmp(pp->name, "lebuffer"))
-               return 0;
-
-       return 1;
-}
-
-static int of_resource_verbose;
-
-static void __init build_device_resources(struct of_device *op,
-                                         struct device *parent)
-{
-       struct of_device *p_op;
-       struct of_bus *bus;
-       int na, ns;
-       int index, num_reg;
-       const void *preg;
-
-       if (!parent)
-               return;
-
-       p_op = to_of_device(parent);
-       bus = of_match_bus(p_op->node);
-       bus->count_cells(op->node, &na, &ns);
-
-       preg = of_get_property(op->node, bus->addr_prop_name, &num_reg);
-       if (!preg || num_reg == 0)
-               return;
-
-       /* Convert to num-cells.  */
-       num_reg /= 4;
-
-       /* Conver to num-entries.  */
-       num_reg /= na + ns;
-
-       for (index = 0; index < num_reg; index++) {
-               struct resource *r = &op->resource[index];
-               u32 addr[OF_MAX_ADDR_CELLS];
-               const u32 *reg = (preg + (index * ((na + ns) * 4)));
-               struct device_node *dp = op->node;
-               struct device_node *pp = p_op->node;
-               struct of_bus *pbus, *dbus;
-               u64 size, result = OF_BAD_ADDR;
-               unsigned long flags;
-               int dna, dns;
-               int pna, pns;
-
-               size = of_read_addr(reg + na, ns);
-
-               memcpy(addr, reg, na * 4);
-
-               flags = bus->get_flags(reg, 0);
-
-               if (use_1to1_mapping(pp)) {
-                       result = of_read_addr(addr, na);
-                       goto build_res;
-               }
-
-               dna = na;
-               dns = ns;
-               dbus = bus;
-
-               while (1) {
-                       dp = pp;
-                       pp = dp->parent;
-                       if (!pp) {
-                               result = of_read_addr(addr, dna);
-                               break;
-                       }
-
-                       pbus = of_match_bus(pp);
-                       pbus->count_cells(dp, &pna, &pns);
-
-                       if (build_one_resource(dp, dbus, pbus, addr,
-                                              dna, dns, pna))
-                               break;
-
-                       flags = pbus->get_flags(addr, flags);
-
-                       dna = pna;
-                       dns = pns;
-                       dbus = pbus;
-               }
-
-       build_res:
-               memset(r, 0, sizeof(*r));
-
-               if (of_resource_verbose)
-                       printk("%s reg[%d] -> %llx\n",
-                              op->node->full_name, index,
-                              result);
-
-               if (result != OF_BAD_ADDR) {
-                       r->start = result & 0xffffffff;
-                       r->end = result + size - 1;
-                       r->flags = flags | ((result >> 32ULL) & 0xffUL);
-               }
-               r->name = op->node->name;
-       }
-}
-
-static struct of_device * __init scan_one_device(struct device_node *dp,
-                                                struct device *parent)
-{
-       struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL);
-       const struct linux_prom_irqs *intr;
-       struct dev_archdata *sd;
-       int len, i;
-
-       if (!op)
-               return NULL;
-
-       sd = &op->dev.archdata;
-       sd->prom_node = dp;
-       sd->op = op;
-
-       op->node = dp;
-
-       op->clock_freq = of_getintprop_default(dp, "clock-frequency",
-                                              (25*1000*1000));
-       op->portid = of_getintprop_default(dp, "upa-portid", -1);
-       if (op->portid == -1)
-               op->portid = of_getintprop_default(dp, "portid", -1);
-
-       intr = of_get_property(dp, "intr", &len);
-       if (intr) {
-               op->num_irqs = len / sizeof(struct linux_prom_irqs);
-               for (i = 0; i < op->num_irqs; i++)
-                       op->irqs[i] = intr[i].pri;
-       } else {
-               const unsigned int *irq =
-                       of_get_property(dp, "interrupts", &len);
-
-               if (irq) {
-                       op->num_irqs = len / sizeof(unsigned int);
-                       for (i = 0; i < op->num_irqs; i++)
-                               op->irqs[i] = irq[i];
-               } else {
-                       op->num_irqs = 0;
-               }
-       }
-       if (sparc_cpu_model == sun4d) {
-               static int pil_to_sbus[] = {
-                       0, 0, 1, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 0,
-               };
-               struct device_node *io_unit, *sbi = dp->parent;
-               const struct linux_prom_registers *regs;
-               int board, slot;
-
-               while (sbi) {
-                       if (!strcmp(sbi->name, "sbi"))
-                               break;
-
-                       sbi = sbi->parent;
-               }
-               if (!sbi)
-                       goto build_resources;
-
-               regs = of_get_property(dp, "reg", NULL);
-               if (!regs)
-                       goto build_resources;
-
-               slot = regs->which_io;
-
-               /* If SBI's parent is not io-unit or the io-unit lacks
-                * a "board#" property, something is very wrong.
-                */
-               if (!sbi->parent || strcmp(sbi->parent->name, "io-unit")) {
-                       printk("%s: Error, parent is not io-unit.\n",
-                              sbi->full_name);
-                       goto build_resources;
-               }
-               io_unit = sbi->parent;
-               board = of_getintprop_default(io_unit, "board#", -1);
-               if (board == -1) {
-                       printk("%s: Error, lacks board# property.\n",
-                              io_unit->full_name);
-                       goto build_resources;
-               }
-
-               for (i = 0; i < op->num_irqs; i++) {
-                       int this_irq = op->irqs[i];
-                       int sbusl = pil_to_sbus[this_irq];
-
-                       if (sbusl)
-                               this_irq = (((board + 1) << 5) +
-                                           (sbusl << 2) +
-                                           slot);
-
-                       op->irqs[i] = this_irq;
-               }
-       }
-
-build_resources:
-       build_device_resources(op, parent);
-
-       op->dev.parent = parent;
-       op->dev.bus = &of_platform_bus_type;
-       if (!parent)
-               dev_set_name(&op->dev, "root");
-       else
-               dev_set_name(&op->dev, "%08x", dp->node);
-
-       if (of_device_register(op)) {
-               printk("%s: Could not register of device.\n",
-                      dp->full_name);
-               kfree(op);
-               op = NULL;
-       }
-
-       return op;
-}
-
-static void __init scan_tree(struct device_node *dp, struct device *parent)
-{
-       while (dp) {
-               struct of_device *op = scan_one_device(dp, parent);
-
-               if (op)
-                       scan_tree(dp->child, &op->dev);
-
-               dp = dp->sibling;
-       }
-}
-
-static void __init scan_of_devices(void)
-{
-       struct device_node *root = of_find_node_by_path("/");
-       struct of_device *parent;
-
-       parent = scan_one_device(root, NULL);
-       if (!parent)
-               return;
-
-       scan_tree(root->child, &parent->dev);
-}
-
-static int __init of_bus_driver_init(void)
-{
-       int err;
-
-       err = of_bus_type_init(&of_platform_bus_type, "of");
-       if (!err)
-               scan_of_devices();
-
-       return err;
-}
-
-postcore_initcall(of_bus_driver_init);
-
-static int __init of_debug(char *str)
-{
-       int val = 0;
-
-       get_option(&str, &val);
-       if (val & 1)
-               of_resource_verbose = 1;
-       return 1;
-}
-
-__setup("of_debug=", of_debug);
diff --git a/arch/sparc/kernel/of_device_32.c b/arch/sparc/kernel/of_device_32.c
new file mode 100644 (file)
index 0000000..0a83bd7
--- /dev/null
@@ -0,0 +1,627 @@
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+
+static int node_match(struct device *dev, void *data)
+{
+       struct of_device *op = to_of_device(dev);
+       struct device_node *dp = data;
+
+       return (op->node == dp);
+}
+
+struct of_device *of_find_device_by_node(struct device_node *dp)
+{
+       struct device *dev = bus_find_device(&of_platform_bus_type, NULL,
+                                            dp, node_match);
+
+       if (dev)
+               return to_of_device(dev);
+
+       return NULL;
+}
+EXPORT_SYMBOL(of_find_device_by_node);
+
+unsigned int irq_of_parse_and_map(struct device_node *node, int index)
+{
+       struct of_device *op = of_find_device_by_node(node);
+
+       if (!op || index >= op->num_irqs)
+               return 0;
+
+       return op->irqs[index];
+}
+EXPORT_SYMBOL(irq_of_parse_and_map);
+
+/* Take the archdata values for IOMMU, STC, and HOSTDATA found in
+ * BUS and propagate to all child of_device objects.
+ */
+void of_propagate_archdata(struct of_device *bus)
+{
+       struct dev_archdata *bus_sd = &bus->dev.archdata;
+       struct device_node *bus_dp = bus->node;
+       struct device_node *dp;
+
+       for (dp = bus_dp->child; dp; dp = dp->sibling) {
+               struct of_device *op = of_find_device_by_node(dp);
+
+               op->dev.archdata.iommu = bus_sd->iommu;
+               op->dev.archdata.stc = bus_sd->stc;
+               op->dev.archdata.host_controller = bus_sd->host_controller;
+               op->dev.archdata.numa_node = bus_sd->numa_node;
+
+               if (dp->child)
+                       of_propagate_archdata(op);
+       }
+}
+
+struct bus_type of_platform_bus_type;
+EXPORT_SYMBOL(of_platform_bus_type);
+
+static inline u64 of_read_addr(const u32 *cell, int size)
+{
+       u64 r = 0;
+       while (size--)
+               r = (r << 32) | *(cell++);
+       return r;
+}
+
+static void __init get_cells(struct device_node *dp,
+                            int *addrc, int *sizec)
+{
+       if (addrc)
+               *addrc = of_n_addr_cells(dp);
+       if (sizec)
+               *sizec = of_n_size_cells(dp);
+}
+
+/* Max address size we deal with */
+#define OF_MAX_ADDR_CELLS      4
+
+struct of_bus {
+       const char      *name;
+       const char      *addr_prop_name;
+       int             (*match)(struct device_node *parent);
+       void            (*count_cells)(struct device_node *child,
+                                      int *addrc, int *sizec);
+       int             (*map)(u32 *addr, const u32 *range,
+                              int na, int ns, int pna);
+       unsigned long   (*get_flags)(const u32 *addr, unsigned long);
+};
+
+/*
+ * Default translator (generic bus)
+ */
+
+static void of_bus_default_count_cells(struct device_node *dev,
+                                      int *addrc, int *sizec)
+{
+       get_cells(dev, addrc, sizec);
+}
+
+/* Make sure the least significant 64-bits are in-range.  Even
+ * for 3 or 4 cell values it is a good enough approximation.
+ */
+static int of_out_of_range(const u32 *addr, const u32 *base,
+                          const u32 *size, int na, int ns)
+{
+       u64 a = of_read_addr(addr, na);
+       u64 b = of_read_addr(base, na);
+
+       if (a < b)
+               return 1;
+
+       b += of_read_addr(size, ns);
+       if (a >= b)
+               return 1;
+
+       return 0;
+}
+
+static int of_bus_default_map(u32 *addr, const u32 *range,
+                             int na, int ns, int pna)
+{
+       u32 result[OF_MAX_ADDR_CELLS];
+       int i;
+
+       if (ns > 2) {
+               printk("of_device: Cannot handle size cells (%d) > 2.", ns);
+               return -EINVAL;
+       }
+
+       if (of_out_of_range(addr, range, range + na + pna, na, ns))
+               return -EINVAL;
+
+       /* Start with the parent range base.  */
+       memcpy(result, range + na, pna * 4);
+
+       /* Add in the child address offset.  */
+       for (i = 0; i < na; i++)
+               result[pna - 1 - i] +=
+                       (addr[na - 1 - i] -
+                        range[na - 1 - i]);
+
+       memcpy(addr, result, pna * 4);
+
+       return 0;
+}
+
+static unsigned long of_bus_default_get_flags(const u32 *addr, unsigned long flags)
+{
+       if (flags)
+               return flags;
+       return IORESOURCE_MEM;
+}
+
+/*
+ * PCI bus specific translator
+ */
+
+static int of_bus_pci_match(struct device_node *np)
+{
+       if (!strcmp(np->type, "pci") || !strcmp(np->type, "pciex")) {
+               /* Do not do PCI specific frobbing if the
+                * PCI bridge lacks a ranges property.  We
+                * want to pass it through up to the next
+                * parent as-is, not with the PCI translate
+                * method which chops off the top address cell.
+                */
+               if (!of_find_property(np, "ranges", NULL))
+                       return 0;
+
+               return 1;
+       }
+
+       return 0;
+}
+
+static void of_bus_pci_count_cells(struct device_node *np,
+                                  int *addrc, int *sizec)
+{
+       if (addrc)
+               *addrc = 3;
+       if (sizec)
+               *sizec = 2;
+}
+
+static int of_bus_pci_map(u32 *addr, const u32 *range,
+                         int na, int ns, int pna)
+{
+       u32 result[OF_MAX_ADDR_CELLS];
+       int i;
+
+       /* Check address type match */
+       if ((addr[0] ^ range[0]) & 0x03000000)
+               return -EINVAL;
+
+       if (of_out_of_range(addr + 1, range + 1, range + na + pna,
+                           na - 1, ns))
+               return -EINVAL;
+
+       /* Start with the parent range base.  */
+       memcpy(result, range + na, pna * 4);
+
+       /* Add in the child address offset, skipping high cell.  */
+       for (i = 0; i < na - 1; i++)
+               result[pna - 1 - i] +=
+                       (addr[na - 1 - i] -
+                        range[na - 1 - i]);
+
+       memcpy(addr, result, pna * 4);
+
+       return 0;
+}
+
+static unsigned long of_bus_pci_get_flags(const u32 *addr, unsigned long flags)
+{
+       u32 w = addr[0];
+
+       /* For PCI, we override whatever child busses may have used.  */
+       flags = 0;
+       switch((w >> 24) & 0x03) {
+       case 0x01:
+               flags |= IORESOURCE_IO;
+               break;
+
+       case 0x02: /* 32 bits */
+       case 0x03: /* 64 bits */
+               flags |= IORESOURCE_MEM;
+               break;
+       }
+       if (w & 0x40000000)
+               flags |= IORESOURCE_PREFETCH;
+       return flags;
+}
+
+/*
+ * SBUS bus specific translator
+ */
+
+static int of_bus_sbus_match(struct device_node *np)
+{
+       return !strcmp(np->name, "sbus") ||
+               !strcmp(np->name, "sbi");
+}
+
+static void of_bus_sbus_count_cells(struct device_node *child,
+                                  int *addrc, int *sizec)
+{
+       if (addrc)
+               *addrc = 2;
+       if (sizec)
+               *sizec = 1;
+}
+
+static int of_bus_sbus_map(u32 *addr, const u32 *range, int na, int ns, int pna)
+{
+       return of_bus_default_map(addr, range, na, ns, pna);
+}
+
+static unsigned long of_bus_sbus_get_flags(const u32 *addr, unsigned long flags)
+{
+       return IORESOURCE_MEM;
+}
+
+
+/*
+ * Array of bus specific translators
+ */
+
+static struct of_bus of_busses[] = {
+       /* PCI */
+       {
+               .name = "pci",
+               .addr_prop_name = "assigned-addresses",
+               .match = of_bus_pci_match,
+               .count_cells = of_bus_pci_count_cells,
+               .map = of_bus_pci_map,
+               .get_flags = of_bus_pci_get_flags,
+       },
+       /* SBUS */
+       {
+               .name = "sbus",
+               .addr_prop_name = "reg",
+               .match = of_bus_sbus_match,
+               .count_cells = of_bus_sbus_count_cells,
+               .map = of_bus_sbus_map,
+               .get_flags = of_bus_sbus_get_flags,
+       },
+       /* Default */
+       {
+               .name = "default",
+               .addr_prop_name = "reg",
+               .match = NULL,
+               .count_cells = of_bus_default_count_cells,
+               .map = of_bus_default_map,
+               .get_flags = of_bus_default_get_flags,
+       },
+};
+
+static struct of_bus *of_match_bus(struct device_node *np)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(of_busses); i ++)
+               if (!of_busses[i].match || of_busses[i].match(np))
+                       return &of_busses[i];
+       BUG();
+       return NULL;
+}
+
+static int __init build_one_resource(struct device_node *parent,
+                                    struct of_bus *bus,
+                                    struct of_bus *pbus,
+                                    u32 *addr,
+                                    int na, int ns, int pna)
+{
+       const u32 *ranges;
+       unsigned int rlen;
+       int rone;
+
+       ranges = of_get_property(parent, "ranges", &rlen);
+       if (ranges == NULL || rlen == 0) {
+               u32 result[OF_MAX_ADDR_CELLS];
+               int i;
+
+               memset(result, 0, pna * 4);
+               for (i = 0; i < na; i++)
+                       result[pna - 1 - i] =
+                               addr[na - 1 - i];
+
+               memcpy(addr, result, pna * 4);
+               return 0;
+       }
+
+       /* Now walk through the ranges */
+       rlen /= 4;
+       rone = na + pna + ns;
+       for (; rlen >= rone; rlen -= rone, ranges += rone) {
+               if (!bus->map(addr, ranges, na, ns, pna))
+                       return 0;
+       }
+
+       return 1;
+}
+
+static int __init use_1to1_mapping(struct device_node *pp)
+{
+       /* If we have a ranges property in the parent, use it.  */
+       if (of_find_property(pp, "ranges", NULL) != NULL)
+               return 0;
+
+       /* Some SBUS devices use intermediate nodes to express
+        * hierarchy within the device itself.  These aren't
+        * real bus nodes, and don't have a 'ranges' property.
+        * But, we should still pass the translation work up
+        * to the SBUS itself.
+        */
+       if (!strcmp(pp->name, "dma") ||
+           !strcmp(pp->name, "espdma") ||
+           !strcmp(pp->name, "ledma") ||
+           !strcmp(pp->name, "lebuffer"))
+               return 0;
+
+       return 1;
+}
+
+static int of_resource_verbose;
+
+static void __init build_device_resources(struct of_device *op,
+                                         struct device *parent)
+{
+       struct of_device *p_op;
+       struct of_bus *bus;
+       int na, ns;
+       int index, num_reg;
+       const void *preg;
+
+       if (!parent)
+               return;
+
+       p_op = to_of_device(parent);
+       bus = of_match_bus(p_op->node);
+       bus->count_cells(op->node, &na, &ns);
+
+       preg = of_get_property(op->node, bus->addr_prop_name, &num_reg);
+       if (!preg || num_reg == 0)
+               return;
+
+       /* Convert to num-cells.  */
+       num_reg /= 4;
+
+       /* Conver to num-entries.  */
+       num_reg /= na + ns;
+
+       for (index = 0; index < num_reg; index++) {
+               struct resource *r = &op->resource[index];
+               u32 addr[OF_MAX_ADDR_CELLS];
+               const u32 *reg = (preg + (index * ((na + ns) * 4)));
+               struct device_node *dp = op->node;
+               struct device_node *pp = p_op->node;
+               struct of_bus *pbus, *dbus;
+               u64 size, result = OF_BAD_ADDR;
+               unsigned long flags;
+               int dna, dns;
+               int pna, pns;
+
+               size = of_read_addr(reg + na, ns);
+
+               memcpy(addr, reg, na * 4);
+
+               flags = bus->get_flags(reg, 0);
+
+               if (use_1to1_mapping(pp)) {
+                       result = of_read_addr(addr, na);
+                       goto build_res;
+               }
+
+               dna = na;
+               dns = ns;
+               dbus = bus;
+
+               while (1) {
+                       dp = pp;
+                       pp = dp->parent;
+                       if (!pp) {
+                               result = of_read_addr(addr, dna);
+                               break;
+                       }
+
+                       pbus = of_match_bus(pp);
+                       pbus->count_cells(dp, &pna, &pns);
+
+                       if (build_one_resource(dp, dbus, pbus, addr,
+                                              dna, dns, pna))
+                               break;
+
+                       flags = pbus->get_flags(addr, flags);
+
+                       dna = pna;
+                       dns = pns;
+                       dbus = pbus;
+               }
+
+       build_res:
+               memset(r, 0, sizeof(*r));
+
+               if (of_resource_verbose)
+                       printk("%s reg[%d] -> %llx\n",
+                              op->node->full_name, index,
+                              result);
+
+               if (result != OF_BAD_ADDR) {
+                       r->start = result & 0xffffffff;
+                       r->end = result + size - 1;
+                       r->flags = flags | ((result >> 32ULL) & 0xffUL);
+               }
+               r->name = op->node->name;
+       }
+}
+
+static struct of_device * __init scan_one_device(struct device_node *dp,
+                                                struct device *parent)
+{
+       struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL);
+       const struct linux_prom_irqs *intr;
+       struct dev_archdata *sd;
+       int len, i;
+
+       if (!op)
+               return NULL;
+
+       sd = &op->dev.archdata;
+       sd->prom_node = dp;
+       sd->op = op;
+
+       op->node = dp;
+
+       op->clock_freq = of_getintprop_default(dp, "clock-frequency",
+                                              (25*1000*1000));
+       op->portid = of_getintprop_default(dp, "upa-portid", -1);
+       if (op->portid == -1)
+               op->portid = of_getintprop_default(dp, "portid", -1);
+
+       intr = of_get_property(dp, "intr", &len);
+       if (intr) {
+               op->num_irqs = len / sizeof(struct linux_prom_irqs);
+               for (i = 0; i < op->num_irqs; i++)
+                       op->irqs[i] = intr[i].pri;
+       } else {
+               const unsigned int *irq =
+                       of_get_property(dp, "interrupts", &len);
+
+               if (irq) {
+                       op->num_irqs = len / sizeof(unsigned int);
+                       for (i = 0; i < op->num_irqs; i++)
+                               op->irqs[i] = irq[i];
+               } else {
+                       op->num_irqs = 0;
+               }
+       }
+       if (sparc_cpu_model == sun4d) {
+               static int pil_to_sbus[] = {
+                       0, 0, 1, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 0,
+               };
+               struct device_node *io_unit, *sbi = dp->parent;
+               const struct linux_prom_registers *regs;
+               int board, slot;
+
+               while (sbi) {
+                       if (!strcmp(sbi->name, "sbi"))
+                               break;
+
+                       sbi = sbi->parent;
+               }
+               if (!sbi)
+                       goto build_resources;
+
+               regs = of_get_property(dp, "reg", NULL);
+               if (!regs)
+                       goto build_resources;
+
+               slot = regs->which_io;
+
+               /* If SBI's parent is not io-unit or the io-unit lacks
+                * a "board#" property, something is very wrong.
+                */
+               if (!sbi->parent || strcmp(sbi->parent->name, "io-unit")) {
+                       printk("%s: Error, parent is not io-unit.\n",
+                              sbi->full_name);
+                       goto build_resources;
+               }
+               io_unit = sbi->parent;
+               board = of_getintprop_default(io_unit, "board#", -1);
+               if (board == -1) {
+                       printk("%s: Error, lacks board# property.\n",
+                              io_unit->full_name);
+                       goto build_resources;
+               }
+
+               for (i = 0; i < op->num_irqs; i++) {
+                       int this_irq = op->irqs[i];
+                       int sbusl = pil_to_sbus[this_irq];
+
+                       if (sbusl)
+                               this_irq = (((board + 1) << 5) +
+                                           (sbusl << 2) +
+                                           slot);
+
+                       op->irqs[i] = this_irq;
+               }
+       }
+
+build_resources:
+       build_device_resources(op, parent);
+
+       op->dev.parent = parent;
+       op->dev.bus = &of_platform_bus_type;
+       if (!parent)
+               dev_set_name(&op->dev, "root");
+       else
+               dev_set_name(&op->dev, "%08x", dp->node);
+
+       if (of_device_register(op)) {
+               printk("%s: Could not register of device.\n",
+                      dp->full_name);
+               kfree(op);
+               op = NULL;
+       }
+
+       return op;
+}
+
+static void __init scan_tree(struct device_node *dp, struct device *parent)
+{
+       while (dp) {
+               struct of_device *op = scan_one_device(dp, parent);
+
+               if (op)
+                       scan_tree(dp->child, &op->dev);
+
+               dp = dp->sibling;
+       }
+}
+
+static void __init scan_of_devices(void)
+{
+       struct device_node *root = of_find_node_by_path("/");
+       struct of_device *parent;
+
+       parent = scan_one_device(root, NULL);
+       if (!parent)
+               return;
+
+       scan_tree(root->child, &parent->dev);
+}
+
+static int __init of_bus_driver_init(void)
+{
+       int err;
+
+       err = of_bus_type_init(&of_platform_bus_type, "of");
+       if (!err)
+               scan_of_devices();
+
+       return err;
+}
+
+postcore_initcall(of_bus_driver_init);
+
+static int __init of_debug(char *str)
+{
+       int val = 0;
+
+       get_option(&str, &val);
+       if (val & 1)
+               of_resource_verbose = 1;
+       return 1;
+}
+
+__setup("of_debug=", of_debug);
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
deleted file mode 100644 (file)
index e8c43ff..0000000
+++ /dev/null
@@ -1,709 +0,0 @@
-/*  linux/arch/sparc/kernel/process.c
- *
- *  Copyright (C) 1995, 2008 David S. Miller (davem@davemloft.net)
- *  Copyright (C) 1996 Eddie C. Dost   (ecd@skynet.be)
- */
-
-/*
- * This file handles the architecture-dependent parts of process handling..
- */
-
-#include <stdarg.h>
-
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/stddef.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/user.h>
-#include <linux/smp.h>
-#include <linux/reboot.h>
-#include <linux/delay.h>
-#include <linux/pm.h>
-#include <linux/init.h>
-
-#include <asm/auxio.h>
-#include <asm/oplib.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/page.h>
-#include <asm/pgalloc.h>
-#include <asm/pgtable.h>
-#include <asm/delay.h>
-#include <asm/processor.h>
-#include <asm/psr.h>
-#include <asm/elf.h>
-#include <asm/prom.h>
-#include <asm/unistd.h>
-
-/* 
- * Power management idle function 
- * Set in pm platform drivers (apc.c and pmc.c)
- */
-void (*pm_idle)(void);
-
-/* 
- * Power-off handler instantiation for pm.h compliance
- * This is done via auxio, but could be used as a fallback
- * handler when auxio is not present-- unused for now...
- */
-void (*pm_power_off)(void) = machine_power_off;
-EXPORT_SYMBOL(pm_power_off);
-
-/*
- * sysctl - toggle power-off restriction for serial console 
- * systems in machine_power_off()
- */
-int scons_pwroff = 1;
-
-extern void fpsave(unsigned long *, unsigned long *, void *, unsigned long *);
-
-struct task_struct *last_task_used_math = NULL;
-struct thread_info *current_set[NR_CPUS];
-
-#ifndef CONFIG_SMP
-
-#define SUN4C_FAULT_HIGH 100
-
-/*
- * the idle loop on a Sparc... ;)
- */
-void cpu_idle(void)
-{
-       /* endless idle loop with no priority at all */
-       for (;;) {
-               if (ARCH_SUN4C) {
-                       static int count = HZ;
-                       static unsigned long last_jiffies;
-                       static unsigned long last_faults;
-                       static unsigned long fps;
-                       unsigned long now;
-                       unsigned long faults;
-
-                       extern unsigned long sun4c_kernel_faults;
-                       extern void sun4c_grow_kernel_ring(void);
-
-                       local_irq_disable();
-                       now = jiffies;
-                       count -= (now - last_jiffies);
-                       last_jiffies = now;
-                       if (count < 0) {
-                               count += HZ;
-                               faults = sun4c_kernel_faults;
-                               fps = (fps + (faults - last_faults)) >> 1;
-                               last_faults = faults;
-#if 0
-                               printk("kernel faults / second = %ld\n", fps);
-#endif
-                               if (fps >= SUN4C_FAULT_HIGH) {
-                                       sun4c_grow_kernel_ring();
-                               }
-                       }
-                       local_irq_enable();
-               }
-
-               if (pm_idle) {
-                       while (!need_resched())
-                               (*pm_idle)();
-               } else {
-                       while (!need_resched())
-                               cpu_relax();
-               }
-               preempt_enable_no_resched();
-               schedule();
-               preempt_disable();
-               check_pgt_cache();
-       }
-}
-
-#else
-
-/* This is being executed in task 0 'user space'. */
-void cpu_idle(void)
-{
-        set_thread_flag(TIF_POLLING_NRFLAG);
-       /* endless idle loop with no priority at all */
-       while(1) {
-               while (!need_resched())
-                       cpu_relax();
-               preempt_enable_no_resched();
-               schedule();
-               preempt_disable();
-               check_pgt_cache();
-       }
-}
-
-#endif
-
-/* XXX cli/sti -> local_irq_xxx here, check this works once SMP is fixed. */
-void machine_halt(void)
-{
-       local_irq_enable();
-       mdelay(8);
-       local_irq_disable();
-       prom_halt();
-       panic("Halt failed!");
-}
-
-void machine_restart(char * cmd)
-{
-       char *p;
-       
-       local_irq_enable();
-       mdelay(8);
-       local_irq_disable();
-
-       p = strchr (reboot_command, '\n');
-       if (p) *p = 0;
-       if (cmd)
-               prom_reboot(cmd);
-       if (*reboot_command)
-               prom_reboot(reboot_command);
-       prom_feval ("reset");
-       panic("Reboot failed!");
-}
-
-void machine_power_off(void)
-{
-#ifdef CONFIG_SUN_AUXIO
-       if (auxio_power_register &&
-           (strcmp(of_console_device->type, "serial") || scons_pwroff))
-               *auxio_power_register |= AUXIO_POWER_OFF;
-#endif
-       machine_halt();
-}
-
-#if 0
-
-static DEFINE_SPINLOCK(sparc_backtrace_lock);
-
-void __show_backtrace(unsigned long fp)
-{
-       struct reg_window *rw;
-       unsigned long flags;
-       int cpu = smp_processor_id();
-
-       spin_lock_irqsave(&sparc_backtrace_lock, flags);
-
-       rw = (struct reg_window *)fp;
-        while(rw && (((unsigned long) rw) >= PAGE_OFFSET) &&
-            !(((unsigned long) rw) & 0x7)) {
-               printk("CPU[%d]: ARGS[%08lx,%08lx,%08lx,%08lx,%08lx,%08lx] "
-                      "FP[%08lx] CALLER[%08lx]: ", cpu,
-                      rw->ins[0], rw->ins[1], rw->ins[2], rw->ins[3],
-                      rw->ins[4], rw->ins[5],
-                      rw->ins[6],
-                      rw->ins[7]);
-               printk("%pS\n", (void *) rw->ins[7]);
-               rw = (struct reg_window *) rw->ins[6];
-       }
-       spin_unlock_irqrestore(&sparc_backtrace_lock, flags);
-}
-
-#define __SAVE __asm__ __volatile__("save %sp, -0x40, %sp\n\t")
-#define __RESTORE __asm__ __volatile__("restore %g0, %g0, %g0\n\t")
-#define __GET_FP(fp) __asm__ __volatile__("mov %%i6, %0" : "=r" (fp))
-
-void show_backtrace(void)
-{
-       unsigned long fp;
-
-       __SAVE; __SAVE; __SAVE; __SAVE;
-       __SAVE; __SAVE; __SAVE; __SAVE;
-       __RESTORE; __RESTORE; __RESTORE; __RESTORE;
-       __RESTORE; __RESTORE; __RESTORE; __RESTORE;
-
-       __GET_FP(fp);
-
-       __show_backtrace(fp);
-}
-
-#ifdef CONFIG_SMP
-void smp_show_backtrace_all_cpus(void)
-{
-       xc0((smpfunc_t) show_backtrace);
-       show_backtrace();
-}
-#endif
-
-void show_stackframe(struct sparc_stackf *sf)
-{
-       unsigned long size;
-       unsigned long *stk;
-       int i;
-
-       printk("l0: %08lx l1: %08lx l2: %08lx l3: %08lx "
-              "l4: %08lx l5: %08lx l6: %08lx l7: %08lx\n",
-              sf->locals[0], sf->locals[1], sf->locals[2], sf->locals[3],
-              sf->locals[4], sf->locals[5], sf->locals[6], sf->locals[7]);
-       printk("i0: %08lx i1: %08lx i2: %08lx i3: %08lx "
-              "i4: %08lx i5: %08lx fp: %08lx i7: %08lx\n",
-              sf->ins[0], sf->ins[1], sf->ins[2], sf->ins[3],
-              sf->ins[4], sf->ins[5], (unsigned long)sf->fp, sf->callers_pc);
-       printk("sp: %08lx x0: %08lx x1: %08lx x2: %08lx "
-              "x3: %08lx x4: %08lx x5: %08lx xx: %08lx\n",
-              (unsigned long)sf->structptr, sf->xargs[0], sf->xargs[1],
-              sf->xargs[2], sf->xargs[3], sf->xargs[4], sf->xargs[5],
-              sf->xxargs[0]);
-       size = ((unsigned long)sf->fp) - ((unsigned long)sf);
-       size -= STACKFRAME_SZ;
-       stk = (unsigned long *)((unsigned long)sf + STACKFRAME_SZ);
-       i = 0;
-       do {
-               printk("s%d: %08lx\n", i++, *stk++);
-       } while ((size -= sizeof(unsigned long)));
-}
-#endif
-
-void show_regs(struct pt_regs *r)
-{
-       struct reg_window *rw = (struct reg_window *) r->u_regs[14];
-
-        printk("PSR: %08lx PC: %08lx NPC: %08lx Y: %08lx    %s\n",
-              r->psr, r->pc, r->npc, r->y, print_tainted());
-       printk("PC: <%pS>\n", (void *) r->pc);
-       printk("%%G: %08lx %08lx  %08lx %08lx  %08lx %08lx  %08lx %08lx\n",
-              r->u_regs[0], r->u_regs[1], r->u_regs[2], r->u_regs[3],
-              r->u_regs[4], r->u_regs[5], r->u_regs[6], r->u_regs[7]);
-       printk("%%O: %08lx %08lx  %08lx %08lx  %08lx %08lx  %08lx %08lx\n",
-              r->u_regs[8], r->u_regs[9], r->u_regs[10], r->u_regs[11],
-              r->u_regs[12], r->u_regs[13], r->u_regs[14], r->u_regs[15]);
-       printk("RPC: <%pS>\n", (void *) r->u_regs[15]);
-
-       printk("%%L: %08lx %08lx  %08lx %08lx  %08lx %08lx  %08lx %08lx\n",
-              rw->locals[0], rw->locals[1], rw->locals[2], rw->locals[3],
-              rw->locals[4], rw->locals[5], rw->locals[6], rw->locals[7]);
-       printk("%%I: %08lx %08lx  %08lx %08lx  %08lx %08lx  %08lx %08lx\n",
-              rw->ins[0], rw->ins[1], rw->ins[2], rw->ins[3],
-              rw->ins[4], rw->ins[5], rw->ins[6], rw->ins[7]);
-}
-
-/*
- * The show_stack is an external API which we do not use ourselves.
- * The oops is printed in die_if_kernel.
- */
-void show_stack(struct task_struct *tsk, unsigned long *_ksp)
-{
-       unsigned long pc, fp;
-       unsigned long task_base;
-       struct reg_window *rw;
-       int count = 0;
-
-       if (tsk != NULL)
-               task_base = (unsigned long) task_stack_page(tsk);
-       else
-               task_base = (unsigned long) current_thread_info();
-
-       fp = (unsigned long) _ksp;
-       do {
-               /* Bogus frame pointer? */
-               if (fp < (task_base + sizeof(struct thread_info)) ||
-                   fp >= (task_base + (PAGE_SIZE << 1)))
-                       break;
-               rw = (struct reg_window *) fp;
-               pc = rw->ins[7];
-               printk("[%08lx : ", pc);
-               printk("%pS ] ", (void *) pc);
-               fp = rw->ins[6];
-       } while (++count < 16);
-       printk("\n");
-}
-
-void dump_stack(void)
-{
-       unsigned long *ksp;
-
-       __asm__ __volatile__("mov       %%fp, %0"
-                            : "=r" (ksp));
-       show_stack(current, ksp);
-}
-
-EXPORT_SYMBOL(dump_stack);
-
-/*
- * Note: sparc64 has a pretty intricated thread_saved_pc, check it out.
- */
-unsigned long thread_saved_pc(struct task_struct *tsk)
-{
-       return task_thread_info(tsk)->kpc;
-}
-
-/*
- * Free current thread data structures etc..
- */
-void exit_thread(void)
-{
-#ifndef CONFIG_SMP
-       if(last_task_used_math == current) {
-#else
-       if (test_thread_flag(TIF_USEDFPU)) {
-#endif
-               /* Keep process from leaving FPU in a bogon state. */
-               put_psr(get_psr() | PSR_EF);
-               fpsave(&current->thread.float_regs[0], &current->thread.fsr,
-                      &current->thread.fpqueue[0], &current->thread.fpqdepth);
-#ifndef CONFIG_SMP
-               last_task_used_math = NULL;
-#else
-               clear_thread_flag(TIF_USEDFPU);
-#endif
-       }
-}
-
-void flush_thread(void)
-{
-       current_thread_info()->w_saved = 0;
-
-#ifndef CONFIG_SMP
-       if(last_task_used_math == current) {
-#else
-       if (test_thread_flag(TIF_USEDFPU)) {
-#endif
-               /* Clean the fpu. */
-               put_psr(get_psr() | PSR_EF);
-               fpsave(&current->thread.float_regs[0], &current->thread.fsr,
-                      &current->thread.fpqueue[0], &current->thread.fpqdepth);
-#ifndef CONFIG_SMP
-               last_task_used_math = NULL;
-#else
-               clear_thread_flag(TIF_USEDFPU);
-#endif
-       }
-
-       /* Now, this task is no longer a kernel thread. */
-       current->thread.current_ds = USER_DS;
-       if (current->thread.flags & SPARC_FLAG_KTHREAD) {
-               current->thread.flags &= ~SPARC_FLAG_KTHREAD;
-
-               /* We must fixup kregs as well. */
-               /* XXX This was not fixed for ti for a while, worked. Unused? */
-               current->thread.kregs = (struct pt_regs *)
-                   (task_stack_page(current) + (THREAD_SIZE - TRACEREG_SZ));
-       }
-}
-
-static inline struct sparc_stackf __user *
-clone_stackframe(struct sparc_stackf __user *dst,
-                struct sparc_stackf __user *src)
-{
-       unsigned long size, fp;
-       struct sparc_stackf *tmp;
-       struct sparc_stackf __user *sp;
-
-       if (get_user(tmp, &src->fp))
-               return NULL;
-
-       fp = (unsigned long) tmp;
-       size = (fp - ((unsigned long) src));
-       fp = (unsigned long) dst;
-       sp = (struct sparc_stackf __user *)(fp - size); 
-
-       /* do_fork() grabs the parent semaphore, we must release it
-        * temporarily so we can build the child clone stack frame
-        * without deadlocking.
-        */
-       if (__copy_user(sp, src, size))
-               sp = NULL;
-       else if (put_user(fp, &sp->fp))
-               sp = NULL;
-
-       return sp;
-}
-
-asmlinkage int sparc_do_fork(unsigned long clone_flags,
-                             unsigned long stack_start,
-                             struct pt_regs *regs,
-                             unsigned long stack_size)
-{
-       unsigned long parent_tid_ptr, child_tid_ptr;
-       unsigned long orig_i1 = regs->u_regs[UREG_I1];
-       long ret;
-
-       parent_tid_ptr = regs->u_regs[UREG_I2];
-       child_tid_ptr = regs->u_regs[UREG_I4];
-
-       ret = do_fork(clone_flags, stack_start,
-                     regs, stack_size,
-                     (int __user *) parent_tid_ptr,
-                     (int __user *) child_tid_ptr);
-
-       /* If we get an error and potentially restart the system
-        * call, we're screwed because copy_thread() clobbered
-        * the parent's %o1.  So detect that case and restore it
-        * here.
-        */
-       if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK)
-               regs->u_regs[UREG_I1] = orig_i1;
-
-       return ret;
-}
-
-/* Copy a Sparc thread.  The fork() return value conventions
- * under SunOS are nothing short of bletcherous:
- * Parent -->  %o0 == childs  pid, %o1 == 0
- * Child  -->  %o0 == parents pid, %o1 == 1
- *
- * NOTE: We have a separate fork kpsr/kwim because
- *       the parent could change these values between
- *       sys_fork invocation and when we reach here
- *       if the parent should sleep while trying to
- *       allocate the task_struct and kernel stack in
- *       do_fork().
- * XXX See comment above sys_vfork in sparc64. todo.
- */
-extern void ret_from_fork(void);
-
-int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
-               unsigned long unused,
-               struct task_struct *p, struct pt_regs *regs)
-{
-       struct thread_info *ti = task_thread_info(p);
-       struct pt_regs *childregs;
-       char *new_stack;
-
-#ifndef CONFIG_SMP
-       if(last_task_used_math == current) {
-#else
-       if (test_thread_flag(TIF_USEDFPU)) {
-#endif
-               put_psr(get_psr() | PSR_EF);
-               fpsave(&p->thread.float_regs[0], &p->thread.fsr,
-                      &p->thread.fpqueue[0], &p->thread.fpqdepth);
-#ifdef CONFIG_SMP
-               clear_thread_flag(TIF_USEDFPU);
-#endif
-       }
-
-       /*
-        *  p->thread_info         new_stack   childregs
-        *  !                      !           !             {if(PSR_PS) }
-        *  V                      V (stk.fr.) V  (pt_regs)  { (stk.fr.) }
-        *  +----- - - - - - ------+===========+============={+==========}+
-        */
-       new_stack = task_stack_page(p) + THREAD_SIZE;
-       if (regs->psr & PSR_PS)
-               new_stack -= STACKFRAME_SZ;
-       new_stack -= STACKFRAME_SZ + TRACEREG_SZ;
-       memcpy(new_stack, (char *)regs - STACKFRAME_SZ, STACKFRAME_SZ + TRACEREG_SZ);
-       childregs = (struct pt_regs *) (new_stack + STACKFRAME_SZ);
-
-       /*
-        * A new process must start with interrupts closed in 2.5,
-        * because this is how Mingo's scheduler works (see schedule_tail
-        * and finish_arch_switch). If we do not do it, a timer interrupt hits
-        * before we unlock, attempts to re-take the rq->lock, and then we die.
-        * Thus, kpsr|=PSR_PIL.
-        */
-       ti->ksp = (unsigned long) new_stack;
-       ti->kpc = (((unsigned long) ret_from_fork) - 0x8);
-       ti->kpsr = current->thread.fork_kpsr | PSR_PIL;
-       ti->kwim = current->thread.fork_kwim;
-
-       if(regs->psr & PSR_PS) {
-               extern struct pt_regs fake_swapper_regs;
-
-               p->thread.kregs = &fake_swapper_regs;
-               new_stack += STACKFRAME_SZ + TRACEREG_SZ;
-               childregs->u_regs[UREG_FP] = (unsigned long) new_stack;
-               p->thread.flags |= SPARC_FLAG_KTHREAD;
-               p->thread.current_ds = KERNEL_DS;
-               memcpy(new_stack, (void *)regs->u_regs[UREG_FP], STACKFRAME_SZ);
-               childregs->u_regs[UREG_G6] = (unsigned long) ti;
-       } else {
-               p->thread.kregs = childregs;
-               childregs->u_regs[UREG_FP] = sp;
-               p->thread.flags &= ~SPARC_FLAG_KTHREAD;
-               p->thread.current_ds = USER_DS;
-
-               if (sp != regs->u_regs[UREG_FP]) {
-                       struct sparc_stackf __user *childstack;
-                       struct sparc_stackf __user *parentstack;
-
-                       /*
-                        * This is a clone() call with supplied user stack.
-                        * Set some valid stack frames to give to the child.
-                        */
-                       childstack = (struct sparc_stackf __user *)
-                               (sp & ~0x7UL);
-                       parentstack = (struct sparc_stackf __user *)
-                               regs->u_regs[UREG_FP];
-
-#if 0
-                       printk("clone: parent stack:\n");
-                       show_stackframe(parentstack);
-#endif
-
-                       childstack = clone_stackframe(childstack, parentstack);
-                       if (!childstack)
-                               return -EFAULT;
-
-#if 0
-                       printk("clone: child stack:\n");
-                       show_stackframe(childstack);
-#endif
-
-                       childregs->u_regs[UREG_FP] = (unsigned long)childstack;
-               }
-       }
-
-#ifdef CONFIG_SMP
-       /* FPU must be disabled on SMP. */
-       childregs->psr &= ~PSR_EF;
-#endif
-
-       /* Set the return value for the child. */
-       childregs->u_regs[UREG_I0] = current->pid;
-       childregs->u_regs[UREG_I1] = 1;
-
-       /* Set the return value for the parent. */
-       regs->u_regs[UREG_I1] = 0;
-
-       if (clone_flags & CLONE_SETTLS)
-               childregs->u_regs[UREG_G7] = regs->u_regs[UREG_I3];
-
-       return 0;
-}
-
-/*
- * fill in the fpu structure for a core dump.
- */
-int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs)
-{
-       if (used_math()) {
-               memset(fpregs, 0, sizeof(*fpregs));
-               fpregs->pr_q_entrysize = 8;
-               return 1;
-       }
-#ifdef CONFIG_SMP
-       if (test_thread_flag(TIF_USEDFPU)) {
-               put_psr(get_psr() | PSR_EF);
-               fpsave(&current->thread.float_regs[0], &current->thread.fsr,
-                      &current->thread.fpqueue[0], &current->thread.fpqdepth);
-               if (regs != NULL) {
-                       regs->psr &= ~(PSR_EF);
-                       clear_thread_flag(TIF_USEDFPU);
-               }
-       }
-#else
-       if (current == last_task_used_math) {
-               put_psr(get_psr() | PSR_EF);
-               fpsave(&current->thread.float_regs[0], &current->thread.fsr,
-                      &current->thread.fpqueue[0], &current->thread.fpqdepth);
-               if (regs != NULL) {
-                       regs->psr &= ~(PSR_EF);
-                       last_task_used_math = NULL;
-               }
-       }
-#endif
-       memcpy(&fpregs->pr_fr.pr_regs[0],
-              &current->thread.float_regs[0],
-              (sizeof(unsigned long) * 32));
-       fpregs->pr_fsr = current->thread.fsr;
-       fpregs->pr_qcnt = current->thread.fpqdepth;
-       fpregs->pr_q_entrysize = 8;
-       fpregs->pr_en = 1;
-       if(fpregs->pr_qcnt != 0) {
-               memcpy(&fpregs->pr_q[0],
-                      &current->thread.fpqueue[0],
-                      sizeof(struct fpq) * fpregs->pr_qcnt);
-       }
-       /* Zero out the rest. */
-       memset(&fpregs->pr_q[fpregs->pr_qcnt], 0,
-              sizeof(struct fpq) * (32 - fpregs->pr_qcnt));
-       return 1;
-}
-
-/*
- * sparc_execve() executes a new program after the asm stub has set
- * things up for us.  This should basically do what I want it to.
- */
-asmlinkage int sparc_execve(struct pt_regs *regs)
-{
-       int error, base = 0;
-       char *filename;
-
-       /* Check for indirect call. */
-       if(regs->u_regs[UREG_G1] == 0)
-               base = 1;
-
-       filename = getname((char __user *)regs->u_regs[base + UREG_I0]);
-       error = PTR_ERR(filename);
-       if(IS_ERR(filename))
-               goto out;
-       error = do_execve(filename,
-                         (char __user * __user *)regs->u_regs[base + UREG_I1],
-                         (char __user * __user *)regs->u_regs[base + UREG_I2],
-                         regs);
-       putname(filename);
-out:
-       return error;
-}
-
-/*
- * This is the mechanism for creating a new kernel thread.
- *
- * NOTE! Only a kernel-only process(ie the swapper or direct descendants
- * who haven't done an "execve()") should use this: it will work within
- * a system call from a "real" process, but the process memory space will
- * not be freed until both the parent and the child have exited.
- */
-pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
-       long retval;
-
-       __asm__ __volatile__("mov %4, %%g2\n\t"    /* Set aside fn ptr... */
-                            "mov %5, %%g3\n\t"    /* and arg. */
-                            "mov %1, %%g1\n\t"
-                            "mov %2, %%o0\n\t"    /* Clone flags. */
-                            "mov 0, %%o1\n\t"     /* usp arg == 0 */
-                            "t 0x10\n\t"          /* Linux/Sparc clone(). */
-                            "cmp %%o1, 0\n\t"
-                            "be 1f\n\t"           /* The parent, just return. */
-                            " nop\n\t"            /* Delay slot. */
-                            "jmpl %%g2, %%o7\n\t" /* Call the function. */
-                            " mov %%g3, %%o0\n\t" /* Get back the arg in delay. */
-                            "mov %3, %%g1\n\t"
-                            "t 0x10\n\t"          /* Linux/Sparc exit(). */
-                            /* Notreached by child. */
-                            "1: mov %%o0, %0\n\t" :
-                            "=r" (retval) :
-                            "i" (__NR_clone), "r" (flags | CLONE_VM | CLONE_UNTRACED),
-                            "i" (__NR_exit),  "r" (fn), "r" (arg) :
-                            "g1", "g2", "g3", "o0", "o1", "memory", "cc");
-       return retval;
-}
-
-unsigned long get_wchan(struct task_struct *task)
-{
-       unsigned long pc, fp, bias = 0;
-       unsigned long task_base = (unsigned long) task;
-        unsigned long ret = 0;
-       struct reg_window *rw;
-       int count = 0;
-
-       if (!task || task == current ||
-            task->state == TASK_RUNNING)
-               goto out;
-
-       fp = task_thread_info(task)->ksp + bias;
-       do {
-               /* Bogus frame pointer? */
-               if (fp < (task_base + sizeof(struct thread_info)) ||
-                   fp >= (task_base + (2 * PAGE_SIZE)))
-                       break;
-               rw = (struct reg_window *) fp;
-               pc = rw->ins[7];
-               if (!in_sched_functions(pc)) {
-                       ret = pc;
-                       goto out;
-               }
-               fp = rw->ins[6] + bias;
-       } while (++count < 16);
-
-out:
-       return ret;
-}
-
diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c
new file mode 100644 (file)
index 0000000..e8c43ff
--- /dev/null
@@ -0,0 +1,709 @@
+/*  linux/arch/sparc/kernel/process.c
+ *
+ *  Copyright (C) 1995, 2008 David S. Miller (davem@davemloft.net)
+ *  Copyright (C) 1996 Eddie C. Dost   (ecd@skynet.be)
+ */
+
+/*
+ * This file handles the architecture-dependent parts of process handling..
+ */
+
+#include <stdarg.h>
+
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/smp.h>
+#include <linux/reboot.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/init.h>
+
+#include <asm/auxio.h>
+#include <asm/oplib.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/page.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <asm/delay.h>
+#include <asm/processor.h>
+#include <asm/psr.h>
+#include <asm/elf.h>
+#include <asm/prom.h>
+#include <asm/unistd.h>
+
+/* 
+ * Power management idle function 
+ * Set in pm platform drivers (apc.c and pmc.c)
+ */
+void (*pm_idle)(void);
+
+/* 
+ * Power-off handler instantiation for pm.h compliance
+ * This is done via auxio, but could be used as a fallback
+ * handler when auxio is not present-- unused for now...
+ */
+void (*pm_power_off)(void) = machine_power_off;
+EXPORT_SYMBOL(pm_power_off);
+
+/*
+ * sysctl - toggle power-off restriction for serial console 
+ * systems in machine_power_off()
+ */
+int scons_pwroff = 1;
+
+extern void fpsave(unsigned long *, unsigned long *, void *, unsigned long *);
+
+struct task_struct *last_task_used_math = NULL;
+struct thread_info *current_set[NR_CPUS];
+
+#ifndef CONFIG_SMP
+
+#define SUN4C_FAULT_HIGH 100
+
+/*
+ * the idle loop on a Sparc... ;)
+ */
+void cpu_idle(void)
+{
+       /* endless idle loop with no priority at all */
+       for (;;) {
+               if (ARCH_SUN4C) {
+                       static int count = HZ;
+                       static unsigned long last_jiffies;
+                       static unsigned long last_faults;
+                       static unsigned long fps;
+                       unsigned long now;
+                       unsigned long faults;
+
+                       extern unsigned long sun4c_kernel_faults;
+                       extern void sun4c_grow_kernel_ring(void);
+
+                       local_irq_disable();
+                       now = jiffies;
+                       count -= (now - last_jiffies);
+                       last_jiffies = now;
+                       if (count < 0) {
+                               count += HZ;
+                               faults = sun4c_kernel_faults;
+                               fps = (fps + (faults - last_faults)) >> 1;
+                               last_faults = faults;
+#if 0
+                               printk("kernel faults / second = %ld\n", fps);
+#endif
+                               if (fps >= SUN4C_FAULT_HIGH) {
+                                       sun4c_grow_kernel_ring();
+                               }
+                       }
+                       local_irq_enable();
+               }
+
+               if (pm_idle) {
+                       while (!need_resched())
+                               (*pm_idle)();
+               } else {
+                       while (!need_resched())
+                               cpu_relax();
+               }
+               preempt_enable_no_resched();
+               schedule();
+               preempt_disable();
+               check_pgt_cache();
+       }
+}
+
+#else
+
+/* This is being executed in task 0 'user space'. */
+void cpu_idle(void)
+{
+        set_thread_flag(TIF_POLLING_NRFLAG);
+       /* endless idle loop with no priority at all */
+       while(1) {
+               while (!need_resched())
+                       cpu_relax();
+               preempt_enable_no_resched();
+               schedule();
+               preempt_disable();
+               check_pgt_cache();
+       }
+}
+
+#endif
+
+/* XXX cli/sti -> local_irq_xxx here, check this works once SMP is fixed. */
+void machine_halt(void)
+{
+       local_irq_enable();
+       mdelay(8);
+       local_irq_disable();
+       prom_halt();
+       panic("Halt failed!");
+}
+
+void machine_restart(char * cmd)
+{
+       char *p;
+       
+       local_irq_enable();
+       mdelay(8);
+       local_irq_disable();
+
+       p = strchr (reboot_command, '\n');
+       if (p) *p = 0;
+       if (cmd)
+               prom_reboot(cmd);
+       if (*reboot_command)
+               prom_reboot(reboot_command);
+       prom_feval ("reset");
+       panic("Reboot failed!");
+}
+
+void machine_power_off(void)
+{
+#ifdef CONFIG_SUN_AUXIO
+       if (auxio_power_register &&
+           (strcmp(of_console_device->type, "serial") || scons_pwroff))
+               *auxio_power_register |= AUXIO_POWER_OFF;
+#endif
+       machine_halt();
+}
+
+#if 0
+
+static DEFINE_SPINLOCK(sparc_backtrace_lock);
+
+void __show_backtrace(unsigned long fp)
+{
+       struct reg_window *rw;
+       unsigned long flags;
+       int cpu = smp_processor_id();
+
+       spin_lock_irqsave(&sparc_backtrace_lock, flags);
+
+       rw = (struct reg_window *)fp;
+        while(rw && (((unsigned long) rw) >= PAGE_OFFSET) &&
+            !(((unsigned long) rw) & 0x7)) {
+               printk("CPU[%d]: ARGS[%08lx,%08lx,%08lx,%08lx,%08lx,%08lx] "
+                      "FP[%08lx] CALLER[%08lx]: ", cpu,
+                      rw->ins[0], rw->ins[1], rw->ins[2], rw->ins[3],
+                      rw->ins[4], rw->ins[5],
+                      rw->ins[6],
+                      rw->ins[7]);
+               printk("%pS\n", (void *) rw->ins[7]);
+               rw = (struct reg_window *) rw->ins[6];
+       }
+       spin_unlock_irqrestore(&sparc_backtrace_lock, flags);
+}
+
+#define __SAVE __asm__ __volatile__("save %sp, -0x40, %sp\n\t")
+#define __RESTORE __asm__ __volatile__("restore %g0, %g0, %g0\n\t")
+#define __GET_FP(fp) __asm__ __volatile__("mov %%i6, %0" : "=r" (fp))
+
+void show_backtrace(void)
+{
+       unsigned long fp;
+
+       __SAVE; __SAVE; __SAVE; __SAVE;
+       __SAVE; __SAVE; __SAVE; __SAVE;
+       __RESTORE; __RESTORE; __RESTORE; __RESTORE;
+       __RESTORE; __RESTORE; __RESTORE; __RESTORE;
+
+       __GET_FP(fp);
+
+       __show_backtrace(fp);
+}
+
+#ifdef CONFIG_SMP
+void smp_show_backtrace_all_cpus(void)
+{
+       xc0((smpfunc_t) show_backtrace);
+       show_backtrace();
+}
+#endif
+
+void show_stackframe(struct sparc_stackf *sf)
+{
+       unsigned long size;
+       unsigned long *stk;
+       int i;
+
+       printk("l0: %08lx l1: %08lx l2: %08lx l3: %08lx "
+              "l4: %08lx l5: %08lx l6: %08lx l7: %08lx\n",
+              sf->locals[0], sf->locals[1], sf->locals[2], sf->locals[3],
+              sf->locals[4], sf->locals[5], sf->locals[6], sf->locals[7]);
+       printk("i0: %08lx i1: %08lx i2: %08lx i3: %08lx "
+              "i4: %08lx i5: %08lx fp: %08lx i7: %08lx\n",
+              sf->ins[0], sf->ins[1], sf->ins[2], sf->ins[3],
+              sf->ins[4], sf->ins[5], (unsigned long)sf->fp, sf->callers_pc);
+       printk("sp: %08lx x0: %08lx x1: %08lx x2: %08lx "
+              "x3: %08lx x4: %08lx x5: %08lx xx: %08lx\n",
+              (unsigned long)sf->structptr, sf->xargs[0], sf->xargs[1],
+              sf->xargs[2], sf->xargs[3], sf->xargs[4], sf->xargs[5],
+              sf->xxargs[0]);
+       size = ((unsigned long)sf->fp) - ((unsigned long)sf);
+       size -= STACKFRAME_SZ;
+       stk = (unsigned long *)((unsigned long)sf + STACKFRAME_SZ);
+       i = 0;
+       do {
+               printk("s%d: %08lx\n", i++, *stk++);
+       } while ((size -= sizeof(unsigned long)));
+}
+#endif
+
+void show_regs(struct pt_regs *r)
+{
+       struct reg_window *rw = (struct reg_window *) r->u_regs[14];
+
+        printk("PSR: %08lx PC: %08lx NPC: %08lx Y: %08lx    %s\n",
+              r->psr, r->pc, r->npc, r->y, print_tainted());
+       printk("PC: <%pS>\n", (void *) r->pc);
+       printk("%%G: %08lx %08lx  %08lx %08lx  %08lx %08lx  %08lx %08lx\n",
+              r->u_regs[0], r->u_regs[1], r->u_regs[2], r->u_regs[3],
+              r->u_regs[4], r->u_regs[5], r->u_regs[6], r->u_regs[7]);
+       printk("%%O: %08lx %08lx  %08lx %08lx  %08lx %08lx  %08lx %08lx\n",
+              r->u_regs[8], r->u_regs[9], r->u_regs[10], r->u_regs[11],
+              r->u_regs[12], r->u_regs[13], r->u_regs[14], r->u_regs[15]);
+       printk("RPC: <%pS>\n", (void *) r->u_regs[15]);
+
+       printk("%%L: %08lx %08lx  %08lx %08lx  %08lx %08lx  %08lx %08lx\n",
+              rw->locals[0], rw->locals[1], rw->locals[2], rw->locals[3],
+              rw->locals[4], rw->locals[5], rw->locals[6], rw->locals[7]);
+       printk("%%I: %08lx %08lx  %08lx %08lx  %08lx %08lx  %08lx %08lx\n",
+              rw->ins[0], rw->ins[1], rw->ins[2], rw->ins[3],
+              rw->ins[4], rw->ins[5], rw->ins[6], rw->ins[7]);
+}
+
+/*
+ * The show_stack is an external API which we do not use ourselves.
+ * The oops is printed in die_if_kernel.
+ */
+void show_stack(struct task_struct *tsk, unsigned long *_ksp)
+{
+       unsigned long pc, fp;
+       unsigned long task_base;
+       struct reg_window *rw;
+       int count = 0;
+
+       if (tsk != NULL)
+               task_base = (unsigned long) task_stack_page(tsk);
+       else
+               task_base = (unsigned long) current_thread_info();
+
+       fp = (unsigned long) _ksp;
+       do {
+               /* Bogus frame pointer? */
+               if (fp < (task_base + sizeof(struct thread_info)) ||
+                   fp >= (task_base + (PAGE_SIZE << 1)))
+                       break;
+               rw = (struct reg_window *) fp;
+               pc = rw->ins[7];
+               printk("[%08lx : ", pc);
+               printk("%pS ] ", (void *) pc);
+               fp = rw->ins[6];
+       } while (++count < 16);
+       printk("\n");
+}
+
+void dump_stack(void)
+{
+       unsigned long *ksp;
+
+       __asm__ __volatile__("mov       %%fp, %0"
+                            : "=r" (ksp));
+       show_stack(current, ksp);
+}
+
+EXPORT_SYMBOL(dump_stack);
+
+/*
+ * Note: sparc64 has a pretty intricated thread_saved_pc, check it out.
+ */
+unsigned long thread_saved_pc(struct task_struct *tsk)
+{
+       return task_thread_info(tsk)->kpc;
+}
+
+/*
+ * Free current thread data structures etc..
+ */
+void exit_thread(void)
+{
+#ifndef CONFIG_SMP
+       if(last_task_used_math == current) {
+#else
+       if (test_thread_flag(TIF_USEDFPU)) {
+#endif
+               /* Keep process from leaving FPU in a bogon state. */
+               put_psr(get_psr() | PSR_EF);
+               fpsave(&current->thread.float_regs[0], &current->thread.fsr,
+                      &current->thread.fpqueue[0], &current->thread.fpqdepth);
+#ifndef CONFIG_SMP
+               last_task_used_math = NULL;
+#else
+               clear_thread_flag(TIF_USEDFPU);
+#endif
+       }
+}
+
+void flush_thread(void)
+{
+       current_thread_info()->w_saved = 0;
+
+#ifndef CONFIG_SMP
+       if(last_task_used_math == current) {
+#else
+       if (test_thread_flag(TIF_USEDFPU)) {
+#endif
+               /* Clean the fpu. */
+               put_psr(get_psr() | PSR_EF);
+               fpsave(&current->thread.float_regs[0], &current->thread.fsr,
+                      &current->thread.fpqueue[0], &current->thread.fpqdepth);
+#ifndef CONFIG_SMP
+               last_task_used_math = NULL;
+#else
+               clear_thread_flag(TIF_USEDFPU);
+#endif
+       }
+
+       /* Now, this task is no longer a kernel thread. */
+       current->thread.current_ds = USER_DS;
+       if (current->thread.flags & SPARC_FLAG_KTHREAD) {
+               current->thread.flags &= ~SPARC_FLAG_KTHREAD;
+
+               /* We must fixup kregs as well. */
+               /* XXX This was not fixed for ti for a while, worked. Unused? */
+               current->thread.kregs = (struct pt_regs *)
+                   (task_stack_page(current) + (THREAD_SIZE - TRACEREG_SZ));
+       }
+}
+
+static inline struct sparc_stackf __user *
+clone_stackframe(struct sparc_stackf __user *dst,
+                struct sparc_stackf __user *src)
+{
+       unsigned long size, fp;
+       struct sparc_stackf *tmp;
+       struct sparc_stackf __user *sp;
+
+       if (get_user(tmp, &src->fp))
+               return NULL;
+
+       fp = (unsigned long) tmp;
+       size = (fp - ((unsigned long) src));
+       fp = (unsigned long) dst;
+       sp = (struct sparc_stackf __user *)(fp - size); 
+
+       /* do_fork() grabs the parent semaphore, we must release it
+        * temporarily so we can build the child clone stack frame
+        * without deadlocking.
+        */
+       if (__copy_user(sp, src, size))
+               sp = NULL;
+       else if (put_user(fp, &sp->fp))
+               sp = NULL;
+
+       return sp;
+}
+
+asmlinkage int sparc_do_fork(unsigned long clone_flags,
+                             unsigned long stack_start,
+                             struct pt_regs *regs,
+                             unsigned long stack_size)
+{
+       unsigned long parent_tid_ptr, child_tid_ptr;
+       unsigned long orig_i1 = regs->u_regs[UREG_I1];
+       long ret;
+
+       parent_tid_ptr = regs->u_regs[UREG_I2];
+       child_tid_ptr = regs->u_regs[UREG_I4];
+
+       ret = do_fork(clone_flags, stack_start,
+                     regs, stack_size,
+                     (int __user *) parent_tid_ptr,
+                     (int __user *) child_tid_ptr);
+
+       /* If we get an error and potentially restart the system
+        * call, we're screwed because copy_thread() clobbered
+        * the parent's %o1.  So detect that case and restore it
+        * here.
+        */
+       if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK)
+               regs->u_regs[UREG_I1] = orig_i1;
+
+       return ret;
+}
+
+/* Copy a Sparc thread.  The fork() return value conventions
+ * under SunOS are nothing short of bletcherous:
+ * Parent -->  %o0 == childs  pid, %o1 == 0
+ * Child  -->  %o0 == parents pid, %o1 == 1
+ *
+ * NOTE: We have a separate fork kpsr/kwim because
+ *       the parent could change these values between
+ *       sys_fork invocation and when we reach here
+ *       if the parent should sleep while trying to
+ *       allocate the task_struct and kernel stack in
+ *       do_fork().
+ * XXX See comment above sys_vfork in sparc64. todo.
+ */
+extern void ret_from_fork(void);
+
+int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
+               unsigned long unused,
+               struct task_struct *p, struct pt_regs *regs)
+{
+       struct thread_info *ti = task_thread_info(p);
+       struct pt_regs *childregs;
+       char *new_stack;
+
+#ifndef CONFIG_SMP
+       if(last_task_used_math == current) {
+#else
+       if (test_thread_flag(TIF_USEDFPU)) {
+#endif
+               put_psr(get_psr() | PSR_EF);
+               fpsave(&p->thread.float_regs[0], &p->thread.fsr,
+                      &p->thread.fpqueue[0], &p->thread.fpqdepth);
+#ifdef CONFIG_SMP
+               clear_thread_flag(TIF_USEDFPU);
+#endif
+       }
+
+       /*
+        *  p->thread_info         new_stack   childregs
+        *  !                      !           !             {if(PSR_PS) }
+        *  V                      V (stk.fr.) V  (pt_regs)  { (stk.fr.) }
+        *  +----- - - - - - ------+===========+============={+==========}+
+        */
+       new_stack = task_stack_page(p) + THREAD_SIZE;
+       if (regs->psr & PSR_PS)
+               new_stack -= STACKFRAME_SZ;
+       new_stack -= STACKFRAME_SZ + TRACEREG_SZ;
+       memcpy(new_stack, (char *)regs - STACKFRAME_SZ, STACKFRAME_SZ + TRACEREG_SZ);
+       childregs = (struct pt_regs *) (new_stack + STACKFRAME_SZ);
+
+       /*
+        * A new process must start with interrupts closed in 2.5,
+        * because this is how Mingo's scheduler works (see schedule_tail
+        * and finish_arch_switch). If we do not do it, a timer interrupt hits
+        * before we unlock, attempts to re-take the rq->lock, and then we die.
+        * Thus, kpsr|=PSR_PIL.
+        */
+       ti->ksp = (unsigned long) new_stack;
+       ti->kpc = (((unsigned long) ret_from_fork) - 0x8);
+       ti->kpsr = current->thread.fork_kpsr | PSR_PIL;
+       ti->kwim = current->thread.fork_kwim;
+
+       if(regs->psr & PSR_PS) {
+               extern struct pt_regs fake_swapper_regs;
+
+               p->thread.kregs = &fake_swapper_regs;
+               new_stack += STACKFRAME_SZ + TRACEREG_SZ;
+               childregs->u_regs[UREG_FP] = (unsigned long) new_stack;
+               p->thread.flags |= SPARC_FLAG_KTHREAD;
+               p->thread.current_ds = KERNEL_DS;
+               memcpy(new_stack, (void *)regs->u_regs[UREG_FP], STACKFRAME_SZ);
+               childregs->u_regs[UREG_G6] = (unsigned long) ti;
+       } else {
+               p->thread.kregs = childregs;
+               childregs->u_regs[UREG_FP] = sp;
+               p->thread.flags &= ~SPARC_FLAG_KTHREAD;
+               p->thread.current_ds = USER_DS;
+
+               if (sp != regs->u_regs[UREG_FP]) {
+                       struct sparc_stackf __user *childstack;
+                       struct sparc_stackf __user *parentstack;
+
+                       /*
+                        * This is a clone() call with supplied user stack.
+                        * Set some valid stack frames to give to the child.
+                        */
+                       childstack = (struct sparc_stackf __user *)
+                               (sp & ~0x7UL);
+                       parentstack = (struct sparc_stackf __user *)
+                               regs->u_regs[UREG_FP];
+
+#if 0
+                       printk("clone: parent stack:\n");
+                       show_stackframe(parentstack);
+#endif
+
+                       childstack = clone_stackframe(childstack, parentstack);
+                       if (!childstack)
+                               return -EFAULT;
+
+#if 0
+                       printk("clone: child stack:\n");
+                       show_stackframe(childstack);
+#endif
+
+                       childregs->u_regs[UREG_FP] = (unsigned long)childstack;
+               }
+       }
+
+#ifdef CONFIG_SMP
+       /* FPU must be disabled on SMP. */
+       childregs->psr &= ~PSR_EF;
+#endif
+
+       /* Set the return value for the child. */
+       childregs->u_regs[UREG_I0] = current->pid;
+       childregs->u_regs[UREG_I1] = 1;
+
+       /* Set the return value for the parent. */
+       regs->u_regs[UREG_I1] = 0;
+
+       if (clone_flags & CLONE_SETTLS)
+               childregs->u_regs[UREG_G7] = regs->u_regs[UREG_I3];
+
+       return 0;
+}
+
+/*
+ * fill in the fpu structure for a core dump.
+ */
+int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs)
+{
+       if (used_math()) {
+               memset(fpregs, 0, sizeof(*fpregs));
+               fpregs->pr_q_entrysize = 8;
+               return 1;
+       }
+#ifdef CONFIG_SMP
+       if (test_thread_flag(TIF_USEDFPU)) {
+               put_psr(get_psr() | PSR_EF);
+               fpsave(&current->thread.float_regs[0], &current->thread.fsr,
+                      &current->thread.fpqueue[0], &current->thread.fpqdepth);
+               if (regs != NULL) {
+                       regs->psr &= ~(PSR_EF);
+                       clear_thread_flag(TIF_USEDFPU);
+               }
+       }
+#else
+       if (current == last_task_used_math) {
+               put_psr(get_psr() | PSR_EF);
+               fpsave(&current->thread.float_regs[0], &current->thread.fsr,
+                      &current->thread.fpqueue[0], &current->thread.fpqdepth);
+               if (regs != NULL) {
+                       regs->psr &= ~(PSR_EF);
+                       last_task_used_math = NULL;
+               }
+       }
+#endif
+       memcpy(&fpregs->pr_fr.pr_regs[0],
+              &current->thread.float_regs[0],
+              (sizeof(unsigned long) * 32));
+       fpregs->pr_fsr = current->thread.fsr;
+       fpregs->pr_qcnt = current->thread.fpqdepth;
+       fpregs->pr_q_entrysize = 8;
+       fpregs->pr_en = 1;
+       if(fpregs->pr_qcnt != 0) {
+               memcpy(&fpregs->pr_q[0],
+                      &current->thread.fpqueue[0],
+                      sizeof(struct fpq) * fpregs->pr_qcnt);
+       }
+       /* Zero out the rest. */
+       memset(&fpregs->pr_q[fpregs->pr_qcnt], 0,
+              sizeof(struct fpq) * (32 - fpregs->pr_qcnt));
+       return 1;
+}
+
+/*
+ * sparc_execve() executes a new program after the asm stub has set
+ * things up for us.  This should basically do what I want it to.
+ */
+asmlinkage int sparc_execve(struct pt_regs *regs)
+{
+       int error, base = 0;
+       char *filename;
+
+       /* Check for indirect call. */
+       if(regs->u_regs[UREG_G1] == 0)
+               base = 1;
+
+       filename = getname((char __user *)regs->u_regs[base + UREG_I0]);
+       error = PTR_ERR(filename);
+       if(IS_ERR(filename))
+               goto out;
+       error = do_execve(filename,
+                         (char __user * __user *)regs->u_regs[base + UREG_I1],
+                         (char __user * __user *)regs->u_regs[base + UREG_I2],
+                         regs);
+       putname(filename);
+out:
+       return error;
+}
+
+/*
+ * This is the mechanism for creating a new kernel thread.
+ *
+ * NOTE! Only a kernel-only process(ie the swapper or direct descendants
+ * who haven't done an "execve()") should use this: it will work within
+ * a system call from a "real" process, but the process memory space will
+ * not be freed until both the parent and the child have exited.
+ */
+pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+{
+       long retval;
+
+       __asm__ __volatile__("mov %4, %%g2\n\t"    /* Set aside fn ptr... */
+                            "mov %5, %%g3\n\t"    /* and arg. */
+                            "mov %1, %%g1\n\t"
+                            "mov %2, %%o0\n\t"    /* Clone flags. */
+                            "mov 0, %%o1\n\t"     /* usp arg == 0 */
+                            "t 0x10\n\t"          /* Linux/Sparc clone(). */
+                            "cmp %%o1, 0\n\t"
+                            "be 1f\n\t"           /* The parent, just return. */
+                            " nop\n\t"            /* Delay slot. */
+                            "jmpl %%g2, %%o7\n\t" /* Call the function. */
+                            " mov %%g3, %%o0\n\t" /* Get back the arg in delay. */
+                            "mov %3, %%g1\n\t"
+                            "t 0x10\n\t"          /* Linux/Sparc exit(). */
+                            /* Notreached by child. */
+                            "1: mov %%o0, %0\n\t" :
+                            "=r" (retval) :
+                            "i" (__NR_clone), "r" (flags | CLONE_VM | CLONE_UNTRACED),
+                            "i" (__NR_exit),  "r" (fn), "r" (arg) :
+                            "g1", "g2", "g3", "o0", "o1", "memory", "cc");
+       return retval;
+}
+
+unsigned long get_wchan(struct task_struct *task)
+{
+       unsigned long pc, fp, bias = 0;
+       unsigned long task_base = (unsigned long) task;
+        unsigned long ret = 0;
+       struct reg_window *rw;
+       int count = 0;
+
+       if (!task || task == current ||
+            task->state == TASK_RUNNING)
+               goto out;
+
+       fp = task_thread_info(task)->ksp + bias;
+       do {
+               /* Bogus frame pointer? */
+               if (fp < (task_base + sizeof(struct thread_info)) ||
+                   fp >= (task_base + (2 * PAGE_SIZE)))
+                       break;
+               rw = (struct reg_window *) fp;
+               pc = rw->ins[7];
+               if (!in_sched_functions(pc)) {
+                       ret = pc;
+                       goto out;
+               }
+               fp = rw->ins[6] + bias;
+       } while (++count < 16);
+
+out:
+       return ret;
+}
+
diff --git a/arch/sparc/kernel/prom.c b/arch/sparc/kernel/prom.c
deleted file mode 100644 (file)
index eee5efc..0000000
+++ /dev/null
@@ -1,566 +0,0 @@
-/*
- * Procedures for creating, accessing and interpreting the device tree.
- *
- * Paul Mackerras      August 1996.
- * Copyright (C) 1996-2005 Paul Mackerras.
- * 
- *  Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
- *    {engebret|bergner}@us.ibm.com 
- *
- *  Adapted for sparc32 by David S. Miller davem@davemloft.net
- *
- *      This program is free software; you can redistribute it and/or
- *      modify it under the terms of the GNU General Public License
- *      as published by the Free Software Foundation; either version
- *      2 of the License, or (at your option) any later version.
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/bootmem.h>
-#include <linux/module.h>
-
-#include <asm/prom.h>
-#include <asm/oplib.h>
-
-extern struct device_node *allnodes;   /* temporary while merging */
-
-extern rwlock_t devtree_lock;  /* temporary while merging */
-
-struct device_node *of_find_node_by_phandle(phandle handle)
-{
-       struct device_node *np;
-
-       for (np = allnodes; np != 0; np = np->allnext)
-               if (np->node == handle)
-                       break;
-
-       return np;
-}
-EXPORT_SYMBOL(of_find_node_by_phandle);
-
-int of_getintprop_default(struct device_node *np, const char *name, int def)
-{
-       struct property *prop;
-       int len;
-
-       prop = of_find_property(np, name, &len);
-       if (!prop || len != 4)
-               return def;
-
-       return *(int *) prop->value;
-}
-EXPORT_SYMBOL(of_getintprop_default);
-
-DEFINE_MUTEX(of_set_property_mutex);
-EXPORT_SYMBOL(of_set_property_mutex);
-
-int of_set_property(struct device_node *dp, const char *name, void *val, int len)
-{
-       struct property **prevp;
-       void *new_val;
-       int err;
-
-       new_val = kmalloc(len, GFP_KERNEL);
-       if (!new_val)
-               return -ENOMEM;
-
-       memcpy(new_val, val, len);
-
-       err = -ENODEV;
-
-       write_lock(&devtree_lock);
-       prevp = &dp->properties;
-       while (*prevp) {
-               struct property *prop = *prevp;
-
-               if (!strcasecmp(prop->name, name)) {
-                       void *old_val = prop->value;
-                       int ret;
-
-                       mutex_lock(&of_set_property_mutex);
-                       ret = prom_setprop(dp->node, (char *) name, val, len);
-                       mutex_unlock(&of_set_property_mutex);
-
-                       err = -EINVAL;
-                       if (ret >= 0) {
-                               prop->value = new_val;
-                               prop->length = len;
-
-                               if (OF_IS_DYNAMIC(prop))
-                                       kfree(old_val);
-
-                               OF_MARK_DYNAMIC(prop);
-
-                               err = 0;
-                       }
-                       break;
-               }
-               prevp = &(*prevp)->next;
-       }
-       write_unlock(&devtree_lock);
-
-       /* XXX Upate procfs if necessary... */
-
-       return err;
-}
-EXPORT_SYMBOL(of_set_property);
-
-int of_find_in_proplist(const char *list, const char *match, int len)
-{
-       while (len > 0) {
-               int l;
-
-               if (!strcmp(list, match))
-                       return 1;
-               l = strlen(list) + 1;
-               list += l;
-               len -= l;
-       }
-       return 0;
-}
-EXPORT_SYMBOL(of_find_in_proplist);
-
-static unsigned int prom_early_allocated;
-
-static void * __init prom_early_alloc(unsigned long size)
-{
-       void *ret;
-
-       ret = __alloc_bootmem(size, SMP_CACHE_BYTES, 0UL);
-       if (ret != NULL)
-               memset(ret, 0, size);
-
-       prom_early_allocated += size;
-
-       return ret;
-}
-
-static int is_root_node(const struct device_node *dp)
-{
-       if (!dp)
-               return 0;
-
-       return (dp->parent == NULL);
-}
-
-/* The following routines deal with the black magic of fully naming a
- * node.
- *
- * Certain well known named nodes are just the simple name string.
- *
- * Actual devices have an address specifier appended to the base name
- * string, like this "foo@addr".  The "addr" can be in any number of
- * formats, and the platform plus the type of the node determine the
- * format and how it is constructed.
- *
- * For children of the ROOT node, the naming convention is fixed and
- * determined by whether this is a sun4u or sun4v system.
- *
- * For children of other nodes, it is bus type specific.  So
- * we walk up the tree until we discover a "device_type" property
- * we recognize and we go from there.
- */
-static void __init sparc32_path_component(struct device_node *dp, char *tmp_buf)
-{
-       struct linux_prom_registers *regs;
-       struct property *rprop;
-
-       rprop = of_find_property(dp, "reg", NULL);
-       if (!rprop)
-               return;
-
-       regs = rprop->value;
-       sprintf(tmp_buf, "%s@%x,%x",
-               dp->name,
-               regs->which_io, regs->phys_addr);
-}
-
-/* "name@slot,offset"  */
-static void __init sbus_path_component(struct device_node *dp, char *tmp_buf)
-{
-       struct linux_prom_registers *regs;
-       struct property *prop;
-
-       prop = of_find_property(dp, "reg", NULL);
-       if (!prop)
-               return;
-
-       regs = prop->value;
-       sprintf(tmp_buf, "%s@%x,%x",
-               dp->name,
-               regs->which_io,
-               regs->phys_addr);
-}
-
-/* "name@devnum[,func]" */
-static void __init pci_path_component(struct device_node *dp, char *tmp_buf)
-{
-       struct linux_prom_pci_registers *regs;
-       struct property *prop;
-       unsigned int devfn;
-
-       prop = of_find_property(dp, "reg", NULL);
-       if (!prop)
-               return;
-
-       regs = prop->value;
-       devfn = (regs->phys_hi >> 8) & 0xff;
-       if (devfn & 0x07) {
-               sprintf(tmp_buf, "%s@%x,%x",
-                       dp->name,
-                       devfn >> 3,
-                       devfn & 0x07);
-       } else {
-               sprintf(tmp_buf, "%s@%x",
-                       dp->name,
-                       devfn >> 3);
-       }
-}
-
-/* "name@addrhi,addrlo" */
-static void __init ebus_path_component(struct device_node *dp, char *tmp_buf)
-{
-       struct linux_prom_registers *regs;
-       struct property *prop;
-
-       prop = of_find_property(dp, "reg", NULL);
-       if (!prop)
-               return;
-
-       regs = prop->value;
-
-       sprintf(tmp_buf, "%s@%x,%x",
-               dp->name,
-               regs->which_io, regs->phys_addr);
-}
-
-static void __init __build_path_component(struct device_node *dp, char *tmp_buf)
-{
-       struct device_node *parent = dp->parent;
-
-       if (parent != NULL) {
-               if (!strcmp(parent->type, "pci") ||
-                   !strcmp(parent->type, "pciex"))
-                       return pci_path_component(dp, tmp_buf);
-               if (!strcmp(parent->type, "sbus"))
-                       return sbus_path_component(dp, tmp_buf);
-               if (!strcmp(parent->type, "ebus"))
-                       return ebus_path_component(dp, tmp_buf);
-
-               /* "isa" is handled with platform naming */
-       }
-
-       /* Use platform naming convention.  */
-       return sparc32_path_component(dp, tmp_buf);
-}
-
-static char * __init build_path_component(struct device_node *dp)
-{
-       char tmp_buf[64], *n;
-
-       tmp_buf[0] = '\0';
-       __build_path_component(dp, tmp_buf);
-       if (tmp_buf[0] == '\0')
-               strcpy(tmp_buf, dp->name);
-
-       n = prom_early_alloc(strlen(tmp_buf) + 1);
-       strcpy(n, tmp_buf);
-
-       return n;
-}
-
-static char * __init build_full_name(struct device_node *dp)
-{
-       int len, ourlen, plen;
-       char *n;
-
-       plen = strlen(dp->parent->full_name);
-       ourlen = strlen(dp->path_component_name);
-       len = ourlen + plen + 2;
-
-       n = prom_early_alloc(len);
-       strcpy(n, dp->parent->full_name);
-       if (!is_root_node(dp->parent)) {
-               strcpy(n + plen, "/");
-               plen++;
-       }
-       strcpy(n + plen, dp->path_component_name);
-
-       return n;
-}
-
-static unsigned int unique_id;
-
-static struct property * __init build_one_prop(phandle node, char *prev, char *special_name, void *special_val, int special_len)
-{
-       static struct property *tmp = NULL;
-       struct property *p;
-       int len;
-       const char *name;
-
-       if (tmp) {
-               p = tmp;
-               memset(p, 0, sizeof(*p) + 32);
-               tmp = NULL;
-       } else {
-               p = prom_early_alloc(sizeof(struct property) + 32);
-               p->unique_id = unique_id++;
-       }
-
-       p->name = (char *) (p + 1);
-       if (special_name) {
-               strcpy(p->name, special_name);
-               p->length = special_len;
-               p->value = prom_early_alloc(special_len);
-               memcpy(p->value, special_val, special_len);
-       } else {
-               if (prev == NULL) {
-                       name = prom_firstprop(node, NULL);
-               } else {
-                       name = prom_nextprop(node, prev, NULL);
-               }
-               if (strlen(name) == 0) {
-                       tmp = p;
-                       return NULL;
-               }
-               strcpy(p->name, name);
-               p->length = prom_getproplen(node, p->name);
-               if (p->length <= 0) {
-                       p->length = 0;
-               } else {
-                       p->value = prom_early_alloc(p->length + 1);
-                       len = prom_getproperty(node, p->name, p->value,
-                                              p->length);
-                       if (len <= 0)
-                               p->length = 0;
-                       ((unsigned char *)p->value)[p->length] = '\0';
-               }
-       }
-       return p;
-}
-
-static struct property * __init build_prop_list(phandle node)
-{
-       struct property *head, *tail;
-
-       head = tail = build_one_prop(node, NULL,
-                                    ".node", &node, sizeof(node));
-
-       tail->next = build_one_prop(node, NULL, NULL, NULL, 0);
-       tail = tail->next;
-       while(tail) {
-               tail->next = build_one_prop(node, tail->name,
-                                           NULL, NULL, 0);
-               tail = tail->next;
-       }
-
-       return head;
-}
-
-static char * __init get_one_property(phandle node, char *name)
-{
-       char *buf = "<NULL>";
-       int len;
-
-       len = prom_getproplen(node, name);
-       if (len > 0) {
-               buf = prom_early_alloc(len);
-               len = prom_getproperty(node, name, buf, len);
-       }
-
-       return buf;
-}
-
-static struct device_node * __init create_node(phandle node)
-{
-       struct device_node *dp;
-
-       if (!node)
-               return NULL;
-
-       dp = prom_early_alloc(sizeof(*dp));
-       dp->unique_id = unique_id++;
-
-       kref_init(&dp->kref);
-
-       dp->name = get_one_property(node, "name");
-       dp->type = get_one_property(node, "device_type");
-       dp->node = node;
-
-       /* Build interrupts later... */
-
-       dp->properties = build_prop_list(node);
-
-       return dp;
-}
-
-static struct device_node * __init build_tree(struct device_node *parent, phandle node, struct device_node ***nextp)
-{
-       struct device_node *dp;
-
-       dp = create_node(node);
-       if (dp) {
-               *(*nextp) = dp;
-               *nextp = &dp->allnext;
-
-               dp->parent = parent;
-               dp->path_component_name = build_path_component(dp);
-               dp->full_name = build_full_name(dp);
-
-               dp->child = build_tree(dp, prom_getchild(node), nextp);
-
-               dp->sibling = build_tree(parent, prom_getsibling(node), nextp);
-       }
-
-       return dp;
-}
-
-struct device_node *of_console_device;
-EXPORT_SYMBOL(of_console_device);
-
-char *of_console_path;
-EXPORT_SYMBOL(of_console_path);
-
-char *of_console_options;
-EXPORT_SYMBOL(of_console_options);
-
-extern void restore_current(void);
-
-static void __init of_console_init(void)
-{
-       char *msg = "OF stdout device is: %s\n";
-       struct device_node *dp;
-       unsigned long flags;
-       const char *type;
-       phandle node;
-       int skip, tmp, fd;
-
-       of_console_path = prom_early_alloc(256);
-
-       switch (prom_vers) {
-       case PROM_V0:
-               skip = 0;
-               switch (*romvec->pv_stdout) {
-               case PROMDEV_SCREEN:
-                       type = "display";
-                       break;
-
-               case PROMDEV_TTYB:
-                       skip = 1;
-                       /* FALLTHRU */
-
-               case PROMDEV_TTYA:
-                       type = "serial";
-                       break;
-
-               default:
-                       prom_printf("Invalid PROM_V0 stdout value %u\n",
-                                   *romvec->pv_stdout);
-                       prom_halt();
-               }
-
-               tmp = skip;
-               for_each_node_by_type(dp, type) {
-                       if (!tmp--)
-                               break;
-               }
-               if (!dp) {
-                       prom_printf("Cannot find PROM_V0 console node.\n");
-                       prom_halt();
-               }
-               of_console_device = dp;
-
-               strcpy(of_console_path, dp->full_name);
-               if (!strcmp(type, "serial")) {
-                       strcat(of_console_path,
-                              (skip ? ":b" : ":a"));
-               }
-               break;
-
-       default:
-       case PROM_V2:
-       case PROM_V3:
-               fd = *romvec->pv_v2bootargs.fd_stdout;
-
-               spin_lock_irqsave(&prom_lock, flags);
-               node = (*romvec->pv_v2devops.v2_inst2pkg)(fd);
-               restore_current();
-               spin_unlock_irqrestore(&prom_lock, flags);
-
-               if (!node) {
-                       prom_printf("Cannot resolve stdout node from "
-                                   "instance %08x.\n", fd);
-                       prom_halt();
-               }
-               dp = of_find_node_by_phandle(node);
-               type = of_get_property(dp, "device_type", NULL);
-
-               if (!type) {
-                       prom_printf("Console stdout lacks "
-                                   "device_type property.\n");
-                       prom_halt();
-               }
-
-               if (strcmp(type, "display") && strcmp(type, "serial")) {
-                       prom_printf("Console device_type is neither display "
-                                   "nor serial.\n");
-                       prom_halt();
-               }
-
-               of_console_device = dp;
-
-               if (prom_vers == PROM_V2) {
-                       strcpy(of_console_path, dp->full_name);
-                       switch (*romvec->pv_stdout) {
-                       case PROMDEV_TTYA:
-                               strcat(of_console_path, ":a");
-                               break;
-                       case PROMDEV_TTYB:
-                               strcat(of_console_path, ":b");
-                               break;
-                       }
-               } else {
-                       const char *path;
-
-                       dp = of_find_node_by_path("/");
-                       path = of_get_property(dp, "stdout-path", NULL);
-                       if (!path) {
-                               prom_printf("No stdout-path in root node.\n");
-                               prom_halt();
-                       }
-                       strcpy(of_console_path, path);
-               }
-               break;
-       }
-
-       of_console_options = strrchr(of_console_path, ':');
-       if (of_console_options) {
-               of_console_options++;
-               if (*of_console_options == '\0')
-                       of_console_options = NULL;
-       }
-
-       prom_printf(msg, of_console_path);
-       printk(msg, of_console_path);
-}
-
-void __init prom_build_devicetree(void)
-{
-       struct device_node **nextp;
-
-       allnodes = create_node(prom_root_node);
-       allnodes->path_component_name = "";
-       allnodes->full_name = "/";
-
-       nextp = &allnodes->allnext;
-       allnodes->child = build_tree(allnodes,
-                                    prom_getchild(allnodes->node),
-                                    &nextp);
-       of_console_init();
-
-       printk("PROM: Built device tree with %u bytes of memory.\n",
-              prom_early_allocated);
-}
diff --git a/arch/sparc/kernel/prom_32.c b/arch/sparc/kernel/prom_32.c
new file mode 100644 (file)
index 0000000..eee5efc
--- /dev/null
@@ -0,0 +1,566 @@
+/*
+ * Procedures for creating, accessing and interpreting the device tree.
+ *
+ * Paul Mackerras      August 1996.
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ * 
+ *  Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
+ *    {engebret|bergner}@us.ibm.com 
+ *
+ *  Adapted for sparc32 by David S. Miller davem@davemloft.net
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/bootmem.h>
+#include <linux/module.h>
+
+#include <asm/prom.h>
+#include <asm/oplib.h>
+
+extern struct device_node *allnodes;   /* temporary while merging */
+
+extern rwlock_t devtree_lock;  /* temporary while merging */
+
+struct device_node *of_find_node_by_phandle(phandle handle)
+{
+       struct device_node *np;
+
+       for (np = allnodes; np != 0; np = np->allnext)
+               if (np->node == handle)
+                       break;
+
+       return np;
+}
+EXPORT_SYMBOL(of_find_node_by_phandle);
+
+int of_getintprop_default(struct device_node *np, const char *name, int def)
+{
+       struct property *prop;
+       int len;
+
+       prop = of_find_property(np, name, &len);
+       if (!prop || len != 4)
+               return def;
+
+       return *(int *) prop->value;
+}
+EXPORT_SYMBOL(of_getintprop_default);
+
+DEFINE_MUTEX(of_set_property_mutex);
+EXPORT_SYMBOL(of_set_property_mutex);
+
+int of_set_property(struct device_node *dp, const char *name, void *val, int len)
+{
+       struct property **prevp;
+       void *new_val;
+       int err;
+
+       new_val = kmalloc(len, GFP_KERNEL);
+       if (!new_val)
+               return -ENOMEM;
+
+       memcpy(new_val, val, len);
+
+       err = -ENODEV;
+
+       write_lock(&devtree_lock);
+       prevp = &dp->properties;
+       while (*prevp) {
+               struct property *prop = *prevp;
+
+               if (!strcasecmp(prop->name, name)) {
+                       void *old_val = prop->value;
+                       int ret;
+
+                       mutex_lock(&of_set_property_mutex);
+                       ret = prom_setprop(dp->node, (char *) name, val, len);
+                       mutex_unlock(&of_set_property_mutex);
+
+                       err = -EINVAL;
+                       if (ret >= 0) {
+                               prop->value = new_val;
+                               prop->length = len;
+
+                               if (OF_IS_DYNAMIC(prop))
+                                       kfree(old_val);
+
+                               OF_MARK_DYNAMIC(prop);
+
+                               err = 0;
+                       }
+                       break;
+               }
+               prevp = &(*prevp)->next;
+       }
+       write_unlock(&devtree_lock);
+
+       /* XXX Upate procfs if necessary... */
+
+       return err;
+}
+EXPORT_SYMBOL(of_set_property);
+
+int of_find_in_proplist(const char *list, const char *match, int len)
+{
+       while (len > 0) {
+               int l;
+
+               if (!strcmp(list, match))
+                       return 1;
+               l = strlen(list) + 1;
+               list += l;
+               len -= l;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(of_find_in_proplist);
+
+static unsigned int prom_early_allocated;
+
+static void * __init prom_early_alloc(unsigned long size)
+{
+       void *ret;
+
+       ret = __alloc_bootmem(size, SMP_CACHE_BYTES, 0UL);
+       if (ret != NULL)
+               memset(ret, 0, size);
+
+       prom_early_allocated += size;
+
+       return ret;
+}
+
+static int is_root_node(const struct device_node *dp)
+{
+       if (!dp)
+               return 0;
+
+       return (dp->parent == NULL);
+}
+
+/* The following routines deal with the black magic of fully naming a
+ * node.
+ *
+ * Certain well known named nodes are just the simple name string.
+ *
+ * Actual devices have an address specifier appended to the base name
+ * string, like this "foo@addr".  The "addr" can be in any number of
+ * formats, and the platform plus the type of the node determine the
+ * format and how it is constructed.
+ *
+ * For children of the ROOT node, the naming convention is fixed and
+ * determined by whether this is a sun4u or sun4v system.
+ *
+ * For children of other nodes, it is bus type specific.  So
+ * we walk up the tree until we discover a "device_type" property
+ * we recognize and we go from there.
+ */
+static void __init sparc32_path_component(struct device_node *dp, char *tmp_buf)
+{
+       struct linux_prom_registers *regs;
+       struct property *rprop;
+
+       rprop = of_find_property(dp, "reg", NULL);
+       if (!rprop)
+               return;
+
+       regs = rprop->value;
+       sprintf(tmp_buf, "%s@%x,%x",
+               dp->name,
+               regs->which_io, regs->phys_addr);
+}
+
+/* "name@slot,offset"  */
+static void __init sbus_path_component(struct device_node *dp, char *tmp_buf)
+{
+       struct linux_prom_registers *regs;
+       struct property *prop;
+
+       prop = of_find_property(dp, "reg", NULL);
+       if (!prop)
+               return;
+
+       regs = prop->value;
+       sprintf(tmp_buf, "%s@%x,%x",
+               dp->name,
+               regs->which_io,
+               regs->phys_addr);
+}
+
+/* "name@devnum[,func]" */
+static void __init pci_path_component(struct device_node *dp, char *tmp_buf)
+{
+       struct linux_prom_pci_registers *regs;
+       struct property *prop;
+       unsigned int devfn;
+
+       prop = of_find_property(dp, "reg", NULL);
+       if (!prop)
+               return;
+
+       regs = prop->value;
+       devfn = (regs->phys_hi >> 8) & 0xff;
+       if (devfn & 0x07) {
+               sprintf(tmp_buf, "%s@%x,%x",
+                       dp->name,
+                       devfn >> 3,
+                       devfn & 0x07);
+       } else {
+               sprintf(tmp_buf, "%s@%x",
+                       dp->name,
+                       devfn >> 3);
+       }
+}
+
+/* "name@addrhi,addrlo" */
+static void __init ebus_path_component(struct device_node *dp, char *tmp_buf)
+{
+       struct linux_prom_registers *regs;
+       struct property *prop;
+
+       prop = of_find_property(dp, "reg", NULL);
+       if (!prop)
+               return;
+
+       regs = prop->value;
+
+       sprintf(tmp_buf, "%s@%x,%x",
+               dp->name,
+               regs->which_io, regs->phys_addr);
+}
+
+static void __init __build_path_component(struct device_node *dp, char *tmp_buf)
+{
+       struct device_node *parent = dp->parent;
+
+       if (parent != NULL) {
+               if (!strcmp(parent->type, "pci") ||
+                   !strcmp(parent->type, "pciex"))
+                       return pci_path_component(dp, tmp_buf);
+               if (!strcmp(parent->type, "sbus"))
+                       return sbus_path_component(dp, tmp_buf);
+               if (!strcmp(parent->type, "ebus"))
+                       return ebus_path_component(dp, tmp_buf);
+
+               /* "isa" is handled with platform naming */
+       }
+
+       /* Use platform naming convention.  */
+       return sparc32_path_component(dp, tmp_buf);
+}
+
+static char * __init build_path_component(struct device_node *dp)
+{
+       char tmp_buf[64], *n;
+
+       tmp_buf[0] = '\0';
+       __build_path_component(dp, tmp_buf);
+       if (tmp_buf[0] == '\0')
+               strcpy(tmp_buf, dp->name);
+
+       n = prom_early_alloc(strlen(tmp_buf) + 1);
+       strcpy(n, tmp_buf);
+
+       return n;
+}
+
+static char * __init build_full_name(struct device_node *dp)
+{
+       int len, ourlen, plen;
+       char *n;
+
+       plen = strlen(dp->parent->full_name);
+       ourlen = strlen(dp->path_component_name);
+       len = ourlen + plen + 2;
+
+       n = prom_early_alloc(len);
+       strcpy(n, dp->parent->full_name);
+       if (!is_root_node(dp->parent)) {
+               strcpy(n + plen, "/");
+               plen++;
+       }
+       strcpy(n + plen, dp->path_component_name);
+
+       return n;
+}
+
+static unsigned int unique_id;
+
+static struct property * __init build_one_prop(phandle node, char *prev, char *special_name, void *special_val, int special_len)
+{
+       static struct property *tmp = NULL;
+       struct property *p;
+       int len;
+       const char *name;
+
+       if (tmp) {
+               p = tmp;
+               memset(p, 0, sizeof(*p) + 32);
+               tmp = NULL;
+       } else {
+               p = prom_early_alloc(sizeof(struct property) + 32);
+               p->unique_id = unique_id++;
+       }
+
+       p->name = (char *) (p + 1);
+       if (special_name) {
+               strcpy(p->name, special_name);
+               p->length = special_len;
+               p->value = prom_early_alloc(special_len);
+               memcpy(p->value, special_val, special_len);
+       } else {
+               if (prev == NULL) {
+                       name = prom_firstprop(node, NULL);
+               } else {
+                       name = prom_nextprop(node, prev, NULL);
+               }
+               if (strlen(name) == 0) {
+                       tmp = p;
+                       return NULL;
+               }
+               strcpy(p->name, name);
+               p->length = prom_getproplen(node, p->name);
+               if (p->length <= 0) {
+                       p->length = 0;
+               } else {
+                       p->value = prom_early_alloc(p->length + 1);
+                       len = prom_getproperty(node, p->name, p->value,
+                                              p->length);
+                       if (len <= 0)
+                               p->length = 0;
+                       ((unsigned char *)p->value)[p->length] = '\0';
+               }
+       }
+       return p;
+}
+
+static struct property * __init build_prop_list(phandle node)
+{
+       struct property *head, *tail;
+
+       head = tail = build_one_prop(node, NULL,
+                                    ".node", &node, sizeof(node));
+
+       tail->next = build_one_prop(node, NULL, NULL, NULL, 0);
+       tail = tail->next;
+       while(tail) {
+               tail->next = build_one_prop(node, tail->name,
+                                           NULL, NULL, 0);
+               tail = tail->next;
+       }
+
+       return head;
+}
+
+static char * __init get_one_property(phandle node, char *name)
+{
+       char *buf = "<NULL>";
+       int len;
+
+       len = prom_getproplen(node, name);
+       if (len > 0) {
+               buf = prom_early_alloc(len);
+               len = prom_getproperty(node, name, buf, len);
+       }
+
+       return buf;
+}
+
+static struct device_node * __init create_node(phandle node)
+{
+       struct device_node *dp;
+
+       if (!node)
+               return NULL;
+
+       dp = prom_early_alloc(sizeof(*dp));
+       dp->unique_id = unique_id++;
+
+       kref_init(&dp->kref);
+
+       dp->name = get_one_property(node, "name");
+       dp->type = get_one_property(node, "device_type");
+       dp->node = node;
+
+       /* Build interrupts later... */
+
+       dp->properties = build_prop_list(node);
+
+       return dp;
+}
+
+static struct device_node * __init build_tree(struct device_node *parent, phandle node, struct device_node ***nextp)
+{
+       struct device_node *dp;
+
+       dp = create_node(node);
+       if (dp) {
+               *(*nextp) = dp;
+               *nextp = &dp->allnext;
+
+               dp->parent = parent;
+               dp->path_component_name = build_path_component(dp);
+               dp->full_name = build_full_name(dp);
+
+               dp->child = build_tree(dp, prom_getchild(node), nextp);
+
+               dp->sibling = build_tree(parent, prom_getsibling(node), nextp);
+       }
+
+       return dp;
+}
+
+struct device_node *of_console_device;
+EXPORT_SYMBOL(of_console_device);
+
+char *of_console_path;
+EXPORT_SYMBOL(of_console_path);
+
+char *of_console_options;
+EXPORT_SYMBOL(of_console_options);
+
+extern void restore_current(void);
+
+static void __init of_console_init(void)
+{
+       char *msg = "OF stdout device is: %s\n";
+       struct device_node *dp;
+       unsigned long flags;
+       const char *type;
+       phandle node;
+       int skip, tmp, fd;
+
+       of_console_path = prom_early_alloc(256);
+
+       switch (prom_vers) {
+       case PROM_V0:
+               skip = 0;
+               switch (*romvec->pv_stdout) {
+               case PROMDEV_SCREEN:
+                       type = "display";
+                       break;
+
+               case PROMDEV_TTYB:
+                       skip = 1;
+                       /* FALLTHRU */
+
+               case PROMDEV_TTYA:
+                       type = "serial";
+                       break;
+
+               default:
+                       prom_printf("Invalid PROM_V0 stdout value %u\n",
+                                   *romvec->pv_stdout);
+                       prom_halt();
+               }
+
+               tmp = skip;
+               for_each_node_by_type(dp, type) {
+                       if (!tmp--)
+                               break;
+               }
+               if (!dp) {
+                       prom_printf("Cannot find PROM_V0 console node.\n");
+                       prom_halt();
+               }
+               of_console_device = dp;
+
+               strcpy(of_console_path, dp->full_name);
+               if (!strcmp(type, "serial")) {
+                       strcat(of_console_path,
+                              (skip ? ":b" : ":a"));
+               }
+               break;
+
+       default:
+       case PROM_V2:
+       case PROM_V3:
+               fd = *romvec->pv_v2bootargs.fd_stdout;
+
+               spin_lock_irqsave(&prom_lock, flags);
+               node = (*romvec->pv_v2devops.v2_inst2pkg)(fd);
+               restore_current();
+               spin_unlock_irqrestore(&prom_lock, flags);
+
+               if (!node) {
+                       prom_printf("Cannot resolve stdout node from "
+                                   "instance %08x.\n", fd);
+                       prom_halt();
+               }
+               dp = of_find_node_by_phandle(node);
+               type = of_get_property(dp, "device_type", NULL);
+
+               if (!type) {
+                       prom_printf("Console stdout lacks "
+                                   "device_type property.\n");
+                       prom_halt();
+               }
+
+               if (strcmp(type, "display") && strcmp(type, "serial")) {
+                       prom_printf("Console device_type is neither display "
+                                   "nor serial.\n");
+                       prom_halt();
+               }
+
+               of_console_device = dp;
+
+               if (prom_vers == PROM_V2) {
+                       strcpy(of_console_path, dp->full_name);
+                       switch (*romvec->pv_stdout) {
+                       case PROMDEV_TTYA:
+                               strcat(of_console_path, ":a");
+                               break;
+                       case PROMDEV_TTYB:
+                               strcat(of_console_path, ":b");
+                               break;
+                       }
+               } else {
+                       const char *path;
+
+                       dp = of_find_node_by_path("/");
+                       path = of_get_property(dp, "stdout-path", NULL);
+                       if (!path) {
+                               prom_printf("No stdout-path in root node.\n");
+                               prom_halt();
+                       }
+                       strcpy(of_console_path, path);
+               }
+               break;
+       }
+
+       of_console_options = strrchr(of_console_path, ':');
+       if (of_console_options) {
+               of_console_options++;
+               if (*of_console_options == '\0')
+                       of_console_options = NULL;
+       }
+
+       prom_printf(msg, of_console_path);
+       printk(msg, of_console_path);
+}
+
+void __init prom_build_devicetree(void)
+{
+       struct device_node **nextp;
+
+       allnodes = create_node(prom_root_node);
+       allnodes->path_component_name = "";
+       allnodes->full_name = "/";
+
+       nextp = &allnodes->allnext;
+       allnodes->child = build_tree(allnodes,
+                                    prom_getchild(allnodes->node),
+                                    &nextp);
+       of_console_init();
+
+       printk("PROM: Built device tree with %u bytes of memory.\n",
+              prom_early_allocated);
+}
diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c
deleted file mode 100644 (file)
index 8ce6285..0000000
+++ /dev/null
@@ -1,466 +0,0 @@
-/* ptrace.c: Sparc process tracing support.
- *
- * Copyright (C) 1996, 2008 David S. Miller (davem@davemloft.net)
- *
- * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson,
- * and David Mosberger.
- *
- * Added Linux support -miguel (weird, eh?, the original code was meant
- * to emulate SunOS).
- */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/errno.h>
-#include <linux/ptrace.h>
-#include <linux/user.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-#include <linux/security.h>
-#include <linux/signal.h>
-#include <linux/regset.h>
-#include <linux/elf.h>
-#include <linux/tracehook.h>
-
-#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-
-/* #define ALLOW_INIT_TRACING */
-
-/*
- * Called by kernel/ptrace.c when detaching..
- *
- * Make sure single step bits etc are not set.
- */
-void ptrace_disable(struct task_struct *child)
-{
-       /* nothing to do */
-}
-
-enum sparc_regset {
-       REGSET_GENERAL,
-       REGSET_FP,
-};
-
-static int genregs32_get(struct task_struct *target,
-                        const struct user_regset *regset,
-                        unsigned int pos, unsigned int count,
-                        void *kbuf, void __user *ubuf)
-{
-       const struct pt_regs *regs = target->thread.kregs;
-       unsigned long __user *reg_window;
-       unsigned long *k = kbuf;
-       unsigned long __user *u = ubuf;
-       unsigned long reg;
-
-       if (target == current)
-               flush_user_windows();
-
-       pos /= sizeof(reg);
-       count /= sizeof(reg);
-
-       if (kbuf) {
-               for (; count > 0 && pos < 16; count--)
-                       *k++ = regs->u_regs[pos++];
-
-               reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
-               for (; count > 0 && pos < 32; count--) {
-                       if (get_user(*k++, &reg_window[pos++]))
-                               return -EFAULT;
-               }
-       } else {
-               for (; count > 0 && pos < 16; count--) {
-                       if (put_user(regs->u_regs[pos++], u++))
-                               return -EFAULT;
-               }
-
-               reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
-               for (; count > 0 && pos < 32; count--) {
-                       if (get_user(reg, &reg_window[pos++]) ||
-                           put_user(reg, u++))
-                               return -EFAULT;
-               }
-       }
-       while (count > 0) {
-               switch (pos) {
-               case 32: /* PSR */
-                       reg = regs->psr;
-                       break;
-               case 33: /* PC */
-                       reg = regs->pc;
-                       break;
-               case 34: /* NPC */
-                       reg = regs->npc;
-                       break;
-               case 35: /* Y */
-                       reg = regs->y;
-                       break;
-               case 36: /* WIM */
-               case 37: /* TBR */
-                       reg = 0;
-                       break;
-               default:
-                       goto finish;
-               }
-
-               if (kbuf)
-                       *k++ = reg;
-               else if (put_user(reg, u++))
-                       return -EFAULT;
-               pos++;
-               count--;
-       }
-finish:
-       pos *= sizeof(reg);
-       count *= sizeof(reg);
-
-       return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
-                                       38 * sizeof(reg), -1);
-}
-
-static int genregs32_set(struct task_struct *target,
-                        const struct user_regset *regset,
-                        unsigned int pos, unsigned int count,
-                        const void *kbuf, const void __user *ubuf)
-{
-       struct pt_regs *regs = target->thread.kregs;
-       unsigned long __user *reg_window;
-       const unsigned long *k = kbuf;
-       const unsigned long __user *u = ubuf;
-       unsigned long reg;
-
-       if (target == current)
-               flush_user_windows();
-
-       pos /= sizeof(reg);
-       count /= sizeof(reg);
-
-       if (kbuf) {
-               for (; count > 0 && pos < 16; count--)
-                       regs->u_regs[pos++] = *k++;
-
-               reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
-               for (; count > 0 && pos < 32; count--) {
-                       if (put_user(*k++, &reg_window[pos++]))
-                               return -EFAULT;
-               }
-       } else {
-               for (; count > 0 && pos < 16; count--) {
-                       if (get_user(reg, u++))
-                               return -EFAULT;
-                       regs->u_regs[pos++] = reg;
-               }
-
-               reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
-               for (; count > 0 && pos < 32; count--) {
-                       if (get_user(reg, u++) ||
-                           put_user(reg, &reg_window[pos++]))
-                               return -EFAULT;
-               }
-       }
-       while (count > 0) {
-               unsigned long psr;
-
-               if (kbuf)
-                       reg = *k++;
-               else if (get_user(reg, u++))
-                       return -EFAULT;
-
-               switch (pos) {
-               case 32: /* PSR */
-                       psr = regs->psr;
-                       psr &= ~(PSR_ICC | PSR_SYSCALL);
-                       psr |= (reg & (PSR_ICC | PSR_SYSCALL));
-                       regs->psr = psr;
-                       break;
-               case 33: /* PC */
-                       regs->pc = reg;
-                       break;
-               case 34: /* NPC */
-                       regs->npc = reg;
-                       break;
-               case 35: /* Y */
-                       regs->y = reg;
-                       break;
-               case 36: /* WIM */
-               case 37: /* TBR */
-                       break;
-               default:
-                       goto finish;
-               }
-
-               pos++;
-               count--;
-       }
-finish:
-       pos *= sizeof(reg);
-       count *= sizeof(reg);
-
-       return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
-                                        38 * sizeof(reg), -1);
-}
-
-static int fpregs32_get(struct task_struct *target,
-                       const struct user_regset *regset,
-                       unsigned int pos, unsigned int count,
-                       void *kbuf, void __user *ubuf)
-{
-       const unsigned long *fpregs = target->thread.float_regs;
-       int ret = 0;
-
-#if 0
-       if (target == current)
-               save_and_clear_fpu();
-#endif
-
-       ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
-                                 fpregs,
-                                 0, 32 * sizeof(u32));
-
-       if (!ret)
-               ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
-                                              32 * sizeof(u32),
-                                              33 * sizeof(u32));
-       if (!ret)
-               ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
-                                         &target->thread.fsr,
-                                         33 * sizeof(u32),
-                                         34 * sizeof(u32));
-
-       if (!ret) {
-               unsigned long val;
-
-               val = (1 << 8) | (8 << 16);
-               ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
-                                         &val,
-                                         34 * sizeof(u32),
-                                         35 * sizeof(u32));
-       }
-
-       if (!ret)
-               ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
-                                              35 * sizeof(u32), -1);
-
-       return ret;
-}
-
-static int fpregs32_set(struct task_struct *target,
-                       const struct user_regset *regset,
-                       unsigned int pos, unsigned int count,
-                       const void *kbuf, const void __user *ubuf)
-{
-       unsigned long *fpregs = target->thread.float_regs;
-       int ret;
-
-#if 0
-       if (target == current)
-               save_and_clear_fpu();
-#endif
-       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
-                                fpregs,
-                                0, 32 * sizeof(u32));
-       if (!ret)
-               user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
-                                         32 * sizeof(u32),
-                                         33 * sizeof(u32));
-       if (!ret && count > 0) {
-               ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
-                                        &target->thread.fsr,
-                                        33 * sizeof(u32),
-                                        34 * sizeof(u32));
-       }
-
-       if (!ret)
-               ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
-                                               34 * sizeof(u32), -1);
-       return ret;
-}
-
-static const struct user_regset sparc32_regsets[] = {
-       /* Format is:
-        *      G0 --> G7
-        *      O0 --> O7
-        *      L0 --> L7
-        *      I0 --> I7
-        *      PSR, PC, nPC, Y, WIM, TBR
-        */
-       [REGSET_GENERAL] = {
-               .core_note_type = NT_PRSTATUS,
-               .n = 38,
-               .size = sizeof(u32), .align = sizeof(u32),
-               .get = genregs32_get, .set = genregs32_set
-       },
-       /* Format is:
-        *      F0 --> F31
-        *      empty 32-bit word
-        *      FSR (32--bit word)
-        *      FPU QUEUE COUNT (8-bit char)
-        *      FPU QUEUE ENTRYSIZE (8-bit char)
-        *      FPU ENABLED (8-bit char)
-        *      empty 8-bit char
-        *      FPU QUEUE (64 32-bit ints)
-        */
-       [REGSET_FP] = {
-               .core_note_type = NT_PRFPREG,
-               .n = 99,
-               .size = sizeof(u32), .align = sizeof(u32),
-               .get = fpregs32_get, .set = fpregs32_set
-       },
-};
-
-static const struct user_regset_view user_sparc32_view = {
-       .name = "sparc", .e_machine = EM_SPARC,
-       .regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets)
-};
-
-const struct user_regset_view *task_user_regset_view(struct task_struct *task)
-{
-       return &user_sparc32_view;
-}
-
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
-{
-       unsigned long addr2 = current->thread.kregs->u_regs[UREG_I4];
-       const struct user_regset_view *view;
-       int ret;
-
-       view = task_user_regset_view(current);
-
-       switch(request) {
-       case PTRACE_GETREGS: {
-               struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
-
-               ret = copy_regset_to_user(child, view, REGSET_GENERAL,
-                                         32 * sizeof(u32),
-                                         4 * sizeof(u32),
-                                         &pregs->psr);
-               if (!ret)
-                       copy_regset_to_user(child, view, REGSET_GENERAL,
-                                           1 * sizeof(u32),
-                                           15 * sizeof(u32),
-                                           &pregs->u_regs[0]);
-               break;
-       }
-
-       case PTRACE_SETREGS: {
-               struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
-
-               ret = copy_regset_from_user(child, view, REGSET_GENERAL,
-                                           32 * sizeof(u32),
-                                           4 * sizeof(u32),
-                                           &pregs->psr);
-               if (!ret)
-                       copy_regset_from_user(child, view, REGSET_GENERAL,
-                                             1 * sizeof(u32),
-                                             15 * sizeof(u32),
-                                             &pregs->u_regs[0]);
-               break;
-       }
-
-       case PTRACE_GETFPREGS: {
-               struct fps {
-                       unsigned long regs[32];
-                       unsigned long fsr;
-                       unsigned long flags;
-                       unsigned long extra;
-                       unsigned long fpqd;
-                       struct fq {
-                               unsigned long *insnaddr;
-                               unsigned long insn;
-                       } fpq[16];
-               };
-               struct fps __user *fps = (struct fps __user *) addr;
-
-               ret = copy_regset_to_user(child, view, REGSET_FP,
-                                         0 * sizeof(u32),
-                                         32 * sizeof(u32),
-                                         &fps->regs[0]);
-               if (!ret)
-                       ret = copy_regset_to_user(child, view, REGSET_FP,
-                                                 33 * sizeof(u32),
-                                                 1 * sizeof(u32),
-                                                 &fps->fsr);
-
-               if (!ret) {
-                       if (__put_user(0, &fps->fpqd) ||
-                           __put_user(0, &fps->flags) ||
-                           __put_user(0, &fps->extra) ||
-                           clear_user(fps->fpq, sizeof(fps->fpq)))
-                               ret = -EFAULT;
-               }
-               break;
-       }
-
-       case PTRACE_SETFPREGS: {
-               struct fps {
-                       unsigned long regs[32];
-                       unsigned long fsr;
-                       unsigned long flags;
-                       unsigned long extra;
-                       unsigned long fpqd;
-                       struct fq {
-                               unsigned long *insnaddr;
-                               unsigned long insn;
-                       } fpq[16];
-               };
-               struct fps __user *fps = (struct fps __user *) addr;
-
-               ret = copy_regset_from_user(child, view, REGSET_FP,
-                                           0 * sizeof(u32),
-                                           32 * sizeof(u32),
-                                           &fps->regs[0]);
-               if (!ret)
-                       ret = copy_regset_from_user(child, view, REGSET_FP,
-                                                   33 * sizeof(u32),
-                                                   1 * sizeof(u32),
-                                                   &fps->fsr);
-               break;
-       }
-
-       case PTRACE_READTEXT:
-       case PTRACE_READDATA:
-               ret = ptrace_readdata(child, addr,
-                                     (void __user *) addr2, data);
-
-               if (ret == data)
-                       ret = 0;
-               else if (ret >= 0)
-                       ret = -EIO;
-               break;
-
-       case PTRACE_WRITETEXT:
-       case PTRACE_WRITEDATA:
-               ret = ptrace_writedata(child, (void __user *) addr2,
-                                      addr, data);
-
-               if (ret == data)
-                       ret = 0;
-               else if (ret >= 0)
-                       ret = -EIO;
-               break;
-
-       default:
-               if (request == PTRACE_SPARC_DETACH)
-                       request = PTRACE_DETACH;
-               ret = ptrace_request(child, request, addr, data);
-               break;
-       }
-
-       return ret;
-}
-
-asmlinkage int syscall_trace(struct pt_regs *regs, int syscall_exit_p)
-{
-       int ret = 0;
-
-       if (test_thread_flag(TIF_SYSCALL_TRACE)) {
-               if (syscall_exit_p)
-                       tracehook_report_syscall_exit(regs, 0);
-               else
-                       ret = tracehook_report_syscall_entry(regs);
-       }
-
-       return ret;
-}
diff --git a/arch/sparc/kernel/ptrace_32.c b/arch/sparc/kernel/ptrace_32.c
new file mode 100644 (file)
index 0000000..8ce6285
--- /dev/null
@@ -0,0 +1,466 @@
+/* ptrace.c: Sparc process tracing support.
+ *
+ * Copyright (C) 1996, 2008 David S. Miller (davem@davemloft.net)
+ *
+ * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson,
+ * and David Mosberger.
+ *
+ * Added Linux support -miguel (weird, eh?, the original code was meant
+ * to emulate SunOS).
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/security.h>
+#include <linux/signal.h>
+#include <linux/regset.h>
+#include <linux/elf.h>
+#include <linux/tracehook.h>
+
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+/* #define ALLOW_INIT_TRACING */
+
+/*
+ * Called by kernel/ptrace.c when detaching..
+ *
+ * Make sure single step bits etc are not set.
+ */
+void ptrace_disable(struct task_struct *child)
+{
+       /* nothing to do */
+}
+
+enum sparc_regset {
+       REGSET_GENERAL,
+       REGSET_FP,
+};
+
+static int genregs32_get(struct task_struct *target,
+                        const struct user_regset *regset,
+                        unsigned int pos, unsigned int count,
+                        void *kbuf, void __user *ubuf)
+{
+       const struct pt_regs *regs = target->thread.kregs;
+       unsigned long __user *reg_window;
+       unsigned long *k = kbuf;
+       unsigned long __user *u = ubuf;
+       unsigned long reg;
+
+       if (target == current)
+               flush_user_windows();
+
+       pos /= sizeof(reg);
+       count /= sizeof(reg);
+
+       if (kbuf) {
+               for (; count > 0 && pos < 16; count--)
+                       *k++ = regs->u_regs[pos++];
+
+               reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
+               for (; count > 0 && pos < 32; count--) {
+                       if (get_user(*k++, &reg_window[pos++]))
+                               return -EFAULT;
+               }
+       } else {
+               for (; count > 0 && pos < 16; count--) {
+                       if (put_user(regs->u_regs[pos++], u++))
+                               return -EFAULT;
+               }
+
+               reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
+               for (; count > 0 && pos < 32; count--) {
+                       if (get_user(reg, &reg_window[pos++]) ||
+                           put_user(reg, u++))
+                               return -EFAULT;
+               }
+       }
+       while (count > 0) {
+               switch (pos) {
+               case 32: /* PSR */
+                       reg = regs->psr;
+                       break;
+               case 33: /* PC */
+                       reg = regs->pc;
+                       break;
+               case 34: /* NPC */
+                       reg = regs->npc;
+                       break;
+               case 35: /* Y */
+                       reg = regs->y;
+                       break;
+               case 36: /* WIM */
+               case 37: /* TBR */
+                       reg = 0;
+                       break;
+               default:
+                       goto finish;
+               }
+
+               if (kbuf)
+                       *k++ = reg;
+               else if (put_user(reg, u++))
+                       return -EFAULT;
+               pos++;
+               count--;
+       }
+finish:
+       pos *= sizeof(reg);
+       count *= sizeof(reg);
+
+       return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
+                                       38 * sizeof(reg), -1);
+}
+
+static int genregs32_set(struct task_struct *target,
+                        const struct user_regset *regset,
+                        unsigned int pos, unsigned int count,
+                        const void *kbuf, const void __user *ubuf)
+{
+       struct pt_regs *regs = target->thread.kregs;
+       unsigned long __user *reg_window;
+       const unsigned long *k = kbuf;
+       const unsigned long __user *u = ubuf;
+       unsigned long reg;
+
+       if (target == current)
+               flush_user_windows();
+
+       pos /= sizeof(reg);
+       count /= sizeof(reg);
+
+       if (kbuf) {
+               for (; count > 0 && pos < 16; count--)
+                       regs->u_regs[pos++] = *k++;
+
+               reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
+               for (; count > 0 && pos < 32; count--) {
+                       if (put_user(*k++, &reg_window[pos++]))
+                               return -EFAULT;
+               }
+       } else {
+               for (; count > 0 && pos < 16; count--) {
+                       if (get_user(reg, u++))
+                               return -EFAULT;
+                       regs->u_regs[pos++] = reg;
+               }
+
+               reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
+               for (; count > 0 && pos < 32; count--) {
+                       if (get_user(reg, u++) ||
+                           put_user(reg, &reg_window[pos++]))
+                               return -EFAULT;
+               }
+       }
+       while (count > 0) {
+               unsigned long psr;
+
+               if (kbuf)
+                       reg = *k++;
+               else if (get_user(reg, u++))
+                       return -EFAULT;
+
+               switch (pos) {
+               case 32: /* PSR */
+                       psr = regs->psr;
+                       psr &= ~(PSR_ICC | PSR_SYSCALL);
+                       psr |= (reg & (PSR_ICC | PSR_SYSCALL));
+                       regs->psr = psr;
+                       break;
+               case 33: /* PC */
+                       regs->pc = reg;
+                       break;
+               case 34: /* NPC */
+                       regs->npc = reg;
+                       break;
+               case 35: /* Y */
+                       regs->y = reg;
+                       break;
+               case 36: /* WIM */
+               case 37: /* TBR */
+                       break;
+               default:
+                       goto finish;
+               }
+
+               pos++;
+               count--;
+       }
+finish:
+       pos *= sizeof(reg);
+       count *= sizeof(reg);
+
+       return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+                                        38 * sizeof(reg), -1);
+}
+
+static int fpregs32_get(struct task_struct *target,
+                       const struct user_regset *regset,
+                       unsigned int pos, unsigned int count,
+                       void *kbuf, void __user *ubuf)
+{
+       const unsigned long *fpregs = target->thread.float_regs;
+       int ret = 0;
+
+#if 0
+       if (target == current)
+               save_and_clear_fpu();
+#endif
+
+       ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                 fpregs,
+                                 0, 32 * sizeof(u32));
+
+       if (!ret)
+               ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
+                                              32 * sizeof(u32),
+                                              33 * sizeof(u32));
+       if (!ret)
+               ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                         &target->thread.fsr,
+                                         33 * sizeof(u32),
+                                         34 * sizeof(u32));
+
+       if (!ret) {
+               unsigned long val;
+
+               val = (1 << 8) | (8 << 16);
+               ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                         &val,
+                                         34 * sizeof(u32),
+                                         35 * sizeof(u32));
+       }
+
+       if (!ret)
+               ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
+                                              35 * sizeof(u32), -1);
+
+       return ret;
+}
+
+static int fpregs32_set(struct task_struct *target,
+                       const struct user_regset *regset,
+                       unsigned int pos, unsigned int count,
+                       const void *kbuf, const void __user *ubuf)
+{
+       unsigned long *fpregs = target->thread.float_regs;
+       int ret;
+
+#if 0
+       if (target == current)
+               save_and_clear_fpu();
+#endif
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                fpregs,
+                                0, 32 * sizeof(u32));
+       if (!ret)
+               user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+                                         32 * sizeof(u32),
+                                         33 * sizeof(u32));
+       if (!ret && count > 0) {
+               ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                        &target->thread.fsr,
+                                        33 * sizeof(u32),
+                                        34 * sizeof(u32));
+       }
+
+       if (!ret)
+               ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+                                               34 * sizeof(u32), -1);
+       return ret;
+}
+
+static const struct user_regset sparc32_regsets[] = {
+       /* Format is:
+        *      G0 --> G7
+        *      O0 --> O7
+        *      L0 --> L7
+        *      I0 --> I7
+        *      PSR, PC, nPC, Y, WIM, TBR
+        */
+       [REGSET_GENERAL] = {
+               .core_note_type = NT_PRSTATUS,
+               .n = 38,
+               .size = sizeof(u32), .align = sizeof(u32),
+               .get = genregs32_get, .set = genregs32_set
+       },
+       /* Format is:
+        *      F0 --> F31
+        *      empty 32-bit word
+        *      FSR (32--bit word)
+        *      FPU QUEUE COUNT (8-bit char)
+        *      FPU QUEUE ENTRYSIZE (8-bit char)
+        *      FPU ENABLED (8-bit char)
+        *      empty 8-bit char
+        *      FPU QUEUE (64 32-bit ints)
+        */
+       [REGSET_FP] = {
+               .core_note_type = NT_PRFPREG,
+               .n = 99,
+               .size = sizeof(u32), .align = sizeof(u32),
+               .get = fpregs32_get, .set = fpregs32_set
+       },
+};
+
+static const struct user_regset_view user_sparc32_view = {
+       .name = "sparc", .e_machine = EM_SPARC,
+       .regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets)
+};
+
+const struct user_regset_view *task_user_regset_view(struct task_struct *task)
+{
+       return &user_sparc32_view;
+}
+
+long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+{
+       unsigned long addr2 = current->thread.kregs->u_regs[UREG_I4];
+       const struct user_regset_view *view;
+       int ret;
+
+       view = task_user_regset_view(current);
+
+       switch(request) {
+       case PTRACE_GETREGS: {
+               struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
+
+               ret = copy_regset_to_user(child, view, REGSET_GENERAL,
+                                         32 * sizeof(u32),
+                                         4 * sizeof(u32),
+                                         &pregs->psr);
+               if (!ret)
+                       copy_regset_to_user(child, view, REGSET_GENERAL,
+                                           1 * sizeof(u32),
+                                           15 * sizeof(u32),
+                                           &pregs->u_regs[0]);
+               break;
+       }
+
+       case PTRACE_SETREGS: {
+               struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
+
+               ret = copy_regset_from_user(child, view, REGSET_GENERAL,
+                                           32 * sizeof(u32),
+                                           4 * sizeof(u32),
+                                           &pregs->psr);
+               if (!ret)
+                       copy_regset_from_user(child, view, REGSET_GENERAL,
+                                             1 * sizeof(u32),
+                                             15 * sizeof(u32),
+                                             &pregs->u_regs[0]);
+               break;
+       }
+
+       case PTRACE_GETFPREGS: {
+               struct fps {
+                       unsigned long regs[32];
+                       unsigned long fsr;
+                       unsigned long flags;
+                       unsigned long extra;
+                       unsigned long fpqd;
+                       struct fq {
+                               unsigned long *insnaddr;
+                               unsigned long insn;
+                       } fpq[16];
+               };
+               struct fps __user *fps = (struct fps __user *) addr;
+
+               ret = copy_regset_to_user(child, view, REGSET_FP,
+                                         0 * sizeof(u32),
+                                         32 * sizeof(u32),
+                                         &fps->regs[0]);
+               if (!ret)
+                       ret = copy_regset_to_user(child, view, REGSET_FP,
+                                                 33 * sizeof(u32),
+                                                 1 * sizeof(u32),
+                                                 &fps->fsr);
+
+               if (!ret) {
+                       if (__put_user(0, &fps->fpqd) ||
+                           __put_user(0, &fps->flags) ||
+                           __put_user(0, &fps->extra) ||
+                           clear_user(fps->fpq, sizeof(fps->fpq)))
+                               ret = -EFAULT;
+               }
+               break;
+       }
+
+       case PTRACE_SETFPREGS: {
+               struct fps {
+                       unsigned long regs[32];
+                       unsigned long fsr;
+                       unsigned long flags;
+                       unsigned long extra;
+                       unsigned long fpqd;
+                       struct fq {
+                               unsigned long *insnaddr;
+                               unsigned long insn;
+                       } fpq[16];
+               };
+               struct fps __user *fps = (struct fps __user *) addr;
+
+               ret = copy_regset_from_user(child, view, REGSET_FP,
+                                           0 * sizeof(u32),
+                                           32 * sizeof(u32),
+                                           &fps->regs[0]);
+               if (!ret)
+                       ret = copy_regset_from_user(child, view, REGSET_FP,
+                                                   33 * sizeof(u32),
+                                                   1 * sizeof(u32),
+                                                   &fps->fsr);
+               break;
+       }
+
+       case PTRACE_READTEXT:
+       case PTRACE_READDATA:
+               ret = ptrace_readdata(child, addr,
+                                     (void __user *) addr2, data);
+
+               if (ret == data)
+                       ret = 0;
+               else if (ret >= 0)
+                       ret = -EIO;
+               break;
+
+       case PTRACE_WRITETEXT:
+       case PTRACE_WRITEDATA:
+               ret = ptrace_writedata(child, (void __user *) addr2,
+                                      addr, data);
+
+               if (ret == data)
+                       ret = 0;
+               else if (ret >= 0)
+                       ret = -EIO;
+               break;
+
+       default:
+               if (request == PTRACE_SPARC_DETACH)
+                       request = PTRACE_DETACH;
+               ret = ptrace_request(child, request, addr, data);
+               break;
+       }
+
+       return ret;
+}
+
+asmlinkage int syscall_trace(struct pt_regs *regs, int syscall_exit_p)
+{
+       int ret = 0;
+
+       if (test_thread_flag(TIF_SYSCALL_TRACE)) {
+               if (syscall_exit_p)
+                       tracehook_report_syscall_exit(regs, 0);
+               else
+                       ret = tracehook_report_syscall_entry(regs);
+       }
+
+       return ret;
+}
diff --git a/arch/sparc/kernel/rtrap.S b/arch/sparc/kernel/rtrap.S
deleted file mode 100644 (file)
index 4da2e1f..0000000
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
- * rtrap.S: Return from Sparc trap low-level code.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <asm/page.h>
-#include <asm/ptrace.h>
-#include <asm/psr.h>
-#include <asm/asi.h>
-#include <asm/smp.h>
-#include <asm/contregs.h>
-#include <asm/winmacro.h>
-#include <asm/asmmacro.h>
-#include <asm/thread_info.h>
-
-#define t_psr     l0
-#define t_pc      l1
-#define t_npc     l2
-#define t_wim     l3
-#define twin_tmp1 l4
-#define glob_tmp  g4
-#define curptr    g6
-
-       /* 7 WINDOW SPARC PATCH INSTRUCTIONS */
-       .globl  rtrap_7win_patch1, rtrap_7win_patch2, rtrap_7win_patch3
-       .globl  rtrap_7win_patch4, rtrap_7win_patch5
-rtrap_7win_patch1:     srl     %t_wim, 0x6, %glob_tmp
-rtrap_7win_patch2:     and     %glob_tmp, 0x7f, %glob_tmp
-rtrap_7win_patch3:     srl     %g1, 7, %g2
-rtrap_7win_patch4:     srl     %g2, 6, %g2
-rtrap_7win_patch5:     and     %g1, 0x7f, %g1
-       /* END OF PATCH INSTRUCTIONS */
-
-       /* We need to check for a few things which are:
-        * 1) The need to call schedule() because this
-        *    processes quantum is up.
-        * 2) Pending signals for this process, if any
-        *    exist we need to call do_signal() to do
-        *    the needy.
-        *
-        * Else we just check if the rett would land us
-        * in an invalid window, if so we need to grab
-        * it off the user/kernel stack first.
-        */
-
-       .globl  ret_trap_entry, rtrap_patch1, rtrap_patch2
-       .globl  rtrap_patch3, rtrap_patch4, rtrap_patch5
-       .globl  ret_trap_lockless_ipi
-ret_trap_entry:
-ret_trap_lockless_ipi:
-       andcc   %t_psr, PSR_PS, %g0
-       sethi   %hi(PSR_SYSCALL), %g1
-       be      1f
-        andn   %t_psr, %g1, %t_psr
-
-       wr      %t_psr, 0x0, %psr
-       b       ret_trap_kernel
-        nop
-
-1:
-       ld      [%curptr + TI_FLAGS], %g2
-       andcc   %g2, (_TIF_NEED_RESCHED), %g0
-       be      signal_p
-        nop
-
-       call    schedule
-        nop
-
-       ld      [%curptr + TI_FLAGS], %g2
-signal_p:
-       andcc   %g2, _TIF_DO_NOTIFY_RESUME_MASK, %g0
-       bz,a    ret_trap_continue
-        ld     [%sp + STACKFRAME_SZ + PT_PSR], %t_psr
-
-       mov     %g2, %o2
-       mov     %l5, %o1
-       call    do_notify_resume
-        add    %sp, STACKFRAME_SZ, %o0 ! pt_regs ptr
-
-       /* Fall through. */
-       ld      [%sp + STACKFRAME_SZ + PT_PSR], %t_psr
-       clr     %l6
-ret_trap_continue:
-       sethi   %hi(PSR_SYSCALL), %g1
-       andn    %t_psr, %g1, %t_psr
-       wr      %t_psr, 0x0, %psr
-       WRITE_PAUSE
-
-       ld      [%curptr + TI_W_SAVED], %twin_tmp1
-       orcc    %g0, %twin_tmp1, %g0
-       be      ret_trap_nobufwins
-        nop
-
-       wr      %t_psr, PSR_ET, %psr
-       WRITE_PAUSE
-
-       mov     1, %o1
-       call    try_to_clear_window_buffer
-        add    %sp, STACKFRAME_SZ, %o0
-
-       b       signal_p
-        ld     [%curptr + TI_FLAGS], %g2
-
-ret_trap_nobufwins:
-       /* Load up the user's out registers so we can pull
-        * a window from the stack, if necessary.
-        */
-       LOAD_PT_INS(sp)
-
-       /* If there are already live user windows in the
-        * set we can return from trap safely.
-        */
-       ld      [%curptr + TI_UWINMASK], %twin_tmp1
-       orcc    %g0, %twin_tmp1, %g0
-       bne     ret_trap_userwins_ok
-        nop
-
-               /* Calculate new %wim, we have to pull a register
-                * window from the users stack.
-                */
-ret_trap_pull_one_window:
-               rd      %wim, %t_wim
-               sll     %t_wim, 0x1, %twin_tmp1
-rtrap_patch1:  srl     %t_wim, 0x7, %glob_tmp
-               or      %glob_tmp, %twin_tmp1, %glob_tmp
-rtrap_patch2:  and     %glob_tmp, 0xff, %glob_tmp
-
-               wr      %glob_tmp, 0x0, %wim
-
-                               /* Here comes the architecture specific 
-                                * branch to the user stack checking routine
-                                * for return from traps.
-                                */
-                               .globl  rtrap_mmu_patchme
-rtrap_mmu_patchme:     b       sun4c_rett_stackchk
-                                andcc  %fp, 0x7, %g0   
-
-ret_trap_userwins_ok:
-       LOAD_PT_PRIV(sp, t_psr, t_pc, t_npc)
-       or      %t_pc, %t_npc, %g2
-       andcc   %g2, 0x3, %g0
-       sethi   %hi(PSR_SYSCALL), %g2
-       be      1f
-        andn   %t_psr, %g2, %t_psr
-
-       b       ret_trap_unaligned_pc
-        add    %sp, STACKFRAME_SZ, %o0
-
-1:
-       LOAD_PT_YREG(sp, g1)
-       LOAD_PT_GLOBALS(sp)
-
-       wr      %t_psr, 0x0, %psr
-       WRITE_PAUSE
-
-       jmp     %t_pc
-       rett    %t_npc
-       
-ret_trap_unaligned_pc:
-       ld      [%sp + STACKFRAME_SZ + PT_PC], %o1
-       ld      [%sp + STACKFRAME_SZ + PT_NPC], %o2
-       ld      [%sp + STACKFRAME_SZ + PT_PSR], %o3
-
-       wr      %t_wim, 0x0, %wim               ! or else...
-
-       wr      %t_psr, PSR_ET, %psr
-       WRITE_PAUSE
-
-       call    do_memaccess_unaligned
-        nop
-
-       b       signal_p
-        ld     [%curptr + TI_FLAGS], %g2
-
-ret_trap_kernel:
-               /* Will the rett land us in the invalid window? */
-               mov     2, %g1
-               sll     %g1, %t_psr, %g1
-rtrap_patch3:  srl     %g1, 8, %g2
-               or      %g1, %g2, %g1
-               rd      %wim, %g2
-               andcc   %g2, %g1, %g0
-               be      1f              ! Nope, just return from the trap
-                sll    %g2, 0x1, %g1
-
-               /* We have to grab a window before returning. */
-rtrap_patch4:  srl     %g2, 7,  %g2
-               or      %g1, %g2, %g1
-rtrap_patch5:  and     %g1, 0xff, %g1
-
-       wr      %g1, 0x0, %wim
-
-       /* Grrr, make sure we load from the right %sp... */
-       LOAD_PT_ALL(sp, t_psr, t_pc, t_npc, g1)
-
-       restore %g0, %g0, %g0
-       LOAD_WINDOW(sp)
-       b       2f
-        save   %g0, %g0, %g0
-
-       /* Reload the entire frame in case this is from a
-        * kernel system call or whatever...
-        */
-1:
-       LOAD_PT_ALL(sp, t_psr, t_pc, t_npc, g1)
-2:
-       sethi   %hi(PSR_SYSCALL), %twin_tmp1
-       andn    %t_psr, %twin_tmp1, %t_psr
-       wr      %t_psr, 0x0, %psr
-       WRITE_PAUSE
-
-       jmp     %t_pc
-       rett    %t_npc
-
-ret_trap_user_stack_is_bolixed:
-       wr      %t_wim, 0x0, %wim
-
-       wr      %t_psr, PSR_ET, %psr
-       WRITE_PAUSE
-
-       call    window_ret_fault
-        add    %sp, STACKFRAME_SZ, %o0
-
-       b       signal_p
-        ld     [%curptr + TI_FLAGS], %g2
-
-sun4c_rett_stackchk:
-       be      1f
-        and    %fp, 0xfff, %g1         ! delay slot
-
-       b       ret_trap_user_stack_is_bolixed + 0x4
-        wr     %t_wim, 0x0, %wim
-
-       /* See if we have to check the sanity of one page or two */
-1:
-       add     %g1, 0x38, %g1
-       sra     %fp, 29, %g2
-       add     %g2, 0x1, %g2
-       andncc  %g2, 0x1, %g0
-       be      1f
-        andncc %g1, 0xff8, %g0
-
-       /* %sp is in vma hole, yuck */
-       b       ret_trap_user_stack_is_bolixed + 0x4
-        wr     %t_wim, 0x0, %wim
-
-1:
-       be      sun4c_rett_onepage      /* Only one page to check */
-        lda    [%fp] ASI_PTE, %g2
-
-sun4c_rett_twopages:
-       add     %fp, 0x38, %g1
-       sra     %g1, 29, %g2
-       add     %g2, 0x1, %g2
-       andncc  %g2, 0x1, %g0
-       be      1f
-        lda    [%g1] ASI_PTE, %g2
-
-       /* Second page is in vma hole */
-       b       ret_trap_user_stack_is_bolixed + 0x4
-        wr     %t_wim, 0x0, %wim
-
-1:
-       srl     %g2, 29, %g2
-       andcc   %g2, 0x4, %g0
-       bne     sun4c_rett_onepage
-        lda    [%fp] ASI_PTE, %g2
-
-       /* Second page has bad perms */
-       b       ret_trap_user_stack_is_bolixed + 0x4
-        wr     %t_wim, 0x0, %wim
-
-sun4c_rett_onepage:
-       srl     %g2, 29, %g2
-       andcc   %g2, 0x4, %g0
-       bne,a   1f
-        restore %g0, %g0, %g0
-
-       /* A page had bad page permissions, losing... */
-       b       ret_trap_user_stack_is_bolixed + 0x4
-        wr     %t_wim, 0x0, %wim
-
-       /* Whee, things are ok, load the window and continue. */
-1:
-       LOAD_WINDOW(sp)
-
-       b       ret_trap_userwins_ok
-        save   %g0, %g0, %g0
-
-       .globl  srmmu_rett_stackchk
-srmmu_rett_stackchk:
-       bne     ret_trap_user_stack_is_bolixed
-        sethi   %hi(PAGE_OFFSET), %g1
-       cmp     %g1, %fp
-       bleu    ret_trap_user_stack_is_bolixed
-        mov    AC_M_SFSR, %g1
-       lda     [%g1] ASI_M_MMUREGS, %g0
-
-       lda     [%g0] ASI_M_MMUREGS, %g1
-       or      %g1, 0x2, %g1
-       sta     %g1, [%g0] ASI_M_MMUREGS
-
-       restore %g0, %g0, %g0
-
-       LOAD_WINDOW(sp)
-
-       save    %g0, %g0, %g0
-
-       andn    %g1, 0x2, %g1
-       sta     %g1, [%g0] ASI_M_MMUREGS
-
-       mov     AC_M_SFAR, %g2
-       lda     [%g2] ASI_M_MMUREGS, %g2
-
-       mov     AC_M_SFSR, %g1
-       lda     [%g1] ASI_M_MMUREGS, %g1
-       andcc   %g1, 0x2, %g0
-       be      ret_trap_userwins_ok
-        nop
-
-       b,a     ret_trap_user_stack_is_bolixed
diff --git a/arch/sparc/kernel/rtrap_32.S b/arch/sparc/kernel/rtrap_32.S
new file mode 100644 (file)
index 0000000..4da2e1f
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+ * rtrap.S: Return from Sparc trap low-level code.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/page.h>
+#include <asm/ptrace.h>
+#include <asm/psr.h>
+#include <asm/asi.h>
+#include <asm/smp.h>
+#include <asm/contregs.h>
+#include <asm/winmacro.h>
+#include <asm/asmmacro.h>
+#include <asm/thread_info.h>
+
+#define t_psr     l0
+#define t_pc      l1
+#define t_npc     l2
+#define t_wim     l3
+#define twin_tmp1 l4
+#define glob_tmp  g4
+#define curptr    g6
+
+       /* 7 WINDOW SPARC PATCH INSTRUCTIONS */
+       .globl  rtrap_7win_patch1, rtrap_7win_patch2, rtrap_7win_patch3
+       .globl  rtrap_7win_patch4, rtrap_7win_patch5
+rtrap_7win_patch1:     srl     %t_wim, 0x6, %glob_tmp
+rtrap_7win_patch2:     and     %glob_tmp, 0x7f, %glob_tmp
+rtrap_7win_patch3:     srl     %g1, 7, %g2
+rtrap_7win_patch4:     srl     %g2, 6, %g2
+rtrap_7win_patch5:     and     %g1, 0x7f, %g1
+       /* END OF PATCH INSTRUCTIONS */
+
+       /* We need to check for a few things which are:
+        * 1) The need to call schedule() because this
+        *    processes quantum is up.
+        * 2) Pending signals for this process, if any
+        *    exist we need to call do_signal() to do
+        *    the needy.
+        *
+        * Else we just check if the rett would land us
+        * in an invalid window, if so we need to grab
+        * it off the user/kernel stack first.
+        */
+
+       .globl  ret_trap_entry, rtrap_patch1, rtrap_patch2
+       .globl  rtrap_patch3, rtrap_patch4, rtrap_patch5
+       .globl  ret_trap_lockless_ipi
+ret_trap_entry:
+ret_trap_lockless_ipi:
+       andcc   %t_psr, PSR_PS, %g0
+       sethi   %hi(PSR_SYSCALL), %g1
+       be      1f
+        andn   %t_psr, %g1, %t_psr
+
+       wr      %t_psr, 0x0, %psr
+       b       ret_trap_kernel
+        nop
+
+1:
+       ld      [%curptr + TI_FLAGS], %g2
+       andcc   %g2, (_TIF_NEED_RESCHED), %g0
+       be      signal_p
+        nop
+
+       call    schedule
+        nop
+
+       ld      [%curptr + TI_FLAGS], %g2
+signal_p:
+       andcc   %g2, _TIF_DO_NOTIFY_RESUME_MASK, %g0
+       bz,a    ret_trap_continue
+        ld     [%sp + STACKFRAME_SZ + PT_PSR], %t_psr
+
+       mov     %g2, %o2
+       mov     %l5, %o1
+       call    do_notify_resume
+        add    %sp, STACKFRAME_SZ, %o0 ! pt_regs ptr
+
+       /* Fall through. */
+       ld      [%sp + STACKFRAME_SZ + PT_PSR], %t_psr
+       clr     %l6
+ret_trap_continue:
+       sethi   %hi(PSR_SYSCALL), %g1
+       andn    %t_psr, %g1, %t_psr
+       wr      %t_psr, 0x0, %psr
+       WRITE_PAUSE
+
+       ld      [%curptr + TI_W_SAVED], %twin_tmp1
+       orcc    %g0, %twin_tmp1, %g0
+       be      ret_trap_nobufwins
+        nop
+
+       wr      %t_psr, PSR_ET, %psr
+       WRITE_PAUSE
+
+       mov     1, %o1
+       call    try_to_clear_window_buffer
+        add    %sp, STACKFRAME_SZ, %o0
+
+       b       signal_p
+        ld     [%curptr + TI_FLAGS], %g2
+
+ret_trap_nobufwins:
+       /* Load up the user's out registers so we can pull
+        * a window from the stack, if necessary.
+        */
+       LOAD_PT_INS(sp)
+
+       /* If there are already live user windows in the
+        * set we can return from trap safely.
+        */
+       ld      [%curptr + TI_UWINMASK], %twin_tmp1
+       orcc    %g0, %twin_tmp1, %g0
+       bne     ret_trap_userwins_ok
+        nop
+
+               /* Calculate new %wim, we have to pull a register
+                * window from the users stack.
+                */
+ret_trap_pull_one_window:
+               rd      %wim, %t_wim
+               sll     %t_wim, 0x1, %twin_tmp1
+rtrap_patch1:  srl     %t_wim, 0x7, %glob_tmp
+               or      %glob_tmp, %twin_tmp1, %glob_tmp
+rtrap_patch2:  and     %glob_tmp, 0xff, %glob_tmp
+
+               wr      %glob_tmp, 0x0, %wim
+
+                               /* Here comes the architecture specific 
+                                * branch to the user stack checking routine
+                                * for return from traps.
+                                */
+                               .globl  rtrap_mmu_patchme
+rtrap_mmu_patchme:     b       sun4c_rett_stackchk
+                                andcc  %fp, 0x7, %g0   
+
+ret_trap_userwins_ok:
+       LOAD_PT_PRIV(sp, t_psr, t_pc, t_npc)
+       or      %t_pc, %t_npc, %g2
+       andcc   %g2, 0x3, %g0
+       sethi   %hi(PSR_SYSCALL), %g2
+       be      1f
+        andn   %t_psr, %g2, %t_psr
+
+       b       ret_trap_unaligned_pc
+        add    %sp, STACKFRAME_SZ, %o0
+
+1:
+       LOAD_PT_YREG(sp, g1)
+       LOAD_PT_GLOBALS(sp)
+
+       wr      %t_psr, 0x0, %psr
+       WRITE_PAUSE
+
+       jmp     %t_pc
+       rett    %t_npc
+       
+ret_trap_unaligned_pc:
+       ld      [%sp + STACKFRAME_SZ + PT_PC], %o1
+       ld      [%sp + STACKFRAME_SZ + PT_NPC], %o2
+       ld      [%sp + STACKFRAME_SZ + PT_PSR], %o3
+
+       wr      %t_wim, 0x0, %wim               ! or else...
+
+       wr      %t_psr, PSR_ET, %psr
+       WRITE_PAUSE
+
+       call    do_memaccess_unaligned
+        nop
+
+       b       signal_p
+        ld     [%curptr + TI_FLAGS], %g2
+
+ret_trap_kernel:
+               /* Will the rett land us in the invalid window? */
+               mov     2, %g1
+               sll     %g1, %t_psr, %g1
+rtrap_patch3:  srl     %g1, 8, %g2
+               or      %g1, %g2, %g1
+               rd      %wim, %g2
+               andcc   %g2, %g1, %g0
+               be      1f              ! Nope, just return from the trap
+                sll    %g2, 0x1, %g1
+
+               /* We have to grab a window before returning. */
+rtrap_patch4:  srl     %g2, 7,  %g2
+               or      %g1, %g2, %g1
+rtrap_patch5:  and     %g1, 0xff, %g1
+
+       wr      %g1, 0x0, %wim
+
+       /* Grrr, make sure we load from the right %sp... */
+       LOAD_PT_ALL(sp, t_psr, t_pc, t_npc, g1)
+
+       restore %g0, %g0, %g0
+       LOAD_WINDOW(sp)
+       b       2f
+        save   %g0, %g0, %g0
+
+       /* Reload the entire frame in case this is from a
+        * kernel system call or whatever...
+        */
+1:
+       LOAD_PT_ALL(sp, t_psr, t_pc, t_npc, g1)
+2:
+       sethi   %hi(PSR_SYSCALL), %twin_tmp1
+       andn    %t_psr, %twin_tmp1, %t_psr
+       wr      %t_psr, 0x0, %psr
+       WRITE_PAUSE
+
+       jmp     %t_pc
+       rett    %t_npc
+
+ret_trap_user_stack_is_bolixed:
+       wr      %t_wim, 0x0, %wim
+
+       wr      %t_psr, PSR_ET, %psr
+       WRITE_PAUSE
+
+       call    window_ret_fault
+        add    %sp, STACKFRAME_SZ, %o0
+
+       b       signal_p
+        ld     [%curptr + TI_FLAGS], %g2
+
+sun4c_rett_stackchk:
+       be      1f
+        and    %fp, 0xfff, %g1         ! delay slot
+
+       b       ret_trap_user_stack_is_bolixed + 0x4
+        wr     %t_wim, 0x0, %wim
+
+       /* See if we have to check the sanity of one page or two */
+1:
+       add     %g1, 0x38, %g1
+       sra     %fp, 29, %g2
+       add     %g2, 0x1, %g2
+       andncc  %g2, 0x1, %g0
+       be      1f
+        andncc %g1, 0xff8, %g0
+
+       /* %sp is in vma hole, yuck */
+       b       ret_trap_user_stack_is_bolixed + 0x4
+        wr     %t_wim, 0x0, %wim
+
+1:
+       be      sun4c_rett_onepage      /* Only one page to check */
+        lda    [%fp] ASI_PTE, %g2
+
+sun4c_rett_twopages:
+       add     %fp, 0x38, %g1
+       sra     %g1, 29, %g2
+       add     %g2, 0x1, %g2
+       andncc  %g2, 0x1, %g0
+       be      1f
+        lda    [%g1] ASI_PTE, %g2
+
+       /* Second page is in vma hole */
+       b       ret_trap_user_stack_is_bolixed + 0x4
+        wr     %t_wim, 0x0, %wim
+
+1:
+       srl     %g2, 29, %g2
+       andcc   %g2, 0x4, %g0
+       bne     sun4c_rett_onepage
+        lda    [%fp] ASI_PTE, %g2
+
+       /* Second page has bad perms */
+       b       ret_trap_user_stack_is_bolixed + 0x4
+        wr     %t_wim, 0x0, %wim
+
+sun4c_rett_onepage:
+       srl     %g2, 29, %g2
+       andcc   %g2, 0x4, %g0
+       bne,a   1f
+        restore %g0, %g0, %g0
+
+       /* A page had bad page permissions, losing... */
+       b       ret_trap_user_stack_is_bolixed + 0x4
+        wr     %t_wim, 0x0, %wim
+
+       /* Whee, things are ok, load the window and continue. */
+1:
+       LOAD_WINDOW(sp)
+
+       b       ret_trap_userwins_ok
+        save   %g0, %g0, %g0
+
+       .globl  srmmu_rett_stackchk
+srmmu_rett_stackchk:
+       bne     ret_trap_user_stack_is_bolixed
+        sethi   %hi(PAGE_OFFSET), %g1
+       cmp     %g1, %fp
+       bleu    ret_trap_user_stack_is_bolixed
+        mov    AC_M_SFSR, %g1
+       lda     [%g1] ASI_M_MMUREGS, %g0
+
+       lda     [%g0] ASI_M_MMUREGS, %g1
+       or      %g1, 0x2, %g1
+       sta     %g1, [%g0] ASI_M_MMUREGS
+
+       restore %g0, %g0, %g0
+
+       LOAD_WINDOW(sp)
+
+       save    %g0, %g0, %g0
+
+       andn    %g1, 0x2, %g1
+       sta     %g1, [%g0] ASI_M_MMUREGS
+
+       mov     AC_M_SFAR, %g2
+       lda     [%g2] ASI_M_MMUREGS, %g2
+
+       mov     AC_M_SFSR, %g1
+       lda     [%g1] ASI_M_MMUREGS, %g1
+       andcc   %g1, 0x2, %g0
+       be      ret_trap_userwins_ok
+        nop
+
+       b,a     ret_trap_user_stack_is_bolixed
diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
deleted file mode 100644 (file)
index 24fe307..0000000
+++ /dev/null
@@ -1,423 +0,0 @@
-/*
- *  linux/arch/sparc/kernel/setup.c
- *
- *  Copyright (C) 1995  David S. Miller (davem@caip.rutgers.edu)
- *  Copyright (C) 2000  Anton Blanchard (anton@samba.org)
- */
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/initrd.h>
-#include <asm/smp.h>
-#include <linux/user.h>
-#include <linux/screen_info.h>
-#include <linux/delay.h>
-#include <linux/fs.h>
-#include <linux/seq_file.h>
-#include <linux/syscalls.h>
-#include <linux/kdev_t.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/console.h>
-#include <linux/spinlock.h>
-#include <linux/root_dev.h>
-#include <linux/cpu.h>
-#include <linux/kdebug.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/processor.h>
-#include <asm/oplib.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/traps.h>
-#include <asm/vaddrs.h>
-#include <asm/mbus.h>
-#include <asm/idprom.h>
-#include <asm/machines.h>
-#include <asm/cpudata.h>
-#include <asm/setup.h>
-
-struct screen_info screen_info = {
-       0, 0,                   /* orig-x, orig-y */
-       0,                      /* unused */
-       0,                      /* orig-video-page */
-       0,                      /* orig-video-mode */
-       128,                    /* orig-video-cols */
-       0,0,0,                  /* ega_ax, ega_bx, ega_cx */
-       54,                     /* orig-video-lines */
-       0,                      /* orig-video-isVGA */
-       16                      /* orig-video-points */
-};
-
-/* Typing sync at the prom prompt calls the function pointed to by
- * romvec->pv_synchook which I set to the following function.
- * This should sync all filesystems and return, for now it just
- * prints out pretty messages and returns.
- */
-
-extern unsigned long trapbase;
-
-/* Pretty sick eh? */
-static void prom_sync_me(void)
-{
-       unsigned long prom_tbr, flags;
-
-       /* XXX Badly broken. FIX! - Anton */
-       local_irq_save(flags);
-       __asm__ __volatile__("rd %%tbr, %0\n\t" : "=r" (prom_tbr));
-       __asm__ __volatile__("wr %0, 0x0, %%tbr\n\t"
-                            "nop\n\t"
-                            "nop\n\t"
-                            "nop\n\t" : : "r" (&trapbase));
-
-       prom_printf("PROM SYNC COMMAND...\n");
-       show_free_areas();
-       if(current->pid != 0) {
-               local_irq_enable();
-               sys_sync();
-               local_irq_disable();
-       }
-       prom_printf("Returning to prom\n");
-
-       __asm__ __volatile__("wr %0, 0x0, %%tbr\n\t"
-                            "nop\n\t"
-                            "nop\n\t"
-                            "nop\n\t" : : "r" (prom_tbr));
-       local_irq_restore(flags);
-
-       return;
-}
-
-static unsigned int boot_flags __initdata = 0;
-#define BOOTME_DEBUG  0x1
-
-/* Exported for mm/init.c:paging_init. */
-unsigned long cmdline_memory_size __initdata = 0;
-
-static void
-prom_console_write(struct console *con, const char *s, unsigned n)
-{
-       prom_write(s, n);
-}
-
-static struct console prom_debug_console = {
-       .name =         "debug",
-       .write =        prom_console_write,
-       .flags =        CON_PRINTBUFFER,
-       .index =        -1,
-};
-
-/* 
- * Process kernel command line switches that are specific to the
- * SPARC or that require special low-level processing.
- */
-static void __init process_switch(char c)
-{
-       switch (c) {
-       case 'd':
-               boot_flags |= BOOTME_DEBUG;
-               break;
-       case 's':
-               break;
-       case 'h':
-               prom_printf("boot_flags_init: Halt!\n");
-               prom_halt();
-               break;
-       case 'p':
-               /* Use PROM debug console. */
-               register_console(&prom_debug_console);
-               break;
-       default:
-               printk("Unknown boot switch (-%c)\n", c);
-               break;
-       }
-}
-
-static void __init boot_flags_init(char *commands)
-{
-       while (*commands) {
-               /* Move to the start of the next "argument". */
-               while (*commands && *commands == ' ')
-                       commands++;
-
-               /* Process any command switches, otherwise skip it. */
-               if (*commands == '\0')
-                       break;
-               if (*commands == '-') {
-                       commands++;
-                       while (*commands && *commands != ' ')
-                               process_switch(*commands++);
-                       continue;
-               }
-               if (!strncmp(commands, "mem=", 4)) {
-                       /*
-                        * "mem=XXX[kKmM] overrides the PROM-reported
-                        * memory size.
-                        */
-                       cmdline_memory_size = simple_strtoul(commands + 4,
-                                                    &commands, 0);
-                       if (*commands == 'K' || *commands == 'k') {
-                               cmdline_memory_size <<= 10;
-                               commands++;
-                       } else if (*commands=='M' || *commands=='m') {
-                               cmdline_memory_size <<= 20;
-                               commands++;
-                       }
-               }
-               while (*commands && *commands != ' ')
-                       commands++;
-       }
-}
-
-/* This routine will in the future do all the nasty prom stuff
- * to probe for the mmu type and its parameters, etc. This will
- * also be where SMP things happen.
- */
-
-extern void sun4c_probe_vac(void);
-extern char cputypval;
-extern unsigned long start, end;
-
-extern unsigned short root_flags;
-extern unsigned short root_dev;
-extern unsigned short ram_flags;
-#define RAMDISK_IMAGE_START_MASK       0x07FF
-#define RAMDISK_PROMPT_FLAG            0x8000
-#define RAMDISK_LOAD_FLAG              0x4000
-
-extern int root_mountflags;
-
-char reboot_command[COMMAND_LINE_SIZE];
-enum sparc_cpu sparc_cpu_model;
-
-struct tt_entry *sparc_ttable;
-
-struct pt_regs fake_swapper_regs;
-
-void __init setup_arch(char **cmdline_p)
-{
-       int i;
-       unsigned long highest_paddr;
-
-       sparc_ttable = (struct tt_entry *) &start;
-
-       /* Initialize PROM console and command line. */
-       *cmdline_p = prom_getbootargs();
-       strcpy(boot_command_line, *cmdline_p);
-       parse_early_param();
-
-       /* Set sparc_cpu_model */
-       sparc_cpu_model = sun_unknown;
-       if (!strcmp(&cputypval,"sun4 "))
-               sparc_cpu_model = sun4;
-       if (!strcmp(&cputypval,"sun4c"))
-               sparc_cpu_model = sun4c;
-       if (!strcmp(&cputypval,"sun4m"))
-               sparc_cpu_model = sun4m;
-       if (!strcmp(&cputypval,"sun4s"))
-               sparc_cpu_model = sun4m; /* CP-1200 with PROM 2.30 -E */
-       if (!strcmp(&cputypval,"sun4d"))
-               sparc_cpu_model = sun4d;
-       if (!strcmp(&cputypval,"sun4e"))
-               sparc_cpu_model = sun4e;
-       if (!strcmp(&cputypval,"sun4u"))
-               sparc_cpu_model = sun4u;
-
-       printk("ARCH: ");
-       switch(sparc_cpu_model) {
-       case sun4:
-               printk("SUN4\n");
-               break;
-       case sun4c:
-               printk("SUN4C\n");
-               break;
-       case sun4m:
-               printk("SUN4M\n");
-               break;
-       case sun4d:
-               printk("SUN4D\n");
-               break;
-       case sun4e:
-               printk("SUN4E\n");
-               break;
-       case sun4u:
-               printk("SUN4U\n");
-               break;
-       default:
-               printk("UNKNOWN!\n");
-               break;
-       };
-
-#ifdef CONFIG_DUMMY_CONSOLE
-       conswitchp = &dummy_con;
-#elif defined(CONFIG_PROM_CONSOLE)
-       conswitchp = &prom_con;
-#endif
-       boot_flags_init(*cmdline_p);
-
-       idprom_init();
-       if (ARCH_SUN4C)
-               sun4c_probe_vac();
-       load_mmu();
-
-       phys_base = 0xffffffffUL;
-       highest_paddr = 0UL;
-       for (i = 0; sp_banks[i].num_bytes != 0; i++) {
-               unsigned long top;
-
-               if (sp_banks[i].base_addr < phys_base)
-                       phys_base = sp_banks[i].base_addr;
-               top = sp_banks[i].base_addr +
-                       sp_banks[i].num_bytes;
-               if (highest_paddr < top)
-                       highest_paddr = top;
-       }
-       pfn_base = phys_base >> PAGE_SHIFT;
-
-       if (!root_flags)
-               root_mountflags &= ~MS_RDONLY;
-       ROOT_DEV = old_decode_dev(root_dev);
-#ifdef CONFIG_BLK_DEV_RAM
-       rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK;
-       rd_prompt = ((ram_flags & RAMDISK_PROMPT_FLAG) != 0);
-       rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0);     
-#endif
-
-       prom_setsync(prom_sync_me);
-
-       if((boot_flags&BOOTME_DEBUG) && (linux_dbvec!=0) && 
-          ((*(short *)linux_dbvec) != -1)) {
-               printk("Booted under KADB. Syncing trap table.\n");
-               (*(linux_dbvec->teach_debugger))();
-       }
-
-       init_mm.context = (unsigned long) NO_CONTEXT;
-       init_task.thread.kregs = &fake_swapper_regs;
-
-       paging_init();
-
-       smp_setup_cpu_possible_map();
-}
-
-extern char *sparc_cpu_type;
-extern char *sparc_fpu_type;
-
-static int ncpus_probed;
-
-static int show_cpuinfo(struct seq_file *m, void *__unused)
-{
-       seq_printf(m,
-                  "cpu\t\t: %s\n"
-                  "fpu\t\t: %s\n"
-                  "promlib\t\t: Version %d Revision %d\n"
-                  "prom\t\t: %d.%d\n"
-                  "type\t\t: %s\n"
-                  "ncpus probed\t: %d\n"
-                  "ncpus active\t: %d\n"
-#ifndef CONFIG_SMP
-                  "CPU0Bogo\t: %lu.%02lu\n"
-                  "CPU0ClkTck\t: %ld\n"
-#endif
-                  ,
-                  sparc_cpu_type ? sparc_cpu_type : "undetermined",
-                  sparc_fpu_type ? sparc_fpu_type : "undetermined",
-                  romvec->pv_romvers,
-                  prom_rev,
-                  romvec->pv_printrev >> 16,
-                  romvec->pv_printrev & 0xffff,
-                  &cputypval,
-                  ncpus_probed,
-                  num_online_cpus()
-#ifndef CONFIG_SMP
-                  , cpu_data(0).udelay_val/(500000/HZ),
-                  (cpu_data(0).udelay_val/(5000/HZ)) % 100,
-                  cpu_data(0).clock_tick
-#endif
-               );
-
-#ifdef CONFIG_SMP
-       smp_bogo(m);
-#endif
-       mmu_info(m);
-#ifdef CONFIG_SMP
-       smp_info(m);
-#endif
-       return 0;
-}
-
-static void *c_start(struct seq_file *m, loff_t *pos)
-{
-       /* The pointer we are returning is arbitrary,
-        * it just has to be non-NULL and not IS_ERR
-        * in the success case.
-        */
-       return *pos == 0 ? &c_start : NULL;
-}
-
-static void *c_next(struct seq_file *m, void *v, loff_t *pos)
-{
-       ++*pos;
-       return c_start(m, pos);
-}
-
-static void c_stop(struct seq_file *m, void *v)
-{
-}
-
-const struct seq_operations cpuinfo_op = {
-       .start =c_start,
-       .next = c_next,
-       .stop = c_stop,
-       .show = show_cpuinfo,
-};
-
-extern int stop_a_enabled;
-
-void sun_do_break(void)
-{
-       if (!stop_a_enabled)
-               return;
-
-       printk("\n");
-       flush_user_windows();
-
-       prom_cmdline();
-}
-
-int stop_a_enabled = 1;
-
-static int __init topology_init(void)
-{
-       int i, ncpus, err;
-
-       /* Count the number of physically present processors in
-        * the machine, even on uniprocessor, so that /proc/cpuinfo
-        * output is consistent with 2.4.x
-        */
-       ncpus = 0;
-       while (!cpu_find_by_instance(ncpus, NULL, NULL))
-               ncpus++;
-       ncpus_probed = ncpus;
-
-       err = 0;
-       for_each_online_cpu(i) {
-               struct cpu *p = kzalloc(sizeof(*p), GFP_KERNEL);
-               if (!p)
-                       err = -ENOMEM;
-               else
-                       register_cpu(p, i);
-       }
-
-       return err;
-}
-
-subsys_initcall(topology_init);
diff --git a/arch/sparc/kernel/setup_32.c b/arch/sparc/kernel/setup_32.c
new file mode 100644 (file)
index 0000000..24fe307
--- /dev/null
@@ -0,0 +1,423 @@
+/*
+ *  linux/arch/sparc/kernel/setup.c
+ *
+ *  Copyright (C) 1995  David S. Miller (davem@caip.rutgers.edu)
+ *  Copyright (C) 2000  Anton Blanchard (anton@samba.org)
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/initrd.h>
+#include <asm/smp.h>
+#include <linux/user.h>
+#include <linux/screen_info.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/seq_file.h>
+#include <linux/syscalls.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/console.h>
+#include <linux/spinlock.h>
+#include <linux/root_dev.h>
+#include <linux/cpu.h>
+#include <linux/kdebug.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/oplib.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/traps.h>
+#include <asm/vaddrs.h>
+#include <asm/mbus.h>
+#include <asm/idprom.h>
+#include <asm/machines.h>
+#include <asm/cpudata.h>
+#include <asm/setup.h>
+
+struct screen_info screen_info = {
+       0, 0,                   /* orig-x, orig-y */
+       0,                      /* unused */
+       0,                      /* orig-video-page */
+       0,                      /* orig-video-mode */
+       128,                    /* orig-video-cols */
+       0,0,0,                  /* ega_ax, ega_bx, ega_cx */
+       54,                     /* orig-video-lines */
+       0,                      /* orig-video-isVGA */
+       16                      /* orig-video-points */
+};
+
+/* Typing sync at the prom prompt calls the function pointed to by
+ * romvec->pv_synchook which I set to the following function.
+ * This should sync all filesystems and return, for now it just
+ * prints out pretty messages and returns.
+ */
+
+extern unsigned long trapbase;
+
+/* Pretty sick eh? */
+static void prom_sync_me(void)
+{
+       unsigned long prom_tbr, flags;
+
+       /* XXX Badly broken. FIX! - Anton */
+       local_irq_save(flags);
+       __asm__ __volatile__("rd %%tbr, %0\n\t" : "=r" (prom_tbr));
+       __asm__ __volatile__("wr %0, 0x0, %%tbr\n\t"
+                            "nop\n\t"
+                            "nop\n\t"
+                            "nop\n\t" : : "r" (&trapbase));
+
+       prom_printf("PROM SYNC COMMAND...\n");
+       show_free_areas();
+       if(current->pid != 0) {
+               local_irq_enable();
+               sys_sync();
+               local_irq_disable();
+       }
+       prom_printf("Returning to prom\n");
+
+       __asm__ __volatile__("wr %0, 0x0, %%tbr\n\t"
+                            "nop\n\t"
+                            "nop\n\t"
+                            "nop\n\t" : : "r" (prom_tbr));
+       local_irq_restore(flags);
+
+       return;
+}
+
+static unsigned int boot_flags __initdata = 0;
+#define BOOTME_DEBUG  0x1
+
+/* Exported for mm/init.c:paging_init. */
+unsigned long cmdline_memory_size __initdata = 0;
+
+static void
+prom_console_write(struct console *con, const char *s, unsigned n)
+{
+       prom_write(s, n);
+}
+
+static struct console prom_debug_console = {
+       .name =         "debug",
+       .write =        prom_console_write,
+       .flags =        CON_PRINTBUFFER,
+       .index =        -1,
+};
+
+/* 
+ * Process kernel command line switches that are specific to the
+ * SPARC or that require special low-level processing.
+ */
+static void __init process_switch(char c)
+{
+       switch (c) {
+       case 'd':
+               boot_flags |= BOOTME_DEBUG;
+               break;
+       case 's':
+               break;
+       case 'h':
+               prom_printf("boot_flags_init: Halt!\n");
+               prom_halt();
+               break;
+       case 'p':
+               /* Use PROM debug console. */
+               register_console(&prom_debug_console);
+               break;
+       default:
+               printk("Unknown boot switch (-%c)\n", c);
+               break;
+       }
+}
+
+static void __init boot_flags_init(char *commands)
+{
+       while (*commands) {
+               /* Move to the start of the next "argument". */
+               while (*commands && *commands == ' ')
+                       commands++;
+
+               /* Process any command switches, otherwise skip it. */
+               if (*commands == '\0')
+                       break;
+               if (*commands == '-') {
+                       commands++;
+                       while (*commands && *commands != ' ')
+                               process_switch(*commands++);
+                       continue;
+               }
+               if (!strncmp(commands, "mem=", 4)) {
+                       /*
+                        * "mem=XXX[kKmM] overrides the PROM-reported
+                        * memory size.
+                        */
+                       cmdline_memory_size = simple_strtoul(commands + 4,
+                                                    &commands, 0);
+                       if (*commands == 'K' || *commands == 'k') {
+                               cmdline_memory_size <<= 10;
+                               commands++;
+                       } else if (*commands=='M' || *commands=='m') {
+                               cmdline_memory_size <<= 20;
+                               commands++;
+                       }
+               }
+               while (*commands && *commands != ' ')
+                       commands++;
+       }
+}
+
+/* This routine will in the future do all the nasty prom stuff
+ * to probe for the mmu type and its parameters, etc. This will
+ * also be where SMP things happen.
+ */
+
+extern void sun4c_probe_vac(void);
+extern char cputypval;
+extern unsigned long start, end;
+
+extern unsigned short root_flags;
+extern unsigned short root_dev;
+extern unsigned short ram_flags;
+#define RAMDISK_IMAGE_START_MASK       0x07FF
+#define RAMDISK_PROMPT_FLAG            0x8000
+#define RAMDISK_LOAD_FLAG              0x4000
+
+extern int root_mountflags;
+
+char reboot_command[COMMAND_LINE_SIZE];
+enum sparc_cpu sparc_cpu_model;
+
+struct tt_entry *sparc_ttable;
+
+struct pt_regs fake_swapper_regs;
+
+void __init setup_arch(char **cmdline_p)
+{
+       int i;
+       unsigned long highest_paddr;
+
+       sparc_ttable = (struct tt_entry *) &start;
+
+       /* Initialize PROM console and command line. */
+       *cmdline_p = prom_getbootargs();
+       strcpy(boot_command_line, *cmdline_p);
+       parse_early_param();
+
+       /* Set sparc_cpu_model */
+       sparc_cpu_model = sun_unknown;
+       if (!strcmp(&cputypval,"sun4 "))
+               sparc_cpu_model = sun4;
+       if (!strcmp(&cputypval,"sun4c"))
+               sparc_cpu_model = sun4c;
+       if (!strcmp(&cputypval,"sun4m"))
+               sparc_cpu_model = sun4m;
+       if (!strcmp(&cputypval,"sun4s"))
+               sparc_cpu_model = sun4m; /* CP-1200 with PROM 2.30 -E */
+       if (!strcmp(&cputypval,"sun4d"))
+               sparc_cpu_model = sun4d;
+       if (!strcmp(&cputypval,"sun4e"))
+               sparc_cpu_model = sun4e;
+       if (!strcmp(&cputypval,"sun4u"))
+               sparc_cpu_model = sun4u;
+
+       printk("ARCH: ");
+       switch(sparc_cpu_model) {
+       case sun4:
+               printk("SUN4\n");
+               break;
+       case sun4c:
+               printk("SUN4C\n");
+               break;
+       case sun4m:
+               printk("SUN4M\n");
+               break;
+       case sun4d:
+               printk("SUN4D\n");
+               break;
+       case sun4e:
+               printk("SUN4E\n");
+               break;
+       case sun4u:
+               printk("SUN4U\n");
+               break;
+       default:
+               printk("UNKNOWN!\n");
+               break;
+       };
+
+#ifdef CONFIG_DUMMY_CONSOLE
+       conswitchp = &dummy_con;
+#elif defined(CONFIG_PROM_CONSOLE)
+       conswitchp = &prom_con;
+#endif
+       boot_flags_init(*cmdline_p);
+
+       idprom_init();
+       if (ARCH_SUN4C)
+               sun4c_probe_vac();
+       load_mmu();
+
+       phys_base = 0xffffffffUL;
+       highest_paddr = 0UL;
+       for (i = 0; sp_banks[i].num_bytes != 0; i++) {
+               unsigned long top;
+
+               if (sp_banks[i].base_addr < phys_base)
+                       phys_base = sp_banks[i].base_addr;
+               top = sp_banks[i].base_addr +
+                       sp_banks[i].num_bytes;
+               if (highest_paddr < top)
+                       highest_paddr = top;
+       }
+       pfn_base = phys_base >> PAGE_SHIFT;
+
+       if (!root_flags)
+               root_mountflags &= ~MS_RDONLY;
+       ROOT_DEV = old_decode_dev(root_dev);
+#ifdef CONFIG_BLK_DEV_RAM
+       rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK;
+       rd_prompt = ((ram_flags & RAMDISK_PROMPT_FLAG) != 0);
+       rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0);     
+#endif
+
+       prom_setsync(prom_sync_me);
+
+       if((boot_flags&BOOTME_DEBUG) && (linux_dbvec!=0) && 
+          ((*(short *)linux_dbvec) != -1)) {
+               printk("Booted under KADB. Syncing trap table.\n");
+               (*(linux_dbvec->teach_debugger))();
+       }
+
+       init_mm.context = (unsigned long) NO_CONTEXT;
+       init_task.thread.kregs = &fake_swapper_regs;
+
+       paging_init();
+
+       smp_setup_cpu_possible_map();
+}
+
+extern char *sparc_cpu_type;
+extern char *sparc_fpu_type;
+
+static int ncpus_probed;
+
+static int show_cpuinfo(struct seq_file *m, void *__unused)
+{
+       seq_printf(m,
+                  "cpu\t\t: %s\n"
+                  "fpu\t\t: %s\n"
+                  "promlib\t\t: Version %d Revision %d\n"
+                  "prom\t\t: %d.%d\n"
+                  "type\t\t: %s\n"
+                  "ncpus probed\t: %d\n"
+                  "ncpus active\t: %d\n"
+#ifndef CONFIG_SMP
+                  "CPU0Bogo\t: %lu.%02lu\n"
+                  "CPU0ClkTck\t: %ld\n"
+#endif
+                  ,
+                  sparc_cpu_type ? sparc_cpu_type : "undetermined",
+                  sparc_fpu_type ? sparc_fpu_type : "undetermined",
+                  romvec->pv_romvers,
+                  prom_rev,
+                  romvec->pv_printrev >> 16,
+                  romvec->pv_printrev & 0xffff,
+                  &cputypval,
+                  ncpus_probed,
+                  num_online_cpus()
+#ifndef CONFIG_SMP
+                  , cpu_data(0).udelay_val/(500000/HZ),
+                  (cpu_data(0).udelay_val/(5000/HZ)) % 100,
+                  cpu_data(0).clock_tick
+#endif
+               );
+
+#ifdef CONFIG_SMP
+       smp_bogo(m);
+#endif
+       mmu_info(m);
+#ifdef CONFIG_SMP
+       smp_info(m);
+#endif
+       return 0;
+}
+
+static void *c_start(struct seq_file *m, loff_t *pos)
+{
+       /* The pointer we are returning is arbitrary,
+        * it just has to be non-NULL and not IS_ERR
+        * in the success case.
+        */
+       return *pos == 0 ? &c_start : NULL;
+}
+
+static void *c_next(struct seq_file *m, void *v, loff_t *pos)
+{
+       ++*pos;
+       return c_start(m, pos);
+}
+
+static void c_stop(struct seq_file *m, void *v)
+{
+}
+
+const struct seq_operations cpuinfo_op = {
+       .start =c_start,
+       .next = c_next,
+       .stop = c_stop,
+       .show = show_cpuinfo,
+};
+
+extern int stop_a_enabled;
+
+void sun_do_break(void)
+{
+       if (!stop_a_enabled)
+               return;
+
+       printk("\n");
+       flush_user_windows();
+
+       prom_cmdline();
+}
+
+int stop_a_enabled = 1;
+
+static int __init topology_init(void)
+{
+       int i, ncpus, err;
+
+       /* Count the number of physically present processors in
+        * the machine, even on uniprocessor, so that /proc/cpuinfo
+        * output is consistent with 2.4.x
+        */
+       ncpus = 0;
+       while (!cpu_find_by_instance(ncpus, NULL, NULL))
+               ncpus++;
+       ncpus_probed = ncpus;
+
+       err = 0;
+       for_each_online_cpu(i) {
+               struct cpu *p = kzalloc(sizeof(*p), GFP_KERNEL);
+               if (!p)
+                       err = -ENOMEM;
+               else
+                       register_cpu(p, i);
+       }
+
+       return err;
+}
+
+subsys_initcall(topology_init);
diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c
deleted file mode 100644 (file)
index c94f91c..0000000
+++ /dev/null
@@ -1,631 +0,0 @@
-/*  linux/arch/sparc/kernel/signal.c
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- *  Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
- *  Copyright (C) 1997 Eddie C. Dost   (ecd@skynet.be)
- */
-
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/wait.h>
-#include <linux/ptrace.h>
-#include <linux/unistd.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/smp.h>
-#include <linux/binfmts.h>     /* do_coredum */
-#include <linux/bitops.h>
-#include <linux/tracehook.h>
-
-#include <asm/uaccess.h>
-#include <asm/ptrace.h>
-#include <asm/pgalloc.h>
-#include <asm/pgtable.h>
-#include <asm/cacheflush.h>    /* flush_sig_insns */
-
-#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-
-extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
-                  void *fpqueue, unsigned long *fpqdepth);
-extern void fpload(unsigned long *fpregs, unsigned long *fsr);
-
-struct signal_frame {
-       struct sparc_stackf     ss;
-       __siginfo_t             info;
-       __siginfo_fpu_t __user  *fpu_save;
-       unsigned long           insns[2] __attribute__ ((aligned (8)));
-       unsigned int            extramask[_NSIG_WORDS - 1];
-       unsigned int            extra_size; /* Should be 0 */
-       __siginfo_fpu_t         fpu_state;
-};
-
-struct rt_signal_frame {
-       struct sparc_stackf     ss;
-       siginfo_t               info;
-       struct pt_regs          regs;
-       sigset_t                mask;
-       __siginfo_fpu_t __user  *fpu_save;
-       unsigned int            insns[2];
-       stack_t                 stack;
-       unsigned int            extra_size; /* Should be 0 */
-       __siginfo_fpu_t         fpu_state;
-};
-
-/* Align macros */
-#define SF_ALIGNEDSZ  (((sizeof(struct signal_frame) + 7) & (~7)))
-#define RT_ALIGNEDSZ  (((sizeof(struct rt_signal_frame) + 7) & (~7)))
-
-static int _sigpause_common(old_sigset_t set)
-{
-       set &= _BLOCKABLE;
-       spin_lock_irq(&current->sighand->siglock);
-       current->saved_sigmask = current->blocked;
-       siginitset(&current->blocked, set);
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
-
-       current->state = TASK_INTERRUPTIBLE;
-       schedule();
-       set_thread_flag(TIF_RESTORE_SIGMASK);
-
-       return -ERESTARTNOHAND;
-}
-
-asmlinkage int sys_sigsuspend(old_sigset_t set)
-{
-       return _sigpause_common(set);
-}
-
-static inline int
-restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
-{
-       int err;
-#ifdef CONFIG_SMP
-       if (test_tsk_thread_flag(current, TIF_USEDFPU))
-               regs->psr &= ~PSR_EF;
-#else
-       if (current == last_task_used_math) {
-               last_task_used_math = NULL;
-               regs->psr &= ~PSR_EF;
-       }
-#endif
-       set_used_math();
-       clear_tsk_thread_flag(current, TIF_USEDFPU);
-
-       if (!access_ok(VERIFY_READ, fpu, sizeof(*fpu)))
-               return -EFAULT;
-
-       err = __copy_from_user(&current->thread.float_regs[0], &fpu->si_float_regs[0],
-                              (sizeof(unsigned long) * 32));
-       err |= __get_user(current->thread.fsr, &fpu->si_fsr);
-       err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
-       if (current->thread.fpqdepth != 0)
-               err |= __copy_from_user(&current->thread.fpqueue[0],
-                                       &fpu->si_fpqueue[0],
-                                       ((sizeof(unsigned long) +
-                                       (sizeof(unsigned long *)))*16));
-       return err;
-}
-
-asmlinkage void do_sigreturn(struct pt_regs *regs)
-{
-       struct signal_frame __user *sf;
-       unsigned long up_psr, pc, npc;
-       sigset_t set;
-       __siginfo_fpu_t __user *fpu_save;
-       int err;
-
-       /* Always make any pending restarted system calls return -EINTR */
-       current_thread_info()->restart_block.fn = do_no_restart_syscall;
-
-       synchronize_user_stack();
-
-       sf = (struct signal_frame __user *) regs->u_regs[UREG_FP];
-
-       /* 1. Make sure we are not getting garbage from the user */
-       if (!access_ok(VERIFY_READ, sf, sizeof(*sf)))
-               goto segv_and_exit;
-
-       if (((unsigned long) sf) & 3)
-               goto segv_and_exit;
-
-       err = __get_user(pc,  &sf->info.si_regs.pc);
-       err |= __get_user(npc, &sf->info.si_regs.npc);
-
-       if ((pc | npc) & 3)
-               goto segv_and_exit;
-
-       /* 2. Restore the state */
-       up_psr = regs->psr;
-       err |= __copy_from_user(regs, &sf->info.si_regs, sizeof(struct pt_regs));
-
-       /* User can only change condition codes and FPU enabling in %psr. */
-       regs->psr = (up_psr & ~(PSR_ICC | PSR_EF))
-                 | (regs->psr & (PSR_ICC | PSR_EF));
-
-       /* Prevent syscall restart.  */
-       pt_regs_clear_syscall(regs);
-
-       err |= __get_user(fpu_save, &sf->fpu_save);
-
-       if (fpu_save)
-               err |= restore_fpu_state(regs, fpu_save);
-
-       /* This is pretty much atomic, no amount locking would prevent
-        * the races which exist anyways.
-        */
-       err |= __get_user(set.sig[0], &sf->info.si_mask);
-       err |= __copy_from_user(&set.sig[1], &sf->extramask,
-                               (_NSIG_WORDS-1) * sizeof(unsigned int));
-                          
-       if (err)
-               goto segv_and_exit;
-
-       sigdelsetmask(&set, ~_BLOCKABLE);
-       spin_lock_irq(&current->sighand->siglock);
-       current->blocked = set;
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
-       return;
-
-segv_and_exit:
-       force_sig(SIGSEGV, current);
-}
-
-asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
-{
-       struct rt_signal_frame __user *sf;
-       unsigned int psr, pc, npc;
-       __siginfo_fpu_t __user *fpu_save;
-       mm_segment_t old_fs;
-       sigset_t set;
-       stack_t st;
-       int err;
-
-       synchronize_user_stack();
-       sf = (struct rt_signal_frame __user *) regs->u_regs[UREG_FP];
-       if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) ||
-           (((unsigned long) sf) & 0x03))
-               goto segv;
-
-       err = __get_user(pc, &sf->regs.pc);
-       err |= __get_user(npc, &sf->regs.npc);
-       err |= ((pc | npc) & 0x03);
-
-       err |= __get_user(regs->y, &sf->regs.y);
-       err |= __get_user(psr, &sf->regs.psr);
-
-       err |= __copy_from_user(&regs->u_regs[UREG_G1],
-                               &sf->regs.u_regs[UREG_G1], 15 * sizeof(u32));
-
-       regs->psr = (regs->psr & ~PSR_ICC) | (psr & PSR_ICC);
-
-       /* Prevent syscall restart.  */
-       pt_regs_clear_syscall(regs);
-
-       err |= __get_user(fpu_save, &sf->fpu_save);
-
-       if (fpu_save)
-               err |= restore_fpu_state(regs, fpu_save);
-       err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t));
-       
-       err |= __copy_from_user(&st, &sf->stack, sizeof(stack_t));
-       
-       if (err)
-               goto segv;
-               
-       regs->pc = pc;
-       regs->npc = npc;
-       
-       /* It is more difficult to avoid calling this function than to
-        * call it and ignore errors.
-        */
-       old_fs = get_fs();
-       set_fs(KERNEL_DS);
-       do_sigaltstack((const stack_t __user *) &st, NULL, (unsigned long)sf);
-       set_fs(old_fs);
-
-       sigdelsetmask(&set, ~_BLOCKABLE);
-       spin_lock_irq(&current->sighand->siglock);
-       current->blocked = set;
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
-       return;
-segv:
-       force_sig(SIGSEGV, current);
-}
-
-/* Checks if the fp is valid */
-static inline int invalid_frame_pointer(void __user *fp, int fplen)
-{
-       if ((((unsigned long) fp) & 7) ||
-           !__access_ok((unsigned long)fp, fplen) ||
-           ((sparc_cpu_model == sun4 || sparc_cpu_model == sun4c) &&
-            ((unsigned long) fp < 0xe0000000 && (unsigned long) fp >= 0x20000000)))
-               return 1;
-       
-       return 0;
-}
-
-static inline void __user *get_sigframe(struct sigaction *sa, struct pt_regs *regs, unsigned long framesize)
-{
-       unsigned long sp = regs->u_regs[UREG_FP];
-
-       /*
-        * If we are on the alternate signal stack and would overflow it, don't.
-        * Return an always-bogus address instead so we will die with SIGSEGV.
-        */
-       if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize)))
-               return (void __user *) -1L;
-
-       /* This is the X/Open sanctioned signal stack switching.  */
-       if (sa->sa_flags & SA_ONSTACK) {
-               if (sas_ss_flags(sp) == 0)
-                       sp = current->sas_ss_sp + current->sas_ss_size;
-       }
-
-       /* Always align the stack frame.  This handles two cases.  First,
-        * sigaltstack need not be mindful of platform specific stack
-        * alignment.  Second, if we took this signal because the stack
-        * is not aligned properly, we'd like to take the signal cleanly
-        * and report that.
-        */
-       sp &= ~7UL;
-
-       return (void __user *)(sp - framesize);
-}
-
-static inline int
-save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
-{
-       int err = 0;
-#ifdef CONFIG_SMP
-       if (test_tsk_thread_flag(current, TIF_USEDFPU)) {
-               put_psr(get_psr() | PSR_EF);
-               fpsave(&current->thread.float_regs[0], &current->thread.fsr,
-                      &current->thread.fpqueue[0], &current->thread.fpqdepth);
-               regs->psr &= ~(PSR_EF);
-               clear_tsk_thread_flag(current, TIF_USEDFPU);
-       }
-#else
-       if (current == last_task_used_math) {
-               put_psr(get_psr() | PSR_EF);
-               fpsave(&current->thread.float_regs[0], &current->thread.fsr,
-                      &current->thread.fpqueue[0], &current->thread.fpqdepth);
-               last_task_used_math = NULL;
-               regs->psr &= ~(PSR_EF);
-       }
-#endif
-       err |= __copy_to_user(&fpu->si_float_regs[0],
-                             &current->thread.float_regs[0],
-                             (sizeof(unsigned long) * 32));
-       err |= __put_user(current->thread.fsr, &fpu->si_fsr);
-       err |= __put_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
-       if (current->thread.fpqdepth != 0)
-               err |= __copy_to_user(&fpu->si_fpqueue[0],
-                                     &current->thread.fpqueue[0],
-                                     ((sizeof(unsigned long) +
-                                     (sizeof(unsigned long *)))*16));
-       clear_used_math();
-       return err;
-}
-
-static void setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
-                       int signo, sigset_t *oldset)
-{
-       struct signal_frame __user *sf;
-       int sigframe_size, err;
-
-       /* 1. Make sure everything is clean */
-       synchronize_user_stack();
-
-       sigframe_size = SF_ALIGNEDSZ;
-       if (!used_math())
-               sigframe_size -= sizeof(__siginfo_fpu_t);
-
-       sf = (struct signal_frame __user *)
-               get_sigframe(&ka->sa, regs, sigframe_size);
-
-       if (invalid_frame_pointer(sf, sigframe_size))
-               goto sigill_and_return;
-
-       if (current_thread_info()->w_saved != 0)
-               goto sigill_and_return;
-
-       /* 2. Save the current process state */
-       err = __copy_to_user(&sf->info.si_regs, regs, sizeof(struct pt_regs));
-       
-       err |= __put_user(0, &sf->extra_size);
-
-       if (used_math()) {
-               err |= save_fpu_state(regs, &sf->fpu_state);
-               err |= __put_user(&sf->fpu_state, &sf->fpu_save);
-       } else {
-               err |= __put_user(0, &sf->fpu_save);
-       }
-
-       err |= __put_user(oldset->sig[0], &sf->info.si_mask);
-       err |= __copy_to_user(sf->extramask, &oldset->sig[1],
-                             (_NSIG_WORDS - 1) * sizeof(unsigned int));
-       err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
-                             sizeof(struct reg_window));
-       if (err)
-               goto sigsegv;
-       
-       /* 3. signal handler back-trampoline and parameters */
-       regs->u_regs[UREG_FP] = (unsigned long) sf;
-       regs->u_regs[UREG_I0] = signo;
-       regs->u_regs[UREG_I1] = (unsigned long) &sf->info;
-       regs->u_regs[UREG_I2] = (unsigned long) &sf->info;
-
-       /* 4. signal handler */
-       regs->pc = (unsigned long) ka->sa.sa_handler;
-       regs->npc = (regs->pc + 4);
-
-       /* 5. return to kernel instructions */
-       if (ka->ka_restorer)
-               regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
-       else {
-               regs->u_regs[UREG_I7] = (unsigned long)(&(sf->insns[0]) - 2);
-
-               /* mov __NR_sigreturn, %g1 */
-               err |= __put_user(0x821020d8, &sf->insns[0]);
-
-               /* t 0x10 */
-               err |= __put_user(0x91d02010, &sf->insns[1]);
-               if (err)
-                       goto sigsegv;
-
-               /* Flush instruction space. */
-               flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
-       }
-       return;
-
-sigill_and_return:
-       do_exit(SIGILL);
-sigsegv:
-       force_sigsegv(signo, current);
-}
-
-static void setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
-                          int signo, sigset_t *oldset, siginfo_t *info)
-{
-       struct rt_signal_frame __user *sf;
-       int sigframe_size;
-       unsigned int psr;
-       int err;
-
-       synchronize_user_stack();
-       sigframe_size = RT_ALIGNEDSZ;
-       if (!used_math())
-               sigframe_size -= sizeof(__siginfo_fpu_t);
-       sf = (struct rt_signal_frame __user *)
-               get_sigframe(&ka->sa, regs, sigframe_size);
-       if (invalid_frame_pointer(sf, sigframe_size))
-               goto sigill;
-       if (current_thread_info()->w_saved != 0)
-               goto sigill;
-
-       err  = __put_user(regs->pc, &sf->regs.pc);
-       err |= __put_user(regs->npc, &sf->regs.npc);
-       err |= __put_user(regs->y, &sf->regs.y);
-       psr = regs->psr;
-       if (used_math())
-               psr |= PSR_EF;
-       err |= __put_user(psr, &sf->regs.psr);
-       err |= __copy_to_user(&sf->regs.u_regs, regs->u_regs, sizeof(regs->u_regs));
-       err |= __put_user(0, &sf->extra_size);
-
-       if (psr & PSR_EF) {
-               err |= save_fpu_state(regs, &sf->fpu_state);
-               err |= __put_user(&sf->fpu_state, &sf->fpu_save);
-       } else {
-               err |= __put_user(0, &sf->fpu_save);
-       }
-       err |= __copy_to_user(&sf->mask, &oldset->sig[0], sizeof(sigset_t));
-       
-       /* Setup sigaltstack */
-       err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp);
-       err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags);
-       err |= __put_user(current->sas_ss_size, &sf->stack.ss_size);
-       
-       err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
-                             sizeof(struct reg_window));       
-
-       err |= copy_siginfo_to_user(&sf->info, info);
-
-       if (err)
-               goto sigsegv;
-
-       regs->u_regs[UREG_FP] = (unsigned long) sf;
-       regs->u_regs[UREG_I0] = signo;
-       regs->u_regs[UREG_I1] = (unsigned long) &sf->info;
-       regs->u_regs[UREG_I2] = (unsigned long) &sf->regs;
-
-       regs->pc = (unsigned long) ka->sa.sa_handler;
-       regs->npc = (regs->pc + 4);
-
-       if (ka->ka_restorer)
-               regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
-       else {
-               regs->u_regs[UREG_I7] = (unsigned long)(&(sf->insns[0]) - 2);
-
-               /* mov __NR_sigreturn, %g1 */
-               err |= __put_user(0x821020d8, &sf->insns[0]);
-
-               /* t 0x10 */
-               err |= __put_user(0x91d02010, &sf->insns[1]);
-               if (err)
-                       goto sigsegv;
-
-               /* Flush instruction space. */
-               flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
-       }
-       return;
-
-sigill:
-       do_exit(SIGILL);
-sigsegv:
-       force_sigsegv(signo, current);
-}
-
-static inline void
-handle_signal(unsigned long signr, struct k_sigaction *ka,
-             siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
-{
-       if (ka->sa.sa_flags & SA_SIGINFO)
-               setup_rt_frame(ka, regs, signr, oldset, info);
-       else
-               setup_frame(ka, regs, signr, oldset);
-
-       spin_lock_irq(&current->sighand->siglock);
-       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
-       if (!(ka->sa.sa_flags & SA_NOMASK))
-               sigaddset(&current->blocked, signr);
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
-}
-
-static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
-                                  struct sigaction *sa)
-{
-       switch(regs->u_regs[UREG_I0]) {
-       case ERESTART_RESTARTBLOCK:
-       case ERESTARTNOHAND:
-       no_system_call_restart:
-               regs->u_regs[UREG_I0] = EINTR;
-               regs->psr |= PSR_C;
-               break;
-       case ERESTARTSYS:
-               if (!(sa->sa_flags & SA_RESTART))
-                       goto no_system_call_restart;
-               /* fallthrough */
-       case ERESTARTNOINTR:
-               regs->u_regs[UREG_I0] = orig_i0;
-               regs->pc -= 4;
-               regs->npc -= 4;
-       }
-}
-
-/* Note that 'init' is a special process: it doesn't get signals it doesn't
- * want to handle. Thus you cannot kill init even with a SIGKILL even by
- * mistake.
- */
-static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
-{
-       struct k_sigaction ka;
-       int restart_syscall;
-       sigset_t *oldset;
-       siginfo_t info;
-       int signr;
-
-       if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C))
-               restart_syscall = 1;
-       else
-               restart_syscall = 0;
-
-       if (test_thread_flag(TIF_RESTORE_SIGMASK))
-               oldset = &current->saved_sigmask;
-       else
-               oldset = &current->blocked;
-
-       signr = get_signal_to_deliver(&info, &ka, regs, NULL);
-
-       /* If the debugger messes with the program counter, it clears
-        * the software "in syscall" bit, directing us to not perform
-        * a syscall restart.
-        */
-       if (restart_syscall && !pt_regs_is_syscall(regs))
-               restart_syscall = 0;
-
-       if (signr > 0) {
-               if (restart_syscall)
-                       syscall_restart(orig_i0, regs, &ka.sa);
-               handle_signal(signr, &ka, &info, oldset, regs);
-
-               /* a signal was successfully delivered; the saved
-                * sigmask will have been stored in the signal frame,
-                * and will be restored by sigreturn, so we can simply
-                * clear the TIF_RESTORE_SIGMASK flag.
-                */
-               if (test_thread_flag(TIF_RESTORE_SIGMASK))
-                       clear_thread_flag(TIF_RESTORE_SIGMASK);
-
-               tracehook_signal_handler(signr, &info, &ka, regs, 0);
-               return;
-       }
-       if (restart_syscall &&
-           (regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
-            regs->u_regs[UREG_I0] == ERESTARTSYS ||
-            regs->u_regs[UREG_I0] == ERESTARTNOINTR)) {
-               /* replay the system call when we are done */
-               regs->u_regs[UREG_I0] = orig_i0;
-               regs->pc -= 4;
-               regs->npc -= 4;
-       }
-       if (restart_syscall &&
-           regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) {
-               regs->u_regs[UREG_G1] = __NR_restart_syscall;
-               regs->pc -= 4;
-               regs->npc -= 4;
-       }
-
-       /* if there's no signal to deliver, we just put the saved sigmask
-        * back
-        */
-       if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
-               clear_thread_flag(TIF_RESTORE_SIGMASK);
-               sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
-       }
-}
-
-void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0,
-                     unsigned long thread_info_flags)
-{
-       if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
-               do_signal(regs, orig_i0);
-       if (thread_info_flags & _TIF_NOTIFY_RESUME) {
-               clear_thread_flag(TIF_NOTIFY_RESUME);
-               tracehook_notify_resume(regs);
-       }
-}
-
-asmlinkage int
-do_sys_sigstack(struct sigstack __user *ssptr, struct sigstack __user *ossptr,
-               unsigned long sp)
-{
-       int ret = -EFAULT;
-
-       /* First see if old state is wanted. */
-       if (ossptr) {
-               if (put_user(current->sas_ss_sp + current->sas_ss_size,
-                            &ossptr->the_stack) ||
-                   __put_user(on_sig_stack(sp), &ossptr->cur_status))
-                       goto out;
-       }
-
-       /* Now see if we want to update the new state. */
-       if (ssptr) {
-               char *ss_sp;
-
-               if (get_user(ss_sp, &ssptr->the_stack))
-                       goto out;
-               /* If the current stack was set with sigaltstack, don't
-                  swap stacks while we are on it.  */
-               ret = -EPERM;
-               if (current->sas_ss_sp && on_sig_stack(sp))
-                       goto out;
-
-               /* Since we don't know the extent of the stack, and we don't
-                  track onstack-ness, but rather calculate it, we must
-                  presume a size.  Ho hum this interface is lossy.  */
-               current->sas_ss_sp = (unsigned long)ss_sp - SIGSTKSZ;
-               current->sas_ss_size = SIGSTKSZ;
-       }
-       ret = 0;
-out:
-       return ret;
-}
diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c
new file mode 100644 (file)
index 0000000..c94f91c
--- /dev/null
@@ -0,0 +1,631 @@
+/*  linux/arch/sparc/kernel/signal.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ *  Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *  Copyright (C) 1997 Eddie C. Dost   (ecd@skynet.be)
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/unistd.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/smp.h>
+#include <linux/binfmts.h>     /* do_coredum */
+#include <linux/bitops.h>
+#include <linux/tracehook.h>
+
+#include <asm/uaccess.h>
+#include <asm/ptrace.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <asm/cacheflush.h>    /* flush_sig_insns */
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
+                  void *fpqueue, unsigned long *fpqdepth);
+extern void fpload(unsigned long *fpregs, unsigned long *fsr);
+
+struct signal_frame {
+       struct sparc_stackf     ss;
+       __siginfo_t             info;
+       __siginfo_fpu_t __user  *fpu_save;
+       unsigned long           insns[2] __attribute__ ((aligned (8)));
+       unsigned int            extramask[_NSIG_WORDS - 1];
+       unsigned int            extra_size; /* Should be 0 */
+       __siginfo_fpu_t         fpu_state;
+};
+
+struct rt_signal_frame {
+       struct sparc_stackf     ss;
+       siginfo_t               info;
+       struct pt_regs          regs;
+       sigset_t                mask;
+       __siginfo_fpu_t __user  *fpu_save;
+       unsigned int            insns[2];
+       stack_t                 stack;
+       unsigned int            extra_size; /* Should be 0 */
+       __siginfo_fpu_t         fpu_state;
+};
+
+/* Align macros */
+#define SF_ALIGNEDSZ  (((sizeof(struct signal_frame) + 7) & (~7)))
+#define RT_ALIGNEDSZ  (((sizeof(struct rt_signal_frame) + 7) & (~7)))
+
+static int _sigpause_common(old_sigset_t set)
+{
+       set &= _BLOCKABLE;
+       spin_lock_irq(&current->sighand->siglock);
+       current->saved_sigmask = current->blocked;
+       siginitset(&current->blocked, set);
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
+
+       current->state = TASK_INTERRUPTIBLE;
+       schedule();
+       set_thread_flag(TIF_RESTORE_SIGMASK);
+
+       return -ERESTARTNOHAND;
+}
+
+asmlinkage int sys_sigsuspend(old_sigset_t set)
+{
+       return _sigpause_common(set);
+}
+
+static inline int
+restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
+{
+       int err;
+#ifdef CONFIG_SMP
+       if (test_tsk_thread_flag(current, TIF_USEDFPU))
+               regs->psr &= ~PSR_EF;
+#else
+       if (current == last_task_used_math) {
+               last_task_used_math = NULL;
+               regs->psr &= ~PSR_EF;
+       }
+#endif
+       set_used_math();
+       clear_tsk_thread_flag(current, TIF_USEDFPU);
+
+       if (!access_ok(VERIFY_READ, fpu, sizeof(*fpu)))
+               return -EFAULT;
+
+       err = __copy_from_user(&current->thread.float_regs[0], &fpu->si_float_regs[0],
+                              (sizeof(unsigned long) * 32));
+       err |= __get_user(current->thread.fsr, &fpu->si_fsr);
+       err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
+       if (current->thread.fpqdepth != 0)
+               err |= __copy_from_user(&current->thread.fpqueue[0],
+                                       &fpu->si_fpqueue[0],
+                                       ((sizeof(unsigned long) +
+                                       (sizeof(unsigned long *)))*16));
+       return err;
+}
+
+asmlinkage void do_sigreturn(struct pt_regs *regs)
+{
+       struct signal_frame __user *sf;
+       unsigned long up_psr, pc, npc;
+       sigset_t set;
+       __siginfo_fpu_t __user *fpu_save;
+       int err;
+
+       /* Always make any pending restarted system calls return -EINTR */
+       current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
+       synchronize_user_stack();
+
+       sf = (struct signal_frame __user *) regs->u_regs[UREG_FP];
+
+       /* 1. Make sure we are not getting garbage from the user */
+       if (!access_ok(VERIFY_READ, sf, sizeof(*sf)))
+               goto segv_and_exit;
+
+       if (((unsigned long) sf) & 3)
+               goto segv_and_exit;
+
+       err = __get_user(pc,  &sf->info.si_regs.pc);
+       err |= __get_user(npc, &sf->info.si_regs.npc);
+
+       if ((pc | npc) & 3)
+               goto segv_and_exit;
+
+       /* 2. Restore the state */
+       up_psr = regs->psr;
+       err |= __copy_from_user(regs, &sf->info.si_regs, sizeof(struct pt_regs));
+
+       /* User can only change condition codes and FPU enabling in %psr. */
+       regs->psr = (up_psr & ~(PSR_ICC | PSR_EF))
+                 | (regs->psr & (PSR_ICC | PSR_EF));
+
+       /* Prevent syscall restart.  */
+       pt_regs_clear_syscall(regs);
+
+       err |= __get_user(fpu_save, &sf->fpu_save);
+
+       if (fpu_save)
+               err |= restore_fpu_state(regs, fpu_save);
+
+       /* This is pretty much atomic, no amount locking would prevent
+        * the races which exist anyways.
+        */
+       err |= __get_user(set.sig[0], &sf->info.si_mask);
+       err |= __copy_from_user(&set.sig[1], &sf->extramask,
+                               (_NSIG_WORDS-1) * sizeof(unsigned int));
+                          
+       if (err)
+               goto segv_and_exit;
+
+       sigdelsetmask(&set, ~_BLOCKABLE);
+       spin_lock_irq(&current->sighand->siglock);
+       current->blocked = set;
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
+       return;
+
+segv_and_exit:
+       force_sig(SIGSEGV, current);
+}
+
+asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
+{
+       struct rt_signal_frame __user *sf;
+       unsigned int psr, pc, npc;
+       __siginfo_fpu_t __user *fpu_save;
+       mm_segment_t old_fs;
+       sigset_t set;
+       stack_t st;
+       int err;
+
+       synchronize_user_stack();
+       sf = (struct rt_signal_frame __user *) regs->u_regs[UREG_FP];
+       if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) ||
+           (((unsigned long) sf) & 0x03))
+               goto segv;
+
+       err = __get_user(pc, &sf->regs.pc);
+       err |= __get_user(npc, &sf->regs.npc);
+       err |= ((pc | npc) & 0x03);
+
+       err |= __get_user(regs->y, &sf->regs.y);
+       err |= __get_user(psr, &sf->regs.psr);
+
+       err |= __copy_from_user(&regs->u_regs[UREG_G1],
+                               &sf->regs.u_regs[UREG_G1], 15 * sizeof(u32));
+
+       regs->psr = (regs->psr & ~PSR_ICC) | (psr & PSR_ICC);
+
+       /* Prevent syscall restart.  */
+       pt_regs_clear_syscall(regs);
+
+       err |= __get_user(fpu_save, &sf->fpu_save);
+
+       if (fpu_save)
+               err |= restore_fpu_state(regs, fpu_save);
+       err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t));
+       
+       err |= __copy_from_user(&st, &sf->stack, sizeof(stack_t));
+       
+       if (err)
+               goto segv;
+               
+       regs->pc = pc;
+       regs->npc = npc;
+       
+       /* It is more difficult to avoid calling this function than to
+        * call it and ignore errors.
+        */
+       old_fs = get_fs();
+       set_fs(KERNEL_DS);
+       do_sigaltstack((const stack_t __user *) &st, NULL, (unsigned long)sf);
+       set_fs(old_fs);
+
+       sigdelsetmask(&set, ~_BLOCKABLE);
+       spin_lock_irq(&current->sighand->siglock);
+       current->blocked = set;
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
+       return;
+segv:
+       force_sig(SIGSEGV, current);
+}
+
+/* Checks if the fp is valid */
+static inline int invalid_frame_pointer(void __user *fp, int fplen)
+{
+       if ((((unsigned long) fp) & 7) ||
+           !__access_ok((unsigned long)fp, fplen) ||
+           ((sparc_cpu_model == sun4 || sparc_cpu_model == sun4c) &&
+            ((unsigned long) fp < 0xe0000000 && (unsigned long) fp >= 0x20000000)))
+               return 1;
+       
+       return 0;
+}
+
+static inline void __user *get_sigframe(struct sigaction *sa, struct pt_regs *regs, unsigned long framesize)
+{
+       unsigned long sp = regs->u_regs[UREG_FP];
+
+       /*
+        * If we are on the alternate signal stack and would overflow it, don't.
+        * Return an always-bogus address instead so we will die with SIGSEGV.
+        */
+       if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize)))
+               return (void __user *) -1L;
+
+       /* This is the X/Open sanctioned signal stack switching.  */
+       if (sa->sa_flags & SA_ONSTACK) {
+               if (sas_ss_flags(sp) == 0)
+                       sp = current->sas_ss_sp + current->sas_ss_size;
+       }
+
+       /* Always align the stack frame.  This handles two cases.  First,
+        * sigaltstack need not be mindful of platform specific stack
+        * alignment.  Second, if we took this signal because the stack
+        * is not aligned properly, we'd like to take the signal cleanly
+        * and report that.
+        */
+       sp &= ~7UL;
+
+       return (void __user *)(sp - framesize);
+}
+
+static inline int
+save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
+{
+       int err = 0;
+#ifdef CONFIG_SMP
+       if (test_tsk_thread_flag(current, TIF_USEDFPU)) {
+               put_psr(get_psr() | PSR_EF);
+               fpsave(&current->thread.float_regs[0], &current->thread.fsr,
+                      &current->thread.fpqueue[0], &current->thread.fpqdepth);
+               regs->psr &= ~(PSR_EF);
+               clear_tsk_thread_flag(current, TIF_USEDFPU);
+       }
+#else
+       if (current == last_task_used_math) {
+               put_psr(get_psr() | PSR_EF);
+               fpsave(&current->thread.float_regs[0], &current->thread.fsr,
+                      &current->thread.fpqueue[0], &current->thread.fpqdepth);
+               last_task_used_math = NULL;
+               regs->psr &= ~(PSR_EF);
+       }
+#endif
+       err |= __copy_to_user(&fpu->si_float_regs[0],
+                             &current->thread.float_regs[0],
+                             (sizeof(unsigned long) * 32));
+       err |= __put_user(current->thread.fsr, &fpu->si_fsr);
+       err |= __put_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
+       if (current->thread.fpqdepth != 0)
+               err |= __copy_to_user(&fpu->si_fpqueue[0],
+                                     &current->thread.fpqueue[0],
+                                     ((sizeof(unsigned long) +
+                                     (sizeof(unsigned long *)))*16));
+       clear_used_math();
+       return err;
+}
+
+static void setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
+                       int signo, sigset_t *oldset)
+{
+       struct signal_frame __user *sf;
+       int sigframe_size, err;
+
+       /* 1. Make sure everything is clean */
+       synchronize_user_stack();
+
+       sigframe_size = SF_ALIGNEDSZ;
+       if (!used_math())
+               sigframe_size -= sizeof(__siginfo_fpu_t);
+
+       sf = (struct signal_frame __user *)
+               get_sigframe(&ka->sa, regs, sigframe_size);
+
+       if (invalid_frame_pointer(sf, sigframe_size))
+               goto sigill_and_return;
+
+       if (current_thread_info()->w_saved != 0)
+               goto sigill_and_return;
+
+       /* 2. Save the current process state */
+       err = __copy_to_user(&sf->info.si_regs, regs, sizeof(struct pt_regs));
+       
+       err |= __put_user(0, &sf->extra_size);
+
+       if (used_math()) {
+               err |= save_fpu_state(regs, &sf->fpu_state);
+               err |= __put_user(&sf->fpu_state, &sf->fpu_save);
+       } else {
+               err |= __put_user(0, &sf->fpu_save);
+       }
+
+       err |= __put_user(oldset->sig[0], &sf->info.si_mask);
+       err |= __copy_to_user(sf->extramask, &oldset->sig[1],
+                             (_NSIG_WORDS - 1) * sizeof(unsigned int));
+       err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
+                             sizeof(struct reg_window));
+       if (err)
+               goto sigsegv;
+       
+       /* 3. signal handler back-trampoline and parameters */
+       regs->u_regs[UREG_FP] = (unsigned long) sf;
+       regs->u_regs[UREG_I0] = signo;
+       regs->u_regs[UREG_I1] = (unsigned long) &sf->info;
+       regs->u_regs[UREG_I2] = (unsigned long) &sf->info;
+
+       /* 4. signal handler */
+       regs->pc = (unsigned long) ka->sa.sa_handler;
+       regs->npc = (regs->pc + 4);
+
+       /* 5. return to kernel instructions */
+       if (ka->ka_restorer)
+               regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
+       else {
+               regs->u_regs[UREG_I7] = (unsigned long)(&(sf->insns[0]) - 2);
+
+               /* mov __NR_sigreturn, %g1 */
+               err |= __put_user(0x821020d8, &sf->insns[0]);
+
+               /* t 0x10 */
+               err |= __put_user(0x91d02010, &sf->insns[1]);
+               if (err)
+                       goto sigsegv;
+
+               /* Flush instruction space. */
+               flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
+       }
+       return;
+
+sigill_and_return:
+       do_exit(SIGILL);
+sigsegv:
+       force_sigsegv(signo, current);
+}
+
+static void setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
+                          int signo, sigset_t *oldset, siginfo_t *info)
+{
+       struct rt_signal_frame __user *sf;
+       int sigframe_size;
+       unsigned int psr;
+       int err;
+
+       synchronize_user_stack();
+       sigframe_size = RT_ALIGNEDSZ;
+       if (!used_math())
+               sigframe_size -= sizeof(__siginfo_fpu_t);
+       sf = (struct rt_signal_frame __user *)
+               get_sigframe(&ka->sa, regs, sigframe_size);
+       if (invalid_frame_pointer(sf, sigframe_size))
+               goto sigill;
+       if (current_thread_info()->w_saved != 0)
+               goto sigill;
+
+       err  = __put_user(regs->pc, &sf->regs.pc);
+       err |= __put_user(regs->npc, &sf->regs.npc);
+       err |= __put_user(regs->y, &sf->regs.y);
+       psr = regs->psr;
+       if (used_math())
+               psr |= PSR_EF;
+       err |= __put_user(psr, &sf->regs.psr);
+       err |= __copy_to_user(&sf->regs.u_regs, regs->u_regs, sizeof(regs->u_regs));
+       err |= __put_user(0, &sf->extra_size);
+
+       if (psr & PSR_EF) {
+               err |= save_fpu_state(regs, &sf->fpu_state);
+               err |= __put_user(&sf->fpu_state, &sf->fpu_save);
+       } else {
+               err |= __put_user(0, &sf->fpu_save);
+       }
+       err |= __copy_to_user(&sf->mask, &oldset->sig[0], sizeof(sigset_t));
+       
+       /* Setup sigaltstack */
+       err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp);
+       err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags);
+       err |= __put_user(current->sas_ss_size, &sf->stack.ss_size);
+       
+       err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
+                             sizeof(struct reg_window));       
+
+       err |= copy_siginfo_to_user(&sf->info, info);
+
+       if (err)
+               goto sigsegv;
+
+       regs->u_regs[UREG_FP] = (unsigned long) sf;
+       regs->u_regs[UREG_I0] = signo;
+       regs->u_regs[UREG_I1] = (unsigned long) &sf->info;
+       regs->u_regs[UREG_I2] = (unsigned long) &sf->regs;
+
+       regs->pc = (unsigned long) ka->sa.sa_handler;
+       regs->npc = (regs->pc + 4);
+
+       if (ka->ka_restorer)
+               regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
+       else {
+               regs->u_regs[UREG_I7] = (unsigned long)(&(sf->insns[0]) - 2);
+
+               /* mov __NR_sigreturn, %g1 */
+               err |= __put_user(0x821020d8, &sf->insns[0]);
+
+               /* t 0x10 */
+               err |= __put_user(0x91d02010, &sf->insns[1]);
+               if (err)
+                       goto sigsegv;
+
+               /* Flush instruction space. */
+               flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
+       }
+       return;
+
+sigill:
+       do_exit(SIGILL);
+sigsegv:
+       force_sigsegv(signo, current);
+}
+
+static inline void
+handle_signal(unsigned long signr, struct k_sigaction *ka,
+             siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
+{
+       if (ka->sa.sa_flags & SA_SIGINFO)
+               setup_rt_frame(ka, regs, signr, oldset, info);
+       else
+               setup_frame(ka, regs, signr, oldset);
+
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NOMASK))
+               sigaddset(&current->blocked, signr);
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
+}
+
+static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
+                                  struct sigaction *sa)
+{
+       switch(regs->u_regs[UREG_I0]) {
+       case ERESTART_RESTARTBLOCK:
+       case ERESTARTNOHAND:
+       no_system_call_restart:
+               regs->u_regs[UREG_I0] = EINTR;
+               regs->psr |= PSR_C;
+               break;
+       case ERESTARTSYS:
+               if (!(sa->sa_flags & SA_RESTART))
+                       goto no_system_call_restart;
+               /* fallthrough */
+       case ERESTARTNOINTR:
+               regs->u_regs[UREG_I0] = orig_i0;
+               regs->pc -= 4;
+               regs->npc -= 4;
+       }
+}
+
+/* Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ */
+static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
+{
+       struct k_sigaction ka;
+       int restart_syscall;
+       sigset_t *oldset;
+       siginfo_t info;
+       int signr;
+
+       if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C))
+               restart_syscall = 1;
+       else
+               restart_syscall = 0;
+
+       if (test_thread_flag(TIF_RESTORE_SIGMASK))
+               oldset = &current->saved_sigmask;
+       else
+               oldset = &current->blocked;
+
+       signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+
+       /* If the debugger messes with the program counter, it clears
+        * the software "in syscall" bit, directing us to not perform
+        * a syscall restart.
+        */
+       if (restart_syscall && !pt_regs_is_syscall(regs))
+               restart_syscall = 0;
+
+       if (signr > 0) {
+               if (restart_syscall)
+                       syscall_restart(orig_i0, regs, &ka.sa);
+               handle_signal(signr, &ka, &info, oldset, regs);
+
+               /* a signal was successfully delivered; the saved
+                * sigmask will have been stored in the signal frame,
+                * and will be restored by sigreturn, so we can simply
+                * clear the TIF_RESTORE_SIGMASK flag.
+                */
+               if (test_thread_flag(TIF_RESTORE_SIGMASK))
+                       clear_thread_flag(TIF_RESTORE_SIGMASK);
+
+               tracehook_signal_handler(signr, &info, &ka, regs, 0);
+               return;
+       }
+       if (restart_syscall &&
+           (regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
+            regs->u_regs[UREG_I0] == ERESTARTSYS ||
+            regs->u_regs[UREG_I0] == ERESTARTNOINTR)) {
+               /* replay the system call when we are done */
+               regs->u_regs[UREG_I0] = orig_i0;
+               regs->pc -= 4;
+               regs->npc -= 4;
+       }
+       if (restart_syscall &&
+           regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) {
+               regs->u_regs[UREG_G1] = __NR_restart_syscall;
+               regs->pc -= 4;
+               regs->npc -= 4;
+       }
+
+       /* if there's no signal to deliver, we just put the saved sigmask
+        * back
+        */
+       if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
+               clear_thread_flag(TIF_RESTORE_SIGMASK);
+               sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
+       }
+}
+
+void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0,
+                     unsigned long thread_info_flags)
+{
+       if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
+               do_signal(regs, orig_i0);
+       if (thread_info_flags & _TIF_NOTIFY_RESUME) {
+               clear_thread_flag(TIF_NOTIFY_RESUME);
+               tracehook_notify_resume(regs);
+       }
+}
+
+asmlinkage int
+do_sys_sigstack(struct sigstack __user *ssptr, struct sigstack __user *ossptr,
+               unsigned long sp)
+{
+       int ret = -EFAULT;
+
+       /* First see if old state is wanted. */
+       if (ossptr) {
+               if (put_user(current->sas_ss_sp + current->sas_ss_size,
+                            &ossptr->the_stack) ||
+                   __put_user(on_sig_stack(sp), &ossptr->cur_status))
+                       goto out;
+       }
+
+       /* Now see if we want to update the new state. */
+       if (ssptr) {
+               char *ss_sp;
+
+               if (get_user(ss_sp, &ssptr->the_stack))
+                       goto out;
+               /* If the current stack was set with sigaltstack, don't
+                  swap stacks while we are on it.  */
+               ret = -EPERM;
+               if (current->sas_ss_sp && on_sig_stack(sp))
+                       goto out;
+
+               /* Since we don't know the extent of the stack, and we don't
+                  track onstack-ness, but rather calculate it, we must
+                  presume a size.  Ho hum this interface is lossy.  */
+               current->sas_ss_sp = (unsigned long)ss_sp - SIGSTKSZ;
+               current->sas_ss_size = SIGSTKSZ;
+       }
+       ret = 0;
+out:
+       return ret;
+}
diff --git a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c
deleted file mode 100644 (file)
index e396c1f..0000000
+++ /dev/null
@@ -1,423 +0,0 @@
-/* smp.c: Sparc SMP support.
- *
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- * Copyright (C) 2004 Keith M Wesolowski (wesolows@foobazco.org)
- */
-
-#include <asm/head.h>
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/threads.h>
-#include <linux/smp.h>
-#include <linux/interrupt.h>
-#include <linux/kernel_stat.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/seq_file.h>
-#include <linux/cache.h>
-#include <linux/delay.h>
-
-#include <asm/ptrace.h>
-#include <asm/atomic.h>
-
-#include <asm/irq.h>
-#include <asm/page.h>
-#include <asm/pgalloc.h>
-#include <asm/pgtable.h>
-#include <asm/oplib.h>
-#include <asm/cacheflush.h>
-#include <asm/tlbflush.h>
-#include <asm/cpudata.h>
-
-#include "irq.h"
-
-volatile unsigned long cpu_callin_map[NR_CPUS] __cpuinitdata = {0,};
-unsigned char boot_cpu_id = 0;
-unsigned char boot_cpu_id4 = 0; /* boot_cpu_id << 2 */
-
-cpumask_t cpu_online_map = CPU_MASK_NONE;
-cpumask_t phys_cpu_present_map = CPU_MASK_NONE;
-cpumask_t smp_commenced_mask = CPU_MASK_NONE;
-
-/* The only guaranteed locking primitive available on all Sparc
- * processors is 'ldstub [%reg + immediate], %dest_reg' which atomically
- * places the current byte at the effective address into dest_reg and
- * places 0xff there afterwards.  Pretty lame locking primitive
- * compared to the Alpha and the Intel no?  Most Sparcs have 'swap'
- * instruction which is much better...
- */
-
-void __cpuinit smp_store_cpu_info(int id)
-{
-       int cpu_node;
-
-       cpu_data(id).udelay_val = loops_per_jiffy;
-
-       cpu_find_by_mid(id, &cpu_node);
-       cpu_data(id).clock_tick = prom_getintdefault(cpu_node,
-                                                    "clock-frequency", 0);
-       cpu_data(id).prom_node = cpu_node;
-       cpu_data(id).mid = cpu_get_hwmid(cpu_node);
-
-       if (cpu_data(id).mid < 0)
-               panic("No MID found for CPU%d at node 0x%08d", id, cpu_node);
-}
-
-void __init smp_cpus_done(unsigned int max_cpus)
-{
-       extern void smp4m_smp_done(void);
-       extern void smp4d_smp_done(void);
-       unsigned long bogosum = 0;
-       int cpu, num;
-
-       for (cpu = 0, num = 0; cpu < NR_CPUS; cpu++)
-               if (cpu_online(cpu)) {
-                       num++;
-                       bogosum += cpu_data(cpu).udelay_val;
-               }
-
-       printk("Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
-               num, bogosum/(500000/HZ),
-               (bogosum/(5000/HZ))%100);
-
-       switch(sparc_cpu_model) {
-       case sun4:
-               printk("SUN4\n");
-               BUG();
-               break;
-       case sun4c:
-               printk("SUN4C\n");
-               BUG();
-               break;
-       case sun4m:
-               smp4m_smp_done();
-               break;
-       case sun4d:
-               smp4d_smp_done();
-               break;
-       case sun4e:
-               printk("SUN4E\n");
-               BUG();
-               break;
-       case sun4u:
-               printk("SUN4U\n");
-               BUG();
-               break;
-       default:
-               printk("UNKNOWN!\n");
-               BUG();
-               break;
-       };
-}
-
-void cpu_panic(void)
-{
-       printk("CPU[%d]: Returns from cpu_idle!\n", smp_processor_id());
-       panic("SMP bolixed\n");
-}
-
-struct linux_prom_registers smp_penguin_ctable __cpuinitdata = { 0 };
-
-void smp_send_reschedule(int cpu)
-{
-       /* See sparc64 */
-}
-
-void smp_send_stop(void)
-{
-}
-
-void smp_flush_cache_all(void)
-{
-       xc0((smpfunc_t) BTFIXUP_CALL(local_flush_cache_all));
-       local_flush_cache_all();
-}
-
-void smp_flush_tlb_all(void)
-{
-       xc0((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_all));
-       local_flush_tlb_all();
-}
-
-void smp_flush_cache_mm(struct mm_struct *mm)
-{
-       if(mm->context != NO_CONTEXT) {
-               cpumask_t cpu_mask = mm->cpu_vm_mask;
-               cpu_clear(smp_processor_id(), cpu_mask);
-               if (!cpus_empty(cpu_mask))
-                       xc1((smpfunc_t) BTFIXUP_CALL(local_flush_cache_mm), (unsigned long) mm);
-               local_flush_cache_mm(mm);
-       }
-}
-
-void smp_flush_tlb_mm(struct mm_struct *mm)
-{
-       if(mm->context != NO_CONTEXT) {
-               cpumask_t cpu_mask = mm->cpu_vm_mask;
-               cpu_clear(smp_processor_id(), cpu_mask);
-               if (!cpus_empty(cpu_mask)) {
-                       xc1((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_mm), (unsigned long) mm);
-                       if(atomic_read(&mm->mm_users) == 1 && current->active_mm == mm)
-                               mm->cpu_vm_mask = cpumask_of_cpu(smp_processor_id());
-               }
-               local_flush_tlb_mm(mm);
-       }
-}
-
-void smp_flush_cache_range(struct vm_area_struct *vma, unsigned long start,
-                          unsigned long end)
-{
-       struct mm_struct *mm = vma->vm_mm;
-
-       if (mm->context != NO_CONTEXT) {
-               cpumask_t cpu_mask = mm->cpu_vm_mask;
-               cpu_clear(smp_processor_id(), cpu_mask);
-               if (!cpus_empty(cpu_mask))
-                       xc3((smpfunc_t) BTFIXUP_CALL(local_flush_cache_range), (unsigned long) vma, start, end);
-               local_flush_cache_range(vma, start, end);
-       }
-}
-
-void smp_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
-                        unsigned long end)
-{
-       struct mm_struct *mm = vma->vm_mm;
-
-       if (mm->context != NO_CONTEXT) {
-               cpumask_t cpu_mask = mm->cpu_vm_mask;
-               cpu_clear(smp_processor_id(), cpu_mask);
-               if (!cpus_empty(cpu_mask))
-                       xc3((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_range), (unsigned long) vma, start, end);
-               local_flush_tlb_range(vma, start, end);
-       }
-}
-
-void smp_flush_cache_page(struct vm_area_struct *vma, unsigned long page)
-{
-       struct mm_struct *mm = vma->vm_mm;
-
-       if(mm->context != NO_CONTEXT) {
-               cpumask_t cpu_mask = mm->cpu_vm_mask;
-               cpu_clear(smp_processor_id(), cpu_mask);
-               if (!cpus_empty(cpu_mask))
-                       xc2((smpfunc_t) BTFIXUP_CALL(local_flush_cache_page), (unsigned long) vma, page);
-               local_flush_cache_page(vma, page);
-       }
-}
-
-void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
-{
-       struct mm_struct *mm = vma->vm_mm;
-
-       if(mm->context != NO_CONTEXT) {
-               cpumask_t cpu_mask = mm->cpu_vm_mask;
-               cpu_clear(smp_processor_id(), cpu_mask);
-               if (!cpus_empty(cpu_mask))
-                       xc2((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_page), (unsigned long) vma, page);
-               local_flush_tlb_page(vma, page);
-       }
-}
-
-void smp_reschedule_irq(void)
-{
-       set_need_resched();
-}
-
-void smp_flush_page_to_ram(unsigned long page)
-{
-       /* Current theory is that those who call this are the one's
-        * who have just dirtied their cache with the pages contents
-        * in kernel space, therefore we only run this on local cpu.
-        *
-        * XXX This experiment failed, research further... -DaveM
-        */
-#if 1
-       xc1((smpfunc_t) BTFIXUP_CALL(local_flush_page_to_ram), page);
-#endif
-       local_flush_page_to_ram(page);
-}
-
-void smp_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr)
-{
-       cpumask_t cpu_mask = mm->cpu_vm_mask;
-       cpu_clear(smp_processor_id(), cpu_mask);
-       if (!cpus_empty(cpu_mask))
-               xc2((smpfunc_t) BTFIXUP_CALL(local_flush_sig_insns), (unsigned long) mm, insn_addr);
-       local_flush_sig_insns(mm, insn_addr);
-}
-
-extern unsigned int lvl14_resolution;
-
-/* /proc/profile writes can call this, don't __init it please. */
-static DEFINE_SPINLOCK(prof_setup_lock);
-
-int setup_profiling_timer(unsigned int multiplier)
-{
-       int i;
-       unsigned long flags;
-
-       /* Prevent level14 ticker IRQ flooding. */
-       if((!multiplier) || (lvl14_resolution / multiplier) < 500)
-               return -EINVAL;
-
-       spin_lock_irqsave(&prof_setup_lock, flags);
-       for_each_possible_cpu(i) {
-               load_profile_irq(i, lvl14_resolution / multiplier);
-               prof_multiplier(i) = multiplier;
-       }
-       spin_unlock_irqrestore(&prof_setup_lock, flags);
-
-       return 0;
-}
-
-void __init smp_prepare_cpus(unsigned int max_cpus)
-{
-       extern void __init smp4m_boot_cpus(void);
-       extern void __init smp4d_boot_cpus(void);
-       int i, cpuid, extra;
-
-       printk("Entering SMP Mode...\n");
-
-       extra = 0;
-       for (i = 0; !cpu_find_by_instance(i, NULL, &cpuid); i++) {
-               if (cpuid >= NR_CPUS)
-                       extra++;
-       }
-       /* i = number of cpus */
-       if (extra && max_cpus > i - extra)
-               printk("Warning: NR_CPUS is too low to start all cpus\n");
-
-       smp_store_cpu_info(boot_cpu_id);
-
-       switch(sparc_cpu_model) {
-       case sun4:
-               printk("SUN4\n");
-               BUG();
-               break;
-       case sun4c:
-               printk("SUN4C\n");
-               BUG();
-               break;
-       case sun4m:
-               smp4m_boot_cpus();
-               break;
-       case sun4d:
-               smp4d_boot_cpus();
-               break;
-       case sun4e:
-               printk("SUN4E\n");
-               BUG();
-               break;
-       case sun4u:
-               printk("SUN4U\n");
-               BUG();
-               break;
-       default:
-               printk("UNKNOWN!\n");
-               BUG();
-               break;
-       };
-}
-
-/* Set this up early so that things like the scheduler can init
- * properly.  We use the same cpu mask for both the present and
- * possible cpu map.
- */
-void __init smp_setup_cpu_possible_map(void)
-{
-       int instance, mid;
-
-       instance = 0;
-       while (!cpu_find_by_instance(instance, NULL, &mid)) {
-               if (mid < NR_CPUS) {
-                       cpu_set(mid, phys_cpu_present_map);
-                       cpu_set(mid, cpu_present_map);
-               }
-               instance++;
-       }
-}
-
-void __init smp_prepare_boot_cpu(void)
-{
-       int cpuid = hard_smp_processor_id();
-
-       if (cpuid >= NR_CPUS) {
-               prom_printf("Serious problem, boot cpu id >= NR_CPUS\n");
-               prom_halt();
-       }
-       if (cpuid != 0)
-               printk("boot cpu id != 0, this could work but is untested\n");
-
-       current_thread_info()->cpu = cpuid;
-       cpu_set(cpuid, cpu_online_map);
-       cpu_set(cpuid, phys_cpu_present_map);
-}
-
-int __cpuinit __cpu_up(unsigned int cpu)
-{
-       extern int __cpuinit smp4m_boot_one_cpu(int);
-       extern int __cpuinit smp4d_boot_one_cpu(int);
-       int ret=0;
-
-       switch(sparc_cpu_model) {
-       case sun4:
-               printk("SUN4\n");
-               BUG();
-               break;
-       case sun4c:
-               printk("SUN4C\n");
-               BUG();
-               break;
-       case sun4m:
-               ret = smp4m_boot_one_cpu(cpu);
-               break;
-       case sun4d:
-               ret = smp4d_boot_one_cpu(cpu);
-               break;
-       case sun4e:
-               printk("SUN4E\n");
-               BUG();
-               break;
-       case sun4u:
-               printk("SUN4U\n");
-               BUG();
-               break;
-       default:
-               printk("UNKNOWN!\n");
-               BUG();
-               break;
-       };
-
-       if (!ret) {
-               cpu_set(cpu, smp_commenced_mask);
-               while (!cpu_online(cpu))
-                       mb();
-       }
-       return ret;
-}
-
-void smp_bogo(struct seq_file *m)
-{
-       int i;
-       
-       for_each_online_cpu(i) {
-               seq_printf(m,
-                          "Cpu%dBogo\t: %lu.%02lu\n",
-                          i,
-                          cpu_data(i).udelay_val/(500000/HZ),
-                          (cpu_data(i).udelay_val/(5000/HZ))%100);
-       }
-}
-
-void smp_info(struct seq_file *m)
-{
-       int i;
-
-       seq_printf(m, "State:\n");
-       for_each_online_cpu(i)
-               seq_printf(m, "CPU%d\t\t: online\n", i);
-}
diff --git a/arch/sparc/kernel/smp_32.c b/arch/sparc/kernel/smp_32.c
new file mode 100644 (file)
index 0000000..e396c1f
--- /dev/null
@@ -0,0 +1,423 @@
+/* smp.c: Sparc SMP support.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 2004 Keith M Wesolowski (wesolows@foobazco.org)
+ */
+
+#include <asm/head.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/threads.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/seq_file.h>
+#include <linux/cache.h>
+#include <linux/delay.h>
+
+#include <asm/ptrace.h>
+#include <asm/atomic.h>
+
+#include <asm/irq.h>
+#include <asm/page.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <asm/oplib.h>
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
+#include <asm/cpudata.h>
+
+#include "irq.h"
+
+volatile unsigned long cpu_callin_map[NR_CPUS] __cpuinitdata = {0,};
+unsigned char boot_cpu_id = 0;
+unsigned char boot_cpu_id4 = 0; /* boot_cpu_id << 2 */
+
+cpumask_t cpu_online_map = CPU_MASK_NONE;
+cpumask_t phys_cpu_present_map = CPU_MASK_NONE;
+cpumask_t smp_commenced_mask = CPU_MASK_NONE;
+
+/* The only guaranteed locking primitive available on all Sparc
+ * processors is 'ldstub [%reg + immediate], %dest_reg' which atomically
+ * places the current byte at the effective address into dest_reg and
+ * places 0xff there afterwards.  Pretty lame locking primitive
+ * compared to the Alpha and the Intel no?  Most Sparcs have 'swap'
+ * instruction which is much better...
+ */
+
+void __cpuinit smp_store_cpu_info(int id)
+{
+       int cpu_node;
+
+       cpu_data(id).udelay_val = loops_per_jiffy;
+
+       cpu_find_by_mid(id, &cpu_node);
+       cpu_data(id).clock_tick = prom_getintdefault(cpu_node,
+                                                    "clock-frequency", 0);
+       cpu_data(id).prom_node = cpu_node;
+       cpu_data(id).mid = cpu_get_hwmid(cpu_node);
+
+       if (cpu_data(id).mid < 0)
+               panic("No MID found for CPU%d at node 0x%08d", id, cpu_node);
+}
+
+void __init smp_cpus_done(unsigned int max_cpus)
+{
+       extern void smp4m_smp_done(void);
+       extern void smp4d_smp_done(void);
+       unsigned long bogosum = 0;
+       int cpu, num;
+
+       for (cpu = 0, num = 0; cpu < NR_CPUS; cpu++)
+               if (cpu_online(cpu)) {
+                       num++;
+                       bogosum += cpu_data(cpu).udelay_val;
+               }
+
+       printk("Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
+               num, bogosum/(500000/HZ),
+               (bogosum/(5000/HZ))%100);
+
+       switch(sparc_cpu_model) {
+       case sun4:
+               printk("SUN4\n");
+               BUG();
+               break;
+       case sun4c:
+               printk("SUN4C\n");
+               BUG();
+               break;
+       case sun4m:
+               smp4m_smp_done();
+               break;
+       case sun4d:
+               smp4d_smp_done();
+               break;
+       case sun4e:
+               printk("SUN4E\n");
+               BUG();
+               break;
+       case sun4u:
+               printk("SUN4U\n");
+               BUG();
+               break;
+       default:
+               printk("UNKNOWN!\n");
+               BUG();
+               break;
+       };
+}
+
+void cpu_panic(void)
+{
+       printk("CPU[%d]: Returns from cpu_idle!\n", smp_processor_id());
+       panic("SMP bolixed\n");
+}
+
+struct linux_prom_registers smp_penguin_ctable __cpuinitdata = { 0 };
+
+void smp_send_reschedule(int cpu)
+{
+       /* See sparc64 */
+}
+
+void smp_send_stop(void)
+{
+}
+
+void smp_flush_cache_all(void)
+{
+       xc0((smpfunc_t) BTFIXUP_CALL(local_flush_cache_all));
+       local_flush_cache_all();
+}
+
+void smp_flush_tlb_all(void)
+{
+       xc0((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_all));
+       local_flush_tlb_all();
+}
+
+void smp_flush_cache_mm(struct mm_struct *mm)
+{
+       if(mm->context != NO_CONTEXT) {
+               cpumask_t cpu_mask = mm->cpu_vm_mask;
+               cpu_clear(smp_processor_id(), cpu_mask);
+               if (!cpus_empty(cpu_mask))
+                       xc1((smpfunc_t) BTFIXUP_CALL(local_flush_cache_mm), (unsigned long) mm);
+               local_flush_cache_mm(mm);
+       }
+}
+
+void smp_flush_tlb_mm(struct mm_struct *mm)
+{
+       if(mm->context != NO_CONTEXT) {
+               cpumask_t cpu_mask = mm->cpu_vm_mask;
+               cpu_clear(smp_processor_id(), cpu_mask);
+               if (!cpus_empty(cpu_mask)) {
+                       xc1((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_mm), (unsigned long) mm);
+                       if(atomic_read(&mm->mm_users) == 1 && current->active_mm == mm)
+                               mm->cpu_vm_mask = cpumask_of_cpu(smp_processor_id());
+               }
+               local_flush_tlb_mm(mm);
+       }
+}
+
+void smp_flush_cache_range(struct vm_area_struct *vma, unsigned long start,
+                          unsigned long end)
+{
+       struct mm_struct *mm = vma->vm_mm;
+
+       if (mm->context != NO_CONTEXT) {
+               cpumask_t cpu_mask = mm->cpu_vm_mask;
+               cpu_clear(smp_processor_id(), cpu_mask);
+               if (!cpus_empty(cpu_mask))
+                       xc3((smpfunc_t) BTFIXUP_CALL(local_flush_cache_range), (unsigned long) vma, start, end);
+               local_flush_cache_range(vma, start, end);
+       }
+}
+
+void smp_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
+                        unsigned long end)
+{
+       struct mm_struct *mm = vma->vm_mm;
+
+       if (mm->context != NO_CONTEXT) {
+               cpumask_t cpu_mask = mm->cpu_vm_mask;
+               cpu_clear(smp_processor_id(), cpu_mask);
+               if (!cpus_empty(cpu_mask))
+                       xc3((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_range), (unsigned long) vma, start, end);
+               local_flush_tlb_range(vma, start, end);
+       }
+}
+
+void smp_flush_cache_page(struct vm_area_struct *vma, unsigned long page)
+{
+       struct mm_struct *mm = vma->vm_mm;
+
+       if(mm->context != NO_CONTEXT) {
+               cpumask_t cpu_mask = mm->cpu_vm_mask;
+               cpu_clear(smp_processor_id(), cpu_mask);
+               if (!cpus_empty(cpu_mask))
+                       xc2((smpfunc_t) BTFIXUP_CALL(local_flush_cache_page), (unsigned long) vma, page);
+               local_flush_cache_page(vma, page);
+       }
+}
+
+void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+{
+       struct mm_struct *mm = vma->vm_mm;
+
+       if(mm->context != NO_CONTEXT) {
+               cpumask_t cpu_mask = mm->cpu_vm_mask;
+               cpu_clear(smp_processor_id(), cpu_mask);
+               if (!cpus_empty(cpu_mask))
+                       xc2((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_page), (unsigned long) vma, page);
+               local_flush_tlb_page(vma, page);
+       }
+}
+
+void smp_reschedule_irq(void)
+{
+       set_need_resched();
+}
+
+void smp_flush_page_to_ram(unsigned long page)
+{
+       /* Current theory is that those who call this are the one's
+        * who have just dirtied their cache with the pages contents
+        * in kernel space, therefore we only run this on local cpu.
+        *
+        * XXX This experiment failed, research further... -DaveM
+        */
+#if 1
+       xc1((smpfunc_t) BTFIXUP_CALL(local_flush_page_to_ram), page);
+#endif
+       local_flush_page_to_ram(page);
+}
+
+void smp_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr)
+{
+       cpumask_t cpu_mask = mm->cpu_vm_mask;
+       cpu_clear(smp_processor_id(), cpu_mask);
+       if (!cpus_empty(cpu_mask))
+               xc2((smpfunc_t) BTFIXUP_CALL(local_flush_sig_insns), (unsigned long) mm, insn_addr);
+       local_flush_sig_insns(mm, insn_addr);
+}
+
+extern unsigned int lvl14_resolution;
+
+/* /proc/profile writes can call this, don't __init it please. */
+static DEFINE_SPINLOCK(prof_setup_lock);
+
+int setup_profiling_timer(unsigned int multiplier)
+{
+       int i;
+       unsigned long flags;
+
+       /* Prevent level14 ticker IRQ flooding. */
+       if((!multiplier) || (lvl14_resolution / multiplier) < 500)
+               return -EINVAL;
+
+       spin_lock_irqsave(&prof_setup_lock, flags);
+       for_each_possible_cpu(i) {
+               load_profile_irq(i, lvl14_resolution / multiplier);
+               prof_multiplier(i) = multiplier;
+       }
+       spin_unlock_irqrestore(&prof_setup_lock, flags);
+
+       return 0;
+}
+
+void __init smp_prepare_cpus(unsigned int max_cpus)
+{
+       extern void __init smp4m_boot_cpus(void);
+       extern void __init smp4d_boot_cpus(void);
+       int i, cpuid, extra;
+
+       printk("Entering SMP Mode...\n");
+
+       extra = 0;
+       for (i = 0; !cpu_find_by_instance(i, NULL, &cpuid); i++) {
+               if (cpuid >= NR_CPUS)
+                       extra++;
+       }
+       /* i = number of cpus */
+       if (extra && max_cpus > i - extra)
+               printk("Warning: NR_CPUS is too low to start all cpus\n");
+
+       smp_store_cpu_info(boot_cpu_id);
+
+       switch(sparc_cpu_model) {
+       case sun4:
+               printk("SUN4\n");
+               BUG();
+               break;
+       case sun4c:
+               printk("SUN4C\n");
+               BUG();
+               break;
+       case sun4m:
+               smp4m_boot_cpus();
+               break;
+       case sun4d:
+               smp4d_boot_cpus();
+               break;
+       case sun4e:
+               printk("SUN4E\n");
+               BUG();
+               break;
+       case sun4u:
+               printk("SUN4U\n");
+               BUG();
+               break;
+       default:
+               printk("UNKNOWN!\n");
+               BUG();
+               break;
+       };
+}
+
+/* Set this up early so that things like the scheduler can init
+ * properly.  We use the same cpu mask for both the present and
+ * possible cpu map.
+ */
+void __init smp_setup_cpu_possible_map(void)
+{
+       int instance, mid;
+
+       instance = 0;
+       while (!cpu_find_by_instance(instance, NULL, &mid)) {
+               if (mid < NR_CPUS) {
+                       cpu_set(mid, phys_cpu_present_map);
+                       cpu_set(mid, cpu_present_map);
+               }
+               instance++;
+       }
+}
+
+void __init smp_prepare_boot_cpu(void)
+{
+       int cpuid = hard_smp_processor_id();
+
+       if (cpuid >= NR_CPUS) {
+               prom_printf("Serious problem, boot cpu id >= NR_CPUS\n");
+               prom_halt();
+       }
+       if (cpuid != 0)
+               printk("boot cpu id != 0, this could work but is untested\n");
+
+       current_thread_info()->cpu = cpuid;
+       cpu_set(cpuid, cpu_online_map);
+       cpu_set(cpuid, phys_cpu_present_map);
+}
+
+int __cpuinit __cpu_up(unsigned int cpu)
+{
+       extern int __cpuinit smp4m_boot_one_cpu(int);
+       extern int __cpuinit smp4d_boot_one_cpu(int);
+       int ret=0;
+
+       switch(sparc_cpu_model) {
+       case sun4:
+               printk("SUN4\n");
+               BUG();
+               break;
+       case sun4c:
+               printk("SUN4C\n");
+               BUG();
+               break;
+       case sun4m:
+               ret = smp4m_boot_one_cpu(cpu);
+               break;
+       case sun4d:
+               ret = smp4d_boot_one_cpu(cpu);
+               break;
+       case sun4e:
+               printk("SUN4E\n");
+               BUG();
+               break;
+       case sun4u:
+               printk("SUN4U\n");
+               BUG();
+               break;
+       default:
+               printk("UNKNOWN!\n");
+               BUG();
+               break;
+       };
+
+       if (!ret) {
+               cpu_set(cpu, smp_commenced_mask);
+               while (!cpu_online(cpu))
+                       mb();
+       }
+       return ret;
+}
+
+void smp_bogo(struct seq_file *m)
+{
+       int i;
+       
+       for_each_online_cpu(i) {
+               seq_printf(m,
+                          "Cpu%dBogo\t: %lu.%02lu\n",
+                          i,
+                          cpu_data(i).udelay_val/(500000/HZ),
+                          (cpu_data(i).udelay_val/(5000/HZ))%100);
+       }
+}
+
+void smp_info(struct seq_file *m)
+{
+       int i;
+
+       seq_printf(m, "State:\n");
+       for_each_online_cpu(i)
+               seq_printf(m, "CPU%d\t\t: online\n", i);
+}
diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c
deleted file mode 100644 (file)
index b0dfff8..0000000
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
- *
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
- */
-
-/* Tell string.h we don't want memcpy etc. as cpp defines */
-#define EXPORT_SYMTAB_STROPS
-#define PROMLIB_INTERNAL
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/in6.h>
-#include <linux/spinlock.h>
-#include <linux/mm.h>
-#include <linux/syscalls.h>
-#ifdef CONFIG_PCI
-#include <linux/pci.h>
-#endif
-#include <linux/pm.h>
-#ifdef CONFIG_HIGHMEM
-#include <linux/highmem.h>
-#endif
-
-#include <asm/oplib.h>
-#include <asm/delay.h>
-#include <asm/system.h>
-#include <asm/auxio.h>
-#include <asm/pgtable.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/idprom.h>
-#include <asm/head.h>
-#include <asm/smp.h>
-#include <asm/ptrace.h>
-#include <asm/uaccess.h>
-#include <asm/checksum.h>
-#ifdef CONFIG_SBUS
-#include <asm/dma.h>
-#endif
-#include <asm/io-unit.h>
-#include <asm/bug.h>
-
-extern spinlock_t rtc_lock;
-
-struct poll {
-       int fd;
-       short events;
-       short revents;
-};
-
-extern void (*__copy_1page)(void *, const void *);
-extern void __memmove(void *, const void *, __kernel_size_t);
-extern void (*bzero_1page)(void *);
-extern void *__bzero(void *, size_t);
-extern void *__memscan_zero(void *, size_t);
-extern void *__memscan_generic(void *, int, size_t);
-extern int __memcmp(const void *, const void *, __kernel_size_t);
-extern int __strncmp(const char *, const char *, __kernel_size_t);
-
-extern int __ashrdi3(int, int);
-extern int __ashldi3(int, int);
-extern int __lshrdi3(int, int);
-extern int __muldi3(int, int);
-extern int __divdi3(int, int);
-
-/* Private functions with odd calling conventions. */
-extern void ___atomic24_add(void);
-extern void ___atomic24_sub(void);
-extern void ___rw_read_enter(void);
-extern void ___rw_read_try(void);
-extern void ___rw_read_exit(void);
-extern void ___rw_write_enter(void);
-
-/* Alias functions whose names begin with "." and export the aliases.
- * The module references will be fixed up by module_frob_arch_sections.
- */
-extern int _Div(int, int);
-extern int _Mul(int, int);
-extern int _Rem(int, int);
-extern unsigned _Udiv(unsigned, unsigned);
-extern unsigned _Umul(unsigned, unsigned);
-extern unsigned _Urem(unsigned, unsigned);
-
-/* used by various drivers */
-EXPORT_SYMBOL(sparc_cpu_model);
-EXPORT_SYMBOL(kernel_thread);
-#ifdef CONFIG_SMP
-// XXX find what uses (or used) these.   AV: see asm/spinlock.h
-EXPORT_SYMBOL(___rw_read_enter);
-EXPORT_SYMBOL(___rw_read_try);
-EXPORT_SYMBOL(___rw_read_exit);
-EXPORT_SYMBOL(___rw_write_enter);
-#endif
-
-EXPORT_SYMBOL(sparc_valid_addr_bitmap);
-EXPORT_SYMBOL(phys_base);
-EXPORT_SYMBOL(pfn_base);
-
-/* Atomic operations. */
-EXPORT_SYMBOL(___atomic24_add);
-EXPORT_SYMBOL(___atomic24_sub);
-
-/* Per-CPU information table */
-EXPORT_PER_CPU_SYMBOL(__cpu_data);
-
-#ifdef CONFIG_SMP
-/* IRQ implementation. */
-EXPORT_SYMBOL(synchronize_irq);
-
-/* CPU online map and active count. */
-EXPORT_SYMBOL(cpu_online_map);
-EXPORT_SYMBOL(phys_cpu_present_map);
-#endif
-
-EXPORT_SYMBOL(__udelay);
-EXPORT_SYMBOL(__ndelay);
-EXPORT_SYMBOL(rtc_lock);
-#ifdef CONFIG_SUN_AUXIO
-EXPORT_SYMBOL(set_auxio);
-EXPORT_SYMBOL(get_auxio);
-#endif
-EXPORT_SYMBOL(io_remap_pfn_range);
-
-#ifndef CONFIG_SMP
-EXPORT_SYMBOL(BTFIXUP_CALL(___xchg32));
-#else
-EXPORT_SYMBOL(BTFIXUP_CALL(__hard_smp_processor_id));
-#endif
-EXPORT_SYMBOL(BTFIXUP_CALL(mmu_unlockarea));
-EXPORT_SYMBOL(BTFIXUP_CALL(mmu_lockarea));
-EXPORT_SYMBOL(BTFIXUP_CALL(mmu_get_scsi_sgl));
-EXPORT_SYMBOL(BTFIXUP_CALL(mmu_get_scsi_one));
-EXPORT_SYMBOL(BTFIXUP_CALL(mmu_release_scsi_sgl));
-EXPORT_SYMBOL(BTFIXUP_CALL(mmu_release_scsi_one));
-
-EXPORT_SYMBOL(BTFIXUP_CALL(pgprot_noncached));
-
-#ifdef CONFIG_SBUS
-EXPORT_SYMBOL(sbus_set_sbus64);
-#endif
-#ifdef CONFIG_PCI
-EXPORT_SYMBOL(insb);
-EXPORT_SYMBOL(outsb);
-EXPORT_SYMBOL(insw);
-EXPORT_SYMBOL(outsw);
-EXPORT_SYMBOL(insl);
-EXPORT_SYMBOL(outsl);
-EXPORT_SYMBOL(pci_alloc_consistent);
-EXPORT_SYMBOL(pci_free_consistent);
-EXPORT_SYMBOL(pci_map_single);
-EXPORT_SYMBOL(pci_unmap_single);
-EXPORT_SYMBOL(pci_dma_sync_single_for_cpu);
-EXPORT_SYMBOL(pci_dma_sync_single_for_device);
-EXPORT_SYMBOL(pci_dma_sync_sg_for_cpu);
-EXPORT_SYMBOL(pci_dma_sync_sg_for_device);
-EXPORT_SYMBOL(pci_map_sg);
-EXPORT_SYMBOL(pci_unmap_sg);
-EXPORT_SYMBOL(pci_map_page);
-EXPORT_SYMBOL(pci_unmap_page);
-/* Actually, ioremap/iounmap are not PCI specific. But it is ok for drivers. */
-EXPORT_SYMBOL(ioremap);
-EXPORT_SYMBOL(iounmap);
-#endif
-
-/* in arch/sparc/mm/highmem.c */
-#ifdef CONFIG_HIGHMEM
-EXPORT_SYMBOL(kmap_atomic);
-EXPORT_SYMBOL(kunmap_atomic);
-#endif
-
-/* prom symbols */
-EXPORT_SYMBOL(idprom);
-EXPORT_SYMBOL(prom_root_node);
-EXPORT_SYMBOL(prom_getchild);
-EXPORT_SYMBOL(prom_getsibling);
-EXPORT_SYMBOL(prom_searchsiblings);
-EXPORT_SYMBOL(prom_firstprop);
-EXPORT_SYMBOL(prom_nextprop);
-EXPORT_SYMBOL(prom_getproplen);
-EXPORT_SYMBOL(prom_getproperty);
-EXPORT_SYMBOL(prom_node_has_property);
-EXPORT_SYMBOL(prom_setprop);
-EXPORT_SYMBOL(saved_command_line);
-EXPORT_SYMBOL(prom_apply_obio_ranges);
-EXPORT_SYMBOL(prom_feval);
-EXPORT_SYMBOL(prom_getbool);
-EXPORT_SYMBOL(prom_getstring);
-EXPORT_SYMBOL(prom_getint);
-EXPORT_SYMBOL(prom_getintdefault);
-EXPORT_SYMBOL(prom_finddevice);
-EXPORT_SYMBOL(romvec);
-EXPORT_SYMBOL(__prom_getchild);
-EXPORT_SYMBOL(__prom_getsibling);
-
-/* sparc library symbols */
-EXPORT_SYMBOL(memscan);
-EXPORT_SYMBOL(strlen);
-EXPORT_SYMBOL(strncmp);
-EXPORT_SYMBOL(page_kernel);
-
-/* Special internal versions of library functions. */
-EXPORT_SYMBOL(__copy_1page);
-EXPORT_SYMBOL(__memcpy);
-EXPORT_SYMBOL(__memset);
-EXPORT_SYMBOL(bzero_1page);
-EXPORT_SYMBOL(__bzero);
-EXPORT_SYMBOL(__memscan_zero);
-EXPORT_SYMBOL(__memscan_generic);
-EXPORT_SYMBOL(__memcmp);
-EXPORT_SYMBOL(__strncmp);
-EXPORT_SYMBOL(__memmove);
-
-/* Moving data to/from userspace. */
-EXPORT_SYMBOL(__copy_user);
-EXPORT_SYMBOL(__strncpy_from_user);
-EXPORT_SYMBOL(__strnlen_user);
-
-/* Networking helper routines. */
-EXPORT_SYMBOL(__csum_partial_copy_sparc_generic);
-EXPORT_SYMBOL(csum_partial);
-
-/* Cache flushing.  */
-EXPORT_SYMBOL(sparc_flush_page_to_ram);
-
-/* For when serial stuff is built as modules. */
-EXPORT_SYMBOL(sun_do_break);
-
-EXPORT_SYMBOL(__ret_efault);
-
-EXPORT_SYMBOL(memcmp);
-EXPORT_SYMBOL(memcpy);
-EXPORT_SYMBOL(memset);
-EXPORT_SYMBOL(memmove);
-EXPORT_SYMBOL(__ashrdi3);
-EXPORT_SYMBOL(__ashldi3);
-EXPORT_SYMBOL(__lshrdi3);
-EXPORT_SYMBOL(__muldi3);
-EXPORT_SYMBOL(__divdi3);
-
-EXPORT_SYMBOL(_Rem);
-EXPORT_SYMBOL(_Urem);
-EXPORT_SYMBOL(_Mul);
-EXPORT_SYMBOL(_Umul);
-EXPORT_SYMBOL(_Div);
-EXPORT_SYMBOL(_Udiv);
-
-#ifdef CONFIG_DEBUG_BUGVERBOSE
-EXPORT_SYMBOL(do_BUG);
-#endif
-
-/* Sun Power Management Idle Handler */
-EXPORT_SYMBOL(pm_idle);
-
-EXPORT_SYMBOL(empty_zero_page);
diff --git a/arch/sparc/kernel/sparc_ksyms_32.c b/arch/sparc/kernel/sparc_ksyms_32.c
new file mode 100644 (file)
index 0000000..b0dfff8
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
+ */
+
+/* Tell string.h we don't want memcpy etc. as cpp defines */
+#define EXPORT_SYMTAB_STROPS
+#define PROMLIB_INTERNAL
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/in6.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/syscalls.h>
+#ifdef CONFIG_PCI
+#include <linux/pci.h>
+#endif
+#include <linux/pm.h>
+#ifdef CONFIG_HIGHMEM
+#include <linux/highmem.h>
+#endif
+
+#include <asm/oplib.h>
+#include <asm/delay.h>
+#include <asm/system.h>
+#include <asm/auxio.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/idprom.h>
+#include <asm/head.h>
+#include <asm/smp.h>
+#include <asm/ptrace.h>
+#include <asm/uaccess.h>
+#include <asm/checksum.h>
+#ifdef CONFIG_SBUS
+#include <asm/dma.h>
+#endif
+#include <asm/io-unit.h>
+#include <asm/bug.h>
+
+extern spinlock_t rtc_lock;
+
+struct poll {
+       int fd;
+       short events;
+       short revents;
+};
+
+extern void (*__copy_1page)(void *, const void *);
+extern void __memmove(void *, const void *, __kernel_size_t);
+extern void (*bzero_1page)(void *);
+extern void *__bzero(void *, size_t);
+extern void *__memscan_zero(void *, size_t);
+extern void *__memscan_generic(void *, int, size_t);
+extern int __memcmp(const void *, const void *, __kernel_size_t);
+extern int __strncmp(const char *, const char *, __kernel_size_t);
+
+extern int __ashrdi3(int, int);
+extern int __ashldi3(int, int);
+extern int __lshrdi3(int, int);
+extern int __muldi3(int, int);
+extern int __divdi3(int, int);
+
+/* Private functions with odd calling conventions. */
+extern void ___atomic24_add(void);
+extern void ___atomic24_sub(void);
+extern void ___rw_read_enter(void);
+extern void ___rw_read_try(void);
+extern void ___rw_read_exit(void);
+extern void ___rw_write_enter(void);
+
+/* Alias functions whose names begin with "." and export the aliases.
+ * The module references will be fixed up by module_frob_arch_sections.
+ */
+extern int _Div(int, int);
+extern int _Mul(int, int);
+extern int _Rem(int, int);
+extern unsigned _Udiv(unsigned, unsigned);
+extern unsigned _Umul(unsigned, unsigned);
+extern unsigned _Urem(unsigned, unsigned);
+
+/* used by various drivers */
+EXPORT_SYMBOL(sparc_cpu_model);
+EXPORT_SYMBOL(kernel_thread);
+#ifdef CONFIG_SMP
+// XXX find what uses (or used) these.   AV: see asm/spinlock.h
+EXPORT_SYMBOL(___rw_read_enter);
+EXPORT_SYMBOL(___rw_read_try);
+EXPORT_SYMBOL(___rw_read_exit);
+EXPORT_SYMBOL(___rw_write_enter);
+#endif
+
+EXPORT_SYMBOL(sparc_valid_addr_bitmap);
+EXPORT_SYMBOL(phys_base);
+EXPORT_SYMBOL(pfn_base);
+
+/* Atomic operations. */
+EXPORT_SYMBOL(___atomic24_add);
+EXPORT_SYMBOL(___atomic24_sub);
+
+/* Per-CPU information table */
+EXPORT_PER_CPU_SYMBOL(__cpu_data);
+
+#ifdef CONFIG_SMP
+/* IRQ implementation. */
+EXPORT_SYMBOL(synchronize_irq);
+
+/* CPU online map and active count. */
+EXPORT_SYMBOL(cpu_online_map);
+EXPORT_SYMBOL(phys_cpu_present_map);
+#endif
+
+EXPORT_SYMBOL(__udelay);
+EXPORT_SYMBOL(__ndelay);
+EXPORT_SYMBOL(rtc_lock);
+#ifdef CONFIG_SUN_AUXIO
+EXPORT_SYMBOL(set_auxio);
+EXPORT_SYMBOL(get_auxio);
+#endif
+EXPORT_SYMBOL(io_remap_pfn_range);
+
+#ifndef CONFIG_SMP
+EXPORT_SYMBOL(BTFIXUP_CALL(___xchg32));
+#else
+EXPORT_SYMBOL(BTFIXUP_CALL(__hard_smp_processor_id));
+#endif
+EXPORT_SYMBOL(BTFIXUP_CALL(mmu_unlockarea));
+EXPORT_SYMBOL(BTFIXUP_CALL(mmu_lockarea));
+EXPORT_SYMBOL(BTFIXUP_CALL(mmu_get_scsi_sgl));
+EXPORT_SYMBOL(BTFIXUP_CALL(mmu_get_scsi_one));
+EXPORT_SYMBOL(BTFIXUP_CALL(mmu_release_scsi_sgl));
+EXPORT_SYMBOL(BTFIXUP_CALL(mmu_release_scsi_one));
+
+EXPORT_SYMBOL(BTFIXUP_CALL(pgprot_noncached));
+
+#ifdef CONFIG_SBUS
+EXPORT_SYMBOL(sbus_set_sbus64);
+#endif
+#ifdef CONFIG_PCI
+EXPORT_SYMBOL(insb);
+EXPORT_SYMBOL(outsb);
+EXPORT_SYMBOL(insw);
+EXPORT_SYMBOL(outsw);
+EXPORT_SYMBOL(insl);
+EXPORT_SYMBOL(outsl);
+EXPORT_SYMBOL(pci_alloc_consistent);
+EXPORT_SYMBOL(pci_free_consistent);
+EXPORT_SYMBOL(pci_map_single);
+EXPORT_SYMBOL(pci_unmap_single);
+EXPORT_SYMBOL(pci_dma_sync_single_for_cpu);
+EXPORT_SYMBOL(pci_dma_sync_single_for_device);
+EXPORT_SYMBOL(pci_dma_sync_sg_for_cpu);
+EXPORT_SYMBOL(pci_dma_sync_sg_for_device);
+EXPORT_SYMBOL(pci_map_sg);
+EXPORT_SYMBOL(pci_unmap_sg);
+EXPORT_SYMBOL(pci_map_page);
+EXPORT_SYMBOL(pci_unmap_page);
+/* Actually, ioremap/iounmap are not PCI specific. But it is ok for drivers. */
+EXPORT_SYMBOL(ioremap);
+EXPORT_SYMBOL(iounmap);
+#endif
+
+/* in arch/sparc/mm/highmem.c */
+#ifdef CONFIG_HIGHMEM
+EXPORT_SYMBOL(kmap_atomic);
+EXPORT_SYMBOL(kunmap_atomic);
+#endif
+
+/* prom symbols */
+EXPORT_SYMBOL(idprom);
+EXPORT_SYMBOL(prom_root_node);
+EXPORT_SYMBOL(prom_getchild);
+EXPORT_SYMBOL(prom_getsibling);
+EXPORT_SYMBOL(prom_searchsiblings);
+EXPORT_SYMBOL(prom_firstprop);
+EXPORT_SYMBOL(prom_nextprop);
+EXPORT_SYMBOL(prom_getproplen);
+EXPORT_SYMBOL(prom_getproperty);
+EXPORT_SYMBOL(prom_node_has_property);
+EXPORT_SYMBOL(prom_setprop);
+EXPORT_SYMBOL(saved_command_line);
+EXPORT_SYMBOL(prom_apply_obio_ranges);
+EXPORT_SYMBOL(prom_feval);
+EXPORT_SYMBOL(prom_getbool);
+EXPORT_SYMBOL(prom_getstring);
+EXPORT_SYMBOL(prom_getint);
+EXPORT_SYMBOL(prom_getintdefault);
+EXPORT_SYMBOL(prom_finddevice);
+EXPORT_SYMBOL(romvec);
+EXPORT_SYMBOL(__prom_getchild);
+EXPORT_SYMBOL(__prom_getsibling);
+
+/* sparc library symbols */
+EXPORT_SYMBOL(memscan);
+EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(strncmp);
+EXPORT_SYMBOL(page_kernel);
+
+/* Special internal versions of library functions. */
+EXPORT_SYMBOL(__copy_1page);
+EXPORT_SYMBOL(__memcpy);
+EXPORT_SYMBOL(__memset);
+EXPORT_SYMBOL(bzero_1page);
+EXPORT_SYMBOL(__bzero);
+EXPORT_SYMBOL(__memscan_zero);
+EXPORT_SYMBOL(__memscan_generic);
+EXPORT_SYMBOL(__memcmp);
+EXPORT_SYMBOL(__strncmp);
+EXPORT_SYMBOL(__memmove);
+
+/* Moving data to/from userspace. */
+EXPORT_SYMBOL(__copy_user);
+EXPORT_SYMBOL(__strncpy_from_user);
+EXPORT_SYMBOL(__strnlen_user);
+
+/* Networking helper routines. */
+EXPORT_SYMBOL(__csum_partial_copy_sparc_generic);
+EXPORT_SYMBOL(csum_partial);
+
+/* Cache flushing.  */
+EXPORT_SYMBOL(sparc_flush_page_to_ram);
+
+/* For when serial stuff is built as modules. */
+EXPORT_SYMBOL(sun_do_break);
+
+EXPORT_SYMBOL(__ret_efault);
+
+EXPORT_SYMBOL(memcmp);
+EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(memset);
+EXPORT_SYMBOL(memmove);
+EXPORT_SYMBOL(__ashrdi3);
+EXPORT_SYMBOL(__ashldi3);
+EXPORT_SYMBOL(__lshrdi3);
+EXPORT_SYMBOL(__muldi3);
+EXPORT_SYMBOL(__divdi3);
+
+EXPORT_SYMBOL(_Rem);
+EXPORT_SYMBOL(_Urem);
+EXPORT_SYMBOL(_Mul);
+EXPORT_SYMBOL(_Umul);
+EXPORT_SYMBOL(_Div);
+EXPORT_SYMBOL(_Udiv);
+
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+EXPORT_SYMBOL(do_BUG);
+#endif
+
+/* Sun Power Management Idle Handler */
+EXPORT_SYMBOL(pm_idle);
+
+EXPORT_SYMBOL(empty_zero_page);
diff --git a/arch/sparc/kernel/sys_sparc.c b/arch/sparc/kernel/sys_sparc.c
deleted file mode 100644 (file)
index 03035c8..0000000
+++ /dev/null
@@ -1,466 +0,0 @@
-/* linux/arch/sparc/kernel/sys_sparc.c
- *
- * This file contains various random system calls that
- * have a non-standard calling sequence on the Linux/sparc
- * platform.
- */
-
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/file.h>
-#include <linux/sem.h>
-#include <linux/msg.h>
-#include <linux/shm.h>
-#include <linux/stat.h>
-#include <linux/syscalls.h>
-#include <linux/mman.h>
-#include <linux/utsname.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-#include <linux/ipc.h>
-
-#include <asm/uaccess.h>
-#include <asm/unistd.h>
-
-/* #define DEBUG_UNIMP_SYSCALL */
-
-/* XXX Make this per-binary type, this way we can detect the type of
- * XXX a binary.  Every Sparc executable calls this very early on.
- */
-asmlinkage unsigned long sys_getpagesize(void)
-{
-       return PAGE_SIZE; /* Possibly older binaries want 8192 on sun4's? */
-}
-
-#define COLOUR_ALIGN(addr)      (((addr)+SHMLBA-1)&~(SHMLBA-1))
-
-unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags)
-{
-       struct vm_area_struct * vmm;
-
-       if (flags & MAP_FIXED) {
-               /* We do not accept a shared mapping if it would violate
-                * cache aliasing constraints.
-                */
-               if ((flags & MAP_SHARED) && (addr & (SHMLBA - 1)))
-                       return -EINVAL;
-               return addr;
-       }
-
-       /* See asm-sparc/uaccess.h */
-       if (len > TASK_SIZE - PAGE_SIZE)
-               return -ENOMEM;
-       if (ARCH_SUN4C && len > 0x20000000)
-               return -ENOMEM;
-       if (!addr)
-               addr = TASK_UNMAPPED_BASE;
-
-       if (flags & MAP_SHARED)
-               addr = COLOUR_ALIGN(addr);
-       else
-               addr = PAGE_ALIGN(addr);
-
-       for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
-               /* At this point:  (!vmm || addr < vmm->vm_end). */
-               if (ARCH_SUN4C && addr < 0xe0000000 && 0x20000000 - len < addr) {
-                       addr = PAGE_OFFSET;
-                       vmm = find_vma(current->mm, PAGE_OFFSET);
-               }
-               if (TASK_SIZE - PAGE_SIZE - len < addr)
-                       return -ENOMEM;
-               if (!vmm || addr + len <= vmm->vm_start)
-                       return addr;
-               addr = vmm->vm_end;
-               if (flags & MAP_SHARED)
-                       addr = COLOUR_ALIGN(addr);
-       }
-}
-
-asmlinkage unsigned long sparc_brk(unsigned long brk)
-{
-       if(ARCH_SUN4C) {
-               if ((brk & 0xe0000000) != (current->mm->brk & 0xe0000000))
-                       return current->mm->brk;
-       }
-       return sys_brk(brk);
-}
-
-/*
- * sys_pipe() is the normal C calling standard for creating
- * a pipe. It's not the way unix traditionally does this, though.
- */
-asmlinkage int sparc_pipe(struct pt_regs *regs)
-{
-       int fd[2];
-       int error;
-
-       error = do_pipe_flags(fd, 0);
-       if (error)
-               goto out;
-       regs->u_regs[UREG_I1] = fd[1];
-       error = fd[0];
-out:
-       return error;
-}
-
-/*
- * sys_ipc() is the de-multiplexer for the SysV IPC calls..
- *
- * This is really horribly ugly.
- */
-
-asmlinkage int sys_ipc (uint call, int first, int second, int third, void __user *ptr, long fifth)
-{
-       int version, err;
-
-       version = call >> 16; /* hack for backward compatibility */
-       call &= 0xffff;
-
-       if (call <= SEMCTL)
-               switch (call) {
-               case SEMOP:
-                       err = sys_semtimedop (first, (struct sembuf __user *)ptr, second, NULL);
-                       goto out;
-               case SEMTIMEDOP:
-                       err = sys_semtimedop (first, (struct sembuf __user *)ptr, second, (const struct timespec __user *) fifth);
-                       goto out;
-               case SEMGET:
-                       err = sys_semget (first, second, third);
-                       goto out;
-               case SEMCTL: {
-                       union semun fourth;
-                       err = -EINVAL;
-                       if (!ptr)
-                               goto out;
-                       err = -EFAULT;
-                       if (get_user(fourth.__pad,
-                                    (void __user * __user *)ptr))
-                               goto out;
-                       err = sys_semctl (first, second, third, fourth);
-                       goto out;
-                       }
-               default:
-                       err = -ENOSYS;
-                       goto out;
-               }
-       if (call <= MSGCTL) 
-               switch (call) {
-               case MSGSND:
-                       err = sys_msgsnd (first, (struct msgbuf __user *) ptr, 
-                                         second, third);
-                       goto out;
-               case MSGRCV:
-                       switch (version) {
-                       case 0: {
-                               struct ipc_kludge tmp;
-                               err = -EINVAL;
-                               if (!ptr)
-                                       goto out;
-                               err = -EFAULT;
-                               if (copy_from_user(&tmp, (struct ipc_kludge __user *) ptr, sizeof (tmp)))
-                                       goto out;
-                               err = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third);
-                               goto out;
-                               }
-                       case 1: default:
-                               err = sys_msgrcv (first,
-                                                 (struct msgbuf __user *) ptr,
-                                                 second, fifth, third);
-                               goto out;
-                       }
-               case MSGGET:
-                       err = sys_msgget ((key_t) first, second);
-                       goto out;
-               case MSGCTL:
-                       err = sys_msgctl (first, second, (struct msqid_ds __user *) ptr);
-                       goto out;
-               default:
-                       err = -ENOSYS;
-                       goto out;
-               }
-       if (call <= SHMCTL) 
-               switch (call) {
-               case SHMAT:
-                       switch (version) {
-                       case 0: default: {
-                               ulong raddr;
-                               err = do_shmat (first, (char __user *) ptr, second, &raddr);
-                               if (err)
-                                       goto out;
-                               err = -EFAULT;
-                               if (put_user (raddr, (ulong __user *) third))
-                                       goto out;
-                               err = 0;
-                               goto out;
-                               }
-                       case 1: /* iBCS2 emulator entry point */
-                               err = -EINVAL;
-                               goto out;
-                       }
-               case SHMDT: 
-                       err = sys_shmdt ((char __user *)ptr);
-                       goto out;
-               case SHMGET:
-                       err = sys_shmget (first, second, third);
-                       goto out;
-               case SHMCTL:
-                       err = sys_shmctl (first, second, (struct shmid_ds __user *) ptr);
-                       goto out;
-               default:
-                       err = -ENOSYS;
-                       goto out;
-               }
-       else
-               err = -ENOSYS;
-out:
-       return err;
-}
-
-int sparc_mmap_check(unsigned long addr, unsigned long len)
-{
-       if (ARCH_SUN4C &&
-           (len > 0x20000000 ||
-            (addr < 0xe0000000 && addr + len > 0x20000000)))
-               return -EINVAL;
-
-       /* See asm-sparc/uaccess.h */
-       if (len > TASK_SIZE - PAGE_SIZE || addr + len > TASK_SIZE - PAGE_SIZE)
-               return -EINVAL;
-
-       return 0;
-}
-
-/* Linux version of mmap */
-static unsigned long do_mmap2(unsigned long addr, unsigned long len,
-       unsigned long prot, unsigned long flags, unsigned long fd,
-       unsigned long pgoff)
-{
-       struct file * file = NULL;
-       unsigned long retval = -EBADF;
-
-       if (!(flags & MAP_ANONYMOUS)) {
-               file = fget(fd);
-               if (!file)
-                       goto out;
-       }
-
-       len = PAGE_ALIGN(len);
-       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-
-       down_write(&current->mm->mmap_sem);
-       retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-       up_write(&current->mm->mmap_sem);
-
-       if (file)
-               fput(file);
-out:
-       return retval;
-}
-
-asmlinkage unsigned long sys_mmap2(unsigned long addr, unsigned long len,
-       unsigned long prot, unsigned long flags, unsigned long fd,
-       unsigned long pgoff)
-{
-       /* Make sure the shift for mmap2 is constant (12), no matter what PAGE_SIZE
-          we have. */
-       return do_mmap2(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT - 12));
-}
-
-asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
-       unsigned long prot, unsigned long flags, unsigned long fd,
-       unsigned long off)
-{
-       return do_mmap2(addr, len, prot, flags, fd, off >> PAGE_SHIFT);
-}
-
-long sparc_remap_file_pages(unsigned long start, unsigned long size,
-                          unsigned long prot, unsigned long pgoff,
-                          unsigned long flags)
-{
-       /* This works on an existing mmap so we don't need to validate
-        * the range as that was done at the original mmap call.
-        */
-       return sys_remap_file_pages(start, size, prot,
-                                   (pgoff >> (PAGE_SHIFT - 12)), flags);
-}
-
-extern unsigned long do_mremap(unsigned long addr,
-       unsigned long old_len, unsigned long new_len,
-       unsigned long flags, unsigned long new_addr);
-                
-asmlinkage unsigned long sparc_mremap(unsigned long addr,
-       unsigned long old_len, unsigned long new_len,
-       unsigned long flags, unsigned long new_addr)
-{
-       unsigned long ret = -EINVAL;
-
-       if (unlikely(sparc_mmap_check(addr, old_len)))
-               goto out;
-       if (unlikely(sparc_mmap_check(new_addr, new_len)))
-               goto out;
-       down_write(&current->mm->mmap_sem);
-       ret = do_mremap(addr, old_len, new_len, flags, new_addr);
-       up_write(&current->mm->mmap_sem);
-out:
-       return ret;       
-}
-
-/* we come to here via sys_nis_syscall so it can setup the regs argument */
-asmlinkage unsigned long
-c_sys_nis_syscall (struct pt_regs *regs)
-{
-       static int count = 0;
-
-       if (count++ > 5)
-               return -ENOSYS;
-       printk ("%s[%d]: Unimplemented SPARC system call %d\n",
-               current->comm, task_pid_nr(current), (int)regs->u_regs[1]);
-#ifdef DEBUG_UNIMP_SYSCALL     
-       show_regs (regs);
-#endif
-       return -ENOSYS;
-}
-
-/* #define DEBUG_SPARC_BREAKPOINT */
-
-asmlinkage void
-sparc_breakpoint (struct pt_regs *regs)
-{
-       siginfo_t info;
-
-       lock_kernel();
-#ifdef DEBUG_SPARC_BREAKPOINT
-        printk ("TRAP: Entering kernel PC=%x, nPC=%x\n", regs->pc, regs->npc);
-#endif
-       info.si_signo = SIGTRAP;
-       info.si_errno = 0;
-       info.si_code = TRAP_BRKPT;
-       info.si_addr = (void __user *)regs->pc;
-       info.si_trapno = 0;
-       force_sig_info(SIGTRAP, &info, current);
-
-#ifdef DEBUG_SPARC_BREAKPOINT
-       printk ("TRAP: Returning to space: PC=%x nPC=%x\n", regs->pc, regs->npc);
-#endif
-       unlock_kernel();
-}
-
-asmlinkage int
-sparc_sigaction (int sig, const struct old_sigaction __user *act,
-                struct old_sigaction __user *oact)
-{
-       struct k_sigaction new_ka, old_ka;
-       int ret;
-
-       WARN_ON_ONCE(sig >= 0);
-       sig = -sig;
-
-       if (act) {
-               unsigned long mask;
-
-               if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
-                   __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
-                   __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
-                       return -EFAULT;
-               __get_user(new_ka.sa.sa_flags, &act->sa_flags);
-               __get_user(mask, &act->sa_mask);
-               siginitset(&new_ka.sa.sa_mask, mask);
-               new_ka.ka_restorer = NULL;
-       }
-
-       ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
-
-       if (!ret && oact) {
-               /* In the clone() case we could copy half consistent
-                * state to the user, however this could sleep and
-                * deadlock us if we held the signal lock on SMP.  So for
-                * now I take the easy way out and do no locking.
-                */
-               if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
-                   __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
-                   __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
-                       return -EFAULT;
-               __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
-               __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
-       }
-
-       return ret;
-}
-
-asmlinkage long
-sys_rt_sigaction(int sig,
-                const struct sigaction __user *act,
-                struct sigaction __user *oact,
-                void __user *restorer,
-                size_t sigsetsize)
-{
-       struct k_sigaction new_ka, old_ka;
-       int ret;
-
-       /* XXX: Don't preclude handling different sized sigset_t's.  */
-       if (sigsetsize != sizeof(sigset_t))
-               return -EINVAL;
-
-       if (act) {
-               new_ka.ka_restorer = restorer;
-               if (copy_from_user(&new_ka.sa, act, sizeof(*act)))
-                       return -EFAULT;
-       }
-
-       ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
-
-       if (!ret && oact) {
-               if (copy_to_user(oact, &old_ka.sa, sizeof(*oact)))
-                       return -EFAULT;
-       }
-
-       return ret;
-}
-
-asmlinkage int sys_getdomainname(char __user *name, int len)
-{
-       int nlen, err;
-       
-       if (len < 0)
-               return -EINVAL;
-
-       down_read(&uts_sem);
-       
-       nlen = strlen(utsname()->domainname) + 1;
-       err = -EINVAL;
-       if (nlen > len)
-               goto out;
-
-       err = -EFAULT;
-       if (!copy_to_user(name, utsname()->domainname, nlen))
-               err = 0;
-
-out:
-       up_read(&uts_sem);
-       return err;
-}
-
-/*
- * Do a system call from kernel instead of calling sys_execve so we
- * end up with proper pt_regs.
- */
-int kernel_execve(const char *filename, char *const argv[], char *const envp[])
-{
-       long __res;
-       register long __g1 __asm__ ("g1") = __NR_execve;
-       register long __o0 __asm__ ("o0") = (long)(filename);
-       register long __o1 __asm__ ("o1") = (long)(argv);
-       register long __o2 __asm__ ("o2") = (long)(envp);
-       asm volatile ("t 0x10\n\t"
-                     "bcc 1f\n\t"
-                     "mov %%o0, %0\n\t"
-                     "sub %%g0, %%o0, %0\n\t"
-                     "1:\n\t"
-                     : "=r" (__res), "=&r" (__o0)
-                     : "1" (__o0), "r" (__o1), "r" (__o2), "r" (__g1)
-                     : "cc");
-       return __res;
-}
diff --git a/arch/sparc/kernel/sys_sparc_32.c b/arch/sparc/kernel/sys_sparc_32.c
new file mode 100644 (file)
index 0000000..03035c8
--- /dev/null
@@ -0,0 +1,466 @@
+/* linux/arch/sparc/kernel/sys_sparc.c
+ *
+ * This file contains various random system calls that
+ * have a non-standard calling sequence on the Linux/sparc
+ * platform.
+ */
+
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/stat.h>
+#include <linux/syscalls.h>
+#include <linux/mman.h>
+#include <linux/utsname.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/ipc.h>
+
+#include <asm/uaccess.h>
+#include <asm/unistd.h>
+
+/* #define DEBUG_UNIMP_SYSCALL */
+
+/* XXX Make this per-binary type, this way we can detect the type of
+ * XXX a binary.  Every Sparc executable calls this very early on.
+ */
+asmlinkage unsigned long sys_getpagesize(void)
+{
+       return PAGE_SIZE; /* Possibly older binaries want 8192 on sun4's? */
+}
+
+#define COLOUR_ALIGN(addr)      (((addr)+SHMLBA-1)&~(SHMLBA-1))
+
+unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags)
+{
+       struct vm_area_struct * vmm;
+
+       if (flags & MAP_FIXED) {
+               /* We do not accept a shared mapping if it would violate
+                * cache aliasing constraints.
+                */
+               if ((flags & MAP_SHARED) && (addr & (SHMLBA - 1)))
+                       return -EINVAL;
+               return addr;
+       }
+
+       /* See asm-sparc/uaccess.h */
+       if (len > TASK_SIZE - PAGE_SIZE)
+               return -ENOMEM;
+       if (ARCH_SUN4C && len > 0x20000000)
+               return -ENOMEM;
+       if (!addr)
+               addr = TASK_UNMAPPED_BASE;
+
+       if (flags & MAP_SHARED)
+               addr = COLOUR_ALIGN(addr);
+       else
+               addr = PAGE_ALIGN(addr);
+
+       for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
+               /* At this point:  (!vmm || addr < vmm->vm_end). */
+               if (ARCH_SUN4C && addr < 0xe0000000 && 0x20000000 - len < addr) {
+                       addr = PAGE_OFFSET;
+                       vmm = find_vma(current->mm, PAGE_OFFSET);
+               }
+               if (TASK_SIZE - PAGE_SIZE - len < addr)
+                       return -ENOMEM;
+               if (!vmm || addr + len <= vmm->vm_start)
+                       return addr;
+               addr = vmm->vm_end;
+               if (flags & MAP_SHARED)
+                       addr = COLOUR_ALIGN(addr);
+       }
+}
+
+asmlinkage unsigned long sparc_brk(unsigned long brk)
+{
+       if(ARCH_SUN4C) {
+               if ((brk & 0xe0000000) != (current->mm->brk & 0xe0000000))
+                       return current->mm->brk;
+       }
+       return sys_brk(brk);
+}
+
+/*
+ * sys_pipe() is the normal C calling standard for creating
+ * a pipe. It's not the way unix traditionally does this, though.
+ */
+asmlinkage int sparc_pipe(struct pt_regs *regs)
+{
+       int fd[2];
+       int error;
+
+       error = do_pipe_flags(fd, 0);
+       if (error)
+               goto out;
+       regs->u_regs[UREG_I1] = fd[1];
+       error = fd[0];
+out:
+       return error;
+}
+
+/*
+ * sys_ipc() is the de-multiplexer for the SysV IPC calls..
+ *
+ * This is really horribly ugly.
+ */
+
+asmlinkage int sys_ipc (uint call, int first, int second, int third, void __user *ptr, long fifth)
+{
+       int version, err;
+
+       version = call >> 16; /* hack for backward compatibility */
+       call &= 0xffff;
+
+       if (call <= SEMCTL)
+               switch (call) {
+               case SEMOP:
+                       err = sys_semtimedop (first, (struct sembuf __user *)ptr, second, NULL);
+                       goto out;
+               case SEMTIMEDOP:
+                       err = sys_semtimedop (first, (struct sembuf __user *)ptr, second, (const struct timespec __user *) fifth);
+                       goto out;
+               case SEMGET:
+                       err = sys_semget (first, second, third);
+                       goto out;
+               case SEMCTL: {
+                       union semun fourth;
+                       err = -EINVAL;
+                       if (!ptr)
+                               goto out;
+                       err = -EFAULT;
+                       if (get_user(fourth.__pad,
+                                    (void __user * __user *)ptr))
+                               goto out;
+                       err = sys_semctl (first, second, third, fourth);
+                       goto out;
+                       }
+               default:
+                       err = -ENOSYS;
+                       goto out;
+               }
+       if (call <= MSGCTL) 
+               switch (call) {
+               case MSGSND:
+                       err = sys_msgsnd (first, (struct msgbuf __user *) ptr, 
+                                         second, third);
+                       goto out;
+               case MSGRCV:
+                       switch (version) {
+                       case 0: {
+                               struct ipc_kludge tmp;
+                               err = -EINVAL;
+                               if (!ptr)
+                                       goto out;
+                               err = -EFAULT;
+                               if (copy_from_user(&tmp, (struct ipc_kludge __user *) ptr, sizeof (tmp)))
+                                       goto out;
+                               err = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third);
+                               goto out;
+                               }
+                       case 1: default:
+                               err = sys_msgrcv (first,
+                                                 (struct msgbuf __user *) ptr,
+                                                 second, fifth, third);
+                               goto out;
+                       }
+               case MSGGET:
+                       err = sys_msgget ((key_t) first, second);
+                       goto out;
+               case MSGCTL:
+                       err = sys_msgctl (first, second, (struct msqid_ds __user *) ptr);
+                       goto out;
+               default:
+                       err = -ENOSYS;
+                       goto out;
+               }
+       if (call <= SHMCTL) 
+               switch (call) {
+               case SHMAT:
+                       switch (version) {
+                       case 0: default: {
+                               ulong raddr;
+                               err = do_shmat (first, (char __user *) ptr, second, &raddr);
+                               if (err)
+                                       goto out;
+                               err = -EFAULT;
+                               if (put_user (raddr, (ulong __user *) third))
+                                       goto out;
+                               err = 0;
+                               goto out;
+                               }
+                       case 1: /* iBCS2 emulator entry point */
+                               err = -EINVAL;
+                               goto out;
+                       }
+               case SHMDT: 
+                       err = sys_shmdt ((char __user *)ptr);
+                       goto out;
+               case SHMGET:
+                       err = sys_shmget (first, second, third);
+                       goto out;
+               case SHMCTL:
+                       err = sys_shmctl (first, second, (struct shmid_ds __user *) ptr);
+                       goto out;
+               default:
+                       err = -ENOSYS;
+                       goto out;
+               }
+       else
+               err = -ENOSYS;
+out:
+       return err;
+}
+
+int sparc_mmap_check(unsigned long addr, unsigned long len)
+{
+       if (ARCH_SUN4C &&
+           (len > 0x20000000 ||
+            (addr < 0xe0000000 && addr + len > 0x20000000)))
+               return -EINVAL;
+
+       /* See asm-sparc/uaccess.h */
+       if (len > TASK_SIZE - PAGE_SIZE || addr + len > TASK_SIZE - PAGE_SIZE)
+               return -EINVAL;
+
+       return 0;
+}
+
+/* Linux version of mmap */
+static unsigned long do_mmap2(unsigned long addr, unsigned long len,
+       unsigned long prot, unsigned long flags, unsigned long fd,
+       unsigned long pgoff)
+{
+       struct file * file = NULL;
+       unsigned long retval = -EBADF;
+
+       if (!(flags & MAP_ANONYMOUS)) {
+               file = fget(fd);
+               if (!file)
+                       goto out;
+       }
+
+       len = PAGE_ALIGN(len);
+       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+
+       down_write(&current->mm->mmap_sem);
+       retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+       up_write(&current->mm->mmap_sem);
+
+       if (file)
+               fput(file);
+out:
+       return retval;
+}
+
+asmlinkage unsigned long sys_mmap2(unsigned long addr, unsigned long len,
+       unsigned long prot, unsigned long flags, unsigned long fd,
+       unsigned long pgoff)
+{
+       /* Make sure the shift for mmap2 is constant (12), no matter what PAGE_SIZE
+          we have. */
+       return do_mmap2(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT - 12));
+}
+
+asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
+       unsigned long prot, unsigned long flags, unsigned long fd,
+       unsigned long off)
+{
+       return do_mmap2(addr, len, prot, flags, fd, off >> PAGE_SHIFT);
+}
+
+long sparc_remap_file_pages(unsigned long start, unsigned long size,
+                          unsigned long prot, unsigned long pgoff,
+                          unsigned long flags)
+{
+       /* This works on an existing mmap so we don't need to validate
+        * the range as that was done at the original mmap call.
+        */
+       return sys_remap_file_pages(start, size, prot,
+                                   (pgoff >> (PAGE_SHIFT - 12)), flags);
+}
+
+extern unsigned long do_mremap(unsigned long addr,
+       unsigned long old_len, unsigned long new_len,
+       unsigned long flags, unsigned long new_addr);
+                
+asmlinkage unsigned long sparc_mremap(unsigned long addr,
+       unsigned long old_len, unsigned long new_len,
+       unsigned long flags, unsigned long new_addr)
+{
+       unsigned long ret = -EINVAL;
+
+       if (unlikely(sparc_mmap_check(addr, old_len)))
+               goto out;
+       if (unlikely(sparc_mmap_check(new_addr, new_len)))
+               goto out;
+       down_write(&current->mm->mmap_sem);
+       ret = do_mremap(addr, old_len, new_len, flags, new_addr);
+       up_write(&current->mm->mmap_sem);
+out:
+       return ret;       
+}
+
+/* we come to here via sys_nis_syscall so it can setup the regs argument */
+asmlinkage unsigned long
+c_sys_nis_syscall (struct pt_regs *regs)
+{
+       static int count = 0;
+
+       if (count++ > 5)
+               return -ENOSYS;
+       printk ("%s[%d]: Unimplemented SPARC system call %d\n",
+               current->comm, task_pid_nr(current), (int)regs->u_regs[1]);
+#ifdef DEBUG_UNIMP_SYSCALL     
+       show_regs (regs);
+#endif
+       return -ENOSYS;
+}
+
+/* #define DEBUG_SPARC_BREAKPOINT */
+
+asmlinkage void
+sparc_breakpoint (struct pt_regs *regs)
+{
+       siginfo_t info;
+
+       lock_kernel();
+#ifdef DEBUG_SPARC_BREAKPOINT
+        printk ("TRAP: Entering kernel PC=%x, nPC=%x\n", regs->pc, regs->npc);
+#endif
+       info.si_signo = SIGTRAP;
+       info.si_errno = 0;
+       info.si_code = TRAP_BRKPT;
+       info.si_addr = (void __user *)regs->pc;
+       info.si_trapno = 0;
+       force_sig_info(SIGTRAP, &info, current);
+
+#ifdef DEBUG_SPARC_BREAKPOINT
+       printk ("TRAP: Returning to space: PC=%x nPC=%x\n", regs->pc, regs->npc);
+#endif
+       unlock_kernel();
+}
+
+asmlinkage int
+sparc_sigaction (int sig, const struct old_sigaction __user *act,
+                struct old_sigaction __user *oact)
+{
+       struct k_sigaction new_ka, old_ka;
+       int ret;
+
+       WARN_ON_ONCE(sig >= 0);
+       sig = -sig;
+
+       if (act) {
+               unsigned long mask;
+
+               if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
+                   __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
+                   __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+                       return -EFAULT;
+               __get_user(new_ka.sa.sa_flags, &act->sa_flags);
+               __get_user(mask, &act->sa_mask);
+               siginitset(&new_ka.sa.sa_mask, mask);
+               new_ka.ka_restorer = NULL;
+       }
+
+       ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+       if (!ret && oact) {
+               /* In the clone() case we could copy half consistent
+                * state to the user, however this could sleep and
+                * deadlock us if we held the signal lock on SMP.  So for
+                * now I take the easy way out and do no locking.
+                */
+               if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
+                   __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
+                   __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+                       return -EFAULT;
+               __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+               __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
+       }
+
+       return ret;
+}
+
+asmlinkage long
+sys_rt_sigaction(int sig,
+                const struct sigaction __user *act,
+                struct sigaction __user *oact,
+                void __user *restorer,
+                size_t sigsetsize)
+{
+       struct k_sigaction new_ka, old_ka;
+       int ret;
+
+       /* XXX: Don't preclude handling different sized sigset_t's.  */
+       if (sigsetsize != sizeof(sigset_t))
+               return -EINVAL;
+
+       if (act) {
+               new_ka.ka_restorer = restorer;
+               if (copy_from_user(&new_ka.sa, act, sizeof(*act)))
+                       return -EFAULT;
+       }
+
+       ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+       if (!ret && oact) {
+               if (copy_to_user(oact, &old_ka.sa, sizeof(*oact)))
+                       return -EFAULT;
+       }
+
+       return ret;
+}
+
+asmlinkage int sys_getdomainname(char __user *name, int len)
+{
+       int nlen, err;
+       
+       if (len < 0)
+               return -EINVAL;
+
+       down_read(&uts_sem);
+       
+       nlen = strlen(utsname()->domainname) + 1;
+       err = -EINVAL;
+       if (nlen > len)
+               goto out;
+
+       err = -EFAULT;
+       if (!copy_to_user(name, utsname()->domainname, nlen))
+               err = 0;
+
+out:
+       up_read(&uts_sem);
+       return err;
+}
+
+/*
+ * Do a system call from kernel instead of calling sys_execve so we
+ * end up with proper pt_regs.
+ */
+int kernel_execve(const char *filename, char *const argv[], char *const envp[])
+{
+       long __res;
+       register long __g1 __asm__ ("g1") = __NR_execve;
+       register long __o0 __asm__ ("o0") = (long)(filename);
+       register long __o1 __asm__ ("o1") = (long)(argv);
+       register long __o2 __asm__ ("o2") = (long)(envp);
+       asm volatile ("t 0x10\n\t"
+                     "bcc 1f\n\t"
+                     "mov %%o0, %0\n\t"
+                     "sub %%g0, %%o0, %0\n\t"
+                     "1:\n\t"
+                     : "=r" (__res), "=&r" (__o0)
+                     : "1" (__o0), "r" (__o1), "r" (__o2), "r" (__g1)
+                     : "cc");
+       return __res;
+}
diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S
deleted file mode 100644 (file)
index 7d08075..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/* systbls.S: System call entry point tables for OS compatibility.
- *            The native Linux system call table lives here also.
- *
- * Copyright (C) 1995, 2007 David S. Miller (davem@davemloft.net)
- *
- * Based upon preliminary work which is:
- *
- * Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu)
- */
-
-
-       .data
-       .align 4
-
-       /* First, the Linux native syscall table. */
-
-       .globl sys_call_table
-sys_call_table:
-/*0*/  .long sys_restart_syscall, sys_exit, sys_fork, sys_read, sys_write
-/*5*/  .long sys_open, sys_close, sys_wait4, sys_creat, sys_link
-/*10*/  .long sys_unlink, sunos_execv, sys_chdir, sys_chown16, sys_mknod
-/*15*/ .long sys_chmod, sys_lchown16, sparc_brk, sys_nis_syscall, sys_lseek
-/*20*/ .long sys_getpid, sys_capget, sys_capset, sys_setuid16, sys_getuid16
-/*25*/ .long sys_vmsplice, sys_ptrace, sys_alarm, sys_sigaltstack, sys_pause
-/*30*/ .long sys_utime, sys_lchown, sys_fchown, sys_access, sys_nice
-/*35*/ .long sys_chown, sys_sync, sys_kill, sys_newstat, sys_sendfile
-/*40*/ .long sys_newlstat, sys_dup, sys_pipe, sys_times, sys_getuid
-/*45*/ .long sys_umount, sys_setgid16, sys_getgid16, sys_signal, sys_geteuid16
-/*50*/ .long sys_getegid16, sys_acct, sys_nis_syscall, sys_getgid, sys_ioctl
-/*55*/ .long sys_reboot, sys_mmap2, sys_symlink, sys_readlink, sys_execve
-/*60*/ .long sys_umask, sys_chroot, sys_newfstat, sys_fstat64, sys_getpagesize
-/*65*/ .long sys_msync, sys_vfork, sys_pread64, sys_pwrite64, sys_geteuid
-/*70*/ .long sys_getegid, sys_mmap, sys_setreuid, sys_munmap, sys_mprotect
-/*75*/ .long sys_madvise, sys_vhangup, sys_truncate64, sys_mincore, sys_getgroups16
-/*80*/ .long sys_setgroups16, sys_getpgrp, sys_setgroups, sys_setitimer, sys_ftruncate64
-/*85*/ .long sys_swapon, sys_getitimer, sys_setuid, sys_sethostname, sys_setgid
-/*90*/ .long sys_dup2, sys_setfsuid, sys_fcntl, sys_select, sys_setfsgid
-/*95*/ .long sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*100*/        .long sys_getpriority, sys_rt_sigreturn, sys_rt_sigaction, sys_rt_sigprocmask, sys_rt_sigpending
-/*105*/        .long sys_rt_sigtimedwait, sys_rt_sigqueueinfo, sys_rt_sigsuspend, sys_setresuid, sys_getresuid
-/*110*/        .long sys_setresgid, sys_getresgid, sys_setregid, sys_nis_syscall, sys_nis_syscall
-/*115*/        .long sys_getgroups, sys_gettimeofday, sys_getrusage, sys_nis_syscall, sys_getcwd
-/*120*/        .long sys_readv, sys_writev, sys_settimeofday, sys_fchown16, sys_fchmod
-/*125*/        .long sys_nis_syscall, sys_setreuid16, sys_setregid16, sys_rename, sys_truncate
-/*130*/        .long sys_ftruncate, sys_flock, sys_lstat64, sys_nis_syscall, sys_nis_syscall
-/*135*/        .long sys_nis_syscall, sys_mkdir, sys_rmdir, sys_utimes, sys_stat64
-/*140*/        .long sys_sendfile64, sys_nis_syscall, sys_futex, sys_gettid, sys_getrlimit
-/*145*/        .long sys_setrlimit, sys_pivot_root, sys_prctl, sys_pciconfig_read, sys_pciconfig_write
-/*150*/        .long sys_nis_syscall, sys_inotify_init, sys_inotify_add_watch, sys_poll, sys_getdents64
-/*155*/        .long sys_fcntl64, sys_inotify_rm_watch, sys_statfs, sys_fstatfs, sys_oldumount
-/*160*/        .long sys_sched_setaffinity, sys_sched_getaffinity, sys_getdomainname, sys_setdomainname, sys_nis_syscall
-/*165*/        .long sys_quotactl, sys_set_tid_address, sys_mount, sys_ustat, sys_setxattr
-/*170*/        .long sys_lsetxattr, sys_fsetxattr, sys_getxattr, sys_lgetxattr, sys_getdents
-/*175*/        .long sys_setsid, sys_fchdir, sys_fgetxattr, sys_listxattr, sys_llistxattr
-/*180*/        .long sys_flistxattr, sys_removexattr, sys_lremovexattr, sys_sigpending, sys_ni_syscall
-/*185*/        .long sys_setpgid, sys_fremovexattr, sys_tkill, sys_exit_group, sys_newuname
-/*190*/        .long sys_init_module, sys_personality, sparc_remap_file_pages, sys_epoll_create, sys_epoll_ctl
-/*195*/        .long sys_epoll_wait, sys_ioprio_set, sys_getppid, sparc_sigaction, sys_sgetmask
-/*200*/        .long sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, old_readdir
-/*205*/        .long sys_readahead, sys_socketcall, sys_syslog, sys_lookup_dcookie, sys_fadvise64
-/*210*/        .long sys_fadvise64_64, sys_tgkill, sys_waitpid, sys_swapoff, sys_sysinfo
-/*215*/        .long sys_ipc, sys_sigreturn, sys_clone, sys_ioprio_get, sys_adjtimex
-/*220*/        .long sys_sigprocmask, sys_ni_syscall, sys_delete_module, sys_ni_syscall, sys_getpgid
-/*225*/        .long sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid16, sys_setfsgid16
-/*230*/        .long sys_select, sys_time, sys_splice, sys_stime, sys_statfs64
-                                         /* "We are the Knights of the Forest of Ni!!" */
-/*235*/        .long sys_fstatfs64, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
-/*240*/        .long sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
-/*245*/        .long sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
-/*250*/        .long sparc_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
-/*255*/        .long sys_sync_file_range, sys_clock_settime, sys_clock_gettime, sys_clock_getres, sys_clock_nanosleep
-/*260*/        .long sys_sched_getaffinity, sys_sched_setaffinity, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun
-/*265*/        .long sys_timer_delete, sys_timer_create, sys_nis_syscall, sys_io_setup, sys_io_destroy
-/*270*/        .long sys_io_submit, sys_io_cancel, sys_io_getevents, sys_mq_open, sys_mq_unlink
-/*275*/        .long sys_mq_timedsend, sys_mq_timedreceive, sys_mq_notify, sys_mq_getsetattr, sys_waitid
-/*280*/        .long sys_tee, sys_add_key, sys_request_key, sys_keyctl, sys_openat
-/*285*/        .long sys_mkdirat, sys_mknodat, sys_fchownat, sys_futimesat, sys_fstatat64
-/*290*/        .long sys_unlinkat, sys_renameat, sys_linkat, sys_symlinkat, sys_readlinkat
-/*295*/        .long sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare
-/*300*/        .long sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy
-/*305*/        .long sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait
-/*310*/        .long sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate
-/*315*/        .long sys_timerfd_settime, sys_timerfd_gettime, sys_signalfd4, sys_eventfd2, sys_epoll_create1
-/*320*/        .long sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4
diff --git a/arch/sparc/kernel/systbls_32.S b/arch/sparc/kernel/systbls_32.S
new file mode 100644 (file)
index 0000000..7d08075
--- /dev/null
@@ -0,0 +1,84 @@
+/* systbls.S: System call entry point tables for OS compatibility.
+ *            The native Linux system call table lives here also.
+ *
+ * Copyright (C) 1995, 2007 David S. Miller (davem@davemloft.net)
+ *
+ * Based upon preliminary work which is:
+ *
+ * Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu)
+ */
+
+
+       .data
+       .align 4
+
+       /* First, the Linux native syscall table. */
+
+       .globl sys_call_table
+sys_call_table:
+/*0*/  .long sys_restart_syscall, sys_exit, sys_fork, sys_read, sys_write
+/*5*/  .long sys_open, sys_close, sys_wait4, sys_creat, sys_link
+/*10*/  .long sys_unlink, sunos_execv, sys_chdir, sys_chown16, sys_mknod
+/*15*/ .long sys_chmod, sys_lchown16, sparc_brk, sys_nis_syscall, sys_lseek
+/*20*/ .long sys_getpid, sys_capget, sys_capset, sys_setuid16, sys_getuid16
+/*25*/ .long sys_vmsplice, sys_ptrace, sys_alarm, sys_sigaltstack, sys_pause
+/*30*/ .long sys_utime, sys_lchown, sys_fchown, sys_access, sys_nice
+/*35*/ .long sys_chown, sys_sync, sys_kill, sys_newstat, sys_sendfile
+/*40*/ .long sys_newlstat, sys_dup, sys_pipe, sys_times, sys_getuid
+/*45*/ .long sys_umount, sys_setgid16, sys_getgid16, sys_signal, sys_geteuid16
+/*50*/ .long sys_getegid16, sys_acct, sys_nis_syscall, sys_getgid, sys_ioctl
+/*55*/ .long sys_reboot, sys_mmap2, sys_symlink, sys_readlink, sys_execve
+/*60*/ .long sys_umask, sys_chroot, sys_newfstat, sys_fstat64, sys_getpagesize
+/*65*/ .long sys_msync, sys_vfork, sys_pread64, sys_pwrite64, sys_geteuid
+/*70*/ .long sys_getegid, sys_mmap, sys_setreuid, sys_munmap, sys_mprotect
+/*75*/ .long sys_madvise, sys_vhangup, sys_truncate64, sys_mincore, sys_getgroups16
+/*80*/ .long sys_setgroups16, sys_getpgrp, sys_setgroups, sys_setitimer, sys_ftruncate64
+/*85*/ .long sys_swapon, sys_getitimer, sys_setuid, sys_sethostname, sys_setgid
+/*90*/ .long sys_dup2, sys_setfsuid, sys_fcntl, sys_select, sys_setfsgid
+/*95*/ .long sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*100*/        .long sys_getpriority, sys_rt_sigreturn, sys_rt_sigaction, sys_rt_sigprocmask, sys_rt_sigpending
+/*105*/        .long sys_rt_sigtimedwait, sys_rt_sigqueueinfo, sys_rt_sigsuspend, sys_setresuid, sys_getresuid
+/*110*/        .long sys_setresgid, sys_getresgid, sys_setregid, sys_nis_syscall, sys_nis_syscall
+/*115*/        .long sys_getgroups, sys_gettimeofday, sys_getrusage, sys_nis_syscall, sys_getcwd
+/*120*/        .long sys_readv, sys_writev, sys_settimeofday, sys_fchown16, sys_fchmod
+/*125*/        .long sys_nis_syscall, sys_setreuid16, sys_setregid16, sys_rename, sys_truncate
+/*130*/        .long sys_ftruncate, sys_flock, sys_lstat64, sys_nis_syscall, sys_nis_syscall
+/*135*/        .long sys_nis_syscall, sys_mkdir, sys_rmdir, sys_utimes, sys_stat64
+/*140*/        .long sys_sendfile64, sys_nis_syscall, sys_futex, sys_gettid, sys_getrlimit
+/*145*/        .long sys_setrlimit, sys_pivot_root, sys_prctl, sys_pciconfig_read, sys_pciconfig_write
+/*150*/        .long sys_nis_syscall, sys_inotify_init, sys_inotify_add_watch, sys_poll, sys_getdents64
+/*155*/        .long sys_fcntl64, sys_inotify_rm_watch, sys_statfs, sys_fstatfs, sys_oldumount
+/*160*/        .long sys_sched_setaffinity, sys_sched_getaffinity, sys_getdomainname, sys_setdomainname, sys_nis_syscall
+/*165*/        .long sys_quotactl, sys_set_tid_address, sys_mount, sys_ustat, sys_setxattr
+/*170*/        .long sys_lsetxattr, sys_fsetxattr, sys_getxattr, sys_lgetxattr, sys_getdents
+/*175*/        .long sys_setsid, sys_fchdir, sys_fgetxattr, sys_listxattr, sys_llistxattr
+/*180*/        .long sys_flistxattr, sys_removexattr, sys_lremovexattr, sys_sigpending, sys_ni_syscall
+/*185*/        .long sys_setpgid, sys_fremovexattr, sys_tkill, sys_exit_group, sys_newuname
+/*190*/        .long sys_init_module, sys_personality, sparc_remap_file_pages, sys_epoll_create, sys_epoll_ctl
+/*195*/        .long sys_epoll_wait, sys_ioprio_set, sys_getppid, sparc_sigaction, sys_sgetmask
+/*200*/        .long sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, old_readdir
+/*205*/        .long sys_readahead, sys_socketcall, sys_syslog, sys_lookup_dcookie, sys_fadvise64
+/*210*/        .long sys_fadvise64_64, sys_tgkill, sys_waitpid, sys_swapoff, sys_sysinfo
+/*215*/        .long sys_ipc, sys_sigreturn, sys_clone, sys_ioprio_get, sys_adjtimex
+/*220*/        .long sys_sigprocmask, sys_ni_syscall, sys_delete_module, sys_ni_syscall, sys_getpgid
+/*225*/        .long sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid16, sys_setfsgid16
+/*230*/        .long sys_select, sys_time, sys_splice, sys_stime, sys_statfs64
+                                         /* "We are the Knights of the Forest of Ni!!" */
+/*235*/        .long sys_fstatfs64, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
+/*240*/        .long sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
+/*245*/        .long sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
+/*250*/        .long sparc_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
+/*255*/        .long sys_sync_file_range, sys_clock_settime, sys_clock_gettime, sys_clock_getres, sys_clock_nanosleep
+/*260*/        .long sys_sched_getaffinity, sys_sched_setaffinity, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun
+/*265*/        .long sys_timer_delete, sys_timer_create, sys_nis_syscall, sys_io_setup, sys_io_destroy
+/*270*/        .long sys_io_submit, sys_io_cancel, sys_io_getevents, sys_mq_open, sys_mq_unlink
+/*275*/        .long sys_mq_timedsend, sys_mq_timedreceive, sys_mq_notify, sys_mq_getsetattr, sys_waitid
+/*280*/        .long sys_tee, sys_add_key, sys_request_key, sys_keyctl, sys_openat
+/*285*/        .long sys_mkdirat, sys_mknodat, sys_fchownat, sys_futimesat, sys_fstatat64
+/*290*/        .long sys_unlinkat, sys_renameat, sys_linkat, sys_symlinkat, sys_readlinkat
+/*295*/        .long sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare
+/*300*/        .long sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy
+/*305*/        .long sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait
+/*310*/        .long sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate
+/*315*/        .long sys_timerfd_settime, sys_timerfd_gettime, sys_signalfd4, sys_eventfd2, sys_epoll_create1
+/*320*/        .long sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4
diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c
deleted file mode 100644 (file)
index 00f7383..0000000
+++ /dev/null
@@ -1,328 +0,0 @@
-/* linux/arch/sparc/kernel/time.c
- *
- * Copyright (C) 1995 David S. Miller (davem@davemloft.net)
- * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
- *
- * Chris Davis (cdavis@cois.on.ca) 03/27/1998
- * Added support for the intersil on the sun4/4200
- *
- * Gleb Raiko (rajko@mech.math.msu.su) 08/18/1998
- * Support for MicroSPARC-IIep, PCI CPU.
- *
- * This file handles the Sparc specific time handling details.
- *
- * 1997-09-10  Updated NTP code according to technical memorandum Jan '96
- *             "A Kernel Model for Precision Timekeeping" by Dave Mills
- */
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/time.h>
-#include <linux/rtc.h>
-#include <linux/rtc/m48t59.h>
-#include <linux/timex.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/ioport.h>
-#include <linux/profile.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-
-#include <asm/oplib.h>
-#include <asm/timer.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/idprom.h>
-#include <asm/machines.h>
-#include <asm/page.h>
-#include <asm/pcic.h>
-#include <asm/irq_regs.h>
-
-#include "irq.h"
-
-DEFINE_SPINLOCK(rtc_lock);
-static int set_rtc_mmss(unsigned long);
-static int sbus_do_settimeofday(struct timespec *tv);
-
-unsigned long profile_pc(struct pt_regs *regs)
-{
-       extern char __copy_user_begin[], __copy_user_end[];
-       extern char __atomic_begin[], __atomic_end[];
-       extern char __bzero_begin[], __bzero_end[];
-
-       unsigned long pc = regs->pc;
-
-       if (in_lock_functions(pc) ||
-           (pc >= (unsigned long) __copy_user_begin &&
-            pc < (unsigned long) __copy_user_end) ||
-           (pc >= (unsigned long) __atomic_begin &&
-            pc < (unsigned long) __atomic_end) ||
-           (pc >= (unsigned long) __bzero_begin &&
-            pc < (unsigned long) __bzero_end))
-               pc = regs->u_regs[UREG_RETPC];
-       return pc;
-}
-
-EXPORT_SYMBOL(profile_pc);
-
-__volatile__ unsigned int *master_l10_counter;
-
-/*
- * timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "do_timer()" routine every clocktick
- */
-
-#define TICK_SIZE (tick_nsec / 1000)
-
-static irqreturn_t timer_interrupt(int dummy, void *dev_id)
-{
-       /* last time the cmos clock got updated */
-       static long last_rtc_update;
-
-#ifndef CONFIG_SMP
-       profile_tick(CPU_PROFILING);
-#endif
-
-       /* Protect counter clear so that do_gettimeoffset works */
-       write_seqlock(&xtime_lock);
-
-       clear_clock_irq();
-
-       do_timer(1);
-
-       /* Determine when to update the Mostek clock. */
-       if (ntp_synced() &&
-           xtime.tv_sec > last_rtc_update + 660 &&
-           (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
-           (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
-         if (set_rtc_mmss(xtime.tv_sec) == 0)
-           last_rtc_update = xtime.tv_sec;
-         else
-           last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
-       }
-       write_sequnlock(&xtime_lock);
-
-#ifndef CONFIG_SMP
-       update_process_times(user_mode(get_irq_regs()));
-#endif
-       return IRQ_HANDLED;
-}
-
-static unsigned char mostek_read_byte(struct device *dev, u32 ofs)
-{
-       struct platform_device *pdev = to_platform_device(dev);
-       struct m48t59_plat_data *pdata = pdev->dev.platform_data;
-
-       return readb(pdata->ioaddr + ofs);
-}
-
-static void mostek_write_byte(struct device *dev, u32 ofs, u8 val)
-{
-       struct platform_device *pdev = to_platform_device(dev);
-       struct m48t59_plat_data *pdata = pdev->dev.platform_data;
-
-       writeb(val, pdata->ioaddr + ofs);
-}
-
-static struct m48t59_plat_data m48t59_data = {
-       .read_byte = mostek_read_byte,
-       .write_byte = mostek_write_byte,
-};
-
-/* resource is set at runtime */
-static struct platform_device m48t59_rtc = {
-       .name           = "rtc-m48t59",
-       .id             = 0,
-       .num_resources  = 1,
-       .dev    = {
-               .platform_data = &m48t59_data,
-       },
-};
-
-static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match)
-{
-       struct device_node *dp = op->node;
-       const char *model = of_get_property(dp, "model", NULL);
-
-       if (!model)
-               return -ENODEV;
-
-       m48t59_rtc.resource = &op->resource[0];
-       if (!strcmp(model, "mk48t02")) {
-               /* Map the clock register io area read-only */
-               m48t59_data.ioaddr = of_ioremap(&op->resource[0], 0,
-                                               2048, "rtc-m48t59");
-               m48t59_data.type = M48T59RTC_TYPE_M48T02;
-       } else if (!strcmp(model, "mk48t08")) {
-               m48t59_data.ioaddr = of_ioremap(&op->resource[0], 0,
-                                               8192, "rtc-m48t59");
-               m48t59_data.type = M48T59RTC_TYPE_M48T08;
-       } else
-               return -ENODEV;
-
-       if (platform_device_register(&m48t59_rtc) < 0)
-               printk(KERN_ERR "Registering RTC device failed\n");
-
-       return 0;
-}
-
-static struct of_device_id __initdata clock_match[] = {
-       {
-               .name = "eeprom",
-       },
-       {},
-};
-
-static struct of_platform_driver clock_driver = {
-       .match_table    = clock_match,
-       .probe          = clock_probe,
-       .driver         = {
-               .name   = "rtc",
-       },
-};
-
-
-/* Probe for the mostek real time clock chip. */
-static int __init clock_init(void)
-{
-       return of_register_driver(&clock_driver, &of_platform_bus_type);
-}
-
-/* Must be after subsys_initcall() so that busses are probed.  Must
- * be before device_initcall() because things like the RTC driver
- * need to see the clock registers.
- */
-fs_initcall(clock_init);
-
-static void __init sbus_time_init(void)
-{
-
-       BTFIXUPSET_CALL(bus_do_settimeofday, sbus_do_settimeofday, BTFIXUPCALL_NORM);
-       btfixup();
-
-       sparc_init_timers(timer_interrupt);
-       
-       /* Now that OBP ticker has been silenced, it is safe to enable IRQ. */
-       local_irq_enable();
-}
-
-void __init time_init(void)
-{
-#ifdef CONFIG_PCI
-       extern void pci_time_init(void);
-       if (pcic_present()) {
-               pci_time_init();
-               return;
-       }
-#endif
-       sbus_time_init();
-}
-
-static inline unsigned long do_gettimeoffset(void)
-{
-       unsigned long val = *master_l10_counter;
-       unsigned long usec = (val >> 10) & 0x1fffff;
-
-       /* Limit hit?  */
-       if (val & 0x80000000)
-               usec += 1000000 / HZ;
-
-       return usec;
-}
-
-/* Ok, my cute asm atomicity trick doesn't work anymore.
- * There are just too many variables that need to be protected
- * now (both members of xtime, et al.)
- */
-void do_gettimeofday(struct timeval *tv)
-{
-       unsigned long flags;
-       unsigned long seq;
-       unsigned long usec, sec;
-       unsigned long max_ntp_tick = tick_usec - tickadj;
-
-       do {
-               seq = read_seqbegin_irqsave(&xtime_lock, flags);
-               usec = do_gettimeoffset();
-
-               /*
-                * If time_adjust is negative then NTP is slowing the clock
-                * so make sure not to go into next possible interval.
-                * Better to lose some accuracy than have time go backwards..
-                */
-               if (unlikely(time_adjust < 0))
-                       usec = min(usec, max_ntp_tick);
-
-               sec = xtime.tv_sec;
-               usec += (xtime.tv_nsec / 1000);
-       } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
-
-       while (usec >= 1000000) {
-               usec -= 1000000;
-               sec++;
-       }
-
-       tv->tv_sec = sec;
-       tv->tv_usec = usec;
-}
-
-EXPORT_SYMBOL(do_gettimeofday);
-
-int do_settimeofday(struct timespec *tv)
-{
-       int ret;
-
-       write_seqlock_irq(&xtime_lock);
-       ret = bus_do_settimeofday(tv);
-       write_sequnlock_irq(&xtime_lock);
-       clock_was_set();
-       return ret;
-}
-
-EXPORT_SYMBOL(do_settimeofday);
-
-static int sbus_do_settimeofday(struct timespec *tv)
-{
-       time_t wtm_sec, sec = tv->tv_sec;
-       long wtm_nsec, nsec = tv->tv_nsec;
-
-       if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
-               return -EINVAL;
-
-       /*
-        * This is revolting. We need to set "xtime" correctly. However, the
-        * value in this location is the value at the most recent update of
-        * wall time.  Discover what correction gettimeofday() would have
-        * made, and then undo it!
-        */
-       nsec -= 1000 * do_gettimeoffset();
-
-       wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
-       wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
-
-       set_normalized_timespec(&xtime, sec, nsec);
-       set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
-
-       ntp_clear();
-       return 0;
-}
-
-static int set_rtc_mmss(unsigned long secs)
-{
-       struct rtc_device *rtc = rtc_class_open("rtc0");
-       int err = -1;
-
-       if (rtc) {
-               err = rtc_set_mmss(rtc, secs);
-               rtc_class_close(rtc);
-       }
-
-       return err;
-}
diff --git a/arch/sparc/kernel/time_32.c b/arch/sparc/kernel/time_32.c
new file mode 100644 (file)
index 0000000..00f7383
--- /dev/null
@@ -0,0 +1,328 @@
+/* linux/arch/sparc/kernel/time.c
+ *
+ * Copyright (C) 1995 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
+ *
+ * Chris Davis (cdavis@cois.on.ca) 03/27/1998
+ * Added support for the intersil on the sun4/4200
+ *
+ * Gleb Raiko (rajko@mech.math.msu.su) 08/18/1998
+ * Support for MicroSPARC-IIep, PCI CPU.
+ *
+ * This file handles the Sparc specific time handling details.
+ *
+ * 1997-09-10  Updated NTP code according to technical memorandum Jan '96
+ *             "A Kernel Model for Precision Timekeeping" by Dave Mills
+ */
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/rtc.h>
+#include <linux/rtc/m48t59.h>
+#include <linux/timex.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/profile.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#include <asm/oplib.h>
+#include <asm/timer.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/idprom.h>
+#include <asm/machines.h>
+#include <asm/page.h>
+#include <asm/pcic.h>
+#include <asm/irq_regs.h>
+
+#include "irq.h"
+
+DEFINE_SPINLOCK(rtc_lock);
+static int set_rtc_mmss(unsigned long);
+static int sbus_do_settimeofday(struct timespec *tv);
+
+unsigned long profile_pc(struct pt_regs *regs)
+{
+       extern char __copy_user_begin[], __copy_user_end[];
+       extern char __atomic_begin[], __atomic_end[];
+       extern char __bzero_begin[], __bzero_end[];
+
+       unsigned long pc = regs->pc;
+
+       if (in_lock_functions(pc) ||
+           (pc >= (unsigned long) __copy_user_begin &&
+            pc < (unsigned long) __copy_user_end) ||
+           (pc >= (unsigned long) __atomic_begin &&
+            pc < (unsigned long) __atomic_end) ||
+           (pc >= (unsigned long) __bzero_begin &&
+            pc < (unsigned long) __bzero_end))
+               pc = regs->u_regs[UREG_RETPC];
+       return pc;
+}
+
+EXPORT_SYMBOL(profile_pc);
+
+__volatile__ unsigned int *master_l10_counter;
+
+/*
+ * timer_interrupt() needs to keep up the real-time clock,
+ * as well as call the "do_timer()" routine every clocktick
+ */
+
+#define TICK_SIZE (tick_nsec / 1000)
+
+static irqreturn_t timer_interrupt(int dummy, void *dev_id)
+{
+       /* last time the cmos clock got updated */
+       static long last_rtc_update;
+
+#ifndef CONFIG_SMP
+       profile_tick(CPU_PROFILING);
+#endif
+
+       /* Protect counter clear so that do_gettimeoffset works */
+       write_seqlock(&xtime_lock);
+
+       clear_clock_irq();
+
+       do_timer(1);
+
+       /* Determine when to update the Mostek clock. */
+       if (ntp_synced() &&
+           xtime.tv_sec > last_rtc_update + 660 &&
+           (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
+           (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
+         if (set_rtc_mmss(xtime.tv_sec) == 0)
+           last_rtc_update = xtime.tv_sec;
+         else
+           last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+       }
+       write_sequnlock(&xtime_lock);
+
+#ifndef CONFIG_SMP
+       update_process_times(user_mode(get_irq_regs()));
+#endif
+       return IRQ_HANDLED;
+}
+
+static unsigned char mostek_read_byte(struct device *dev, u32 ofs)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct m48t59_plat_data *pdata = pdev->dev.platform_data;
+
+       return readb(pdata->ioaddr + ofs);
+}
+
+static void mostek_write_byte(struct device *dev, u32 ofs, u8 val)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct m48t59_plat_data *pdata = pdev->dev.platform_data;
+
+       writeb(val, pdata->ioaddr + ofs);
+}
+
+static struct m48t59_plat_data m48t59_data = {
+       .read_byte = mostek_read_byte,
+       .write_byte = mostek_write_byte,
+};
+
+/* resource is set at runtime */
+static struct platform_device m48t59_rtc = {
+       .name           = "rtc-m48t59",
+       .id             = 0,
+       .num_resources  = 1,
+       .dev    = {
+               .platform_data = &m48t59_data,
+       },
+};
+
+static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match)
+{
+       struct device_node *dp = op->node;
+       const char *model = of_get_property(dp, "model", NULL);
+
+       if (!model)
+               return -ENODEV;
+
+       m48t59_rtc.resource = &op->resource[0];
+       if (!strcmp(model, "mk48t02")) {
+               /* Map the clock register io area read-only */
+               m48t59_data.ioaddr = of_ioremap(&op->resource[0], 0,
+                                               2048, "rtc-m48t59");
+               m48t59_data.type = M48T59RTC_TYPE_M48T02;
+       } else if (!strcmp(model, "mk48t08")) {
+               m48t59_data.ioaddr = of_ioremap(&op->resource[0], 0,
+                                               8192, "rtc-m48t59");
+               m48t59_data.type = M48T59RTC_TYPE_M48T08;
+       } else
+               return -ENODEV;
+
+       if (platform_device_register(&m48t59_rtc) < 0)
+               printk(KERN_ERR "Registering RTC device failed\n");
+
+       return 0;
+}
+
+static struct of_device_id __initdata clock_match[] = {
+       {
+               .name = "eeprom",
+       },
+       {},
+};
+
+static struct of_platform_driver clock_driver = {
+       .match_table    = clock_match,
+       .probe          = clock_probe,
+       .driver         = {
+               .name   = "rtc",
+       },
+};
+
+
+/* Probe for the mostek real time clock chip. */
+static int __init clock_init(void)
+{
+       return of_register_driver(&clock_driver, &of_platform_bus_type);
+}
+
+/* Must be after subsys_initcall() so that busses are probed.  Must
+ * be before device_initcall() because things like the RTC driver
+ * need to see the clock registers.
+ */
+fs_initcall(clock_init);
+
+static void __init sbus_time_init(void)
+{
+
+       BTFIXUPSET_CALL(bus_do_settimeofday, sbus_do_settimeofday, BTFIXUPCALL_NORM);
+       btfixup();
+
+       sparc_init_timers(timer_interrupt);
+       
+       /* Now that OBP ticker has been silenced, it is safe to enable IRQ. */
+       local_irq_enable();
+}
+
+void __init time_init(void)
+{
+#ifdef CONFIG_PCI
+       extern void pci_time_init(void);
+       if (pcic_present()) {
+               pci_time_init();
+               return;
+       }
+#endif
+       sbus_time_init();
+}
+
+static inline unsigned long do_gettimeoffset(void)
+{
+       unsigned long val = *master_l10_counter;
+       unsigned long usec = (val >> 10) & 0x1fffff;
+
+       /* Limit hit?  */
+       if (val & 0x80000000)
+               usec += 1000000 / HZ;
+
+       return usec;
+}
+
+/* Ok, my cute asm atomicity trick doesn't work anymore.
+ * There are just too many variables that need to be protected
+ * now (both members of xtime, et al.)
+ */
+void do_gettimeofday(struct timeval *tv)
+{
+       unsigned long flags;
+       unsigned long seq;
+       unsigned long usec, sec;
+       unsigned long max_ntp_tick = tick_usec - tickadj;
+
+       do {
+               seq = read_seqbegin_irqsave(&xtime_lock, flags);
+               usec = do_gettimeoffset();
+
+               /*
+                * If time_adjust is negative then NTP is slowing the clock
+                * so make sure not to go into next possible interval.
+                * Better to lose some accuracy than have time go backwards..
+                */
+               if (unlikely(time_adjust < 0))
+                       usec = min(usec, max_ntp_tick);
+
+               sec = xtime.tv_sec;
+               usec += (xtime.tv_nsec / 1000);
+       } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
+
+       while (usec >= 1000000) {
+               usec -= 1000000;
+               sec++;
+       }
+
+       tv->tv_sec = sec;
+       tv->tv_usec = usec;
+}
+
+EXPORT_SYMBOL(do_gettimeofday);
+
+int do_settimeofday(struct timespec *tv)
+{
+       int ret;
+
+       write_seqlock_irq(&xtime_lock);
+       ret = bus_do_settimeofday(tv);
+       write_sequnlock_irq(&xtime_lock);
+       clock_was_set();
+       return ret;
+}
+
+EXPORT_SYMBOL(do_settimeofday);
+
+static int sbus_do_settimeofday(struct timespec *tv)
+{
+       time_t wtm_sec, sec = tv->tv_sec;
+       long wtm_nsec, nsec = tv->tv_nsec;
+
+       if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
+               return -EINVAL;
+
+       /*
+        * This is revolting. We need to set "xtime" correctly. However, the
+        * value in this location is the value at the most recent update of
+        * wall time.  Discover what correction gettimeofday() would have
+        * made, and then undo it!
+        */
+       nsec -= 1000 * do_gettimeoffset();
+
+       wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
+       wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
+
+       set_normalized_timespec(&xtime, sec, nsec);
+       set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
+
+       ntp_clear();
+       return 0;
+}
+
+static int set_rtc_mmss(unsigned long secs)
+{
+       struct rtc_device *rtc = rtc_class_open("rtc0");
+       int err = -1;
+
+       if (rtc) {
+               err = rtc_set_mmss(rtc, secs);
+               rtc_class_close(rtc);
+       }
+
+       return err;
+}
diff --git a/arch/sparc/kernel/trampoline.S b/arch/sparc/kernel/trampoline.S
deleted file mode 100644 (file)
index 5e235c5..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * trampoline.S: SMP cpu boot-up trampoline code.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- */
-
-#include <linux/init.h>
-#include <asm/head.h>
-#include <asm/psr.h>
-#include <asm/page.h>
-#include <asm/asi.h>
-#include <asm/ptrace.h>
-#include <asm/vaddrs.h>
-#include <asm/contregs.h>
-#include <asm/thread_info.h>
-
-       .globl sun4m_cpu_startup, __smp4m_processor_id
-       .globl sun4d_cpu_startup, __smp4d_processor_id
-
-       __CPUINIT
-       .align 4
-
-/* When we start up a cpu for the first time it enters this routine.
- * This initializes the chip from whatever state the prom left it
- * in and sets PIL in %psr to 15, no irqs.
- */
-
-sun4m_cpu_startup:
-cpu1_startup:
-       sethi   %hi(trapbase_cpu1), %g3
-       b       1f
-        or     %g3, %lo(trapbase_cpu1), %g3
-
-cpu2_startup:
-       sethi   %hi(trapbase_cpu2), %g3
-       b       1f
-        or     %g3, %lo(trapbase_cpu2), %g3
-
-cpu3_startup:
-       sethi   %hi(trapbase_cpu3), %g3
-       b       1f
-        or     %g3, %lo(trapbase_cpu3), %g3
-
-1:
-       /* Set up a sane %psr -- PIL<0xf> S<0x1> PS<0x1> CWP<0x0> */
-       set     (PSR_PIL | PSR_S | PSR_PS), %g1
-       wr      %g1, 0x0, %psr          ! traps off though
-       WRITE_PAUSE
-
-       /* Our %wim is one behind CWP */
-       mov     2, %g1
-       wr      %g1, 0x0, %wim
-       WRITE_PAUSE
-
-       /* This identifies "this cpu". */
-       wr      %g3, 0x0, %tbr
-       WRITE_PAUSE
-
-       /* Give ourselves a stack and curptr. */
-       set     current_set, %g5
-       srl     %g3, 10, %g4
-       and     %g4, 0xc, %g4
-       ld      [%g5 + %g4], %g6
-
-       sethi   %hi(THREAD_SIZE - STACKFRAME_SZ), %sp
-       or      %sp, %lo(THREAD_SIZE - STACKFRAME_SZ), %sp
-       add     %g6, %sp, %sp
-
-       /* Turn on traps (PSR_ET). */
-       rd      %psr, %g1
-       wr      %g1, PSR_ET, %psr       ! traps on
-       WRITE_PAUSE
-
-       /* Init our caches, etc. */
-       set     poke_srmmu, %g5
-       ld      [%g5], %g5
-       call    %g5
-        nop
-
-       /* Start this processor. */
-       call    smp4m_callin
-        nop
-
-       b,a     smp_do_cpu_idle
-
-       .text
-       .align  4
-
-smp_do_cpu_idle:
-       call    cpu_idle
-        mov    0, %o0
-
-       call    cpu_panic
-        nop
-
-__smp4m_processor_id:
-       rd      %tbr, %g2
-       srl     %g2, 12, %g2
-       and     %g2, 3, %g2
-       retl
-        mov    %g1, %o7
-
-__smp4d_processor_id:
-       lda     [%g0] ASI_M_VIKING_TMP1, %g2
-       retl
-        mov    %g1, %o7
-
-/* CPUID in bootbus can be found at PA 0xff0140000 */
-#define SUN4D_BOOTBUS_CPUID    0xf0140000
-
-       __CPUINIT
-       .align  4
-
-sun4d_cpu_startup:
-       /* Set up a sane %psr -- PIL<0xf> S<0x1> PS<0x1> CWP<0x0> */
-       set     (PSR_PIL | PSR_S | PSR_PS), %g1
-       wr      %g1, 0x0, %psr          ! traps off though
-       WRITE_PAUSE
-
-       /* Our %wim is one behind CWP */
-       mov     2, %g1
-       wr      %g1, 0x0, %wim
-       WRITE_PAUSE
-
-       /* Set tbr - we use just one trap table. */
-       set     trapbase, %g1
-       wr      %g1, 0x0, %tbr
-       WRITE_PAUSE
-
-       /* Get our CPU id out of bootbus */
-       set     SUN4D_BOOTBUS_CPUID, %g3
-       lduba   [%g3] ASI_M_CTL, %g3
-       and     %g3, 0xf8, %g3
-       srl     %g3, 3, %g1
-       sta     %g1, [%g0] ASI_M_VIKING_TMP1
-
-       /* Give ourselves a stack and curptr. */
-       set     current_set, %g5
-       srl     %g3, 1, %g4
-       ld      [%g5 + %g4], %g6
-
-       sethi   %hi(THREAD_SIZE - STACKFRAME_SZ), %sp
-       or      %sp, %lo(THREAD_SIZE - STACKFRAME_SZ), %sp
-       add     %g6, %sp, %sp
-
-       /* Turn on traps (PSR_ET). */
-       rd      %psr, %g1
-       wr      %g1, PSR_ET, %psr       ! traps on
-       WRITE_PAUSE
-
-       /* Init our caches, etc. */
-       set     poke_srmmu, %g5
-       ld      [%g5], %g5
-       call    %g5
-        nop
-
-       /* Start this processor. */
-       call    smp4d_callin
-        nop
-
-       b,a     smp_do_cpu_idle
diff --git a/arch/sparc/kernel/trampoline_32.S b/arch/sparc/kernel/trampoline_32.S
new file mode 100644 (file)
index 0000000..5e235c5
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * trampoline.S: SMP cpu boot-up trampoline code.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/init.h>
+#include <asm/head.h>
+#include <asm/psr.h>
+#include <asm/page.h>
+#include <asm/asi.h>
+#include <asm/ptrace.h>
+#include <asm/vaddrs.h>
+#include <asm/contregs.h>
+#include <asm/thread_info.h>
+
+       .globl sun4m_cpu_startup, __smp4m_processor_id
+       .globl sun4d_cpu_startup, __smp4d_processor_id
+
+       __CPUINIT
+       .align 4
+
+/* When we start up a cpu for the first time it enters this routine.
+ * This initializes the chip from whatever state the prom left it
+ * in and sets PIL in %psr to 15, no irqs.
+ */
+
+sun4m_cpu_startup:
+cpu1_startup:
+       sethi   %hi(trapbase_cpu1), %g3
+       b       1f
+        or     %g3, %lo(trapbase_cpu1), %g3
+
+cpu2_startup:
+       sethi   %hi(trapbase_cpu2), %g3
+       b       1f
+        or     %g3, %lo(trapbase_cpu2), %g3
+
+cpu3_startup:
+       sethi   %hi(trapbase_cpu3), %g3
+       b       1f
+        or     %g3, %lo(trapbase_cpu3), %g3
+
+1:
+       /* Set up a sane %psr -- PIL<0xf> S<0x1> PS<0x1> CWP<0x0> */
+       set     (PSR_PIL | PSR_S | PSR_PS), %g1
+       wr      %g1, 0x0, %psr          ! traps off though
+       WRITE_PAUSE
+
+       /* Our %wim is one behind CWP */
+       mov     2, %g1
+       wr      %g1, 0x0, %wim
+       WRITE_PAUSE
+
+       /* This identifies "this cpu". */
+       wr      %g3, 0x0, %tbr
+       WRITE_PAUSE
+
+       /* Give ourselves a stack and curptr. */
+       set     current_set, %g5
+       srl     %g3, 10, %g4
+       and     %g4, 0xc, %g4
+       ld      [%g5 + %g4], %g6
+
+       sethi   %hi(THREAD_SIZE - STACKFRAME_SZ), %sp
+       or      %sp, %lo(THREAD_SIZE - STACKFRAME_SZ), %sp
+       add     %g6, %sp, %sp
+
+       /* Turn on traps (PSR_ET). */
+       rd      %psr, %g1
+       wr      %g1, PSR_ET, %psr       ! traps on
+       WRITE_PAUSE
+
+       /* Init our caches, etc. */
+       set     poke_srmmu, %g5
+       ld      [%g5], %g5
+       call    %g5
+        nop
+
+       /* Start this processor. */
+       call    smp4m_callin
+        nop
+
+       b,a     smp_do_cpu_idle
+
+       .text
+       .align  4
+
+smp_do_cpu_idle:
+       call    cpu_idle
+        mov    0, %o0
+
+       call    cpu_panic
+        nop
+
+__smp4m_processor_id:
+       rd      %tbr, %g2
+       srl     %g2, 12, %g2
+       and     %g2, 3, %g2
+       retl
+        mov    %g1, %o7
+
+__smp4d_processor_id:
+       lda     [%g0] ASI_M_VIKING_TMP1, %g2
+       retl
+        mov    %g1, %o7
+
+/* CPUID in bootbus can be found at PA 0xff0140000 */
+#define SUN4D_BOOTBUS_CPUID    0xf0140000
+
+       __CPUINIT
+       .align  4
+
+sun4d_cpu_startup:
+       /* Set up a sane %psr -- PIL<0xf> S<0x1> PS<0x1> CWP<0x0> */
+       set     (PSR_PIL | PSR_S | PSR_PS), %g1
+       wr      %g1, 0x0, %psr          ! traps off though
+       WRITE_PAUSE
+
+       /* Our %wim is one behind CWP */
+       mov     2, %g1
+       wr      %g1, 0x0, %wim
+       WRITE_PAUSE
+
+       /* Set tbr - we use just one trap table. */
+       set     trapbase, %g1
+       wr      %g1, 0x0, %tbr
+       WRITE_PAUSE
+
+       /* Get our CPU id out of bootbus */
+       set     SUN4D_BOOTBUS_CPUID, %g3
+       lduba   [%g3] ASI_M_CTL, %g3
+       and     %g3, 0xf8, %g3
+       srl     %g3, 3, %g1
+       sta     %g1, [%g0] ASI_M_VIKING_TMP1
+
+       /* Give ourselves a stack and curptr. */
+       set     current_set, %g5
+       srl     %g3, 1, %g4
+       ld      [%g5 + %g4], %g6
+
+       sethi   %hi(THREAD_SIZE - STACKFRAME_SZ), %sp
+       or      %sp, %lo(THREAD_SIZE - STACKFRAME_SZ), %sp
+       add     %g6, %sp, %sp
+
+       /* Turn on traps (PSR_ET). */
+       rd      %psr, %g1
+       wr      %g1, PSR_ET, %psr       ! traps on
+       WRITE_PAUSE
+
+       /* Init our caches, etc. */
+       set     poke_srmmu, %g5
+       ld      [%g5], %g5
+       call    %g5
+        nop
+
+       /* Start this processor. */
+       call    smp4d_callin
+        nop
+
+       b,a     smp_do_cpu_idle
diff --git a/arch/sparc/kernel/traps.c b/arch/sparc/kernel/traps.c
deleted file mode 100644 (file)
index 2b7d506..0000000
+++ /dev/null
@@ -1,490 +0,0 @@
-/*
- * arch/sparc/kernel/traps.c
- *
- * Copyright 1995, 2008 David S. Miller (davem@davemloft.net)
- * Copyright 2000 Jakub Jelinek (jakub@redhat.com)
- */
-
-/*
- * I hate traps on the sparc, grrr...
- */
-
-#include <linux/sched.h>  /* for jiffies */
-#include <linux/kernel.h>
-#include <linux/signal.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-#include <linux/kdebug.h>
-
-#include <asm/delay.h>
-#include <asm/system.h>
-#include <asm/ptrace.h>
-#include <asm/oplib.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/unistd.h>
-#include <asm/traps.h>
-
-/* #define TRAP_DEBUG */
-
-struct trap_trace_entry {
-       unsigned long pc;
-       unsigned long type;
-};
-
-void syscall_trace_entry(struct pt_regs *regs)
-{
-       printk("%s[%d]: ", current->comm, task_pid_nr(current));
-       printk("scall<%d> (could be %d)\n", (int) regs->u_regs[UREG_G1],
-              (int) regs->u_regs[UREG_I0]);
-}
-
-void syscall_trace_exit(struct pt_regs *regs)
-{
-}
-
-void sun4d_nmi(struct pt_regs *regs)
-{
-       printk("Aieee: sun4d NMI received!\n");
-       printk("you lose buddy boy...\n");
-       show_regs(regs);
-       prom_halt();
-}
-
-static void instruction_dump(unsigned long *pc)
-{
-       int i;
-       
-       if((((unsigned long) pc) & 3))
-                return;
-
-       for(i = -3; i < 6; i++)
-               printk("%c%08lx%c",i?' ':'<',pc[i],i?' ':'>');
-       printk("\n");
-}
-
-#define __SAVE __asm__ __volatile__("save %sp, -0x40, %sp\n\t")
-#define __RESTORE __asm__ __volatile__("restore %g0, %g0, %g0\n\t")
-
-void die_if_kernel(char *str, struct pt_regs *regs)
-{
-       static int die_counter;
-       int count = 0;
-
-       /* Amuse the user. */
-       printk(
-"              \\|/ ____ \\|/\n"
-"              \"@'/ ,. \\`@\"\n"
-"              /_| \\__/ |_\\\n"
-"                 \\__U_/\n");
-
-       printk("%s(%d): %s [#%d]\n", current->comm, task_pid_nr(current), str, ++die_counter);
-       show_regs(regs);
-       add_taint(TAINT_DIE);
-
-       __SAVE; __SAVE; __SAVE; __SAVE;
-       __SAVE; __SAVE; __SAVE; __SAVE;
-       __RESTORE; __RESTORE; __RESTORE; __RESTORE;
-       __RESTORE; __RESTORE; __RESTORE; __RESTORE;
-
-       {
-               struct reg_window *rw = (struct reg_window *)regs->u_regs[UREG_FP];
-
-               /* Stop the back trace when we hit userland or we
-                * find some badly aligned kernel stack. Set an upper
-                * bound in case our stack is trashed and we loop.
-                */
-               while(rw                                        &&
-                     count++ < 30                              &&
-                      (((unsigned long) rw) >= PAGE_OFFSET)    &&
-                     !(((unsigned long) rw) & 0x7)) {
-                       printk("Caller[%08lx]: %pS\n", rw->ins[7],
-                              (void *) rw->ins[7]);
-                       rw = (struct reg_window *)rw->ins[6];
-               }
-       }
-       printk("Instruction DUMP:");
-       instruction_dump ((unsigned long *) regs->pc);
-       if(regs->psr & PSR_PS)
-               do_exit(SIGKILL);
-       do_exit(SIGSEGV);
-}
-
-void do_hw_interrupt(struct pt_regs *regs, unsigned long type)
-{
-       siginfo_t info;
-
-       if(type < 0x80) {
-               /* Sun OS's puke from bad traps, Linux survives! */
-               printk("Unimplemented Sparc TRAP, type = %02lx\n", type);
-               die_if_kernel("Whee... Hello Mr. Penguin", regs);
-       }       
-
-       if(regs->psr & PSR_PS)
-               die_if_kernel("Kernel bad trap", regs);
-
-       info.si_signo = SIGILL;
-       info.si_errno = 0;
-       info.si_code = ILL_ILLTRP;
-       info.si_addr = (void __user *)regs->pc;
-       info.si_trapno = type - 0x80;
-       force_sig_info(SIGILL, &info, current);
-}
-
-void do_illegal_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
-                           unsigned long psr)
-{
-       extern int do_user_muldiv (struct pt_regs *, unsigned long);
-       siginfo_t info;
-
-       if(psr & PSR_PS)
-               die_if_kernel("Kernel illegal instruction", regs);
-#ifdef TRAP_DEBUG
-       printk("Ill instr. at pc=%08lx instruction is %08lx\n",
-              regs->pc, *(unsigned long *)regs->pc);
-#endif
-       if (!do_user_muldiv (regs, pc))
-               return;
-
-       info.si_signo = SIGILL;
-       info.si_errno = 0;
-       info.si_code = ILL_ILLOPC;
-       info.si_addr = (void __user *)pc;
-       info.si_trapno = 0;
-       send_sig_info(SIGILL, &info, current);
-}
-
-void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
-                        unsigned long psr)
-{
-       siginfo_t info;
-
-       if(psr & PSR_PS)
-               die_if_kernel("Penguin instruction from Penguin mode??!?!", regs);
-       info.si_signo = SIGILL;
-       info.si_errno = 0;
-       info.si_code = ILL_PRVOPC;
-       info.si_addr = (void __user *)pc;
-       info.si_trapno = 0;
-       send_sig_info(SIGILL, &info, current);
-}
-
-/* XXX User may want to be allowed to do this. XXX */
-
-void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned long npc,
-                           unsigned long psr)
-{
-       siginfo_t info;
-
-       if(regs->psr & PSR_PS) {
-               printk("KERNEL MNA at pc %08lx npc %08lx called by %08lx\n", pc, npc,
-                      regs->u_regs[UREG_RETPC]);
-               die_if_kernel("BOGUS", regs);
-               /* die_if_kernel("Kernel MNA access", regs); */
-       }
-#if 0
-       show_regs (regs);
-       instruction_dump ((unsigned long *) regs->pc);
-       printk ("do_MNA!\n");
-#endif
-       info.si_signo = SIGBUS;
-       info.si_errno = 0;
-       info.si_code = BUS_ADRALN;
-       info.si_addr = /* FIXME: Should dig out mna address */ (void *)0;
-       info.si_trapno = 0;
-       send_sig_info(SIGBUS, &info, current);
-}
-
-extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
-                  void *fpqueue, unsigned long *fpqdepth);
-extern void fpload(unsigned long *fpregs, unsigned long *fsr);
-
-static unsigned long init_fsr = 0x0UL;
-static unsigned long init_fregs[32] __attribute__ ((aligned (8))) =
-                { ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL,
-                 ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL,
-                 ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL,
-                 ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL };
-
-void do_fpd_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
-                unsigned long psr)
-{
-       /* Sanity check... */
-       if(psr & PSR_PS)
-               die_if_kernel("Kernel gets FloatingPenguinUnit disabled trap", regs);
-
-       put_psr(get_psr() | PSR_EF);    /* Allow FPU ops. */
-       regs->psr |= PSR_EF;
-#ifndef CONFIG_SMP
-       if(last_task_used_math == current)
-               return;
-       if(last_task_used_math) {
-               /* Other processes fpu state, save away */
-               struct task_struct *fptask = last_task_used_math;
-               fpsave(&fptask->thread.float_regs[0], &fptask->thread.fsr,
-                      &fptask->thread.fpqueue[0], &fptask->thread.fpqdepth);
-       }
-       last_task_used_math = current;
-       if(used_math()) {
-               fpload(&current->thread.float_regs[0], &current->thread.fsr);
-       } else {
-               /* Set initial sane state. */
-               fpload(&init_fregs[0], &init_fsr);
-               set_used_math();
-       }
-#else
-       if(!used_math()) {
-               fpload(&init_fregs[0], &init_fsr);
-               set_used_math();
-       } else {
-               fpload(&current->thread.float_regs[0], &current->thread.fsr);
-       }
-       set_thread_flag(TIF_USEDFPU);
-#endif
-}
-
-static unsigned long fake_regs[32] __attribute__ ((aligned (8)));
-static unsigned long fake_fsr;
-static unsigned long fake_queue[32] __attribute__ ((aligned (8)));
-static unsigned long fake_depth;
-
-extern int do_mathemu(struct pt_regs *, struct task_struct *);
-
-void do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
-                unsigned long psr)
-{
-       static int calls;
-       siginfo_t info;
-       unsigned long fsr;
-       int ret = 0;
-#ifndef CONFIG_SMP
-       struct task_struct *fpt = last_task_used_math;
-#else
-       struct task_struct *fpt = current;
-#endif
-       put_psr(get_psr() | PSR_EF);
-       /* If nobody owns the fpu right now, just clear the
-        * error into our fake static buffer and hope it don't
-        * happen again.  Thank you crashme...
-        */
-#ifndef CONFIG_SMP
-       if(!fpt) {
-#else
-       if (!test_tsk_thread_flag(fpt, TIF_USEDFPU)) {
-#endif
-               fpsave(&fake_regs[0], &fake_fsr, &fake_queue[0], &fake_depth);
-               regs->psr &= ~PSR_EF;
-               return;
-       }
-       fpsave(&fpt->thread.float_regs[0], &fpt->thread.fsr,
-              &fpt->thread.fpqueue[0], &fpt->thread.fpqdepth);
-#ifdef DEBUG_FPU
-       printk("Hmm, FP exception, fsr was %016lx\n", fpt->thread.fsr);
-#endif
-
-       switch ((fpt->thread.fsr & 0x1c000)) {
-       /* switch on the contents of the ftt [floating point trap type] field */
-#ifdef DEBUG_FPU
-       case (1 << 14):
-               printk("IEEE_754_exception\n");
-               break;
-#endif
-       case (2 << 14):  /* unfinished_FPop (underflow & co) */
-       case (3 << 14):  /* unimplemented_FPop (quad stuff, maybe sqrt) */
-               ret = do_mathemu(regs, fpt);
-               break;
-#ifdef DEBUG_FPU
-       case (4 << 14):
-               printk("sequence_error (OS bug...)\n");
-               break;
-       case (5 << 14):
-               printk("hardware_error (uhoh!)\n");
-               break;
-       case (6 << 14):
-               printk("invalid_fp_register (user error)\n");
-               break;
-#endif /* DEBUG_FPU */
-       }
-       /* If we successfully emulated the FPop, we pretend the trap never happened :-> */
-       if (ret) {
-               fpload(&current->thread.float_regs[0], &current->thread.fsr);
-               return;
-       }
-       /* nope, better SIGFPE the offending process... */
-              
-#ifdef CONFIG_SMP
-       clear_tsk_thread_flag(fpt, TIF_USEDFPU);
-#endif
-       if(psr & PSR_PS) {
-               /* The first fsr store/load we tried trapped,
-                * the second one will not (we hope).
-                */
-               printk("WARNING: FPU exception from kernel mode. at pc=%08lx\n",
-                      regs->pc);
-               regs->pc = regs->npc;
-               regs->npc += 4;
-               calls++;
-               if(calls > 2)
-                       die_if_kernel("Too many Penguin-FPU traps from kernel mode",
-                                     regs);
-               return;
-       }
-
-       fsr = fpt->thread.fsr;
-       info.si_signo = SIGFPE;
-       info.si_errno = 0;
-       info.si_addr = (void __user *)pc;
-       info.si_trapno = 0;
-       info.si_code = __SI_FAULT;
-       if ((fsr & 0x1c000) == (1 << 14)) {
-               if (fsr & 0x10)
-                       info.si_code = FPE_FLTINV;
-               else if (fsr & 0x08)
-                       info.si_code = FPE_FLTOVF;
-               else if (fsr & 0x04)
-                       info.si_code = FPE_FLTUND;
-               else if (fsr & 0x02)
-                       info.si_code = FPE_FLTDIV;
-               else if (fsr & 0x01)
-                       info.si_code = FPE_FLTRES;
-       }
-       send_sig_info(SIGFPE, &info, fpt);
-#ifndef CONFIG_SMP
-       last_task_used_math = NULL;
-#endif
-       regs->psr &= ~PSR_EF;
-       if(calls > 0)
-               calls=0;
-}
-
-void handle_tag_overflow(struct pt_regs *regs, unsigned long pc, unsigned long npc,
-                        unsigned long psr)
-{
-       siginfo_t info;
-
-       if(psr & PSR_PS)
-               die_if_kernel("Penguin overflow trap from kernel mode", regs);
-       info.si_signo = SIGEMT;
-       info.si_errno = 0;
-       info.si_code = EMT_TAGOVF;
-       info.si_addr = (void __user *)pc;
-       info.si_trapno = 0;
-       send_sig_info(SIGEMT, &info, current);
-}
-
-void handle_watchpoint(struct pt_regs *regs, unsigned long pc, unsigned long npc,
-                      unsigned long psr)
-{
-#ifdef TRAP_DEBUG
-       printk("Watchpoint detected at PC %08lx NPC %08lx PSR %08lx\n",
-              pc, npc, psr);
-#endif
-       if(psr & PSR_PS)
-               panic("Tell me what a watchpoint trap is, and I'll then deal "
-                     "with such a beast...");
-}
-
-void handle_reg_access(struct pt_regs *regs, unsigned long pc, unsigned long npc,
-                      unsigned long psr)
-{
-       siginfo_t info;
-
-#ifdef TRAP_DEBUG
-       printk("Register Access Exception at PC %08lx NPC %08lx PSR %08lx\n",
-              pc, npc, psr);
-#endif
-       info.si_signo = SIGBUS;
-       info.si_errno = 0;
-       info.si_code = BUS_OBJERR;
-       info.si_addr = (void __user *)pc;
-       info.si_trapno = 0;
-       force_sig_info(SIGBUS, &info, current);
-}
-
-void handle_cp_disabled(struct pt_regs *regs, unsigned long pc, unsigned long npc,
-                       unsigned long psr)
-{
-       siginfo_t info;
-
-       info.si_signo = SIGILL;
-       info.si_errno = 0;
-       info.si_code = ILL_COPROC;
-       info.si_addr = (void __user *)pc;
-       info.si_trapno = 0;
-       send_sig_info(SIGILL, &info, current);
-}
-
-void handle_cp_exception(struct pt_regs *regs, unsigned long pc, unsigned long npc,
-                        unsigned long psr)
-{
-       siginfo_t info;
-
-#ifdef TRAP_DEBUG
-       printk("Co-Processor Exception at PC %08lx NPC %08lx PSR %08lx\n",
-              pc, npc, psr);
-#endif
-       info.si_signo = SIGILL;
-       info.si_errno = 0;
-       info.si_code = ILL_COPROC;
-       info.si_addr = (void __user *)pc;
-       info.si_trapno = 0;
-       send_sig_info(SIGILL, &info, current);
-}
-
-void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, unsigned long npc,
-                      unsigned long psr)
-{
-       siginfo_t info;
-
-       info.si_signo = SIGFPE;
-       info.si_errno = 0;
-       info.si_code = FPE_INTDIV;
-       info.si_addr = (void __user *)pc;
-       info.si_trapno = 0;
-       send_sig_info(SIGFPE, &info, current);
-}
-
-#ifdef CONFIG_DEBUG_BUGVERBOSE
-void do_BUG(const char *file, int line)
-{
-        // bust_spinlocks(1);   XXX Not in our original BUG()
-        printk("kernel BUG at %s:%d!\n", file, line);
-}
-#endif
-
-/* Since we have our mappings set up, on multiprocessors we can spin them
- * up here so that timer interrupts work during initialization.
- */
-
-extern void sparc_cpu_startup(void);
-
-void trap_init(void)
-{
-       extern void thread_info_offsets_are_bolixed_pete(void);
-
-       /* Force linker to barf if mismatched */
-       if (TI_UWINMASK    != offsetof(struct thread_info, uwinmask) ||
-           TI_TASK        != offsetof(struct thread_info, task) ||
-           TI_EXECDOMAIN  != offsetof(struct thread_info, exec_domain) ||
-           TI_FLAGS       != offsetof(struct thread_info, flags) ||
-           TI_CPU         != offsetof(struct thread_info, cpu) ||
-           TI_PREEMPT     != offsetof(struct thread_info, preempt_count) ||
-           TI_SOFTIRQ     != offsetof(struct thread_info, softirq_count) ||
-           TI_HARDIRQ     != offsetof(struct thread_info, hardirq_count) ||
-           TI_KSP         != offsetof(struct thread_info, ksp) ||
-           TI_KPC         != offsetof(struct thread_info, kpc) ||
-           TI_KPSR        != offsetof(struct thread_info, kpsr) ||
-           TI_KWIM        != offsetof(struct thread_info, kwim) ||
-           TI_REG_WINDOW  != offsetof(struct thread_info, reg_window) ||
-           TI_RWIN_SPTRS  != offsetof(struct thread_info, rwbuf_stkptrs) ||
-           TI_W_SAVED     != offsetof(struct thread_info, w_saved))
-               thread_info_offsets_are_bolixed_pete();
-
-       /* Attach to the address space of init_task. */
-       atomic_inc(&init_mm.mm_count);
-       current->active_mm = &init_mm;
-
-       /* NOTE: Other cpus have this done as they are started
-        *       up on SMP.
-        */
-}
diff --git a/arch/sparc/kernel/traps_32.c b/arch/sparc/kernel/traps_32.c
new file mode 100644 (file)
index 0000000..2b7d506
--- /dev/null
@@ -0,0 +1,490 @@
+/*
+ * arch/sparc/kernel/traps.c
+ *
+ * Copyright 1995, 2008 David S. Miller (davem@davemloft.net)
+ * Copyright 2000 Jakub Jelinek (jakub@redhat.com)
+ */
+
+/*
+ * I hate traps on the sparc, grrr...
+ */
+
+#include <linux/sched.h>  /* for jiffies */
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/kdebug.h>
+
+#include <asm/delay.h>
+#include <asm/system.h>
+#include <asm/ptrace.h>
+#include <asm/oplib.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/unistd.h>
+#include <asm/traps.h>
+
+/* #define TRAP_DEBUG */
+
+struct trap_trace_entry {
+       unsigned long pc;
+       unsigned long type;
+};
+
+void syscall_trace_entry(struct pt_regs *regs)
+{
+       printk("%s[%d]: ", current->comm, task_pid_nr(current));
+       printk("scall<%d> (could be %d)\n", (int) regs->u_regs[UREG_G1],
+              (int) regs->u_regs[UREG_I0]);
+}
+
+void syscall_trace_exit(struct pt_regs *regs)
+{
+}
+
+void sun4d_nmi(struct pt_regs *regs)
+{
+       printk("Aieee: sun4d NMI received!\n");
+       printk("you lose buddy boy...\n");
+       show_regs(regs);
+       prom_halt();
+}
+
+static void instruction_dump(unsigned long *pc)
+{
+       int i;
+       
+       if((((unsigned long) pc) & 3))
+                return;
+
+       for(i = -3; i < 6; i++)
+               printk("%c%08lx%c",i?' ':'<',pc[i],i?' ':'>');
+       printk("\n");
+}
+
+#define __SAVE __asm__ __volatile__("save %sp, -0x40, %sp\n\t")
+#define __RESTORE __asm__ __volatile__("restore %g0, %g0, %g0\n\t")
+
+void die_if_kernel(char *str, struct pt_regs *regs)
+{
+       static int die_counter;
+       int count = 0;
+
+       /* Amuse the user. */
+       printk(
+"              \\|/ ____ \\|/\n"
+"              \"@'/ ,. \\`@\"\n"
+"              /_| \\__/ |_\\\n"
+"                 \\__U_/\n");
+
+       printk("%s(%d): %s [#%d]\n", current->comm, task_pid_nr(current), str, ++die_counter);
+       show_regs(regs);
+       add_taint(TAINT_DIE);
+
+       __SAVE; __SAVE; __SAVE; __SAVE;
+       __SAVE; __SAVE; __SAVE; __SAVE;
+       __RESTORE; __RESTORE; __RESTORE; __RESTORE;
+       __RESTORE; __RESTORE; __RESTORE; __RESTORE;
+
+       {
+               struct reg_window *rw = (struct reg_window *)regs->u_regs[UREG_FP];
+
+               /* Stop the back trace when we hit userland or we
+                * find some badly aligned kernel stack. Set an upper
+                * bound in case our stack is trashed and we loop.
+                */
+               while(rw                                        &&
+                     count++ < 30                              &&
+                      (((unsigned long) rw) >= PAGE_OFFSET)    &&
+                     !(((unsigned long) rw) & 0x7)) {
+                       printk("Caller[%08lx]: %pS\n", rw->ins[7],
+                              (void *) rw->ins[7]);
+                       rw = (struct reg_window *)rw->ins[6];
+               }
+       }
+       printk("Instruction DUMP:");
+       instruction_dump ((unsigned long *) regs->pc);
+       if(regs->psr & PSR_PS)
+               do_exit(SIGKILL);
+       do_exit(SIGSEGV);
+}
+
+void do_hw_interrupt(struct pt_regs *regs, unsigned long type)
+{
+       siginfo_t info;
+
+       if(type < 0x80) {
+               /* Sun OS's puke from bad traps, Linux survives! */
+               printk("Unimplemented Sparc TRAP, type = %02lx\n", type);
+               die_if_kernel("Whee... Hello Mr. Penguin", regs);
+       }       
+
+       if(regs->psr & PSR_PS)
+               die_if_kernel("Kernel bad trap", regs);
+
+       info.si_signo = SIGILL;
+       info.si_errno = 0;
+       info.si_code = ILL_ILLTRP;
+       info.si_addr = (void __user *)regs->pc;
+       info.si_trapno = type - 0x80;
+       force_sig_info(SIGILL, &info, current);
+}
+
+void do_illegal_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                           unsigned long psr)
+{
+       extern int do_user_muldiv (struct pt_regs *, unsigned long);
+       siginfo_t info;
+
+       if(psr & PSR_PS)
+               die_if_kernel("Kernel illegal instruction", regs);
+#ifdef TRAP_DEBUG
+       printk("Ill instr. at pc=%08lx instruction is %08lx\n",
+              regs->pc, *(unsigned long *)regs->pc);
+#endif
+       if (!do_user_muldiv (regs, pc))
+               return;
+
+       info.si_signo = SIGILL;
+       info.si_errno = 0;
+       info.si_code = ILL_ILLOPC;
+       info.si_addr = (void __user *)pc;
+       info.si_trapno = 0;
+       send_sig_info(SIGILL, &info, current);
+}
+
+void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                        unsigned long psr)
+{
+       siginfo_t info;
+
+       if(psr & PSR_PS)
+               die_if_kernel("Penguin instruction from Penguin mode??!?!", regs);
+       info.si_signo = SIGILL;
+       info.si_errno = 0;
+       info.si_code = ILL_PRVOPC;
+       info.si_addr = (void __user *)pc;
+       info.si_trapno = 0;
+       send_sig_info(SIGILL, &info, current);
+}
+
+/* XXX User may want to be allowed to do this. XXX */
+
+void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                           unsigned long psr)
+{
+       siginfo_t info;
+
+       if(regs->psr & PSR_PS) {
+               printk("KERNEL MNA at pc %08lx npc %08lx called by %08lx\n", pc, npc,
+                      regs->u_regs[UREG_RETPC]);
+               die_if_kernel("BOGUS", regs);
+               /* die_if_kernel("Kernel MNA access", regs); */
+       }
+#if 0
+       show_regs (regs);
+       instruction_dump ((unsigned long *) regs->pc);
+       printk ("do_MNA!\n");
+#endif
+       info.si_signo = SIGBUS;
+       info.si_errno = 0;
+       info.si_code = BUS_ADRALN;
+       info.si_addr = /* FIXME: Should dig out mna address */ (void *)0;
+       info.si_trapno = 0;
+       send_sig_info(SIGBUS, &info, current);
+}
+
+extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
+                  void *fpqueue, unsigned long *fpqdepth);
+extern void fpload(unsigned long *fpregs, unsigned long *fsr);
+
+static unsigned long init_fsr = 0x0UL;
+static unsigned long init_fregs[32] __attribute__ ((aligned (8))) =
+                { ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL,
+                 ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL,
+                 ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL,
+                 ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL };
+
+void do_fpd_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                unsigned long psr)
+{
+       /* Sanity check... */
+       if(psr & PSR_PS)
+               die_if_kernel("Kernel gets FloatingPenguinUnit disabled trap", regs);
+
+       put_psr(get_psr() | PSR_EF);    /* Allow FPU ops. */
+       regs->psr |= PSR_EF;
+#ifndef CONFIG_SMP
+       if(last_task_used_math == current)
+               return;
+       if(last_task_used_math) {
+               /* Other processes fpu state, save away */
+               struct task_struct *fptask = last_task_used_math;
+               fpsave(&fptask->thread.float_regs[0], &fptask->thread.fsr,
+                      &fptask->thread.fpqueue[0], &fptask->thread.fpqdepth);
+       }
+       last_task_used_math = current;
+       if(used_math()) {
+               fpload(&current->thread.float_regs[0], &current->thread.fsr);
+       } else {
+               /* Set initial sane state. */
+               fpload(&init_fregs[0], &init_fsr);
+               set_used_math();
+       }
+#else
+       if(!used_math()) {
+               fpload(&init_fregs[0], &init_fsr);
+               set_used_math();
+       } else {
+               fpload(&current->thread.float_regs[0], &current->thread.fsr);
+       }
+       set_thread_flag(TIF_USEDFPU);
+#endif
+}
+
+static unsigned long fake_regs[32] __attribute__ ((aligned (8)));
+static unsigned long fake_fsr;
+static unsigned long fake_queue[32] __attribute__ ((aligned (8)));
+static unsigned long fake_depth;
+
+extern int do_mathemu(struct pt_regs *, struct task_struct *);
+
+void do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                unsigned long psr)
+{
+       static int calls;
+       siginfo_t info;
+       unsigned long fsr;
+       int ret = 0;
+#ifndef CONFIG_SMP
+       struct task_struct *fpt = last_task_used_math;
+#else
+       struct task_struct *fpt = current;
+#endif
+       put_psr(get_psr() | PSR_EF);
+       /* If nobody owns the fpu right now, just clear the
+        * error into our fake static buffer and hope it don't
+        * happen again.  Thank you crashme...
+        */
+#ifndef CONFIG_SMP
+       if(!fpt) {
+#else
+       if (!test_tsk_thread_flag(fpt, TIF_USEDFPU)) {
+#endif
+               fpsave(&fake_regs[0], &fake_fsr, &fake_queue[0], &fake_depth);
+               regs->psr &= ~PSR_EF;
+               return;
+       }
+       fpsave(&fpt->thread.float_regs[0], &fpt->thread.fsr,
+              &fpt->thread.fpqueue[0], &fpt->thread.fpqdepth);
+#ifdef DEBUG_FPU
+       printk("Hmm, FP exception, fsr was %016lx\n", fpt->thread.fsr);
+#endif
+
+       switch ((fpt->thread.fsr & 0x1c000)) {
+       /* switch on the contents of the ftt [floating point trap type] field */
+#ifdef DEBUG_FPU
+       case (1 << 14):
+               printk("IEEE_754_exception\n");
+               break;
+#endif
+       case (2 << 14):  /* unfinished_FPop (underflow & co) */
+       case (3 << 14):  /* unimplemented_FPop (quad stuff, maybe sqrt) */
+               ret = do_mathemu(regs, fpt);
+               break;
+#ifdef DEBUG_FPU
+       case (4 << 14):
+               printk("sequence_error (OS bug...)\n");
+               break;
+       case (5 << 14):
+               printk("hardware_error (uhoh!)\n");
+               break;
+       case (6 << 14):
+               printk("invalid_fp_register (user error)\n");
+               break;
+#endif /* DEBUG_FPU */
+       }
+       /* If we successfully emulated the FPop, we pretend the trap never happened :-> */
+       if (ret) {
+               fpload(&current->thread.float_regs[0], &current->thread.fsr);
+               return;
+       }
+       /* nope, better SIGFPE the offending process... */
+              
+#ifdef CONFIG_SMP
+       clear_tsk_thread_flag(fpt, TIF_USEDFPU);
+#endif
+       if(psr & PSR_PS) {
+               /* The first fsr store/load we tried trapped,
+                * the second one will not (we hope).
+                */
+               printk("WARNING: FPU exception from kernel mode. at pc=%08lx\n",
+                      regs->pc);
+               regs->pc = regs->npc;
+               regs->npc += 4;
+               calls++;
+               if(calls > 2)
+                       die_if_kernel("Too many Penguin-FPU traps from kernel mode",
+                                     regs);
+               return;
+       }
+
+       fsr = fpt->thread.fsr;
+       info.si_signo = SIGFPE;
+       info.si_errno = 0;
+       info.si_addr = (void __user *)pc;
+       info.si_trapno = 0;
+       info.si_code = __SI_FAULT;
+       if ((fsr & 0x1c000) == (1 << 14)) {
+               if (fsr & 0x10)
+                       info.si_code = FPE_FLTINV;
+               else if (fsr & 0x08)
+                       info.si_code = FPE_FLTOVF;
+               else if (fsr & 0x04)
+                       info.si_code = FPE_FLTUND;
+               else if (fsr & 0x02)
+                       info.si_code = FPE_FLTDIV;
+               else if (fsr & 0x01)
+                       info.si_code = FPE_FLTRES;
+       }
+       send_sig_info(SIGFPE, &info, fpt);
+#ifndef CONFIG_SMP
+       last_task_used_math = NULL;
+#endif
+       regs->psr &= ~PSR_EF;
+       if(calls > 0)
+               calls=0;
+}
+
+void handle_tag_overflow(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                        unsigned long psr)
+{
+       siginfo_t info;
+
+       if(psr & PSR_PS)
+               die_if_kernel("Penguin overflow trap from kernel mode", regs);
+       info.si_signo = SIGEMT;
+       info.si_errno = 0;
+       info.si_code = EMT_TAGOVF;
+       info.si_addr = (void __user *)pc;
+       info.si_trapno = 0;
+       send_sig_info(SIGEMT, &info, current);
+}
+
+void handle_watchpoint(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                      unsigned long psr)
+{
+#ifdef TRAP_DEBUG
+       printk("Watchpoint detected at PC %08lx NPC %08lx PSR %08lx\n",
+              pc, npc, psr);
+#endif
+       if(psr & PSR_PS)
+               panic("Tell me what a watchpoint trap is, and I'll then deal "
+                     "with such a beast...");
+}
+
+void handle_reg_access(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                      unsigned long psr)
+{
+       siginfo_t info;
+
+#ifdef TRAP_DEBUG
+       printk("Register Access Exception at PC %08lx NPC %08lx PSR %08lx\n",
+              pc, npc, psr);
+#endif
+       info.si_signo = SIGBUS;
+       info.si_errno = 0;
+       info.si_code = BUS_OBJERR;
+       info.si_addr = (void __user *)pc;
+       info.si_trapno = 0;
+       force_sig_info(SIGBUS, &info, current);
+}
+
+void handle_cp_disabled(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                       unsigned long psr)
+{
+       siginfo_t info;
+
+       info.si_signo = SIGILL;
+       info.si_errno = 0;
+       info.si_code = ILL_COPROC;
+       info.si_addr = (void __user *)pc;
+       info.si_trapno = 0;
+       send_sig_info(SIGILL, &info, current);
+}
+
+void handle_cp_exception(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                        unsigned long psr)
+{
+       siginfo_t info;
+
+#ifdef TRAP_DEBUG
+       printk("Co-Processor Exception at PC %08lx NPC %08lx PSR %08lx\n",
+              pc, npc, psr);
+#endif
+       info.si_signo = SIGILL;
+       info.si_errno = 0;
+       info.si_code = ILL_COPROC;
+       info.si_addr = (void __user *)pc;
+       info.si_trapno = 0;
+       send_sig_info(SIGILL, &info, current);
+}
+
+void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                      unsigned long psr)
+{
+       siginfo_t info;
+
+       info.si_signo = SIGFPE;
+       info.si_errno = 0;
+       info.si_code = FPE_INTDIV;
+       info.si_addr = (void __user *)pc;
+       info.si_trapno = 0;
+       send_sig_info(SIGFPE, &info, current);
+}
+
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+void do_BUG(const char *file, int line)
+{
+        // bust_spinlocks(1);   XXX Not in our original BUG()
+        printk("kernel BUG at %s:%d!\n", file, line);
+}
+#endif
+
+/* Since we have our mappings set up, on multiprocessors we can spin them
+ * up here so that timer interrupts work during initialization.
+ */
+
+extern void sparc_cpu_startup(void);
+
+void trap_init(void)
+{
+       extern void thread_info_offsets_are_bolixed_pete(void);
+
+       /* Force linker to barf if mismatched */
+       if (TI_UWINMASK    != offsetof(struct thread_info, uwinmask) ||
+           TI_TASK        != offsetof(struct thread_info, task) ||
+           TI_EXECDOMAIN  != offsetof(struct thread_info, exec_domain) ||
+           TI_FLAGS       != offsetof(struct thread_info, flags) ||
+           TI_CPU         != offsetof(struct thread_info, cpu) ||
+           TI_PREEMPT     != offsetof(struct thread_info, preempt_count) ||
+           TI_SOFTIRQ     != offsetof(struct thread_info, softirq_count) ||
+           TI_HARDIRQ     != offsetof(struct thread_info, hardirq_count) ||
+           TI_KSP         != offsetof(struct thread_info, ksp) ||
+           TI_KPC         != offsetof(struct thread_info, kpc) ||
+           TI_KPSR        != offsetof(struct thread_info, kpsr) ||
+           TI_KWIM        != offsetof(struct thread_info, kwim) ||
+           TI_REG_WINDOW  != offsetof(struct thread_info, reg_window) ||
+           TI_RWIN_SPTRS  != offsetof(struct thread_info, rwbuf_stkptrs) ||
+           TI_W_SAVED     != offsetof(struct thread_info, w_saved))
+               thread_info_offsets_are_bolixed_pete();
+
+       /* Attach to the address space of init_task. */
+       atomic_inc(&init_mm.mm_count);
+       current->active_mm = &init_mm;
+
+       /* NOTE: Other cpus have this done as they are started
+        *       up on SMP.
+        */
+}
diff --git a/arch/sparc/kernel/una_asm.S b/arch/sparc/kernel/una_asm.S
deleted file mode 100644 (file)
index 8cc0345..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-/* una_asm.S: Kernel unaligned trap assembler helpers.
- *
- * Copyright (C) 1996,2005,2008 David S. Miller (davem@davemloft.net)
- * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- */
-
-#include <linux/errno.h>
-
-       .text
-
-retl_efault:
-       retl
-        mov    -EFAULT, %o0
-
-       /* int __do_int_store(unsigned long *dst_addr, int size,
-        *                    unsigned long *src_val)
-        *
-        * %o0 = dest_addr
-        * %o1 = size
-        * %o2 = src_val
-        *
-        * Return '0' on success, -EFAULT on failure.
-        */
-       .globl  __do_int_store
-__do_int_store:
-       ld      [%o2], %g1
-       cmp     %1, 2
-       be      2f
-        cmp    %1, 4
-       be      1f
-        srl    %g1, 24, %g2
-       srl     %g1, 16, %g7
-4:     stb     %g2, [%o0]
-       srl     %g1, 8, %g2
-5:     stb     %g7, [%o0 + 1]
-       ld      [%o2 + 4], %g7
-6:     stb     %g2, [%o0 + 2]
-       srl     %g7, 24, %g2
-7:     stb     %g1, [%o0 + 3]
-       srl     %g7, 16, %g1
-8:     stb     %g2, [%o0 + 4]
-       srl     %g7, 8, %g2
-9:     stb     %g1, [%o0 + 5]
-10:    stb     %g2, [%o0 + 6]
-       b       0f
-11:     stb    %g7, [%o0 + 7]
-1:     srl     %g1, 16, %g7
-12:    stb     %g2, [%o0]
-       srl     %g1, 8, %g2
-13:    stb     %g7, [%o0 + 1]
-14:    stb     %g2, [%o0 + 2]
-       b       0f
-15:     stb    %g1, [%o0 + 3]
-2:     srl     %g1, 8, %g2
-16:    stb     %g2, [%o0]
-17:    stb     %g1, [%o0 + 1]
-0:     retl
-        mov    0, %o0
-
-       .section __ex_table,#alloc
-       .word   4b, retl_efault
-       .word   5b, retl_efault
-       .word   6b, retl_efault
-       .word   7b, retl_efault
-       .word   8b, retl_efault
-       .word   9b, retl_efault
-       .word   10b, retl_efault
-       .word   11b, retl_efault
-       .word   12b, retl_efault
-       .word   13b, retl_efault
-       .word   14b, retl_efault
-       .word   15b, retl_efault
-       .word   16b, retl_efault
-       .word   17b, retl_efault
-       .previous
-
-       /* int do_int_load(unsigned long *dest_reg, int size,
-        *                 unsigned long *saddr, int is_signed)
-        *
-        * %o0 = dest_reg
-        * %o1 = size
-        * %o2 = saddr
-        * %o3 = is_signed
-        *
-        * Return '0' on success, -EFAULT on failure.
-        */
-       .globl  do_int_load
-do_int_load:
-       cmp     %o1, 8
-       be      9f
-        cmp    %o1, 4
-       be      6f
-4:      ldub   [%o2], %g1
-5:     ldub    [%o2 + 1], %g2
-       sll     %g1, 8, %g1
-       tst     %o3
-       be      3f
-        or     %g1, %g2, %g1
-       sll     %g1, 16, %g1
-       sra     %g1, 16, %g1
-3:     b       0f
-        st     %g1, [%o0]
-6:     ldub    [%o2 + 1], %g2
-       sll     %g1, 24, %g1
-7:     ldub    [%o2 + 2], %g7
-       sll     %g2, 16, %g2
-8:     ldub    [%o2 + 3], %g3
-       sll     %g7, 8, %g7
-       or      %g3, %g2, %g3
-       or      %g7, %g3, %g7
-       or      %g1, %g7, %g1
-       b       0f
-        st     %g1, [%o0]
-9:     ldub    [%o2], %g1
-10:    ldub    [%o2 + 1], %g2
-       sll     %g1, 24, %g1
-11:    ldub    [%o2 + 2], %g7
-       sll     %g2, 16, %g2
-12:    ldub    [%o2 + 3], %g3
-       sll     %g7, 8, %g7
-       or      %g1, %g2, %g1
-       or      %g7, %g3, %g7
-       or      %g1, %g7, %g7
-13:    ldub    [%o2 + 4], %g1
-       st      %g7, [%o0]
-14:    ldub    [%o2 + 5], %g2
-       sll     %g1, 24, %g1
-15:    ldub    [%o2 + 6], %g7
-       sll     %g2, 16, %g2
-16:    ldub    [%o2 + 7], %g3
-       sll     %g7, 8, %g7
-       or      %g1, %g2, %g1
-       or      %g7, %g3, %g7
-       or      %g1, %g7, %g7
-       st      %g7, [%o0 + 4]
-0:     retl
-        mov    0, %o0
-
-       .section __ex_table,#alloc
-       .word   4b, retl_efault
-       .word   5b, retl_efault
-       .word   6b, retl_efault
-       .word   7b, retl_efault
-       .word   8b, retl_efault
-       .word   9b, retl_efault
-       .word   10b, retl_efault
-       .word   11b, retl_efault
-       .word   12b, retl_efault
-       .word   13b, retl_efault
-       .word   14b, retl_efault
-       .word   15b, retl_efault
-       .word   16b, retl_efault
-       .previous
diff --git a/arch/sparc/kernel/una_asm_32.S b/arch/sparc/kernel/una_asm_32.S
new file mode 100644 (file)
index 0000000..8cc0345
--- /dev/null
@@ -0,0 +1,153 @@
+/* una_asm.S: Kernel unaligned trap assembler helpers.
+ *
+ * Copyright (C) 1996,2005,2008 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/errno.h>
+
+       .text
+
+retl_efault:
+       retl
+        mov    -EFAULT, %o0
+
+       /* int __do_int_store(unsigned long *dst_addr, int size,
+        *                    unsigned long *src_val)
+        *
+        * %o0 = dest_addr
+        * %o1 = size
+        * %o2 = src_val
+        *
+        * Return '0' on success, -EFAULT on failure.
+        */
+       .globl  __do_int_store
+__do_int_store:
+       ld      [%o2], %g1
+       cmp     %1, 2
+       be      2f
+        cmp    %1, 4
+       be      1f
+        srl    %g1, 24, %g2
+       srl     %g1, 16, %g7
+4:     stb     %g2, [%o0]
+       srl     %g1, 8, %g2
+5:     stb     %g7, [%o0 + 1]
+       ld      [%o2 + 4], %g7
+6:     stb     %g2, [%o0 + 2]
+       srl     %g7, 24, %g2
+7:     stb     %g1, [%o0 + 3]
+       srl     %g7, 16, %g1
+8:     stb     %g2, [%o0 + 4]
+       srl     %g7, 8, %g2
+9:     stb     %g1, [%o0 + 5]
+10:    stb     %g2, [%o0 + 6]
+       b       0f
+11:     stb    %g7, [%o0 + 7]
+1:     srl     %g1, 16, %g7
+12:    stb     %g2, [%o0]
+       srl     %g1, 8, %g2
+13:    stb     %g7, [%o0 + 1]
+14:    stb     %g2, [%o0 + 2]
+       b       0f
+15:     stb    %g1, [%o0 + 3]
+2:     srl     %g1, 8, %g2
+16:    stb     %g2, [%o0]
+17:    stb     %g1, [%o0 + 1]
+0:     retl
+        mov    0, %o0
+
+       .section __ex_table,#alloc
+       .word   4b, retl_efault
+       .word   5b, retl_efault
+       .word   6b, retl_efault
+       .word   7b, retl_efault
+       .word   8b, retl_efault
+       .word   9b, retl_efault
+       .word   10b, retl_efault
+       .word   11b, retl_efault
+       .word   12b, retl_efault
+       .word   13b, retl_efault
+       .word   14b, retl_efault
+       .word   15b, retl_efault
+       .word   16b, retl_efault
+       .word   17b, retl_efault
+       .previous
+
+       /* int do_int_load(unsigned long *dest_reg, int size,
+        *                 unsigned long *saddr, int is_signed)
+        *
+        * %o0 = dest_reg
+        * %o1 = size
+        * %o2 = saddr
+        * %o3 = is_signed
+        *
+        * Return '0' on success, -EFAULT on failure.
+        */
+       .globl  do_int_load
+do_int_load:
+       cmp     %o1, 8
+       be      9f
+        cmp    %o1, 4
+       be      6f
+4:      ldub   [%o2], %g1
+5:     ldub    [%o2 + 1], %g2
+       sll     %g1, 8, %g1
+       tst     %o3
+       be      3f
+        or     %g1, %g2, %g1
+       sll     %g1, 16, %g1
+       sra     %g1, 16, %g1
+3:     b       0f
+        st     %g1, [%o0]
+6:     ldub    [%o2 + 1], %g2
+       sll     %g1, 24, %g1
+7:     ldub    [%o2 + 2], %g7
+       sll     %g2, 16, %g2
+8:     ldub    [%o2 + 3], %g3
+       sll     %g7, 8, %g7
+       or      %g3, %g2, %g3
+       or      %g7, %g3, %g7
+       or      %g1, %g7, %g1
+       b       0f
+        st     %g1, [%o0]
+9:     ldub    [%o2], %g1
+10:    ldub    [%o2 + 1], %g2
+       sll     %g1, 24, %g1
+11:    ldub    [%o2 + 2], %g7
+       sll     %g2, 16, %g2
+12:    ldub    [%o2 + 3], %g3
+       sll     %g7, 8, %g7
+       or      %g1, %g2, %g1
+       or      %g7, %g3, %g7
+       or      %g1, %g7, %g7
+13:    ldub    [%o2 + 4], %g1
+       st      %g7, [%o0]
+14:    ldub    [%o2 + 5], %g2
+       sll     %g1, 24, %g1
+15:    ldub    [%o2 + 6], %g7
+       sll     %g2, 16, %g2
+16:    ldub    [%o2 + 7], %g3
+       sll     %g7, 8, %g7
+       or      %g1, %g2, %g1
+       or      %g7, %g3, %g7
+       or      %g1, %g7, %g7
+       st      %g7, [%o0 + 4]
+0:     retl
+        mov    0, %o0
+
+       .section __ex_table,#alloc
+       .word   4b, retl_efault
+       .word   5b, retl_efault
+       .word   6b, retl_efault
+       .word   7b, retl_efault
+       .word   8b, retl_efault
+       .word   9b, retl_efault
+       .word   10b, retl_efault
+       .word   11b, retl_efault
+       .word   12b, retl_efault
+       .word   13b, retl_efault
+       .word   14b, retl_efault
+       .word   15b, retl_efault
+       .word   16b, retl_efault
+       .previous
diff --git a/arch/sparc/kernel/unaligned.c b/arch/sparc/kernel/unaligned.c
deleted file mode 100644 (file)
index c2a28c5..0000000
+++ /dev/null
@@ -1,390 +0,0 @@
-/*
- * unaligned.c: Unaligned load/store trap handling with special
- *              cases for the kernel to do them more quickly.
- *
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- */
-
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <asm/ptrace.h>
-#include <asm/processor.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-
-/* #define DEBUG_MNA */
-
-enum direction {
-       load,    /* ld, ldd, ldh, ldsh */
-       store,   /* st, std, sth, stsh */
-       both,    /* Swap, ldstub, etc. */
-       fpload,
-       fpstore,
-       invalid,
-};
-
-#ifdef DEBUG_MNA
-static char *dirstrings[] = {
-  "load", "store", "both", "fpload", "fpstore", "invalid"
-};
-#endif
-
-static inline enum direction decode_direction(unsigned int insn)
-{
-       unsigned long tmp = (insn >> 21) & 1;
-
-       if(!tmp)
-               return load;
-       else {
-               if(((insn>>19)&0x3f) == 15)
-                       return both;
-               else
-                       return store;
-       }
-}
-
-/* 8 = double-word, 4 = word, 2 = half-word */
-static inline int decode_access_size(unsigned int insn)
-{
-       insn = (insn >> 19) & 3;
-
-       if(!insn)
-               return 4;
-       else if(insn == 3)
-               return 8;
-       else if(insn == 2)
-               return 2;
-       else {
-               printk("Impossible unaligned trap. insn=%08x\n", insn);
-               die_if_kernel("Byte sized unaligned access?!?!", current->thread.kregs);
-               return 4; /* just to keep gcc happy. */
-       }
-}
-
-/* 0x400000 = signed, 0 = unsigned */
-static inline int decode_signedness(unsigned int insn)
-{
-       return (insn & 0x400000);
-}
-
-static inline void maybe_flush_windows(unsigned int rs1, unsigned int rs2,
-                                      unsigned int rd)
-{
-       if(rs2 >= 16 || rs1 >= 16 || rd >= 16) {
-               /* Wheee... */
-               __asm__ __volatile__("save %sp, -0x40, %sp\n\t"
-                                    "save %sp, -0x40, %sp\n\t"
-                                    "save %sp, -0x40, %sp\n\t"
-                                    "save %sp, -0x40, %sp\n\t"
-                                    "save %sp, -0x40, %sp\n\t"
-                                    "save %sp, -0x40, %sp\n\t"
-                                    "save %sp, -0x40, %sp\n\t"
-                                    "restore; restore; restore; restore;\n\t"
-                                    "restore; restore; restore;\n\t");
-       }
-}
-
-static inline int sign_extend_imm13(int imm)
-{
-       return imm << 19 >> 19;
-}
-
-static inline unsigned long fetch_reg(unsigned int reg, struct pt_regs *regs)
-{
-       struct reg_window *win;
-
-       if(reg < 16)
-               return (!reg ? 0 : regs->u_regs[reg]);
-
-       /* Ho hum, the slightly complicated case. */
-       win = (struct reg_window *) regs->u_regs[UREG_FP];
-       return win->locals[reg - 16]; /* yes, I know what this does... */
-}
-
-static inline unsigned long safe_fetch_reg(unsigned int reg, struct pt_regs *regs)
-{
-       struct reg_window __user *win;
-       unsigned long ret;
-
-       if (reg < 16)
-               return (!reg ? 0 : regs->u_regs[reg]);
-
-       /* Ho hum, the slightly complicated case. */
-       win = (struct reg_window __user *) regs->u_regs[UREG_FP];
-
-       if ((unsigned long)win & 3)
-               return -1;
-
-       if (get_user(ret, &win->locals[reg - 16]))
-               return -1;
-
-       return ret;
-}
-
-static inline unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *regs)
-{
-       struct reg_window *win;
-
-       if(reg < 16)
-               return &regs->u_regs[reg];
-       win = (struct reg_window *) regs->u_regs[UREG_FP];
-       return &win->locals[reg - 16];
-}
-
-static unsigned long compute_effective_address(struct pt_regs *regs,
-                                              unsigned int insn)
-{
-       unsigned int rs1 = (insn >> 14) & 0x1f;
-       unsigned int rs2 = insn & 0x1f;
-       unsigned int rd = (insn >> 25) & 0x1f;
-
-       if(insn & 0x2000) {
-               maybe_flush_windows(rs1, 0, rd);
-               return (fetch_reg(rs1, regs) + sign_extend_imm13(insn));
-       } else {
-               maybe_flush_windows(rs1, rs2, rd);
-               return (fetch_reg(rs1, regs) + fetch_reg(rs2, regs));
-       }
-}
-
-unsigned long safe_compute_effective_address(struct pt_regs *regs,
-                                            unsigned int insn)
-{
-       unsigned int rs1 = (insn >> 14) & 0x1f;
-       unsigned int rs2 = insn & 0x1f;
-       unsigned int rd = (insn >> 25) & 0x1f;
-
-       if(insn & 0x2000) {
-               maybe_flush_windows(rs1, 0, rd);
-               return (safe_fetch_reg(rs1, regs) + sign_extend_imm13(insn));
-       } else {
-               maybe_flush_windows(rs1, rs2, rd);
-               return (safe_fetch_reg(rs1, regs) + safe_fetch_reg(rs2, regs));
-       }
-}
-
-/* This is just to make gcc think panic does return... */
-static void unaligned_panic(char *str)
-{
-       panic(str);
-}
-
-/* una_asm.S */
-extern int do_int_load(unsigned long *dest_reg, int size,
-                      unsigned long *saddr, int is_signed);
-extern int __do_int_store(unsigned long *dst_addr, int size,
-                         unsigned long *src_val);
-
-static int do_int_store(int reg_num, int size, unsigned long *dst_addr,
-                       struct pt_regs *regs)
-{
-       unsigned long zero[2] = { 0, 0 };
-       unsigned long *src_val;
-
-       if (reg_num)
-               src_val = fetch_reg_addr(reg_num, regs);
-       else {
-               src_val = &zero[0];
-               if (size == 8)
-                       zero[1] = fetch_reg(1, regs);
-       }
-       return __do_int_store(dst_addr, size, src_val);
-}
-
-extern void smp_capture(void);
-extern void smp_release(void);
-
-static inline void advance(struct pt_regs *regs)
-{
-       regs->pc   = regs->npc;
-       regs->npc += 4;
-}
-
-static inline int floating_point_load_or_store_p(unsigned int insn)
-{
-       return (insn >> 24) & 1;
-}
-
-static inline int ok_for_kernel(unsigned int insn)
-{
-       return !floating_point_load_or_store_p(insn);
-}
-
-static void kernel_mna_trap_fault(struct pt_regs *regs, unsigned int insn)
-{
-       unsigned long g2 = regs->u_regs [UREG_G2];
-       unsigned long fixup = search_extables_range(regs->pc, &g2);
-
-       if (!fixup) {
-               unsigned long address = compute_effective_address(regs, insn);
-               if(address < PAGE_SIZE) {
-                       printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference in mna handler");
-               } else
-                       printk(KERN_ALERT "Unable to handle kernel paging request in mna handler");
-               printk(KERN_ALERT " at virtual address %08lx\n",address);
-               printk(KERN_ALERT "current->{mm,active_mm}->context = %08lx\n",
-                       (current->mm ? current->mm->context :
-                       current->active_mm->context));
-               printk(KERN_ALERT "current->{mm,active_mm}->pgd = %08lx\n",
-                       (current->mm ? (unsigned long) current->mm->pgd :
-                       (unsigned long) current->active_mm->pgd));
-               die_if_kernel("Oops", regs);
-               /* Not reached */
-       }
-       regs->pc = fixup;
-       regs->npc = regs->pc + 4;
-       regs->u_regs [UREG_G2] = g2;
-}
-
-asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
-{
-       enum direction dir = decode_direction(insn);
-       int size = decode_access_size(insn);
-
-       if(!ok_for_kernel(insn) || dir == both) {
-               printk("Unsupported unaligned load/store trap for kernel at <%08lx>.\n",
-                      regs->pc);
-               unaligned_panic("Wheee. Kernel does fpu/atomic unaligned load/store.");
-       } else {
-               unsigned long addr = compute_effective_address(regs, insn);
-               int err;
-
-#ifdef DEBUG_MNA
-               printk("KMNA: pc=%08lx [dir=%s addr=%08lx size=%d] retpc[%08lx]\n",
-                      regs->pc, dirstrings[dir], addr, size, regs->u_regs[UREG_RETPC]);
-#endif
-               switch (dir) {
-               case load:
-                       err = do_int_load(fetch_reg_addr(((insn>>25)&0x1f),
-                                                        regs),
-                                         size, (unsigned long *) addr,
-                                         decode_signedness(insn));
-                       break;
-
-               case store:
-                       err = do_int_store(((insn>>25)&0x1f), size,
-                                          (unsigned long *) addr, regs);
-                       break;
-               default:
-                       panic("Impossible kernel unaligned trap.");
-                       /* Not reached... */
-               }
-               if (err)
-                       kernel_mna_trap_fault(regs, insn);
-               else
-                       advance(regs);
-       }
-}
-
-static inline int ok_for_user(struct pt_regs *regs, unsigned int insn,
-                             enum direction dir)
-{
-       unsigned int reg;
-       int check = (dir == load) ? VERIFY_READ : VERIFY_WRITE;
-       int size = ((insn >> 19) & 3) == 3 ? 8 : 4;
-
-       if ((regs->pc | regs->npc) & 3)
-               return 0;
-
-       /* Must access_ok() in all the necessary places. */
-#define WINREG_ADDR(regnum) \
-       ((void __user *)(((unsigned long *)regs->u_regs[UREG_FP])+(regnum)))
-
-       reg = (insn >> 25) & 0x1f;
-       if (reg >= 16) {
-               if (!access_ok(check, WINREG_ADDR(reg - 16), size))
-                       return -EFAULT;
-       }
-       reg = (insn >> 14) & 0x1f;
-       if (reg >= 16) {
-               if (!access_ok(check, WINREG_ADDR(reg - 16), size))
-                       return -EFAULT;
-       }
-       if (!(insn & 0x2000)) {
-               reg = (insn & 0x1f);
-               if (reg >= 16) {
-                       if (!access_ok(check, WINREG_ADDR(reg - 16), size))
-                               return -EFAULT;
-               }
-       }
-#undef WINREG_ADDR
-       return 0;
-}
-
-static void user_mna_trap_fault(struct pt_regs *regs, unsigned int insn)
-{
-       siginfo_t info;
-
-       info.si_signo = SIGBUS;
-       info.si_errno = 0;
-       info.si_code = BUS_ADRALN;
-       info.si_addr = (void __user *)safe_compute_effective_address(regs, insn);
-       info.si_trapno = 0;
-       send_sig_info(SIGBUS, &info, current);
-}
-
-asmlinkage void user_unaligned_trap(struct pt_regs *regs, unsigned int insn)
-{
-       enum direction dir;
-
-       lock_kernel();
-       if(!(current->thread.flags & SPARC_FLAG_UNALIGNED) ||
-          (((insn >> 30) & 3) != 3))
-               goto kill_user;
-       dir = decode_direction(insn);
-       if(!ok_for_user(regs, insn, dir)) {
-               goto kill_user;
-       } else {
-               int err, size = decode_access_size(insn);
-               unsigned long addr;
-
-               if(floating_point_load_or_store_p(insn)) {
-                       printk("User FPU load/store unaligned unsupported.\n");
-                       goto kill_user;
-               }
-
-               addr = compute_effective_address(regs, insn);
-               switch(dir) {
-               case load:
-                       err = do_int_load(fetch_reg_addr(((insn>>25)&0x1f),
-                                                        regs),
-                                         size, (unsigned long *) addr,
-                                         decode_signedness(insn));
-                       break;
-
-               case store:
-                       err = do_int_store(((insn>>25)&0x1f), size,
-                                          (unsigned long *) addr, regs);
-                       break;
-
-               case both:
-                       /*
-                        * This was supported in 2.4. However, we question
-                        * the value of SWAP instruction across word boundaries.
-                        */
-                       printk("Unaligned SWAP unsupported.\n");
-                       err = -EFAULT;
-                       break;
-
-               default:
-                       unaligned_panic("Impossible user unaligned trap.");
-                       goto out;
-               }
-               if (err)
-                       goto kill_user;
-               else
-                       advance(regs);
-               goto out;
-       }
-
-kill_user:
-       user_mna_trap_fault(regs, insn);
-out:
-       unlock_kernel();
-}
diff --git a/arch/sparc/kernel/unaligned_32.c b/arch/sparc/kernel/unaligned_32.c
new file mode 100644 (file)
index 0000000..c2a28c5
--- /dev/null
@@ -0,0 +1,390 @@
+/*
+ * unaligned.c: Unaligned load/store trap handling with special
+ *              cases for the kernel to do them more quickly.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+
+/* #define DEBUG_MNA */
+
+enum direction {
+       load,    /* ld, ldd, ldh, ldsh */
+       store,   /* st, std, sth, stsh */
+       both,    /* Swap, ldstub, etc. */
+       fpload,
+       fpstore,
+       invalid,
+};
+
+#ifdef DEBUG_MNA
+static char *dirstrings[] = {
+  "load", "store", "both", "fpload", "fpstore", "invalid"
+};
+#endif
+
+static inline enum direction decode_direction(unsigned int insn)
+{
+       unsigned long tmp = (insn >> 21) & 1;
+
+       if(!tmp)
+               return load;
+       else {
+               if(((insn>>19)&0x3f) == 15)
+                       return both;
+               else
+                       return store;
+       }
+}
+
+/* 8 = double-word, 4 = word, 2 = half-word */
+static inline int decode_access_size(unsigned int insn)
+{
+       insn = (insn >> 19) & 3;
+
+       if(!insn)
+               return 4;
+       else if(insn == 3)
+               return 8;
+       else if(insn == 2)
+               return 2;
+       else {
+               printk("Impossible unaligned trap. insn=%08x\n", insn);
+               die_if_kernel("Byte sized unaligned access?!?!", current->thread.kregs);
+               return 4; /* just to keep gcc happy. */
+       }
+}
+
+/* 0x400000 = signed, 0 = unsigned */
+static inline int decode_signedness(unsigned int insn)
+{
+       return (insn & 0x400000);
+}
+
+static inline void maybe_flush_windows(unsigned int rs1, unsigned int rs2,
+                                      unsigned int rd)
+{
+       if(rs2 >= 16 || rs1 >= 16 || rd >= 16) {
+               /* Wheee... */
+               __asm__ __volatile__("save %sp, -0x40, %sp\n\t"
+                                    "save %sp, -0x40, %sp\n\t"
+                                    "save %sp, -0x40, %sp\n\t"
+                                    "save %sp, -0x40, %sp\n\t"
+                                    "save %sp, -0x40, %sp\n\t"
+                                    "save %sp, -0x40, %sp\n\t"
+                                    "save %sp, -0x40, %sp\n\t"
+                                    "restore; restore; restore; restore;\n\t"
+                                    "restore; restore; restore;\n\t");
+       }
+}
+
+static inline int sign_extend_imm13(int imm)
+{
+       return imm << 19 >> 19;
+}
+
+static inline unsigned long fetch_reg(unsigned int reg, struct pt_regs *regs)
+{
+       struct reg_window *win;
+
+       if(reg < 16)
+               return (!reg ? 0 : regs->u_regs[reg]);
+
+       /* Ho hum, the slightly complicated case. */
+       win = (struct reg_window *) regs->u_regs[UREG_FP];
+       return win->locals[reg - 16]; /* yes, I know what this does... */
+}
+
+static inline unsigned long safe_fetch_reg(unsigned int reg, struct pt_regs *regs)
+{
+       struct reg_window __user *win;
+       unsigned long ret;
+
+       if (reg < 16)
+               return (!reg ? 0 : regs->u_regs[reg]);
+
+       /* Ho hum, the slightly complicated case. */
+       win = (struct reg_window __user *) regs->u_regs[UREG_FP];
+
+       if ((unsigned long)win & 3)
+               return -1;
+
+       if (get_user(ret, &win->locals[reg - 16]))
+               return -1;
+
+       return ret;
+}
+
+static inline unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *regs)
+{
+       struct reg_window *win;
+
+       if(reg < 16)
+               return &regs->u_regs[reg];
+       win = (struct reg_window *) regs->u_regs[UREG_FP];
+       return &win->locals[reg - 16];
+}
+
+static unsigned long compute_effective_address(struct pt_regs *regs,
+                                              unsigned int insn)
+{
+       unsigned int rs1 = (insn >> 14) & 0x1f;
+       unsigned int rs2 = insn & 0x1f;
+       unsigned int rd = (insn >> 25) & 0x1f;
+
+       if(insn & 0x2000) {
+               maybe_flush_windows(rs1, 0, rd);
+               return (fetch_reg(rs1, regs) + sign_extend_imm13(insn));
+       } else {
+               maybe_flush_windows(rs1, rs2, rd);
+               return (fetch_reg(rs1, regs) + fetch_reg(rs2, regs));
+       }
+}
+
+unsigned long safe_compute_effective_address(struct pt_regs *regs,
+                                            unsigned int insn)
+{
+       unsigned int rs1 = (insn >> 14) & 0x1f;
+       unsigned int rs2 = insn & 0x1f;
+       unsigned int rd = (insn >> 25) & 0x1f;
+
+       if(insn & 0x2000) {
+               maybe_flush_windows(rs1, 0, rd);
+               return (safe_fetch_reg(rs1, regs) + sign_extend_imm13(insn));
+       } else {
+               maybe_flush_windows(rs1, rs2, rd);
+               return (safe_fetch_reg(rs1, regs) + safe_fetch_reg(rs2, regs));
+       }
+}
+
+/* This is just to make gcc think panic does return... */
+static void unaligned_panic(char *str)
+{
+       panic(str);
+}
+
+/* una_asm.S */
+extern int do_int_load(unsigned long *dest_reg, int size,
+                      unsigned long *saddr, int is_signed);
+extern int __do_int_store(unsigned long *dst_addr, int size,
+                         unsigned long *src_val);
+
+static int do_int_store(int reg_num, int size, unsigned long *dst_addr,
+                       struct pt_regs *regs)
+{
+       unsigned long zero[2] = { 0, 0 };
+       unsigned long *src_val;
+
+       if (reg_num)
+               src_val = fetch_reg_addr(reg_num, regs);
+       else {
+               src_val = &zero[0];
+               if (size == 8)
+                       zero[1] = fetch_reg(1, regs);
+       }
+       return __do_int_store(dst_addr, size, src_val);
+}
+
+extern void smp_capture(void);
+extern void smp_release(void);
+
+static inline void advance(struct pt_regs *regs)
+{
+       regs->pc   = regs->npc;
+       regs->npc += 4;
+}
+
+static inline int floating_point_load_or_store_p(unsigned int insn)
+{
+       return (insn >> 24) & 1;
+}
+
+static inline int ok_for_kernel(unsigned int insn)
+{
+       return !floating_point_load_or_store_p(insn);
+}
+
+static void kernel_mna_trap_fault(struct pt_regs *regs, unsigned int insn)
+{
+       unsigned long g2 = regs->u_regs [UREG_G2];
+       unsigned long fixup = search_extables_range(regs->pc, &g2);
+
+       if (!fixup) {
+               unsigned long address = compute_effective_address(regs, insn);
+               if(address < PAGE_SIZE) {
+                       printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference in mna handler");
+               } else
+                       printk(KERN_ALERT "Unable to handle kernel paging request in mna handler");
+               printk(KERN_ALERT " at virtual address %08lx\n",address);
+               printk(KERN_ALERT "current->{mm,active_mm}->context = %08lx\n",
+                       (current->mm ? current->mm->context :
+                       current->active_mm->context));
+               printk(KERN_ALERT "current->{mm,active_mm}->pgd = %08lx\n",
+                       (current->mm ? (unsigned long) current->mm->pgd :
+                       (unsigned long) current->active_mm->pgd));
+               die_if_kernel("Oops", regs);
+               /* Not reached */
+       }
+       regs->pc = fixup;
+       regs->npc = regs->pc + 4;
+       regs->u_regs [UREG_G2] = g2;
+}
+
+asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
+{
+       enum direction dir = decode_direction(insn);
+       int size = decode_access_size(insn);
+
+       if(!ok_for_kernel(insn) || dir == both) {
+               printk("Unsupported unaligned load/store trap for kernel at <%08lx>.\n",
+                      regs->pc);
+               unaligned_panic("Wheee. Kernel does fpu/atomic unaligned load/store.");
+       } else {
+               unsigned long addr = compute_effective_address(regs, insn);
+               int err;
+
+#ifdef DEBUG_MNA
+               printk("KMNA: pc=%08lx [dir=%s addr=%08lx size=%d] retpc[%08lx]\n",
+                      regs->pc, dirstrings[dir], addr, size, regs->u_regs[UREG_RETPC]);
+#endif
+               switch (dir) {
+               case load:
+                       err = do_int_load(fetch_reg_addr(((insn>>25)&0x1f),
+                                                        regs),
+                                         size, (unsigned long *) addr,
+                                         decode_signedness(insn));
+                       break;
+
+               case store:
+                       err = do_int_store(((insn>>25)&0x1f), size,
+                                          (unsigned long *) addr, regs);
+                       break;
+               default:
+                       panic("Impossible kernel unaligned trap.");
+                       /* Not reached... */
+               }
+               if (err)
+                       kernel_mna_trap_fault(regs, insn);
+               else
+                       advance(regs);
+       }
+}
+
+static inline int ok_for_user(struct pt_regs *regs, unsigned int insn,
+                             enum direction dir)
+{
+       unsigned int reg;
+       int check = (dir == load) ? VERIFY_READ : VERIFY_WRITE;
+       int size = ((insn >> 19) & 3) == 3 ? 8 : 4;
+
+       if ((regs->pc | regs->npc) & 3)
+               return 0;
+
+       /* Must access_ok() in all the necessary places. */
+#define WINREG_ADDR(regnum) \
+       ((void __user *)(((unsigned long *)regs->u_regs[UREG_FP])+(regnum)))
+
+       reg = (insn >> 25) & 0x1f;
+       if (reg >= 16) {
+               if (!access_ok(check, WINREG_ADDR(reg - 16), size))
+                       return -EFAULT;
+       }
+       reg = (insn >> 14) & 0x1f;
+       if (reg >= 16) {
+               if (!access_ok(check, WINREG_ADDR(reg - 16), size))
+                       return -EFAULT;
+       }
+       if (!(insn & 0x2000)) {
+               reg = (insn & 0x1f);
+               if (reg >= 16) {
+                       if (!access_ok(check, WINREG_ADDR(reg - 16), size))
+                               return -EFAULT;
+               }
+       }
+#undef WINREG_ADDR
+       return 0;
+}
+
+static void user_mna_trap_fault(struct pt_regs *regs, unsigned int insn)
+{
+       siginfo_t info;
+
+       info.si_signo = SIGBUS;
+       info.si_errno = 0;
+       info.si_code = BUS_ADRALN;
+       info.si_addr = (void __user *)safe_compute_effective_address(regs, insn);
+       info.si_trapno = 0;
+       send_sig_info(SIGBUS, &info, current);
+}
+
+asmlinkage void user_unaligned_trap(struct pt_regs *regs, unsigned int insn)
+{
+       enum direction dir;
+
+       lock_kernel();
+       if(!(current->thread.flags & SPARC_FLAG_UNALIGNED) ||
+          (((insn >> 30) & 3) != 3))
+               goto kill_user;
+       dir = decode_direction(insn);
+       if(!ok_for_user(regs, insn, dir)) {
+               goto kill_user;
+       } else {
+               int err, size = decode_access_size(insn);
+               unsigned long addr;
+
+               if(floating_point_load_or_store_p(insn)) {
+                       printk("User FPU load/store unaligned unsupported.\n");
+                       goto kill_user;
+               }
+
+               addr = compute_effective_address(regs, insn);
+               switch(dir) {
+               case load:
+                       err = do_int_load(fetch_reg_addr(((insn>>25)&0x1f),
+                                                        regs),
+                                         size, (unsigned long *) addr,
+                                         decode_signedness(insn));
+                       break;
+
+               case store:
+                       err = do_int_store(((insn>>25)&0x1f), size,
+                                          (unsigned long *) addr, regs);
+                       break;
+
+               case both:
+                       /*
+                        * This was supported in 2.4. However, we question
+                        * the value of SWAP instruction across word boundaries.
+                        */
+                       printk("Unaligned SWAP unsupported.\n");
+                       err = -EFAULT;
+                       break;
+
+               default:
+                       unaligned_panic("Impossible user unaligned trap.");
+                       goto out;
+               }
+               if (err)
+                       goto kill_user;
+               else
+                       advance(regs);
+               goto out;
+       }
+
+kill_user:
+       user_mna_trap_fault(regs, insn);
+out:
+       unlock_kernel();
+}