summaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc64/kernel')
-rw-r--r--arch/sparc64/kernel/Makefile55
-rw-r--r--arch/sparc64/kernel/auxio.c42
-rw-r--r--arch/sparc64/kernel/check_asm.sh3
-rw-r--r--arch/sparc64/kernel/cpu.c90
-rw-r--r--arch/sparc64/kernel/devices.c67
-rw-r--r--arch/sparc64/kernel/dtlb_miss.S80
-rw-r--r--arch/sparc64/kernel/dtlb_prot.S56
-rw-r--r--arch/sparc64/kernel/entry.S280
-rw-r--r--arch/sparc64/kernel/etrap.S114
-rw-r--r--arch/sparc64/kernel/hack.S214
-rw-r--r--arch/sparc64/kernel/head.S373
-rw-r--r--arch/sparc64/kernel/idprom.c49
-rw-r--r--arch/sparc64/kernel/ioport.c139
-rw-r--r--arch/sparc64/kernel/irq.c638
-rw-r--r--arch/sparc64/kernel/itlb_miss.S49
-rw-r--r--arch/sparc64/kernel/process.c594
-rw-r--r--arch/sparc64/kernel/rtrap.S109
-rw-r--r--arch/sparc64/kernel/setup.c435
-rw-r--r--arch/sparc64/kernel/signal32.c806
-rw-r--r--arch/sparc64/kernel/sparc64_ksyms.c178
-rw-r--r--arch/sparc64/kernel/sparcelf32.c1281
-rw-r--r--arch/sparc64/kernel/sys_sparc.c270
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c1741
-rw-r--r--arch/sparc64/kernel/systbls.S222
-rw-r--r--arch/sparc64/kernel/time.c352
-rw-r--r--arch/sparc64/kernel/traps.c185
-rw-r--r--arch/sparc64/kernel/ttable.S252
27 files changed, 8674 insertions, 0 deletions
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
new file mode 100644
index 000000000..d66fa06e7
--- /dev/null
+++ b/arch/sparc64/kernel/Makefile
@@ -0,0 +1,55 @@
+# $Id: Makefile,v 1.16 1997/04/17 20:35:37 jj Exp $
+# Makefile for the linux kernel.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+.S.s:
+ $(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s
+
+.S.o:
+ $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
+
+all: kernel.o head.o
+
+O_TARGET := kernel.o
+O_OBJS := etrap.o rtrap.o hack.o process.o setup.o cpu.o idprom.o \
+ systbls.o traps.o entry.o devices.o auxio.o ioport.o \
+ irq.o time.o sys_sparc.o
+OX_OBJS := sparc64_ksyms.o
+
+ifdef CONFIG_SPARC32_COMPAT
+ O_OBJS += sys_sparc32.o signal32.o
+endif
+
+ifdef CONFIG_BINFMT_ELF32
+ O_OBJS += sparcelf32.o
+endif
+
+head.o: head.S ttable.S itlb_miss.S dtlb_miss.S dtlb_prot.S
+ $(CC) -D__ASSEMBLY__ -ansi -c $*.S -o $*.o
+
+check_asm: dummy
+ @echo "#include <linux/sched.h>" > tmp.c
+ $(CC) -E tmp.c -o tmp.i
+ @echo "/* Automatically generated. Do not edit. */" > check_asm.c; echo "#include <linux/sched.h>" >> check_asm.c; echo 'struct task_struct _task; struct mm_struct _mm; struct thread_struct _thread; int main(void) { printf ("/* Automatically generated. Do not edit. */\n#ifndef __ASM_OFFSETS_H__\n#define __ASM_OFFSETS_H__\n\n");' >> check_asm.c
+ $(SH) ./check_asm.sh task tmp.i check_asm.c
+ $(SH) ./check_asm.sh mm tmp.i check_asm.c
+ $(SH) ./check_asm.sh thread tmp.i check_asm.c
+ @echo 'printf ("\n#endif /* __ASM_OFFSETS_H__ */\n"); return 0; }' >> check_asm.c
+ @rm -f tmp.[ci]
+ #$(CC) -o check_asm check_asm.c
+ # <hack> Until we can do this natively, a hack has to take place
+ $(CC) -mmedlow -S -o check_asm.s check_asm.c
+ $(HOSTCC) -o check_asm check_asm.s
+ @rm -f check_asm.s
+ # </hack>
+ ./check_asm > asm_offsets.h
+ @if test -r $(HPATH)/asm/asm_offsets.h; then if cmp -s asm_offsets.h $(HPATH)/asm/asm_offsets.h; then echo $(HPATH)/asm/asm_offsets.h is unchanged; rm -f asm_offsets.h; else mv -f asm_offsets.h $(HPATH)/asm/asm_offsets.h; fi; else mv -f asm_offsets.h $(HPATH)/asm/asm_offsets.h; fi
+ @rm -f check_asm check_asm.c
+
+
+include $(TOPDIR)/Rules.make
diff --git a/arch/sparc64/kernel/auxio.c b/arch/sparc64/kernel/auxio.c
new file mode 100644
index 000000000..6c3ff9174
--- /dev/null
+++ b/arch/sparc64/kernel/auxio.c
@@ -0,0 +1,42 @@
+/* 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 <asm/oplib.h>
+#include <asm/io.h>
+#include <asm/auxio.h>
+#include <asm/sbus.h>
+
+/* Probe and map in the Auxiliary I/O register */
+unsigned char *auxio_register;
+
+__initfunc(void auxio_probe(void))
+{
+ struct linux_sbus *bus;
+ struct linux_sbus_device *sdev = 0;
+ struct linux_prom_registers auxregs[1];
+
+ for_each_sbus(bus) {
+ for_each_sbusdev(sdev, bus) {
+ if(!strcmp(sdev->prom_name, "auxio")) {
+ break;
+ }
+ }
+ }
+
+ if (!sdev) {
+ prom_printf("Cannot find auxio node, cannot continue...\n");
+ prom_halt();
+ }
+ prom_getproperty(sdev->prom_node, "reg", (char *) auxregs, sizeof(auxregs));
+ prom_apply_sbus_ranges(sdev->my_bus, auxregs, 0x1, sdev);
+ /* Map the register both read and write */
+ auxio_register = (unsigned char *) sparc_alloc_io(auxregs[0].phys_addr, 0,
+ auxregs[0].reg_size,
+ "auxiliaryIO",
+ auxregs[0].which_io, 0x0);
+ TURN_ON_LED;
+}
diff --git a/arch/sparc64/kernel/check_asm.sh b/arch/sparc64/kernel/check_asm.sh
new file mode 100644
index 000000000..2d2fbd224
--- /dev/null
+++ b/arch/sparc64/kernel/check_asm.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+sed -n -e '/struct[ ]*'$1'_struct[ ]*{/,/};/p' < $2 | sed '/struct[ ]*'$1'_struct[ ]*{/d;/:[0-9]*[ ]*;/d;/^[ ]*$/d;/};/d;s/^[ ]*//;s/volatile[ ]*//;s/\(unsigned\|signed\|struct\)[ ]*//;s/\(\[\|__attribute__\).*;[ ]*$//;s/;[ ]*$//;s/^[^ ]*[ ]*//;s/,/\
+/g' | sed 's/^[ *]*//;s/[ ]*$//;s/^.*$/printf ("#define AOFF_'$1'_\0 0x%08x\\n#define ASIZ_'$1'_\0 0x%08x\\n", ((char *)\&_'$1'.\0) - ((char *)\&_'$1'), sizeof(_'$1'.\0));/' >> $3
diff --git a/arch/sparc64/kernel/cpu.c b/arch/sparc64/kernel/cpu.c
new file mode 100644
index 000000000..695ad680e
--- /dev/null
+++ b/arch/sparc64/kernel/cpu.c
@@ -0,0 +1,90 @@
+/* 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 <asm/system.h>
+
+struct cpu_iu_info {
+ short manuf;
+ short impl;
+ char* cpu_name; /* should be enough I hope... */
+};
+
+struct cpu_fp_info {
+ short manuf;
+ short impl;
+ char fpu_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.
+ */
+struct cpu_fp_info linux_sparc_fpu[] = {
+ { 0x17, 0x10, 0, "UltraSparc I integrated FPU"},
+ { 0x17, 0x11, 0, "UltraSparc II integrated FPU"},
+ { 0x17, 0x12, 0, "UltraSparc III integrated FPU"},
+};
+
+#define NSPARCFPU (sizeof(linux_sparc_fpu)/sizeof(struct cpu_fp_info))
+
+struct cpu_iu_info linux_sparc_chips[] = {
+ { 0x17, 0x10, "TI UltraSparc I (SpitFire)"},
+ { 0x17, 0x11, "TI UltraSparc II (BlackBird)"},
+ { 0x17, 0x12, "TI UltraSparc III (Cheetah)"}, /* A guess... */
+};
+
+#define NSPARCCHIPS (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info))
+
+char *sparc_cpu_type[NCPUS] = { "cpu-oops", "cpu-oops1", "cpu-oops2", "cpu-oops3" };
+char *sparc_fpu_type[NCPUS] = { "fpu-oops", "fpu-oops1", "fpu-oops2", "fpu-oops3" };
+
+unsigned int fsr_storage;
+
+__initfunc(void cpu_probe(void))
+{
+ int manuf, impl;
+ unsigned i, cpuid;
+ long ver, fpu_vers;
+
+ cpuid = get_cpuid();
+
+ __asm__ __volatile__ ("rdpr %%ver, %0; stx %%fsr, [%1]" : "=r" (ver) : "r" (&fpu_vers));
+
+ manuf = ((ver >> 48)&0xffff);
+ impl = ((ver >> 32)&0xffff);
+
+ fpu_vers = ((fpu_vers>>17)&0x7);
+
+ for(i = 0; i<NSPARCCHIPS; i++) {
+ if(linux_sparc_chips[i].manuf == manuf)
+ if(linux_sparc_chips[i].impl == impl) {
+ sparc_cpu_type[cpuid] = linux_sparc_chips[i].cpu_name;
+ break;
+ }
+ }
+
+ if(i==NSPARCCHIPS) {
+ printk("DEBUG: manuf = 0x%x impl = 0x%x\n", manuf,
+ impl);
+ sparc_cpu_type[cpuid] = "Unknow CPU";
+ }
+
+ for(i = 0; i<NSPARCFPU; i++) {
+ if(linux_sparc_fpu[i].manuf == manuf && linux_sparc_fpu[i].impl == impl)
+ if(linux_sparc_fpu[i].fpu_vers == fpu_vers) {
+ sparc_fpu_type[cpuid] = linux_sparc_fpu[i].fp_name;
+ break;
+ }
+ }
+
+ if(i == NSPARCFPU) {
+ printk("DEBUG: manuf = 0x%x impl = 0x%x fsr.vers = 0x%x\n", manuf, impl,
+ (unsigned)fpu_vers);
+ sparc_fpu_type[cpuid] = "Unknown FPU";
+ }
+}
diff --git a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c
new file mode 100644
index 000000000..6aadd14e0
--- /dev/null
+++ b/arch/sparc64/kernel/devices.c
@@ -0,0 +1,67 @@
+/* devices.c: Initial scan of the prom device tree for important
+ * Sparc device nodes which we need to find.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/kernel.h>
+#include <linux/tasks.h>
+#include <linux/config.h>
+#include <linux/init.h>
+
+#include <asm/page.h>
+#include <asm/oplib.h>
+#include <asm/system.h>
+#include <asm/smp.h>
+
+struct prom_cpuinfo linux_cpus[NCPUS];
+int linux_num_cpus;
+
+extern void cpu_probe(void);
+
+__initfunc(unsigned long
+device_scan(unsigned long mem_start))
+{
+ char node_str[128];
+ int nd, prom_node_cpu, thismid;
+ int cpu_nds[NCPUS]; /* One node for each cpu */
+ int cpu_ctr = 0;
+
+ prom_getstring(prom_root_node, "device_type", node_str, sizeof(node_str));
+
+ if(strcmp(node_str, "cpu") == 0) {
+ cpu_nds[0] = prom_root_node;
+ linux_cpus[0].prom_node = prom_root_node;
+ linux_cpus[0].mid = 0;
+ cpu_ctr++;
+ } else {
+ int scan;
+ scan = prom_getchild(prom_root_node);
+ prom_printf("root child is %08x\n", (unsigned) scan);
+ nd = 0;
+ while((scan = prom_getsibling(scan)) != 0) {
+ prom_getstring(scan, "device_type", node_str, sizeof(node_str));
+ if(strcmp(node_str, "cpu") == 0) {
+ cpu_nds[cpu_ctr] = scan;
+ linux_cpus[cpu_ctr].prom_node = scan;
+ prom_getproperty(scan, "mid", (char *) &thismid, sizeof(thismid));
+ linux_cpus[cpu_ctr].mid = thismid;
+ prom_printf("Found CPU %d <node=%08x,mid=%d>\n",
+ cpu_ctr, (unsigned) scan,
+ thismid);
+ cpu_ctr++;
+ }
+ };
+ if(cpu_ctr == 0) {
+ printk("No CPU nodes found, cannot continue.\n");
+ halt();
+ }
+ printk("Found %d CPU prom device tree node(s).\n", cpu_ctr);
+ };
+ prom_node_cpu = cpu_nds[0];
+
+ linux_num_cpus = cpu_ctr;
+
+ cpu_probe();
+ return mem_start;
+}
diff --git a/arch/sparc64/kernel/dtlb_miss.S b/arch/sparc64/kernel/dtlb_miss.S
new file mode 100644
index 000000000..31b87f3de
--- /dev/null
+++ b/arch/sparc64/kernel/dtlb_miss.S
@@ -0,0 +1,80 @@
+/* $Id: dtlb_miss.S,v 1.11 1997/04/10 01:59:35 davem Exp $
+ * dtlb_miss.S: Data TLB miss code, this is included directly
+ * into the trap table.
+ *
+ * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+/* The basic algorithm is:
+ *
+ * if(faulting_context != 0) {
+ * pgd = pgd_offset(current->mm.pgd, fault_address);
+ * page_table_walk_continue:
+ * pmd = pmd_offset(pgd, fault_address);
+ * pte = pte_offset(pmd, fault_address);
+ * if(pte & _PAGE_V) {
+ * tlb_load(pte, fault_address);
+ * return_from_trap();
+ * }
+ * goto longer_processing;
+ * } else {
+ * if(fault_address >= KERNBASE &&
+ * fault_address < VMALLOC_START) {
+ * tlb_load(__pa(fault_address) | PAGE_KERNEL);
+ * return_from_trap();
+ * } else {
+ * pgd = pgd_offset(swapper_pg_dir, fault_address);
+ * goto page_table_walk_continue;
+ * }
+ * }
+ *
+ * This is optimized for user TLB misses on purpose.
+ */
+
+#define KERN_HIGHBITS (_PAGE_VALID | _PAGE_SZ4MB)
+#define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
+#define KERN_LOWBITS_IO (_PAGE_E | _PAGE_P | _PAGE_W)
+
+ /* ICACHE line 1 */
+ /*0x00*/ ldxa [%g0] ASI_DMMU, %g1 ! Get TAG_TARGET
+ /*0x04*/ srlx %g1, 8, %g3 ! Position PGD offset
+ /*0x08*/ srlx %g1, 48, %g5 ! Shift down CONTEXT bits
+ /*0x0c*/ and %g3, %g2, %g3 ! Mask PGD offset
+ /*0x10*/ sllx %g1, 2, %g4 ! Position PMD offset
+ /*0x14*/ brz,pn %g5, 3f ! Context 0 == kernel
+ /*0x18*/ and %g4, %g2, %g4 ! Mask PMD offset
+ /*0x1c*/ ldxa [%g0] ASI_DMMU_TSB_8KB_PTR, %g1 ! For PTE offset
+
+ /* ICACHE line 2 */
+ /*0x20*/ ldxa [%g7 + %g3] ASI_PHYS_USE_EC, %g5 ! Load PGD
+ /*0x24*/ srlx %g1, 1, %g1 ! PTE offset
+2:/*0x28*/ ldxa [%g5 + %g4] ASI_PHYS_USE_EC, %g3 ! Load PMD
+ /*0x2c*/ ldxa [%g3 + %g1] ASI_PHYS_USE_EC, %g5 ! Load PTE
+ /*0x30*/ brlz,a,pt %g5, 1f ! Valid set?
+ /*0x34*/ stxa %g5, [%g0] ASI_DTLB_DATA_IN ! TLB load
+ /*0x38*/ ba,a,pt %xcc, sparc64_dtlb_refbit_catch ! Nope...
+1:/*0x3c*/ retry ! Trap return
+
+3: /* ICACHE line 3 */
+ /*0x40*/ sllx %g1, 43, %g5 ! This gets >= VMALLOC_START...
+ /*0x44*/ brlz,pn %g5, 4f ! ...if now less than zero.
+ /*0x48*/ andncc %g1, 0x3ff, %g0 ! Slick trick...
+ /*0x4c*/ be,pn %xcc, 4f ! Yes, it is some PROM mapping
+ /*0x50*/ srlx %g5, 21, %g5 ! This is now physical page
+ /*0x54*/ sethi %uhi(KERN_HIGHBITS), %g1 ! Construct PTE
+ /*0x58*/ sllx %g1, 32, %g1 ! Move priv bits up
+ /*0x5c*/ or %g1, %g5, %g1 ! Or in the page
+
+ /* ICACHE line 4 */
+ /*0x60*/ or %g1, (KERN_LOWBITS), %g1 ! Set low priv bits
+ /*0x64*/ stxa %g1, [%g0] ASI_DTLB_DATA_IN ! TLB load
+ /*0x68*/ retry ! Trap return
+4:/*0x6c*/ ldxa [%g0] ASI_DMMU_TSB_8KB_PTR, %g1 ! For PTE offset
+ /*0x70*/ ldxa [%g6 + %g3] ASI_PHYS_USE_EC, %g5 ! Load kern PGD
+ /*0x74*/ ba,pt %xcc, 2b ! Go back up top
+ /*0x78*/ srlx %g1, 1, %g1
+ /*0x7c*/ nop
+
+#undef KERN_HIGHBITS
+#undef KERN_LOWBITS
diff --git a/arch/sparc64/kernel/dtlb_prot.S b/arch/sparc64/kernel/dtlb_prot.S
new file mode 100644
index 000000000..8eec19260
--- /dev/null
+++ b/arch/sparc64/kernel/dtlb_prot.S
@@ -0,0 +1,56 @@
+/* $Id: dtlb_prot.S,v 1.10 1997/03/25 09:47:13 davem Exp $
+ * dtlb_prot.S: Data TLB protection code, this is included directly
+ * into the trap table.
+ *
+ * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+ /* We know kernel never takes protection trap,
+ * this makes this routine a lot easier than it
+ * would be otherwise.
+ */
+
+#define MODIFIED_BITS (_PAGE_WRITE | _PAGE_W | _PAGE_MODIFIED | _PAGE_ACCESSED)
+
+ /* ICACHE line 1 */
+ /*0x00*/ ldxa [%g0] ASI_DMMU, %g1 ! Get TAG_TARGET
+ /*0x04*/ srlx %g1, 8, %g3 ! Position PGD offset
+ /*0x08*/ sllx %g1, 2, %g4 ! Position PMD offset
+ /*0x0c*/ and %g3, %g2, %g3 ! Mask PGD offset
+ /*0x10*/ and %g4, %g2, %g3 ! Mask PMD offset
+ /*0x14*/ ldxa [%g7 + %g3] ASI_PHYS_USE_EC, %g5 ! Load PGD
+ /*0x18*/ ldxa [%g5 + %g3] ASI_PHYS_USE_EC, %g4 ! Load PMD
+ /*0x1c*/ ldxa [%g0] ASI_DMMU_TSB_8KB_PTR, %g1 ! For PTE offset
+
+ /* ICACHE line 2 */
+ /*0x20*/ srlx %g1, 1, %g1 ! PTE offset
+ /*0x24*/ ldxa [%g4 + %g1] ASI_PHYS_USE_EC, %g3 ! Load PTE
+ /*0x28*/ andcc %g3, _PAGE_WRITE, %g0 ! Writable?
+ /*0x2c*/ be,pt %xcc, sparc64_dtlb_fault ! Nope...
+ /*0x30*/ or %g3, (MODIFIED_BITS), %g3 ! Yes it is
+ /*0x34*/ mov TLB_TAG_ACCESS, %g5 ! Get the page
+ /*0x38*/ ldxa [%g5] ASI_DMMU, %g1 ! From MMU
+ /*0x3c*/ add %g2, 7, %g5 ! Compute mask
+
+ /* ICACHE line 3 */
+ /*0x40*/ andn %g1, %g5, %g1 ! Mask page
+ /*0x44*/ or %g1, 0x10, %g1 ! 2ndary Context
+ /*0x48*/ stxa %g0, [%g1] ASI_DMMU_DEMAP ! TLB flush page
+ /*0x4c*/ membar #Sync ! Synchronize
+ /*0x50*/ stxa %g3, [%g4 + %g1] ASI_PHYS_USE_EC ! Update sw PTE
+ /*0x54*/ stxa %g3, [%g0] ASI_DTLB_DATA_IN ! TLB load
+ /*0x58*/ retry ! Trap return
+ /*0x5c*/ nop
+
+ /* ICACHE line 4 */
+ /*0x60*/ nop
+ /*0x64*/ nop
+ /*0x68*/ nop
+ /*0x6c*/ nop
+ /*0x70*/ nop
+ /*0x74*/ nop
+ /*0x78*/ nop
+ /*0x7c*/ nop
+
+#undef MODIFIED_BITS
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
new file mode 100644
index 000000000..16fe5c8a0
--- /dev/null
+++ b/arch/sparc64/kernel/entry.S
@@ -0,0 +1,280 @@
+/* $Id: entry.S,v 1.14 1997/04/14 06:56:54 davem Exp $
+ * arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+
+#include <asm/head.h>
+#include <asm/asi.h>
+#include <asm/smp.h>
+#include <asm/ptrace.h>
+#include <asm/page.h>
+#include <asm/signal.h>
+#include <asm/pgtable.h>
+
+#define curptr g6
+
+#define NR_SYSCALLS 256 /* Each OS is different... */
+
+ .text
+ .align 4
+/* FIXME: This is still debugging hack */
+ .globl sparc64_dtlb_fault, sparc64_dtlb_refbit_catch, sparc64_itlb_refbit_catch
+sparc64_dtlb_fault:
+ rdpr %pstate, %g1
+ wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate
+ ba,pt %xcc, etrap
+ rd %pc, %g7
+ call sparc64_dtlb_fault_handler
+ nop
+
+sparc64_dtlb_refbit_catch:
+ rdpr %pstate, %g1
+ wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate
+ ba,pt %xcc, etrap
+ rd %pc, %g7
+ call sparc64_dtlb_refbit_handler
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+
+sparc64_itlb_refbit_catch:
+ rdpr %pstate, %g1
+ wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate
+ ba,pt %xcc, etrap
+ rd %pc, %g7
+ call sparc64_dtlb_refbit_handler
+ nop
+
+ /* Note check out head.h, this code isn't even used for UP,
+ * for SMP things will be different. In particular the data
+ * registers for cross calls will be:
+ *
+ * DATA 0: Address of function to call
+ * DATA 1: Argument 1, place in %g6
+ * DATA 2: Argument 2, place in %g7
+ *
+ * With this method we can do most of the cross-call tlb/cache
+ * flushing in very quickly.
+ */
+ .align 4
+ .globl do_ivec
+do_ivec:
+ ldxa [%g0] ASI_INTR_RECEIVE, %g1
+ andcc %g1, 0x20, %g0
+ be,pn %xcc, do_ivec_return
+ mov 0x40, %g2
+
+ /* Load up Interrupt Vector Data 0 register. */
+ sethi %uhi(ivector_to_mask), %g4
+ ldxa [%g2] ASI_UDB_INTR_R, %g3
+ or %g4, %ulo(ivector_to_mask), %g4
+ and %g3, 0x7ff, %g3
+ sllx %g4, 32, %g4
+ sethi %hi(ivector_to_mask), %g5
+ sllx %g3, 3, %g3
+ or %g5, %lo(ivector_to_mask), %g5
+ add %g5, %g4, %g4
+ ldx [%g4 + %g3], %g2
+ brz,pn %g2, do_ivec_spurious
+ nop
+
+ /* No branches, worse case we don't know about this interrupt
+ * yet, so we would just write a zero into the softint register
+ * which is completely harmless.
+ */
+ wr %g2, 0x0, %set_softint
+
+do_ivec_return:
+ /* Acknowledge the UPA */
+ stxa %g0, [%g0] ASI_INTR_RECEIVE
+ membar #Sync
+ retry
+
+do_ivec_spurious:
+ stxa %g0, [%g0] ASI_INTR_RECEIVE
+ rdpr %pstate, %g1
+ wrpr %g1, PSTATE_IG | PSTATE_AG, %pstate
+ ba,pt %xcc, etrap
+ rd %pc, %g7
+ call report_spurious_ivec
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ ba,pt %xcc, rtrap
+ nop
+
+breakpoint_t:
+ .asciz "Breakpoint Trap %lx\n"
+ .align 4
+ .globl breakpoint_trap
+breakpoint_trap:
+ mov %o0, %o1
+ sethi %hi(breakpoint_t), %o0
+ or %o0, %lo(breakpoint_t), %o0
+ call prom_printf
+ add %o0, %g4, %o0
+ call prom_cmdline
+ nop
+ ba,a,pt %xcc, rtrap
+
+ .globl sys_pipe, sys_execve, sys_sigpause, sys_nis_syscall
+
+sys_pipe:
+ sethi %hi(sparc_pipe), %g1
+ add %g1, %g4, %g1
+ jmpl %g1 + %lo(sparc_pipe), %g0
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+
+sys_nis_syscall:
+ sethi %hi(c_sys_nis_syscall), %g1
+ add %g1, %g4, %g1
+ jmpl %g1 + %lo(c_sys_nis_syscall), %g0
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+
+sys_execve:
+ sethi %hi(sparc_execve), %g1
+ add %g1, %g4, %g1
+ jmpl %g1 + %lo(sparc_execve), %g0
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+
+sys_sigpause:
+ /* NOTE: %o0 has a correct value already */
+ call do_sigpause
+ add %sp, STACK_BIAS + REGWIN_SZ, %o1
+
+ ld [%curptr + AOFF_task_flags], %l5
+ andcc %l5, 0x20, %g0
+ be,pt %icc, ret_sys_call
+ clr %o0
+ call syscall_trace
+ nop
+ ba,pt %xcc, ret_sys_call
+ clr %o0
+
+ /* This is how fork() was meant to be done, 11 instruction entry. -DaveM */
+ .globl sys_fork, sys_vfork, sys_clone
+sys_fork:
+sys_vfork:
+ mov SIGCHLD, %o0
+ clr %o1
+sys_clone:
+ mov %o7, %l5
+ flushw
+ rdpr %cwp, %o4
+ add %sp, STACK_BIAS + REGWIN_SZ, %o2
+ brz,a %o1, 1f
+ mov %fp, %o1
+1:
+ /* Don't try this at home. */
+ stx %o4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G0]
+ call do_fork
+ add %l5, 8, %o7
+
+linux_sparc_ni_syscall:
+ sethi %hi(sys_ni_syscall), %l7
+ or %l7, %lo(sys_ni_syscall), %l7
+ ba,pt %xcc,syscall_is_too_hard
+ add %l7, %g4, %l7
+
+linux_fast_syscall:
+ andn %l7, 3, %l7
+ mov %i0, %o0
+ mov %i1, %o1
+ mov %i2, %o2
+ jmpl %l7 + %g0, %g0
+ mov %i3, %o3
+
+linux_syscall_trace:
+ call syscall_trace
+ nop
+ mov %i0, %o0
+ mov %i1, %o1
+ mov %i2, %o2
+ mov %i3, %o3
+ ba,pt %xcc, 2f
+ mov %i4, %o4
+
+ .globl ret_from_syscall
+ret_from_syscall:
+ ba,pt %xcc, ret_sys_call
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_I0], %o0
+
+ /* Linux native and SunOS system calls enter here... */
+ .align 4
+ .globl linux_sparc_syscall
+linux_sparc_syscall:
+ /* Direct access to user regs, must faster. */
+ cmp %g1, NR_SYSCALLS
+ add %l7, %g4, %l7
+ bgeu,pn %xcc, linux_sparc_ni_syscall
+ sll %g1, 3, %l4
+ ldx [%l7 + %l4], %l7
+ andcc %l7, 1, %g0
+ bne,pn %icc, linux_fast_syscall
+ /* Just do the next insn in the delay slot */
+
+ .globl syscall_is_too_hard
+syscall_is_too_hard:
+ mov %i0, %o0
+ mov %i1, %o1
+ mov %i2, %o2
+
+ ldx [%curptr + AOFF_task_flags], %l5
+ mov %i3, %o3
+ mov %i4, %o4
+ andcc %l5, 0x20, %g0
+ bne,pn %icc, linux_syscall_trace
+ mov %i0, %l5
+2:
+ call %l7
+ mov %i5, %o5
+
+ stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_I0]
+
+ .globl ret_sys_call
+ret_sys_call:
+ ldx [%curptr + AOFF_task_flags], %l6
+ mov %ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_TSTATE], %g3
+ cmp %o0, -ENOIOCTLCMD
+ sllx %g2, 32, %g2
+ bgeu,pn %xcc, 1f
+ andcc %l6, 0x20, %l6
+
+ /* System call success, clear Carry condition code. */
+ andn %g3, %g2, %g3
+ clr %l6
+ stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_TSTATE]
+ bne,pn %icc, linux_syscall_trace2
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC], %l1 /* pc = npc */
+ add %l1, 0x4, %l2 /* npc = npc+4 */
+ stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_TPC]
+ ba,pt %xcc, rtrap
+ stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC]
+1:
+ /* System call failure, set Carry condition code.
+ * Also, get abs(errno) to return to the process.
+ */
+ sub %g0, %o0, %o0
+ or %g3, %g2, %g3
+ stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_I0]
+ mov 1, %l6
+ stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_TSTATE]
+ bne,pn %icc, linux_syscall_trace2
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC], %l1 /* pc = npc */
+ add %l1, 0x4, %l2 /* npc = npc+4 */
+ stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_TPC]
+ ba,pt %xcc, rtrap
+ stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC]
+
+linux_syscall_trace2:
+ call syscall_trace
+ add %l1, 0x4, %l2 /* npc = npc+4 */
+ stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_TPC]
+ ba,pt %xcc, rtrap
+ stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC]
+
+/* End of entry.S */
diff --git a/arch/sparc64/kernel/etrap.S b/arch/sparc64/kernel/etrap.S
new file mode 100644
index 000000000..7d293a88b
--- /dev/null
+++ b/arch/sparc64/kernel/etrap.S
@@ -0,0 +1,114 @@
+/* $Id: etrap.S,v 1.11 1997/04/14 17:04:45 jj Exp $
+ * etrap.S: Preparing for entry into the kernel on Sparc V9.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <asm/asi.h>
+#include <asm/pstate.h>
+#include <asm/ptrace.h>
+#include <asm/spitfire.h>
+#include <asm/head.h>
+
+/* We assume that pstate, when entering this, has AG and IE bits set, MG and IG clear */
+
+ .text
+ .align 32
+ .globl etrap, etrap_irq
+etrap:
+ rdpr %pil, %g4
+etrap_irq:
+ rdpr %tstate, %g1
+ sllx %g4, 20, %g4
+ rdpr %tpc, %g2
+ or %g1, %g4, %g1
+ rdpr %tnpc, %g3
+
+ /* What happens more often? etrap when already in priv or from userland? */
+ andcc %g1, TSTATE_PRIV, %g0
+ bne,a,pn %xcc, 1f
+ sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g5
+
+ /* Just when going from userland to privileged mode,
+ * we have to change this stuff.
+ *
+ * Setup to run in NUCLEUS context, stash user context in
+ * secondary for later trap return. Note we must not change
+ * trap level until PRIMARY_CONTEXT is set to zero, else
+ * we fall out of NUCLEUS too soon and crash hard.
+ */
+ rdpr %wstate, %g5
+ mov PRIMARY_CONTEXT, %g7
+ ldxa [%g7] ASI_DMMU, %g4
+ mov SECONDARY_CONTEXT, %g6
+ stxa %g0, [%g7] ASI_DMMU
+ stxa %g4, [%g6] ASI_DMMU
+ wrpr %g0, 0x0, %tl
+
+ sll %g5, 3, %g5
+ sethi %uhi(KERNBASE), %g4
+ or %g4, %ulo(KERNBASE), %g4
+ sethi %hi(current_set), %g6
+ or %g6, %lo(current_set), %g6
+ sllx %g4, 32, %g4
+ wrpr %g5, %wstate
+ rdpr %canrestore, %g5
+ ldx [%g6 + %g4], %g6
+#ifdef __SMP__
+/* FIXME: Fix the above insn for SMP */
+#endif
+ wrpr %g0, 0, %canrestore
+ wrpr %g5, 0, %otherwin
+ ba,pt %xcc, 2f
+ ldx [%g6 + AOFF_task_saved_kernel_stack], %g5
+1:
+ wrpr %g0, 0x0, %tl
+2:
+ rd %y, %g4
+ stx %g1, [%g5 + REGWIN_SZ + PT_V9_TSTATE]
+ stx %g2, [%g5 + REGWIN_SZ + PT_V9_TPC]
+ stx %g3, [%g5 + REGWIN_SZ + PT_V9_TNPC]
+ stx %g4, [%g5 + REGWIN_SZ + PT_V9_Y]
+ rdpr %pstate, %g1
+ save %g5, -STACK_BIAS, %sp
+ mov %g1, %l1
+ mov %g7, %l2
+ wrpr %l1, PSTATE_AG, %pstate
+ stx %g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1]
+ stx %g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2]
+ stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3]
+ stx %g4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4]
+ stx %g5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5]
+ stx %g6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6]
+ stx %g7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7]
+ stx %i0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
+ stx %i1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]
+ stx %i2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2]
+ stx %i3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3]
+ stx %i4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4]
+ stx %i5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5]
+ stx %i6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6]
+ stx %i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7]
+ wrpr %l1, (PSTATE_IE | PSTATE_AG), %pstate
+ sethi %uhi(KERNBASE), %g4
+ or %g4, %ulo(KERNBASE), %g4
+ sethi %hi(current_set), %g6
+ or %g6, %lo(current_set), %g6
+ sllx %g4, 32, %g4
+ jmpl %l2 + 0x4, %g0
+ ldx [%g6 + %g4], %g6
+#ifdef __SMP__
+/* FIXME: Fix the above insn for SMP */
+#endif
+
+ .globl etraptl1
+etraptl1:
+ rdpr %tl, %g4
+ rdpr %tstate, %g1
+ sub %g4, 1, %g4
+ rdpr %tpc, %g2
+ rdpr %tnpc, %g3
+ wrpr %g4, 0x0, %tl
+ ba,pt %xcc, 1b
+ sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g5
diff --git a/arch/sparc64/kernel/hack.S b/arch/sparc64/kernel/hack.S
new file mode 100644
index 000000000..0aca22a77
--- /dev/null
+++ b/arch/sparc64/kernel/hack.S
@@ -0,0 +1,214 @@
+/* <hack>
+ This is just a huge ugly hack to get things compiled.
+ Hopefully will disappear quickly, once we get everything
+ to compile... */
+ .text
+ .align 8
+ .globl _sigpause_common
+_sigpause_common: retl;nop
+ .globl breakpoint
+breakpoint: retl;nop
+ .globl do_cee
+do_cee: retl;nop
+ .globl do_cee_tl1
+do_cee_tl1: retl;nop
+ .globl do_dae
+do_dae: retl;nop
+ .globl do_dae_tl1
+do_dae_tl1: retl;nop
+ .globl do_div0
+do_div0: retl;nop
+ .globl do_div0_tl1
+do_div0_tl1: retl;nop
+ .globl do_fpdis
+do_fpdis: retl;nop
+ .globl do_fpdis_tl1
+do_fpdis_tl1: retl;nop
+ .globl do_fpieee
+do_fpieee: retl;nop
+ .globl do_fpieee_tl1
+do_fpieee_tl1: retl;nop
+ .globl do_fpother
+do_fpother: retl;nop
+ .globl do_fpother_tl1
+do_fpother_tl1: retl;nop
+ .globl do_iae
+do_iae: retl;nop
+ .globl do_iae_tl1
+do_iae_tl1: retl;nop
+ .globl do_ill
+do_ill: retl;nop
+ .globl do_ill_tl1
+do_ill_tl1: retl;nop
+ .globl do_irq
+do_irq: retl;nop
+ .globl do_irq_tl1
+do_irq_tl1: retl;nop
+ .globl do_lddfmna
+do_lddfmna: retl;nop
+ .globl do_lddfmna_tl1
+do_lddfmna_tl1: retl;nop
+ .globl do_mna
+do_mna: retl;nop
+ .globl do_mna_tl1
+do_mna_tl1: retl;nop
+ .globl do_paw
+do_paw: retl;nop
+ .globl do_paw_tl1
+do_paw_tl1: retl;nop
+ .globl do_privact
+do_privact: retl;nop
+ .globl do_privop
+do_privop: retl;nop
+ .globl do_signal
+do_signal: retl;nop
+ .globl do_stdfmna
+do_stdfmna: retl;nop
+ .globl do_stdfmna_tl1
+do_stdfmna_tl1: retl;nop
+ .globl do_tof
+do_tof: retl;nop
+ .globl do_tof_tl1
+do_tof_tl1: retl;nop
+ .globl do_vaw
+do_vaw: retl;nop
+ .globl do_vaw_tl1
+do_vaw_tl1: retl;nop
+ .globl floppy_hardint
+floppy_hardint: retl;nop
+ .globl get_cpuid
+get_cpuid: retl;nop
+ .globl getcc
+getcc: retl;nop
+ .globl halt
+halt: retl;nop
+ .globl indirect_syscall
+indirect_syscall: retl;nop
+ .globl install_linux_ticker
+install_linux_ticker: retl;nop
+ .globl install_obp_ticker
+install_obp_ticker: retl;nop
+ .globl linux_dbvec
+linux_dbvec: retl;nop
+ .globl linux_num_cpus
+linux_num_cpus: retl;nop
+ .globl netbsd_syscall
+netbsd_syscall: retl;nop
+ .globl setcc
+setcc: retl;nop
+ .globl solaris_syscall
+solaris_syscall: retl;nop
+ .globl sunos_mmap
+sunos_mmap: retl;nop
+ .globl sunos_syscall
+sunos_syscall: retl;nop
+ .globl svr4_getcontext
+svr4_getcontext: retl;nop
+ .globl svr4_setcontext
+svr4_setcontext: retl;nop
+ .globl sunos_accept
+sunos_accept: retl;nop
+ .globl sunos_audit
+sunos_audit: retl;nop
+ .globl sunos_brk
+sunos_brk: retl;nop
+ .globl sunos_execv
+sunos_execv: retl;nop
+ .globl sunos_fpathconf
+sunos_fpathconf: retl;nop
+ .globl sunos_getdents
+sunos_getdents: retl;nop
+ .globl sunos_getdirentries
+sunos_getdirentries: retl;nop
+ .globl sunos_getdomainname
+sunos_getdomainname: retl;nop
+ .globl sunos_getdtablesize
+sunos_getdtablesize: retl;nop
+ .globl sunos_getgid
+sunos_getgid: retl;nop
+ .globl sunos_gethostid
+sunos_gethostid: retl;nop
+ .globl sunos_getpid
+sunos_getpid: retl;nop
+ .globl sunos_getsockopt
+sunos_getsockopt: retl;nop
+ .globl sunos_getuid
+sunos_getuid: retl;nop
+ .globl sunos_indir
+sunos_indir: retl;nop
+ .globl sunos_ioctl
+sunos_ioctl: retl;nop
+ .globl sunos_killpg
+sunos_killpg: retl;nop
+ .globl sunos_madvise
+sunos_madvise: retl;nop
+ .globl sunos_mctl
+sunos_mctl: retl;nop
+ .globl sunos_mincore
+sunos_mincore: retl;nop
+ .globl sunos_mount
+sunos_mount: retl;nop
+ .globl sunos_nop
+sunos_nop: retl;nop
+ .globl sunos_nosys
+sunos_nosys: retl;nop
+ .globl sunos_open
+sunos_open: retl;nop
+ .globl sunos_pathconf
+sunos_pathconf: retl;nop
+ .globl sunos_poll
+sunos_poll: retl;nop
+ .globl sunos_read
+sunos_read: retl;nop
+ .globl sunos_readv
+sunos_readv: retl;nop
+ .globl sunos_recv
+sunos_recv: retl;nop
+ .globl sunos_sbrk
+sunos_sbrk: retl;nop
+ .globl sunos_select
+sunos_select: retl;nop
+ .globl sunos_semsys
+sunos_semsys: retl;nop
+ .globl sunos_send
+sunos_send: retl;nop
+ .globl sunos_setpgrp
+sunos_setpgrp: retl;nop
+ .globl sunos_setsockopt
+sunos_setsockopt: retl;nop
+ .globl sunos_shmsys
+sunos_shmsys: retl;nop
+ .globl sunos_sigaction
+sunos_sigaction: retl;nop
+ .globl sunos_sigblock
+sunos_sigblock: retl;nop
+ .globl sunos_sigsetmask
+sunos_sigsetmask: retl;nop
+ .globl sunos_sstk
+sunos_sstk: retl;nop
+ .globl sunos_sysconf
+sunos_sysconf: retl;nop
+ .globl sunos_uname
+sunos_uname: retl;nop
+ .globl sunos_vadvise
+sunos_vadvise: retl;nop
+ .globl sunos_wait4
+sunos_wait4: retl;nop
+ .globl sunos_write
+sunos_write: retl;nop
+ .globl sunos_writev
+sunos_writev: retl;nop
+ .globl sys_ptrace
+sys_ptrace: retl;nop
+ .globl sys_sigreturn
+sys_sigreturn: retl;nop
+ .globl sys_sigstack
+sys_sigstack: retl;nop
+ .globl sys_sigsuspend
+sys_sigsuspend: retl;nop
+ .globl syscall_trace
+syscall_trace: retl;nop
+ .globl sys32_ptrace
+sys32_ptrace: retl;nop
+ .globl do_sigpause
+do_sigpause: retl;nop
diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S
new file mode 100644
index 000000000..fdbe87aa3
--- /dev/null
+++ b/arch/sparc64/kernel/head.S
@@ -0,0 +1,373 @@
+/* $Id: head.S,v 1.27 1997/04/04 00:49:49 davem Exp $
+ * head.S: Initial boot code for the Sparc64 port of Linux.
+ *
+ * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996 David Sitsky (David.Sitsky@anu.edu.au)
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ */
+
+#include <linux/version.h>
+#include <asm/pstate.h>
+#include <asm/ptrace.h>
+#include <asm/spitfire.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/errno.h>
+#include <asm/lsu.h>
+#include <asm/head.h>
+
+/* This section from from _start to sparc64_boot_end should fit into
+ * 0xffff.f800.0000.4000 to 0xffff.f800.0000.8000 and will be sharing space
+ * with bootup_user_stack, which is from 0xffff.f800.0000.4000 to
+ * 0xffff.f800.0000.6000 and bootup_kernel_stack, which is from
+ * 0xffff.f800.0000.6000 to 0xffff.f800.0000.8000.
+ */
+
+ .text
+ .globl start, _start, stext, _stext
+_start:
+start:
+_stext:
+stext:
+bootup_user_stack:
+! 0xfffff80000004000
+ b sparc64_boot
+ flushw /* Flush register file. */
+
+/* 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.
+ */
+ .global root_flags, ram_flags, root_dev
+ .global ramdisk_image, ramdisk_size
+
+ .ascii "HdrS"
+ .word LINUX_VERSION_CODE
+ .half 0x0201 /* HdrS version */
+root_flags:
+ .half 1
+root_dev:
+ .half 0
+ram_flags:
+ .half 0
+ramdisk_image:
+ .word 0
+ramdisk_size:
+ .word 0
+ .word reboot_command
+
+ /* We must be careful, 32-bit OpenBOOT will get confused if it
+ * tries to save away a register window to a 64-bit kernel
+ * stack address. Flush all windows, disable interrupts,
+ * remap if necessary, jump onto kernel trap table, then kernel
+ * stack, or else we die.
+ *
+ * PROM entry point is on %o4
+ */
+sparc64_boot:
+ /* Typically PROM has already enabled both MMU's and both on-chip
+ * caches, but we do it here anyway just to be paranoid.
+ */
+ mov (LSU_CONTROL_IC|LSU_CONTROL_DC|LSU_CONTROL_IM|LSU_CONTROL_DM), %g1
+ stxa %g1, [%g0] ASI_LSU_CONTROL
+
+ /*
+ * Make sure we are in privileged mode, have address masking,
+ * using the ordinary globals and have enabled floating
+ * point.
+ *
+ * Again, typically PROM has left %pil at 13 or similar, and
+ * (PSTATE_PRIV | PSTATE_PEF | PSTATE_IE) in %pstate.
+ */
+ wrpr %g0, 0xf, %pil /* Interrupts off. */
+ wrpr %g0, (PSTATE_PRIV|PSTATE_PEF), %pstate
+
+ /* Check if we are 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.
+ */
+current_pc:
+ rd %pc, %g3
+ sethi %uhi(KERNBASE), %g4
+ sllx %g4, 32, %g4
+
+ /* Check the run time program counter. */
+
+ set current_pc, %g5
+ add %g5, %g4, %g5
+ cmp %g3, %g5
+ be %xcc, sun4u_init
+ nop
+
+create_mappings:
+ /* %g5 holds the tlb data */
+ sethi %uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5
+ sllx %g5, 32, %g5
+ or %g5, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W | _PAGE_G), %g5
+
+ /* Base of physical memory cannot reliably be assumed to be
+ * at 0x0! Figure out where it happens to be. -DaveM
+ */
+
+ /* Put PADDR tlb data mask into %g3. */
+ sethi %uhi(_PAGE_PADDR), %g3
+ or %g3, %ulo(_PAGE_PADDR), %g3
+ sllx %g3, 32, %g3
+ sethi %hi(_PAGE_PADDR), %g7
+ or %g7, %lo(_PAGE_PADDR), %g7
+ or %g3, %g7, %g3
+
+ /* Walk through entire ITLB, looking for entry which maps
+ * our %pc currently, stick PADDR from there into %g5 tlb data.
+ */
+ clr %l0 /* TLB entry walker. */
+ set 0x1fff, %l2 /* Page mask. */
+ rd %pc, %l3
+ andn %l3, %l2, %g2 /* vaddr comparator */
+1:
+ /* Yes, the nops seem to be necessary for now, don't ask me why. -DaveM */
+ ldxa [%l0] ASI_ITLB_TAG_READ, %g1
+ nop
+ nop
+ nop
+ andn %g1, %l2, %g1 /* Get vaddr */
+ cmp %g1, %g2
+ be,a,pn %xcc, got_tlbentry
+ ldxa [%l0] ASI_ITLB_DATA_ACCESS, %g1
+ cmp %l1, (63 << 3)
+ blu,pt %xcc, 1b
+ add %l0, (1 << 3), %l0
+
+boot_failed:
+ /* Debugging 8-) */
+ set 0xdeadbeef, %g1
+ t 0x11
+
+got_tlbentry:
+ /* Nops here again, perhaps Cheetah/Blackbird are better behaved... */
+ nop
+ nop
+ nop
+ and %g1, %g3, %g1 /* Mask to just get paddr bits. */
+ sub %g1, %g2, %g1 /* Get rid of %pc offset to get base. */
+
+ /* NOTE: We hold on to %g1 paddr base as we need it below to lock
+ * NOTE: the PROM cif code into the TLB.
+ */
+
+ or %g5, %g1, %g5 /* Or it into TAG being built. */
+
+ /* PROM never puts any TLB entries into the MMU with the lock bit
+ * set. So we gladly use tlb entry 63 for KERNBASE, 62 for
+ * boot time locked PROM CIF handler page, we remove the locked
+ * bit for the CIF page in paging_init().
+ */
+ mov TLB_TAG_ACCESS, %g3
+ mov (63 << 3), %g7
+ stxa %g4, [%g3] ASI_IMMU /* KERNBASE into TLB TAG */
+ stxa %g5, [%g7] ASI_ITLB_DATA_ACCESS /* TTE into TLB DATA */
+ membar #Sync
+
+ /* Same for DTLB */
+ stxa %g4, [%g3] ASI_DMMU /* KERNBASE into TLB TAG */
+ stxa %g5, [%g7] ASI_DTLB_DATA_ACCESS /* TTE into TLB DATA */
+ membar #Sync
+
+ /* Kill instruction prefetch queues. */
+ flush %g4
+ membar #Sync
+
+ ba,pt %xcc, go_to_highmem
+ nop
+
+go_to_highmem:
+ /* Now do a non-relative jump so that PC is in high-memory */
+ set sun4u_init, %g2
+ jmpl %g2 + %g4, %g0
+ nop
+
+sun4u_init:
+ /* Set ctx 0 */
+ mov PRIMARY_CONTEXT, %g7
+ stxa %g0, [%g7] ASI_DMMU
+ membar #Sync
+
+ mov SECONDARY_CONTEXT, %g7
+ stxa %g0, [%g7] ASI_DMMU
+ membar #Sync
+
+ /* The lock bit has to be removed from this page later on,
+ * but before firing up init we will use PROM a lot, so we
+ * lock it there now...
+ */
+
+ /* Compute PROM CIF interface page TTE. */
+ sethi %hi(__p1275_loc), %g7
+ or %g7, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W | _PAGE_L), %g7
+ sethi %uhi(_PAGE_VALID), %g5
+ sethi %hi(0x8000), %g3
+ sllx %g5, 32, %g5
+ mov TLB_TAG_ACCESS, %g6
+ or %g5, %g7, %g5
+ add %g5, %g1, %g5 /* Add in physbase. */
+
+ mov (62 << 3), %g7 /* TLB entry 62 */
+ stxa %g3, [%g6] ASI_IMMU /* CIF page into TLB TAG */
+ stxa %g5, [%g7] ASI_ITLB_DATA_ACCESS /* TTE into TLB DATA */
+ membar #Sync
+
+ /* Same for DTLB */
+ stxa %g3, [%g6] ASI_DMMU /* CIF page into TLB TAG */
+ stxa %g5, [%g7] ASI_DTLB_DATA_ACCESS /* TTE into TLB DATA */
+ membar #Sync
+
+ /* Kill instruction prefetch queues. */
+ flush %g3
+ membar #Sync
+
+ /* We are now safely (we hope) in Nucleus context (0), rewrite
+ * the KERNBASE TTE's so they no longer have the global bit set.
+ * Don't forget to setup TAG_ACCESS first 8-)
+ */
+ mov TLB_TAG_ACCESS, %g2
+ stxa %g4, [%g2] ASI_IMMU
+ stxa %g4, [%g2] ASI_DMMU
+
+ mov (63 << 3), %g7
+ ldxa [%g7] ASI_ITLB_DATA_ACCESS, %g1
+ andn %g1, (_PAGE_G), %g1
+ stxa %g1, [%g7] ASI_ITLB_DATA_ACCESS
+ membar #Sync
+
+ ldxa [%g7] ASI_DTLB_DATA_ACCESS, %g1
+ andn %g1, (_PAGE_G), %g1
+ stxa %g1, [%g7] ASI_DTLB_DATA_ACCESS
+ membar #Sync
+
+ /* Kill instruction prefetch queues. */
+ flush %g4
+ membar #Sync
+
+ /* Compute the number of windows in this machine
+ * store this in nwindows and nwindowsm1
+ */
+ rdpr %ver, %g1 /* Get VERSION register. */
+ sethi %hi(nwindows), %g2
+ and %g1, VERS_MAXWIN, %g5
+ or %g2,%lo(nwindows),%g2
+ add %g5, 1, %g6
+ add %g2, (nwindows - nwindowsm1), %g3
+ stx %g6, [%g2 + %g4]
+ stx %g5, [%g3 + %g4]
+
+ sethi %hi(init_task), %g6
+ or %g6, %lo(init_task), %g6
+ add %g6, %g4, %g6 ! g6 usage is fixed as well
+ mov %sp, %l6
+ mov %o4, %l7
+
+ sethi %hi(bootup_kernel_stack + 0x2000 - STACK_BIAS - REGWIN_SZ), %g5
+ or %g5, %lo(bootup_kernel_stack + 0x2000 - STACK_BIAS - REGWIN_SZ), %g5
+ add %g5, %g4, %sp
+ mov 0, %fp
+ wrpr %g0, 0, %wstate
+ wrpr %g0, 0x0, %tl
+
+ /* Clear the bss */
+ sethi %hi(8191), %l2
+ or %l2, %lo(8191), %l2
+ sethi %hi(__bss_start), %l0
+ or %l0, %lo(__bss_start), %l0
+ sethi %hi(_end), %l1
+ or %l1, %lo(_end), %l1
+ add %l1, %l2, %l1
+ andn %l1, %l2, %l1
+ add %l2, 1, %l2
+ add %l0, %g4, %o0
+1:
+ call bzero_1page
+ add %l0, %l2, %l0
+ cmp %l0, %l1
+ blu,pt %xcc, 1b
+ add %l0, %g4, %o0
+
+ /* Now clear empty_zero_page */
+ call bzero_1page
+ mov %g4, %o0
+
+ mov %l6, %o1 ! OpenPROM stack
+ call prom_init
+ mov %l7, %o0 ! OpenPROM cif handler
+
+ /* Off we go.... */
+ call start_kernel
+ nop
+ /* Not reached... */
+
+ .globl setup_tba
+setup_tba:
+ sethi %hi(sparc64_ttable_tl0), %g5
+ add %g5, %g4, %g5
+ wrpr %g5, %tba
+
+ /* Set up MMU globals */
+ rdpr %pstate, %o1
+ wrpr %o1, PSTATE_MG, %pstate
+
+ /* PGD/PMD offset mask, used by TLB miss handlers. */
+ sethi %hi(0x1ff8), %g2
+ or %g2, %lo(0x1ff8), %g2
+
+ /* Kernel PGDIR used by TLB miss handlers. */
+ mov %o0, %g6
+
+ /* To catch bootup bugs, this is user PGDIR for TLB miss handlers. */
+ clr %g7
+
+ /* Setup Interrupt globals */
+ wrpr %o1, PSTATE_IG, %pstate
+ sethi %uhi(ivector_to_mask), %g4
+ or %g4, %ulo(ivector_to_mask), %g4
+ sethi %hi(ivector_to_mask), %g5
+ or %g5, %lo(ivector_to_mask), %g5
+ or %g5, %g4, %g1 /* IVECTOR table */
+ mov 0x40, %g2 /* INTR data 0 register */
+
+ andn %o1, PSTATE_IE, %o1
+ wrpr %g0, %g0, %wstate
+ wrpr %o1, %g0, %pstate
+
+ /* Zap TSB BASE to zero with TSB_size==1. */
+ mov TSB_REG, %o4
+ mov 1, %o5
+ stxa %o5, [%o4] ASI_DMMU
+ stxa %o5, [%o4] ASI_IMMU
+
+ membar #Sync
+
+ retl
+ nop
+
+sparc64_boot_end:
+ .skip 0x2000 + _start - sparc64_boot_end
+bootup_user_stack_end:
+
+bootup_kernel_stack:
+ .skip 0x2000
+
+! 0xfffff80000008000
+
+#include "ttable.S"
+
+ .data
+ .align 8
+ .globl nwindows, nwindowsm1
+nwindows: .xword 0
+nwindowsm1: .xword 0
+ .section ".fixup",#alloc,#execinstr
+ .globl __ret_efault
+__ret_efault:
+ ret
+ restore %g0, -EFAULT, %o0
diff --git a/arch/sparc64/kernel/idprom.c b/arch/sparc64/kernel/idprom.c
new file mode 100644
index 000000000..08a4a6b6a
--- /dev/null
+++ b/arch/sparc64/kernel/idprom.c
@@ -0,0 +1,49 @@
+/* $Id: idprom.c,v 1.2 1997/04/17 02:28:10 miguel Exp $
+ * 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>
+
+struct idprom *idprom;
+static struct idprom idprom_buffer;
+
+/* Calculate the IDPROM checksum (xor of the data bytes). */
+__initfunc(static unsigned char 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 and verify integrity. */
+__initfunc(void idprom_init(void))
+{
+ prom_get_idprom((char *) &idprom_buffer, sizeof(idprom_buffer));
+
+ idprom = &idprom_buffer;
+
+ if (idprom->id_format != 0x01) {
+ prom_printf("IDPROM: Warning, unknown format type!\n");
+ }
+
+ if (idprom->id_cksum != calc_idprom_cksum(idprom)) {
+ prom_printf("IDPROM: Warning, checksum failure (nvram=%x, calc=%x)!\n",
+ idprom->id_cksum, calc_idprom_cksum(idprom));
+ }
+
+ printk("Ethernet address: %02x:%02x:%02x:%02x:%02x:%02x\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/sparc64/kernel/ioport.c b/arch/sparc64/kernel/ioport.c
new file mode 100644
index 000000000..2f94e9102
--- /dev/null
+++ b/arch/sparc64/kernel/ioport.c
@@ -0,0 +1,139 @@
+/* $Id: ioport.c,v 1.7 1997/04/10 05:13:01 davem Exp $
+ * ioport.c: Simple io mapping allocator.
+ *
+ * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+
+#include <asm/io.h>
+#include <asm/vaddrs.h>
+#include <asm/oplib.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+/* This points to the next to use virtual memory for io mappings */
+static unsigned long dvma_next_free = DVMA_VADDR;
+unsigned long sparc_iobase_vaddr = IOBASE_VADDR;
+
+extern void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr);
+
+/*
+ * sparc_alloc_io:
+ * Map and allocates an obio device.
+ * Implements a simple linear allocator, you can force the function
+ * to use your own mapping, but in practice this should not be used.
+ *
+ * Input:
+ * address: Physical address to map
+ * virtual: if non zero, specifies a fixed virtual address where
+ * the mapping should take place.
+ * len: the length of the mapping
+ * bus_type: Optional high word of physical address.
+ *
+ * Returns:
+ * The virtual address where the mapping actually took place.
+ */
+
+void *sparc_alloc_io (u32 address, void *virtual, int len, char *name,
+ u32 bus_type, int rdonly)
+{
+ unsigned long vaddr, base_address;
+ unsigned long addr = ((unsigned long) address) + (((unsigned long) bus_type) << 32);
+ unsigned long offset = (addr & (~PAGE_MASK));
+
+ if (virtual) {
+ vaddr = (unsigned long) virtual;
+
+ len += offset;
+ if(((unsigned long) virtual + len) > (IOBASE_VADDR + IOBASE_LEN)) {
+ prom_printf("alloc_io: Mapping outside IOBASE area\n");
+ prom_halt();
+ }
+ if(check_region ((vaddr | offset), len)) {
+ prom_printf("alloc_io: 0x%lx is already in use\n", vaddr);
+ prom_halt();
+ }
+
+ /* Tell Linux resource manager about the mapping */
+ request_region ((vaddr | offset), len, name);
+ } else {
+ vaddr = occupy_region(sparc_iobase_vaddr, IOBASE_END,
+ (offset + len + PAGE_SIZE-1) & PAGE_MASK, PAGE_SIZE, name);
+ if (vaddr == 0) {
+ /* Usually we cannot see printks in this case. */
+ prom_printf("alloc_io: cannot occupy %d region\n", len);
+ prom_halt();
+ }
+ }
+
+ base_address = vaddr;
+ /* Do the actual mapping */
+ for (; len > 0; len -= PAGE_SIZE) {
+ mapioaddr(addr, vaddr, bus_type, rdonly);
+ vaddr += PAGE_SIZE;
+ addr += PAGE_SIZE;
+ }
+
+ return (void *) (base_address | offset);
+}
+
+void sparc_free_io (void *virtual, int len)
+{
+ unsigned long vaddr = (unsigned long) virtual & PAGE_MASK;
+ unsigned long plen = (((unsigned long)virtual & ~PAGE_MASK) + len + PAGE_SIZE-1) & PAGE_MASK;
+
+ release_region(vaddr, plen);
+
+ for (; plen != 0;) {
+ plen -= PAGE_SIZE;
+ unmapioaddr(vaddr + plen);
+ }
+}
+
+/* Does DVMA allocations with PAGE_SIZE granularity. How this basically
+ * works is that the ESP chip can do DVMA transfers at ANY address with
+ * certain size and boundary restrictions. But other devices that are
+ * attached to it and would like to do DVMA have to set things up in
+ * a special way, if the DVMA sees a device attached to it transfer data
+ * at addresses above DVMA_VADDR it will grab them, this way it does not
+ * now have to know the peculiarities of where to read the Lance data
+ * from. (for example)
+ *
+ * Returns CPU visible address for the buffer returned, dvma_addr is
+ * set to the DVMA visible address.
+ */
+void *sparc_dvma_malloc (int len, char *name, __u32 *dvma_addr)
+{
+ unsigned long vaddr, base_address;
+
+ vaddr = dvma_next_free;
+ if(check_region (vaddr, len)) {
+ prom_printf("alloc_dma: 0x%lx is already in use\n", vaddr);
+ prom_halt();
+ }
+ if(vaddr + len > (DVMA_VADDR + DVMA_LEN)) {
+ prom_printf("alloc_dvma: out of dvma memory\n");
+ prom_halt();
+ }
+
+ /* Basically these can be mapped just like any old
+ * IO pages, cacheable bit off, etc. The physical
+ * pages are now mapped dynamically to save space.
+ */
+ base_address = vaddr;
+ mmu_map_dma_area(base_address, len, dvma_addr);
+
+ /* Assign the memory area. */
+ dvma_next_free = PAGE_ALIGN(dvma_next_free+len);
+
+ request_region(base_address, len, name);
+
+ return (void *) base_address;
+}
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
new file mode 100644
index 000000000..bc9a8053e
--- /dev/null
+++ b/arch/sparc64/kernel/irq.c
@@ -0,0 +1,638 @@
+/* $Id: irq.c,v 1.12 1997/04/16 05:56:20 davem Exp $
+ * irq.c: UltraSparc IRQ handling/init/registry.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/config.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/kernel_stat.h>
+#include <linux/signal.h>
+#include <linux/interrupt.h>
+#include <linux/malloc.h>
+#include <linux/random.h> /* XXX ADD add_foo_randomness() calls... -DaveM */
+#include <linux/init.h>
+
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+#include <asm/atomic.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/sbus.h>
+#include <asm/iommu.h>
+#include <asm/upa.h>
+#include <asm/oplib.h>
+#include <asm/smp.h>
+#include <asm/hardirq.h>
+#include <asm/softirq.h>
+
+/* Internal flag, should not be visible elsewhere at all. */
+#define SA_SYSIO_MASKED 0x100
+
+/* UPA nodes send interrupt packet to UltraSparc with first data reg value
+ * low 5 bits holding the IRQ identifier being delivered. We must translate
+ * this into a non-vector IRQ so we can set the softint on this cpu. To
+ * make things even more swift we store the complete mask here.
+ */
+
+#define NUM_IVECS 2048 /* XXX may need more on sunfire/wildfire */
+
+unsigned long ivector_to_mask[NUM_IVECS];
+
+/* This is based upon code in the 32-bit Sparc kernel written mostly by
+ * David Redman (djhr@tadpole.co.uk).
+ */
+#define MAX_STATIC_ALLOC 4
+static struct irqaction static_irqaction[MAX_STATIC_ALLOC];
+static int static_irq_count = 0;
+
+static struct irqaction *irq_action[NR_IRQS+1] = {
+ NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL
+};
+
+int get_irq_list(char *buf)
+{
+ int i, len = 0;
+ struct irqaction *action;
+
+ for(i = 0; i < (NR_IRQS + 1); i++) {
+ if(!(action = *(i + irq_action)))
+ continue;
+ len += sprintf(buf + len, "%2d: %8d %c %s",
+ i, kstat.interrupts[i],
+ (action->flags & SA_INTERRUPT) ? '+' : ' ',
+ action->name);
+ for(action = action->next; action; action = action->next) {
+ len += sprintf(buf+len, ",%s %s",
+ (action->flags & SA_INTERRUPT) ? " +" : "",
+ action->name);
+ }
+ len += sprintf(buf + len, "\n");
+ }
+ return len;
+}
+
+/* INO number to Sparc PIL level. */
+static unsigned char ino_to_pil[] = {
+ 0, 1, 2, 3, 5, 7, 8, 9, /* SBUS slot 0 */
+ 0, 1, 2, 3, 5, 7, 8, 9, /* SBUS slot 1 */
+ 0, 1, 2, 3, 5, 7, 8, 9, /* SBUS slot 2 */
+ 0, 1, 2, 3, 5, 7, 8, 9, /* SBUS slot 3 */
+ 3, /* Onboard SCSI */
+ 5, /* Onboard Ethernet */
+/*XXX*/ 8, /* Onboard BPP */
+ 0, /* Bogon */
+ 13, /* Audio */
+/*XXX*/15, /* PowerFail */
+ 0, /* Bogon */
+ 0, /* Bogon */
+ 12, /* Zilog Serial Channels (incl. Keyboard/Mouse lines) */
+ 11, /* Floppy */
+ 0, /* Spare Hardware (bogon for now) */
+ 0, /* Keyboard (bogon for now) */
+ 0, /* Mouse (bogon for now) */
+ 0, /* Serial (bogon for now) */
+ 0, 0, /* Bogon, Bogon */
+ 10, /* Timer 0 */
+ 11, /* Timer 1 */
+ 0, 0, /* Bogon, Bogon */
+ 15, /* Uncorrectable SBUS Error */
+ 15, /* Correctable SBUS Error */
+ 15, /* SBUS Error */
+/*XXX*/ 0, /* Power Management (bogon for now) */
+};
+
+/* INO number to IMAP register offset for SYSIO external IRQ's.
+ * This should conform to both Sunfire/Wildfire server and Fusion
+ * desktop designs.
+ */
+#define offset(x) ((unsigned long)(&(((struct sysio_regs *)0)->x)))
+#define bogon ((unsigned long) -1)
+static unsigned long irq_offsets[] = {
+/* SBUS Slot 0 --> 3, level 1 --> 7 */
+offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),
+offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),
+offset(imap_slot1),offset(imap_slot1),offset(imap_slot1),offset(imap_slot1),
+offset(imap_slot1),offset(imap_slot1),offset(imap_slot1),offset(imap_slot1),
+offset(imap_slot2),offset(imap_slot2),offset(imap_slot2),offset(imap_slot2),
+offset(imap_slot2),offset(imap_slot2),offset(imap_slot2),offset(imap_slot2),
+offset(imap_slot3),offset(imap_slot3),offset(imap_slot3),offset(imap_slot3),
+offset(imap_slot3),offset(imap_slot3),offset(imap_slot3),offset(imap_slot3),
+/* Onboard devices (not relevant/used on SunFire). */
+offset(imap_scsi), offset(imap_eth), offset(imap_bpp), bogon,
+offset(imap_audio), offset(imap_pfail), bogon, bogon,
+offset(imap_kms), offset(imap_flpy), offset(imap_shw),
+offset(imap_kbd), offset(imap_ms), offset(imap_ser), bogon, bogon,
+offset(imap_tim0), offset(imap_tim1), bogon, bogon,
+offset(imap_ue), offset(imap_ce), offset(imap_sberr),
+offset(imap_pmgmt),
+};
+
+#undef bogon
+
+#define NUM_IRQ_ENTRIES (sizeof(irq_offsets) / sizeof(irq_offsets[0]))
+
+/* Convert an "interrupts" property IRQ level to an SBUS/SYSIO
+ * Interrupt Mapping register pointer, or NULL if none exists.
+ */
+static unsigned int *irq_to_imap(unsigned int irq)
+{
+ unsigned long offset;
+ struct sysio_regs *sregs;
+
+ if((irq == 14) ||
+ (irq >= NUM_IRQ_ENTRIES) ||
+ ((offset = irq_offsets[irq]) == ((unsigned long)-1)))
+ return NULL;
+ sregs = SBus_chain->iommu->sysio_regs;
+ offset += ((unsigned long) sregs);
+ return ((unsigned int *)offset) + 1;
+}
+
+/* Convert Interrupt Mapping register pointer to assosciated
+ * Interrupt Clear register pointer.
+ */
+static unsigned int *imap_to_iclr(unsigned int *imap)
+{
+ unsigned long diff;
+
+ diff = offset(iclr_unused0) - offset(imap_slot0);
+ return (unsigned int *) (((unsigned long)imap) + diff);
+}
+
+#undef offset
+
+/* For non-SBUS IRQ's we do nothing, else we must enable them in the
+ * appropriate SYSIO interrupt map registers.
+ */
+void enable_irq(unsigned int irq)
+{
+ unsigned long tid;
+ unsigned int *imap;
+
+ /* If this is for the tick interrupt, just ignore, note
+ * that this is the one and only locally generated interrupt
+ * source, all others come from external sources (essentially
+ * any UPA device which is an interruptor). (actually, on
+ * second thought Ultra can generate local interrupts for
+ * async memory errors and we may setup handlers for those
+ * at some point as well)
+ *
+ * XXX See commentary below in request_irq() this assumption
+ * XXX is broken and needs to be fixed.
+ */
+ if(irq == 14)
+ return;
+
+ /* Check for bogons. */
+ imap = irq_to_imap(irq);
+ if(imap == NULL)
+ goto do_the_stb_watoosi;
+
+ /* We send it to our UPA MID, for SMP this will be different. */
+ __asm__ __volatile__("ldxa [%%g0] %1, %0" : "=r" (tid) : "i" (ASI_UPA_CONFIG));
+ tid = ((tid & UPA_CONFIG_MID) << 9);
+
+ /* NOTE NOTE NOTE, IGN and INO are read-only, IGN is a product
+ * of this SYSIO's preconfigured IGN in the SYSIO Control
+ * Register, the hardware just mirrors that value here.
+ * However for Graphics and UPA Slave devices the full
+ * SYSIO_IMAP_INR field can be set by the programmer here.
+ * (XXX we will have to handle those for FFB etc. XXX)
+ */
+ *imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID);
+ return;
+
+do_the_stb_watoosi:
+ printk("Cannot enable irq(%d), doing the \"STB Watoosi\" instead.", irq);
+ panic("Trying to enable bogon IRQ");
+}
+
+void disable_irq(unsigned int irq)
+{
+ unsigned int *imap;
+
+ /* XXX Grrr, I know this is broken... */
+ if(irq == 14)
+ return;
+
+ /* Check for bogons. */
+ imap = irq_to_imap(irq);
+ if(imap == NULL)
+ goto do_the_stb_watoosi;
+
+ /* NOTE: We do not want to futz with the IRQ clear registers
+ * and move the state to IDLE, the SCSI code does call
+ * disable_irq() to assure atomicity in the queue cmd
+ * SCSI adapter driver code. Thus we'd lose interrupts.
+ */
+ *imap &= ~(SYSIO_IMAP_VALID);
+ return;
+
+do_the_stb_watoosi:
+ printk("Cannot disable irq(%d), doing the \"STB Watoosi\" instead.", irq);
+ panic("Trying to enable bogon IRQ");
+}
+
+int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+ unsigned long irqflags, const char *name, void *dev_cookie)
+{
+ struct irqaction *action, *tmp = NULL;
+ unsigned long flags;
+ unsigned int cpu_irq, *imap, *iclr;
+
+ /* XXX This really is not the way to do it, the "right way"
+ * XXX is to have drivers set SA_SBUS or something like that
+ * XXX in irqflags and we base our decision here on whether
+ * XXX that flag bit is set or not.
+ */
+ if(irq == 14)
+ cpu_irq = irq;
+ else
+ cpu_irq = ino_to_pil[irq];
+
+ if(!handler)
+ return -EINVAL;
+
+ imap = irq_to_imap(irq);
+
+ action = *(cpu_irq + irq_action);
+ if(action) {
+ if((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ))
+ for (tmp = action; tmp->next; tmp = tmp->next)
+ ;
+ else
+ return -EBUSY;
+
+ if((action->flags & SA_INTERRUPT) ^ (irqflags & SA_INTERRUPT)) {
+ printk("Attempt to mix fast and slow interrupts on IRQ%d "
+ "denied\n", irq);
+ return -EBUSY;
+ }
+ action = NULL; /* Or else! */
+ }
+
+ save_and_cli(flags);
+
+ /* 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, name);
+
+ if(action == NULL)
+ action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
+ GFP_KERNEL);
+
+ if(!action) {
+ restore_flags(flags);
+ return -ENOMEM;
+ }
+
+ if(imap) {
+ int ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO));
+
+ ivector_to_mask[ivindex] = (1<<cpu_irq);
+ iclr = imap_to_iclr(imap);
+ action->mask = (unsigned long) iclr;
+ irqflags |= SA_SYSIO_MASKED;
+ } else {
+ action->mask = 0;
+ }
+
+ action->handler = handler;
+ action->flags = irqflags;
+ action->name = name;
+ action->next = NULL;
+ action->dev_id = dev_cookie;
+
+ if(tmp)
+ tmp->next = action;
+ else
+ *(cpu_irq + irq_action) = action;
+
+ enable_irq(irq);
+ restore_flags(flags);
+ return 0;
+}
+
+void free_irq(unsigned int irq, void *dev_cookie)
+{
+ struct irqaction *action;
+ struct irqaction *tmp = NULL;
+ unsigned long flags;
+ unsigned int cpu_irq;
+
+ if(irq == 14)
+ cpu_irq = irq;
+ else
+ cpu_irq = ino_to_pil[irq];
+ action = *(cpu_irq + irq_action);
+ if(!action->handler) {
+ printk("Freeing free IRQ %d\n", irq);
+ return;
+ }
+ if(dev_cookie) {
+ for( ; action; action = action->next) {
+ if(action->dev_id == dev_cookie)
+ break;
+ tmp = action;
+ }
+ if(!action) {
+ printk("Trying to free free shared IRQ %d\n", irq);
+ return;
+ }
+ } else if(action->flags & SA_SHIRQ) {
+ printk("Trying to free shared IRQ %d with NULL device cookie\n", irq);
+ return;
+ }
+
+ if(action->flags & SA_STATIC_ALLOC) {
+ printk("Attempt to free statically allocated IRQ %d (%s)\n",
+ irq, action->name);
+ return;
+ }
+
+ save_and_cli(flags);
+ if(action && tmp)
+ tmp->next = action->next;
+ else
+ *(cpu_irq + irq_action) = action->next;
+
+ if(action->flags & SA_SYSIO_MASKED) {
+ unsigned int *imap = irq_to_imap(irq);
+ if(imap != NULL)
+ ivector_to_mask[*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)] = 0;
+ else
+ printk("free_irq: WHeee, SYSIO_MASKED yet no imap reg.\n");
+ }
+
+ kfree(action);
+ if(!*(cpu_irq + irq_action))
+ disable_irq(irq);
+
+ restore_flags(flags);
+}
+
+/* Per-processor IRQ locking depth, both SMP and non-SMP code use this. */
+unsigned int local_irq_count[NR_CPUS];
+atomic_t __sparc64_bh_counter = ATOMIC_INIT(0);
+
+#ifdef __SMP__
+#error SMP not supported on sparc64 just yet
+#else
+
+#define irq_enter(cpu, irq) (local_irq_count[cpu]++)
+#define irq_exit(cpu, irq) (local_irq_count[cpu]--)
+
+#endif /* __SMP__ */
+
+void report_spurious_ivec(struct pt_regs *regs)
+{
+ printk("IVEC: Spurious interrupt vector received at (%016lx)\n",
+ regs->tpc);
+ return;
+}
+
+void unexpected_irq(int irq, void *dev_cookie, struct pt_regs *regs)
+{
+ int i;
+ struct irqaction *action;
+ unsigned int cpu_irq;
+
+ cpu_irq = irq & NR_IRQS;
+ action = *(cpu_irq + irq_action);
+
+ prom_printf("Unexpected IRQ[%d]: ", irq);
+ prom_printf("PC[%016lx] NPC[%016lx] FP[%016lx]\n",
+ regs->tpc, regs->tnpc, regs->u_regs[14]);
+
+ if(action) {
+ prom_printf("Expecting: ");
+ for(i = 0; i < 16; i++) {
+ if(action->handler)
+ prom_printf("[%s:%d:0x%016lx] ", action->name,
+ i, (unsigned long) action->handler);
+ }
+ }
+ prom_printf("AIEEE\n");
+ prom_printf("bogus interrupt received\n");
+ prom_cmdline ();
+}
+
+void handler_irq(int irq, struct pt_regs *regs)
+{
+ struct irqaction *action;
+ int cpu = smp_processor_id();
+
+ /* XXX */
+ if(irq != 14)
+ clear_softint(1 << irq);
+
+ irq_enter(cpu, irq);
+ action = *(irq + irq_action);
+ kstat.interrupts[irq]++;
+ do {
+ if(!action || !action->handler)
+ unexpected_irq(irq, 0, regs);
+ action->handler(irq, action->dev_id, regs);
+ if(action->flags & SA_SYSIO_MASKED)
+ *((unsigned int *)action->mask) = SYSIO_ICLR_IDLE;
+ } while((action = action->next) != NULL);
+ irq_exit(cpu, irq);
+}
+
+#ifdef CONFIG_BLK_DEV_FD
+extern void floppy_interrupt(int irq, void *dev_cookie, struct pt_regs *regs);
+
+void sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs)
+{
+ struct irqaction *action = *(irq + irq_action);
+ int cpu = smp_processor_id();
+
+ irq_enter(cpu, irq);
+ floppy_interrupt(irq, dev_cookie, regs);
+ if(action->flags & SA_SYSIO_MASKED)
+ *((unsigned int *)action->mask) = SYSIO_ICLR_IDLE;
+ irq_exit(cpu, irq);
+}
+#endif
+
+/* XXX This needs to be written for floppy driver, and soon will be necessary
+ * XXX for serial driver as well.
+ */
+int request_fast_irq(unsigned int irq,
+ void (*handler)(int, void *, struct pt_regs *),
+ unsigned long irqflags, const char *name)
+{
+ return -1;
+}
+
+/* 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;
+}
+
+int probe_irq_off(unsigned long mask)
+{
+ return 0;
+}
+
+/* XXX This is a hack, make it per-cpu so that SMP port will work correctly
+ * XXX with mixed MHZ Ultras in the machine. -DaveM
+ */
+static unsigned long cpu_cfreq;
+static unsigned long tick_offset;
+
+/* XXX This doesn't belong here, just do this cruft in the timer.c handler code. */
+static void timer_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+ extern void timer_interrupt(int, void *, struct pt_regs *);
+ unsigned long compare;
+
+ if (!(get_softint () & 1)) {
+ /* Just to be sure... */
+ clear_softint(1 << 14);
+ printk("Spurious level14 at %016lx\n", regs->tpc);
+ return;
+ }
+
+ timer_interrupt(irq, dev_id, regs);
+
+ /* Acknowledge INT_TIMER */
+ clear_softint(1 << 0);
+
+ /* Set up for next timer tick. */
+ __asm__ __volatile__("rd %%tick_cmpr, %0\n\t"
+ "add %0, %1, %0\n\t"
+ "wr %0, 0x0, %%tick_cmpr"
+ : "=r" (compare)
+ : "r" (tick_offset));
+}
+
+/* This is called from time_init() to get the jiffies timer going. */
+void init_timers(void (*cfunc)(int, void *, struct pt_regs *))
+{
+ int node, err;
+
+ /* XXX FIX this for SMP -JJ */
+ node = linux_cpus [0].prom_node;
+ cpu_cfreq = prom_getint(node, "clock-frequency");
+ tick_offset = cpu_cfreq / HZ;
+ err = request_irq(14, timer_handler, (SA_INTERRUPT|SA_STATIC_ALLOC),
+ "timer", NULL);
+ if(err) {
+ prom_printf("Serious problem, cannot register timer interrupt\n");
+ prom_halt();
+ } else {
+ unsigned long flags;
+
+ save_and_cli(flags);
+
+ __asm__ __volatile__("wr %0, 0x0, %%tick_cmpr\n\t"
+ "wrpr %%g0, 0x0, %%tick"
+ : /* No outputs */
+ : "r" (tick_offset));
+
+ clear_softint (get_softint ());
+
+ restore_flags(flags);
+ }
+ sti();
+}
+
+/* We use this nowhere else, so only define it's layout here. */
+struct sun5_timer {
+ volatile u32 count0, _unused0;
+ volatile u32 limit0, _unused1;
+ volatile u32 count1, _unused2;
+ volatile u32 limit1, _unused3;
+} *prom_timers;
+
+static void map_prom_timers(void)
+{
+ unsigned int addr[3];
+ int tnode, err;
+
+ /* PROM timer node hangs out in the top level of device siblings... */
+ tnode = prom_finddevice("/counter-timer");
+
+ /* Assume if node is not present, PROM uses different tick mechanism
+ * which we should not care about.
+ */
+ if(tnode == 0) {
+ prom_timers = (struct sun5_timer *) 0;
+ prom_printf("AIEEE, no timers\n");
+ return;
+ }
+
+ /* If PROM is really using this, it must be mapped by him. */
+ err = prom_getproperty(tnode, "address", (char *)addr, sizeof(addr));
+ if(err == -1) {
+ prom_printf("PROM does not have timer mapped, trying to continue.\n");
+ prom_timers = (struct sun5_timer *) 0;
+ return;
+ }
+ prom_timers = (struct sun5_timer *) addr[0];
+}
+
+static void kill_prom_timer(void)
+{
+ if(!prom_timers)
+ return;
+
+ /* Just as in sun4c/sun4m PROM uses timer which ticks at IRQ 14.
+ * We turn both off here just to be paranoid.
+ */
+ prom_timers->limit0 = 0;
+ prom_timers->limit1 = 0;
+}
+
+#if 0 /* Unused at this time. -DaveM */
+static void enable_prom_timer(void)
+{
+ if(!prom_timers)
+ return;
+
+ /* Set it to fire off every 10ms. */
+ prom_timers->limit1 = 0xa000270f;
+ prom_timers->count1 = 0;
+}
+#endif
+
+__initfunc(void init_IRQ(void))
+{
+ int i;
+
+ map_prom_timers();
+ kill_prom_timer();
+ for(i = 0; i < NUM_IVECS; i++)
+ ivector_to_mask[i] = 0;
+
+ /* We need to clear any IRQ's pending in the soft interrupt
+ * registers, a spurious one could be left around from the
+ * PROM timer which we just disabled.
+ */
+ clear_softint(get_softint());
+
+ /* Now that ivector table is initialized, it is safe
+ * to receive IRQ vector traps. We will normally take
+ * one or two right now, in case some device PROM used
+ * to boot us wants to speak to us. We just ignore them.
+ */
+ __asm__ __volatile__("rdpr %%pstate, %%g1\n\t"
+ "or %%g1, %0, %%g1\n\t"
+ "wrpr %%g1, 0x0, %%pstate"
+ : /* No outputs */
+ : "i" (PSTATE_IE)
+ : "g1");
+}
diff --git a/arch/sparc64/kernel/itlb_miss.S b/arch/sparc64/kernel/itlb_miss.S
new file mode 100644
index 000000000..61233125c
--- /dev/null
+++ b/arch/sparc64/kernel/itlb_miss.S
@@ -0,0 +1,49 @@
+/* $Id: itlb_miss.S,v 1.10 1997/03/26 12:24:18 davem Exp $
+ * itlb_miss.S: Instruction TLB miss code, this is included directly
+ * into the trap table.
+ *
+ * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+/* Gratuitous comment. */
+
+ /* ICACHE line 1 */
+ /*0x00*/ ldxa [%g0] ASI_IMMU, %g1 ! Get TAG_TARGET
+ /*0x04*/ srlx %g1, 8, %g3 ! Position PGD offset
+ /*0x08*/ srlx %g1, 48, %g5 ! Shift down CONTEXT bits
+ /*0x0c*/ and %g3, %g2, %g3 ! Mask PGD offset
+ /*0x10*/ sllx %g1, 2, %g4 ! Position PMD offset
+ /*0x14*/ ldxa [%g0] ASI_IMMU_TSB_8KB_PTR, %g1 ! For PTE offset
+ /*0x18*/ brz,pn %g5, 3f ! Context 0 == kernel
+ /*0x1c*/ and %g4, %g2, %g4 ! Mask PMD offset
+
+ /* ICACHE line 2 */
+ /*0x20*/ ldxa [%g7 + %g3] ASI_PHYS_USE_EC, %g5 ! Load user PGD
+ /*0x24*/ srlx %g1, 1, %g1 ! PTE offset
+ /*0x28*/ ldxa [%g5 + %g4] ASI_PHYS_USE_EC, %g3 ! Load PMD
+2:/*0x2c*/ ldxa [%g3 + %g1] ASI_PHYS_USE_EC, %g5 ! Load PTE
+ /*0x30*/ brlz,a,pt %g5, 1f ! Valid set?
+ /*0x34*/ stxa %g5, [%g0] ASI_ITLB_DATA_IN ! TLB load
+ /*0x38*/ ba,a,pt %xcc, sparc64_itlb_refbit_catch ! Nope...
+1:/*0x3c*/ retry ! Trap return
+
+3: /* ICACHE line 3 */
+ /*0x40*/ ldxa [%g6 + %g3] ASI_PHYS_USE_EC, %g5 ! Load kern PGD
+ /*0x44*/ srlx %g1, 1, %g1 ! PTE offset
+ /*0x48*/ ba,pt %xcc, 2b ! Continue above
+ /*0x4c*/ ldxa [%g5 + %g4] ASI_PHYS_USE_EC, %g3 ! Load PMD
+ /*0x50*/ nop
+ /*0x54*/ nop
+ /*0x58*/ nop
+ /*0x5c*/ nop
+
+ /* ICACHE line 4 */
+ /*0x60*/ nop
+ /*0x64*/ nop
+ /*0x68*/ nop
+ /*0x6c*/ nop
+ /*0x70*/ nop
+ /*0x74*/ nop
+ /*0x78*/ nop
+ /*0x7c*/ nop
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
new file mode 100644
index 000000000..5ec62a6b6
--- /dev/null
+++ b/arch/sparc64/kernel/process.c
@@ -0,0 +1,594 @@
+/* $Id: process.c,v 1.6 1997/04/07 18:57:07 jj Exp $
+ * arch/sparc64/kernel/process.c
+ *
+ * Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+/*
+ * This file handles the architecture-dependent parts of process handling..
+ */
+
+#define __KERNEL_SYSCALLS__
+#include <stdarg.h>
+
+#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/malloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/config.h>
+#include <linux/reboot.h>
+
+#include <asm/oplib.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/delay.h>
+#include <asm/processor.h>
+#include <asm/pstate.h>
+#include <asm/elf.h>
+#include <asm/fpumacro.h>
+
+#ifndef __SMP__
+
+/*
+ * the idle loop on a Sparc... ;)
+ */
+asmlinkage int sys_idle(void)
+{
+ if (current->pid != 0)
+ return -EPERM;
+
+ /* endless idle loop with no priority at all */
+ current->counter = -100;
+ for (;;)
+ schedule();
+ return 0;
+}
+
+#else
+
+/*
+ * the idle loop on a UltraMultiPenguin...
+ */
+asmlinkage int sys_idle(void)
+{
+ if (current->pid != 0)
+ return -EPERM;
+
+ /* endless idle loop with no priority at all */
+ current->counter = -100;
+ schedule();
+ return 0;
+}
+
+/* This is being executed in task 0 'user space'. */
+int cpu_idle(void *unused)
+{
+ volatile int *spap = &smp_process_available;
+ volatile int cval;
+
+ while(1) {
+ if(0==*spap)
+ continue;
+ cli();
+ /* Acquire exclusive access. */
+ while((cval = smp_swap(spap, -1)) == -1)
+ while(*spap == -1)
+ ;
+ if (0==cval) {
+ /* ho hum, release it. */
+ *spap = 0;
+ sti();
+ continue;
+ }
+ /* Something interesting happened, whee... */
+ *spap = (cval - 1);
+ sti();
+ idle();
+ }
+}
+
+#endif
+
+extern char reboot_command [];
+
+#ifdef CONFIG_SUN_CONSOLE
+extern void console_restore_palette (void);
+extern int serial_console;
+#endif
+
+void machine_halt(void)
+{
+ sti();
+ udelay(8000);
+ cli();
+#ifdef CONFIG_SUN_CONSOLE
+ if (!serial_console)
+ console_restore_palette ();
+#endif
+ prom_halt();
+ panic("Halt failed!");
+}
+
+void machine_restart(char * cmd)
+{
+ char *p;
+
+ sti();
+ udelay(8000);
+ cli();
+
+ p = strchr (reboot_command, '\n');
+ if (p) *p = 0;
+#ifdef CONFIG_SUN_CONSOLE
+ if (!serial_console)
+ console_restore_palette ();
+#endif
+ if (cmd)
+ prom_reboot(cmd);
+ if (*reboot_command)
+ prom_reboot(reboot_command);
+ prom_feval ("reset");
+ panic("Reboot failed!");
+}
+
+void machine_power_off(void)
+{
+ machine_halt();
+}
+
+void show_regwindow(struct reg_window *rw)
+{
+ printk("l0: %016lx l1: %016lx l2: %016lx l3: %016lx\n",
+ rw->locals[0], rw->locals[1], rw->locals[2], rw->locals[3]);
+ printk("l4: %016lx l5: %016lx l6: %016lx l7: %016lx\n",
+ rw->locals[4], rw->locals[5], rw->locals[6], rw->locals[7]);
+ printk("i0: %016lx i1: %016lx i2: %016lx i3: %016lx\n",
+ rw->ins[0], rw->ins[1], rw->ins[2], rw->ins[3]);
+ printk("i4: %016lx i5: %016lx i6: %016lx i7: %016lx\n",
+ rw->ins[4], rw->ins[5], rw->ins[6], rw->ins[7]);
+}
+
+void show_regwindow32(struct reg_window32 *rw)
+{
+ printk("l0: %08x l1: %08x l2: %08x l3: %08x\n"
+ "l4: %08x l5: %08x l6: %08x l7: %08x\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("i0: %08x i1: %08x i2: %08x i3: %08x\n"
+ "i4: %08x i5: %08x i6: %08x i7: %08x\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]);
+}
+
+void show_stackframe(struct sparc_stackf *sf)
+{
+ unsigned long size;
+ unsigned long *stk;
+ int i;
+
+ printk("l0: %016lx l1: %016lx l2: %016lx l3: %016lx\n"
+ "l4: %016lx l5: %016lx l6: %016lx l7: %016lx\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: %016lx i1: %016lx i2: %016lx i3: %016lx\n"
+ "i4: %016lx i5: %016lx fp: %016lx ret_pc: %016lx\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: %016lx x0: %016lx x1: %016lx x2: %016lx\n"
+ "x3: %016lx x4: %016lx x5: %016lx xx: %016lx\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: %016lx\n", i++, *stk++);
+ } while ((size -= sizeof(unsigned long)));
+}
+
+void show_stackframe32(struct sparc_stackf32 *sf)
+{
+ unsigned long size;
+ unsigned *stk;
+ int i;
+
+ printk("l0: %08x l1: %08x l2: %08x l3: %08x\n",
+ sf->locals[0], sf->locals[1], sf->locals[2], sf->locals[3]);
+ printk("l4: %08x l5: %08x l6: %08x l7: %08x\n",
+ sf->locals[4], sf->locals[5], sf->locals[6], sf->locals[7]);
+ printk("i0: %08x i1: %08x i2: %08x i3: %08x\n",
+ sf->ins[0], sf->ins[1], sf->ins[2], sf->ins[3]);
+ printk("i4: %08x i5: %08x fp: %08x ret_pc: %08x\n",
+ sf->ins[4], sf->ins[5], sf->fp, sf->callers_pc);
+ printk("sp: %08x x0: %08x x1: %08x x2: %08x\n"
+ "x3: %08x x4: %08x x5: %08x xx: %08x\n",
+ 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 -= STACKFRAME32_SZ;
+ stk = (unsigned *)((unsigned long)sf + STACKFRAME32_SZ);
+ i = 0;
+ do {
+ printk("s%d: %08x\n", i++, *stk++);
+ } while ((size -= sizeof(unsigned)));
+}
+
+void show_regs(struct pt_regs * regs)
+{
+#if __MPP__
+ printk("CID: %d\n",mpp_cid());
+#endif
+ printk("TSTATE: %016lx TPC: %016lx TNPC: %016lx Y: %016lx\n", regs->tstate,
+ regs->tpc, regs->tnpc, regs->y);
+ printk("g0: %016lx g1: %016lx g2: %016lx g3: %016lx\n",
+ regs->u_regs[0], regs->u_regs[1], regs->u_regs[2],
+ regs->u_regs[3]);
+ printk("g4: %016lx g5: %016lx g6: %016lx g7: %016lx\n",
+ regs->u_regs[4], regs->u_regs[5], regs->u_regs[6],
+ regs->u_regs[7]);
+ printk("o0: %016lx o1: %016lx o2: %016lx o3: %016lx\n",
+ regs->u_regs[8], regs->u_regs[9], regs->u_regs[10],
+ regs->u_regs[11]);
+ printk("o4: %016lx o5: %016lx sp: %016lx ret_pc: %016lx\n",
+ regs->u_regs[12], regs->u_regs[13], regs->u_regs[14],
+ regs->u_regs[15]);
+#if 0
+ show_regwindow((struct reg_window *)(regs->u_regs[14] + STACK_BIAS));
+#endif
+}
+
+void show_regs32(struct pt_regs32 *regs)
+{
+#if __MPP__
+ printk("CID: %d\n",mpp_cid());
+#endif
+ printk("PSR: %08x PC: %08x NPC: %08x Y: %08x\n", regs->psr,
+ regs->pc, regs->npc, regs->y);
+ printk("g0: %08x g1: %08x g2: %08x g3: %08x\n",
+ regs->u_regs[0], regs->u_regs[1], regs->u_regs[2],
+ regs->u_regs[3]);
+ printk("g4: %08x g5: %08x g6: %08x g7: %08x\n",
+ regs->u_regs[4], regs->u_regs[5], regs->u_regs[6],
+ regs->u_regs[7]);
+ printk("o0: %08x o1: %08x o2: %08x o3: %08x\n",
+ regs->u_regs[8], regs->u_regs[9], regs->u_regs[10],
+ regs->u_regs[11]);
+ printk("o4: %08x o5: %08x sp: %08x ret_pc: %08x\n",
+ regs->u_regs[12], regs->u_regs[13], regs->u_regs[14],
+ regs->u_regs[15]);
+ show_regwindow32((struct reg_window32 *)((unsigned long)regs->u_regs[14]));
+}
+
+void show_thread(struct thread_struct *tss)
+{
+ int i;
+
+#if 0
+ printk("kregs: 0x%016lx\n", (unsigned long)tss->kregs);
+ show_regs(tss->kregs);
+#endif
+ printk("sig_address: 0x%016lx\n", tss->sig_address);
+ printk("sig_desc: 0x%016lx\n", tss->sig_desc);
+ printk("ksp: 0x%016lx\n", tss->ksp);
+ printk("kpc: 0x%016lx\n", tss->kpc);
+
+ for (i = 0; i < NSWINS; i++) {
+ if (!tss->rwbuf_stkptrs[i])
+ continue;
+ printk("reg_window[%d]:\n", i);
+ printk("stack ptr: 0x%016lx\n", tss->rwbuf_stkptrs[i]);
+ show_regwindow(&tss->reg_window[i]);
+ }
+ printk("w_saved: 0x%08lx\n", tss->w_saved);
+
+ /* XXX missing: float_regs */
+ printk("fsr: 0x%016lx\n", tss->fsr);
+
+ printk("sstk_info.stack: 0x%016lx\n",
+ (unsigned long)tss->sstk_info.the_stack);
+ printk("sstk_info.status: 0x%016lx\n",
+ (unsigned long)tss->sstk_info.cur_status);
+ printk("flags: 0x%016lx\n", tss->flags);
+ printk("current_ds: 0x%016x\n", tss->current_ds);
+
+ /* XXX missing: core_exec */
+}
+
+/*
+ * Free current thread data structures etc..
+ */
+void exit_thread(void)
+{
+#ifndef __SMP__
+ if(last_task_used_math == current) {
+#else
+ if(current->flags & PF_USEDFPU) {
+#endif
+#ifndef __SMP__
+ last_task_used_math = NULL;
+#else
+ current->flags &= ~PF_USEDFPU;
+#endif
+ }
+}
+
+void flush_thread(void)
+{
+ current->tss.w_saved = 0;
+ current->tss.sstk_info.cur_status = 0;
+ current->tss.sstk_info.the_stack = 0;
+
+ /* No new signal delivery by default */
+ current->tss.new_signal = 0;
+#ifndef __SMP__
+ if(last_task_used_math == current) {
+#else
+ if(current->flags & PF_USEDFPU) {
+#endif
+#ifndef __SMP__
+ last_task_used_math = NULL;
+#else
+ current->flags &= ~PF_USEDFPU;
+#endif
+ }
+
+ /* Now, this task is no longer a kernel thread. */
+ current->tss.flags &= ~SPARC_FLAG_KTHREAD;
+ current->tss.current_ds = USER_DS;
+}
+
+static __inline__ void copy_regs(struct pt_regs *dst, struct pt_regs *src)
+{
+ __asm__ __volatile__("ldd\t[%1 + 0x00], %%g2\n\t"
+ "ldd\t[%1 + 0x08], %%g4\n\t"
+ "ldd\t[%1 + 0x10], %%o4\n\t"
+ "std\t%%g2, [%0 + 0x00]\n\t"
+ "std\t%%g4, [%0 + 0x08]\n\t"
+ "std\t%%o4, [%0 + 0x10]\n\t"
+ "ldd\t[%1 + 0x18], %%g2\n\t"
+ "ldd\t[%1 + 0x20], %%g4\n\t"
+ "ldd\t[%1 + 0x28], %%o4\n\t"
+ "std\t%%g2, [%0 + 0x18]\n\t"
+ "std\t%%g4, [%0 + 0x20]\n\t"
+ "std\t%%o4, [%0 + 0x28]\n\t"
+ "ldd\t[%1 + 0x30], %%g2\n\t"
+ "ldd\t[%1 + 0x38], %%g4\n\t"
+ "ldd\t[%1 + 0x40], %%o4\n\t"
+ "std\t%%g2, [%0 + 0x30]\n\t"
+ "std\t%%g4, [%0 + 0x38]\n\t"
+ "ldd\t[%1 + 0x48], %%g2\n\t"
+ "std\t%%o4, [%0 + 0x40]\n\t"
+ "std\t%%g2, [%0 + 0x48]\n\t" : :
+ "r" (dst), "r" (src) :
+ "g2", "g3", "g4", "g5", "o4", "o5");
+}
+
+static __inline__ void copy_regwin(struct reg_window *dst, struct reg_window *src)
+{
+ __asm__ __volatile__("ldd\t[%1 + 0x00], %%g2\n\t"
+ "ldd\t[%1 + 0x08], %%g4\n\t"
+ "ldd\t[%1 + 0x10], %%o4\n\t"
+ "std\t%%g2, [%0 + 0x00]\n\t"
+ "std\t%%g4, [%0 + 0x08]\n\t"
+ "std\t%%o4, [%0 + 0x10]\n\t"
+ "ldd\t[%1 + 0x18], %%g2\n\t"
+ "ldd\t[%1 + 0x20], %%g4\n\t"
+ "ldd\t[%1 + 0x28], %%o4\n\t"
+ "std\t%%g2, [%0 + 0x18]\n\t"
+ "std\t%%g4, [%0 + 0x20]\n\t"
+ "std\t%%o4, [%0 + 0x28]\n\t"
+ "ldd\t[%1 + 0x30], %%g2\n\t"
+ "ldd\t[%1 + 0x38], %%g4\n\t"
+ "std\t%%g2, [%0 + 0x30]\n\t"
+ "std\t%%g4, [%0 + 0x38]\n\t" : :
+ "r" (dst), "r" (src) :
+ "g2", "g3", "g4", "g5", "o4", "o5");
+}
+
+static __inline__ struct sparc_stackf *
+clone_stackframe(struct sparc_stackf *dst, struct sparc_stackf *src)
+{
+ struct sparc_stackf *sp;
+
+#if 0
+ unsigned long size;
+ size = ((unsigned long)src->fp) - ((unsigned long)src);
+ sp = (struct sparc_stackf *)(((unsigned long)dst) - size);
+
+ if (copy_to_user(sp, src, size))
+ return 0;
+ if (put_user(dst, &sp->fp))
+ return 0;
+#endif
+ return sp;
+}
+
+
+/* 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().
+ */
+extern void ret_from_syscall(void);
+
+int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
+ struct task_struct *p, struct pt_regs *regs)
+{
+ struct pt_regs *childregs;
+ struct reg_window *new_stack, *old_stack;
+ unsigned long stack_offset;
+
+#if 0
+#ifndef __SMP__
+ if(last_task_used_math == current) {
+#else
+ if(current->flags & PF_USEDFPU) {
+#endif
+ put_psr(get_psr() | PSR_EF);
+ fpsave(&p->tss.float_regs[0], &p->tss.fsr);
+#ifdef __SMP__
+ current->flags &= ~PF_USEDFPU;
+#endif
+ }
+#endif
+
+ /* Calculate offset to stack_frame & pt_regs */
+ stack_offset = (PAGE_SIZE - TRACEREG_SZ);
+
+ if(regs->tstate & TSTATE_PRIV)
+ stack_offset -= REGWIN_SZ;
+
+ childregs = ((struct pt_regs *) (p->kernel_stack_page + stack_offset));
+ *childregs = *regs;
+ new_stack = (((struct reg_window *) childregs) - 1);
+ old_stack = (((struct reg_window *) regs) - 1);
+ *new_stack = *old_stack;
+
+ p->saved_kernel_stack = ((unsigned long) new_stack);
+ p->tss.ksp = p->saved_kernel_stack - STACK_BIAS;
+ p->tss.kpc = ((unsigned long) ret_from_syscall) - 0x8;
+ p->tss.kregs = childregs;
+
+ /* Don't look... */
+ p->tss.cwp = regs->u_regs[UREG_G0];
+
+ /* tss.wstate was copied by do_fork() */
+
+ if(regs->tstate & TSTATE_PRIV) {
+ childregs->u_regs[UREG_FP] = p->tss.ksp;
+ p->tss.flags |= SPARC_FLAG_KTHREAD;
+ p->tss.current_ds = KERNEL_DS;
+ childregs->u_regs[UREG_G6] = (unsigned long) p;
+ } else {
+ childregs->u_regs[UREG_FP] = sp;
+ p->tss.flags &= ~SPARC_FLAG_KTHREAD;
+ p->tss.current_ds = USER_DS;
+
+#if 0
+ if (sp != current->tss.kregs->u_regs[UREG_FP]) {
+ struct sparc_stackf *childstack;
+ struct sparc_stackf *parentstack;
+
+ /*
+ * This is a clone() call with supplied user stack.
+ * Set some valid stack frames to give to the child.
+ */
+ childstack = (struct sparc_stackf *)sp;
+ parentstack = (struct sparc_stackf *)
+ current->tss.kregs->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;
+ }
+#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 0
+ printk("CHILD register dump\n");
+ show_regs(childregs);
+ show_regwindow(new_stack);
+ while(1)
+ barrier();
+#endif
+ return 0;
+}
+
+/*
+ * fill in the user structure for a core dump..
+ */
+void dump_thread(struct pt_regs * regs, struct user * dump)
+{
+#if 0
+ unsigned long first_stack_page;
+ dump->magic = SUNOS_CORE_MAGIC;
+ dump->len = sizeof(struct user);
+ dump->regs.psr = regs->psr;
+ dump->regs.pc = regs->pc;
+ dump->regs.npc = regs->npc;
+ dump->regs.y = regs->y;
+ /* fuck me plenty */
+ memcpy(&dump->regs.regs[0], &regs->u_regs[1], (sizeof(unsigned long) * 15));
+ dump->uexec = current->tss.core_exec;
+ dump->u_tsize = (((unsigned long) current->mm->end_code) -
+ ((unsigned long) current->mm->start_code)) & ~(PAGE_SIZE - 1);
+ dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1)));
+ dump->u_dsize -= dump->u_tsize;
+ dump->u_dsize &= ~(PAGE_SIZE - 1);
+ first_stack_page = (regs->u_regs[UREG_FP] & ~(PAGE_SIZE - 1));
+ dump->u_ssize = (TASK_SIZE - first_stack_page) & ~(PAGE_SIZE - 1);
+ memcpy(&dump->fpu.fpstatus.fregs.regs[0], &current->tss.float_regs[0], (sizeof(unsigned long) * 32));
+ dump->fpu.fpstatus.fsr = current->tss.fsr;
+ dump->fpu.fpstatus.flags = dump->fpu.fpstatus.extra = 0;
+ dump->sigcode = current->tss.sig_desc;
+#endif
+}
+
+/*
+ * fill in the fpu structure for a core dump.
+ */
+int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs)
+{
+ /* Currently we report that we couldn't dump the fpu structure */
+ return 0;
+}
+
+/*
+ * 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;
+
+ error = getname((char *) regs->u_regs[base + UREG_I0], &filename);
+ if(error)
+ return error;
+ error = do_execve(filename, (char **) regs->u_regs[base + UREG_I1],
+ (char **) regs->u_regs[base + UREG_I2], regs);
+ putname(filename);
+ return error;
+}
diff --git a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S
new file mode 100644
index 000000000..dfebd7ad8
--- /dev/null
+++ b/arch/sparc64/kernel/rtrap.S
@@ -0,0 +1,109 @@
+/* $Id: rtrap.S,v 1.11 1997/04/03 13:03:50 davem Exp $
+ * rtrap.S: Preparing for return from trap on Sparc V9.
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/asi.h>
+#include <asm/pstate.h>
+#include <asm/ptrace.h>
+#include <asm/spitfire.h>
+
+/* We assume here this is entered with AG, MG and IG bits in pstate clear */
+
+ .text
+ .align 4
+ .globl rtrap
+rtrap:
+ sethi %hi(bh_active), %l2
+ or %l2, %lo(bh_active), %l2
+ sethi %hi(bh_mask), %l1
+ or %l1, %lo(bh_mask), %l1
+ ldx [%l2 + %g4], %l3
+ ldx [%l1 + %g4], %l4
+ andcc %l3, %l4, %g0
+ be,pt %xcc, 2f
+ nop
+ call do_bottom_half
+ nop
+2:
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %l1
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC], %l2
+ sethi %hi(0xf << 20), %l4
+ andcc %l1, TSTATE_PRIV, %l3
+ and %l1, %l4, %l4
+ rdpr %pstate, %l7
+ andn %l1, %l4, %l1 /* XXX May not be needed -DaveM */
+ be,pt %icc, to_user
+ andn %l7, PSTATE_IE, %l7
+3:
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1], %g1
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2], %g2
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3], %g3
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4], %g4
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5], %g5
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6], %g6
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7], %g7
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %i0
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1], %i1
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2], %i2
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3], %i3
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4], %i4
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5], %i5
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6], %i6
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7], %i7
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_Y], %o3
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %o2
+ rdpr %tl, %o4
+ wr %o3, %g0, %y
+ add %o4, 1, %o4
+
+ srl %l4, 20, %l4
+ wrpr %l7, %g0, %pstate
+ wrpr %l4, 0x0, %pil
+ wrpr %o4, %g0, %tl
+ wrpr %l1, %g0, %tstate
+ wrpr %l2, %g0, %tpc
+ brnz,pn %l3, 1f
+ wrpr %o2, %g0, %tnpc
+
+ /* We came here from to_user, ie. we have now AG.
+ * Also have to push user context back into primary.
+ */
+ restore
+
+ mov SECONDARY_CONTEXT, %g6
+ mov PRIMARY_CONTEXT, %g7
+ ldxa [%g6] ASI_DMMU, %g4
+ stxa %g4, [%g7] ASI_DMMU
+
+ rdpr %wstate, %g1
+ rdpr %otherwin, %g2
+ srl %g1, 3, %g1
+ wrpr %g2, %g0, %canrestore
+ wrpr %g1, %g0, %wstate
+ wrpr %g0, %g0, %otherwin
+ retry
+1:
+ restore
+ retry
+to_user:
+ sethi %hi(need_resched), %l0
+ or %l0, %lo(need_resched), %l0
+ ld [%l0 + %g4], %l0
+ wrpr %l7, PSTATE_IE, %pstate
+ brz,pt %l0, 1f
+ ldx [%g6 + AOFF_task_signal], %l0
+ call schedule
+ nop
+1:
+ ldx [%g6 + AOFF_task_blocked], %o0
+ or %l7, PSTATE_AG, %l7 ! Will need this for setting back wstate
+ andncc %l0, %o0, %g0
+ be,pt %xcc, 3b
+ mov %l5, %o2
+ mov %l6, %o3
+ add %sp, STACK_BIAS + REGWIN_SZ, %o1
+ call do_signal
+ add %o7, 3b-.-4, %o7
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
new file mode 100644
index 000000000..170e5563e
--- /dev/null
+++ b/arch/sparc64/kernel/setup.c
@@ -0,0 +1,435 @@
+/* $Id: setup.c,v 1.5 1997/04/04 00:49:52 davem Exp $
+ * linux/arch/sparc64/kernel/setup.c
+ *
+ * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#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/malloc.h>
+#include <asm/smp.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/delay.h>
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+#include <linux/init.h>
+
+#include <asm/segment.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/idprom.h>
+
+struct screen_info screen_info = {
+ 0, 0, /* orig-x, orig-y */
+ { 0, 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 */
+};
+
+unsigned int phys_bytes_of_ram, end_of_phys_memory;
+
+unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end)
+{
+ return memory_start;
+}
+
+/* Typing sync at the prom prompt calls the function pointed to by
+ * the sync callback 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 sparc64_ttable_tl0;
+extern void breakpoint(void);
+#if CONFIG_SUN_CONSOLE
+extern void console_restore_palette(void);
+#endif
+asmlinkage void sys_sync(void); /* it's really int */
+
+/* Pretty sick eh? */
+void prom_sync_me(long *args)
+{
+ unsigned long prom_tba, flags;
+
+ save_and_cli(flags);
+ __asm__ __volatile__("flushw; rdpr %%tba, %0\n\t" : "=r" (prom_tba));
+ __asm__ __volatile__("wrpr %0, 0x0, %%tba\n\t" : : "r" (&sparc64_ttable_tl0));
+
+#ifdef CONFIG_SUN_CONSOLE
+ console_restore_palette ();
+#endif
+ prom_printf("PROM SYNC COMMAND...\n");
+ show_free_areas();
+ if(current->pid != 0) {
+ sti();
+ sys_sync();
+ cli();
+ }
+ prom_printf("Returning to prom\n");
+
+ __asm__ __volatile__("flushw; wrpr %0, 0x0, %%tba\n\t" : : "r" (prom_tba));
+ restore_flags(flags);
+
+ return;
+}
+
+extern void rs_kgdb_hook(int tty_num); /* sparc/serial.c */
+
+unsigned int boot_flags = 0;
+#define BOOTME_DEBUG 0x1
+#define BOOTME_SINGLE 0x2
+#define BOOTME_KGDB 0x4
+
+#ifdef CONFIG_SUN_CONSOLE
+extern char *console_fb_path;
+static int console_fb = 0;
+#endif
+static unsigned long memory_size = 0;
+
+void kernel_enter_debugger(void)
+{
+#if 0
+ if (boot_flags & BOOTME_KGDB) {
+ printk("KGDB: Entered\n");
+ breakpoint();
+ }
+#endif
+}
+
+int obp_system_intr(void)
+{
+ if (boot_flags & BOOTME_KGDB) {
+ printk("KGDB: system interrupted\n");
+ breakpoint();
+ return 1;
+ }
+ if (boot_flags & BOOTME_DEBUG) {
+ printk("OBP: system interrupted\n");
+ prom_halt();
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Process kernel command line switches that are specific to the
+ * SPARC or that require special low-level processing.
+ */
+__initfunc(static void process_switch(char c))
+{
+ switch (c) {
+ case 'd':
+ boot_flags |= BOOTME_DEBUG;
+ break;
+ case 's':
+ boot_flags |= BOOTME_SINGLE;
+ break;
+ case 'h':
+ prom_printf("boot_flags_init: Halt!\n");
+ halt();
+ break;
+ default:
+ printk("Unknown boot switch (-%c)\n", c);
+ break;
+ }
+}
+
+__initfunc(static void 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;
+ else if (*commands == '-') {
+ commands++;
+ while (*commands && *commands != ' ')
+ process_switch(*commands++);
+ } else if (strlen(commands) >= 9
+ && !strncmp(commands, "kgdb=tty", 8)) {
+ boot_flags |= BOOTME_KGDB;
+ switch (commands[8]) {
+#ifdef CONFIG_SUN_SERIAL
+ case 'a':
+ rs_kgdb_hook(0);
+ prom_printf("KGDB: Using serial line /dev/ttya.\n");
+ break;
+ case 'b':
+ rs_kgdb_hook(1);
+ prom_printf("KGDB: Using serial line /dev/ttyb.\n");
+ break;
+#endif
+ default:
+ printk("KGDB: Unknown tty line.\n");
+ boot_flags &= ~BOOTME_KGDB;
+ break;
+ }
+ commands += 9;
+ } else {
+#if CONFIG_SUN_CONSOLE
+ if (!strncmp(commands, "console=", 8)) {
+ commands += 8;
+ if (!strncmp (commands, "ttya", 4)) {
+ console_fb = 2;
+ prom_printf ("Using /dev/ttya as console.\n");
+ } else if (!strncmp (commands, "ttyb", 4)) {
+ console_fb = 3;
+ prom_printf ("Using /dev/ttyb as console.\n");
+ } else {
+ console_fb = 1;
+ console_fb_path = commands;
+ }
+ } else
+#endif
+ if (!strncmp(commands, "mem=", 4)) {
+ /*
+ * "mem=XXX[kKmM]" overrides the PROM-reported
+ * memory size.
+ */
+ memory_size = simple_strtoul(commands + 4,
+ &commands, 0);
+ if (*commands == 'K' || *commands == 'k') {
+ memory_size <<= 10;
+ commands++;
+ } else if (*commands=='M' || *commands=='m') {
+ memory_size <<= 20;
+ commands++;
+ }
+ }
+ while (*commands && *commands != ' ')
+ commands++;
+ }
+ }
+}
+
+extern int prom_probe_memory(void);
+extern unsigned long start, end;
+extern void panic_setup(char *, int *);
+extern unsigned long sun_serial_setup(unsigned long);
+
+extern unsigned short root_flags;
+extern unsigned short root_dev;
+extern unsigned short ram_flags;
+extern unsigned ramdisk_image;
+extern unsigned ramdisk_size;
+#define RAMDISK_IMAGE_START_MASK 0x07FF
+#define RAMDISK_PROMPT_FLAG 0x8000
+#define RAMDISK_LOAD_FLAG 0x4000
+
+extern int root_mountflags;
+
+extern void register_console(void (*proc)(const char *));
+
+char saved_command_line[256];
+char reboot_command[256];
+
+unsigned long phys_base;
+
+static struct pt_regs fake_swapper_regs = { { 0, }, 0, 0, 0, 0 };
+
+__initfunc(void setup_arch(char **cmdline_p,
+ unsigned long * memory_start_p, unsigned long * memory_end_p))
+{
+ unsigned long lowest_paddr;
+ int total, i;
+
+ /* Initialize PROM console and command line. */
+ *cmdline_p = prom_getbootargs();
+ strcpy(saved_command_line, *cmdline_p);
+
+ printk("ARCH: SUN4U\n");
+
+ boot_flags_init(*cmdline_p);
+#if 0
+ if((boot_flags&BOOTME_DEBUG) && (linux_dbvec!=0) &&
+ ((*(short *)linux_dbvec) != -1)) {
+ printk("Booted under KADB. Syncing trap table.\n");
+ (*(linux_dbvec->teach_debugger))();
+ }
+ if((boot_flags & BOOTME_KGDB)) {
+ set_debug_traps();
+ prom_printf ("Breakpoint!\n");
+ breakpoint();
+ }
+#endif
+
+ idprom_init();
+ total = prom_probe_memory();
+
+ lowest_paddr = 0xffffffffffffffffUL;
+ for(i=0; sp_banks[i].num_bytes != 0; i++) {
+ if(sp_banks[i].base_addr < lowest_paddr)
+ lowest_paddr = sp_banks[i].base_addr;
+ end_of_phys_memory = sp_banks[i].base_addr +
+ sp_banks[i].num_bytes;
+ if (memory_size) {
+ if (end_of_phys_memory > memory_size) {
+ sp_banks[i].num_bytes -=
+ (end_of_phys_memory - memory_size);
+ end_of_phys_memory = memory_size;
+ sp_banks[++i].base_addr = 0xdeadbeef;
+ sp_banks[i].num_bytes = 0;
+ }
+ }
+ }
+ prom_setsync(prom_sync_me);
+
+ /* In paging_init() we tip off this value to see if we need
+ * to change init_mm.pgd to point to the real alias mapping.
+ */
+ phys_base = lowest_paddr;
+
+ *memory_start_p = PAGE_ALIGN(((unsigned long) &end));
+ *memory_end_p = (end_of_phys_memory + PAGE_OFFSET);
+
+#ifndef NO_DAVEM_DEBUGGING
+ prom_printf("phys_base[%016lx] memory_start[%016lx] memory_end[%016lx]\n",
+ phys_base, *memory_start_p, *memory_end_p);
+#endif
+
+ if (!root_flags)
+ root_mountflags &= ~MS_RDONLY;
+ ROOT_DEV = to_kdev_t(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
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (ramdisk_image) {
+ initrd_start = ramdisk_image;
+ if (initrd_start < PAGE_OFFSET) initrd_start += PAGE_OFFSET;
+ initrd_end = initrd_start + ramdisk_size;
+ if (initrd_end > *memory_end_p) {
+ printk(KERN_CRIT "initrd extends beyond end of memory "
+ "(0x%016lx > 0x%016lx)\ndisabling initrd\n",
+ initrd_end,*memory_end_p);
+ initrd_start = 0;
+ }
+ if (initrd_start >= *memory_start_p && initrd_start < *memory_start_p + 2 * PAGE_SIZE) {
+ initrd_below_start_ok = 1;
+ *memory_start_p = PAGE_ALIGN (initrd_end);
+ }
+ }
+#endif
+
+ /* Due to stack alignment restrictions and assumptions... */
+ init_task.mm->mmap->vm_page_prot = PAGE_SHARED;
+ init_task.mm->mmap->vm_start = PAGE_OFFSET;
+ init_task.mm->mmap->vm_end = *memory_end_p;
+ init_task.mm->context = (unsigned long) NO_CONTEXT;
+ init_task.tss.kregs = &fake_swapper_regs;
+
+#ifdef CONFIG_SUN_SERIAL
+ *memory_start_p = sun_serial_setup(*memory_start_p); /* set this up ASAP */
+#endif
+ {
+ extern int serial_console; /* in console.c, of course */
+#if !CONFIG_SUN_SERIAL
+ serial_console = 0;
+#else
+ switch (console_fb) {
+ case 0: /* Let's get our io devices from prom */
+ {
+ int idev = prom_query_input_device();
+ int odev = prom_query_output_device();
+ if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) {
+ serial_console = 0;
+ } else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) {
+ serial_console = 1;
+ } else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) {
+ serial_console = 2;
+ } else {
+ prom_printf("Inconsistent console\n");
+ prom_halt();
+ }
+ }
+ break;
+ case 1: serial_console = 0; break; /* Force one of the framebuffers as console */
+ case 2: serial_console = 1; break; /* Force ttya as console */
+ case 3: serial_console = 2; break; /* Force ttyb as console */
+ }
+#endif
+ }
+}
+
+asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
+{
+ return -EIO;
+}
+
+/* BUFFER is PAGE_SIZE bytes long. */
+
+extern char *sparc_cpu_type[];
+extern char *sparc_fpu_type[];
+
+extern char *smp_info(void);
+extern char *mmu_info(void);
+
+int get_cpuinfo(char *buffer)
+{
+ int cpuid=get_cpuid();
+
+ return sprintf(buffer, "cpu\t\t: %s\n"
+ "fpu\t\t: %s\n"
+ "promlib\t\t: Version 3 Revision %d\n"
+ "prom\t\t: %d.%d.%d\n"
+ "type\t\t: sun4u\n"
+ "ncpus probed\t: %d\n"
+ "ncpus active\t: %d\n"
+#ifndef __SMP__
+ "BogoMips\t: %lu.%02lu\n"
+#else
+ "Cpu0Bogo\t: %lu.%02lu\n"
+ "Cpu1Bogo\t: %lu.%02lu\n"
+ "Cpu2Bogo\t: %lu.%02lu\n"
+ "Cpu3Bogo\t: %lu.%02lu\n"
+#endif
+ "%s"
+#ifdef __SMP__
+ "%s"
+#endif
+ ,
+ sparc_cpu_type[cpuid],
+ sparc_fpu_type[cpuid],
+ prom_rev, prom_prev >> 16, (prom_prev >> 8) & 0xff, prom_prev & 0xff,
+ linux_num_cpus, smp_num_cpus,
+#ifndef __SMP__
+ loops_per_sec/500000, (loops_per_sec/5000) % 100,
+#else
+ cpu_data[0].udelay_val/500000, (cpu_data[0].udelay_val/5000)%100,
+ cpu_data[1].udelay_val/500000, (cpu_data[1].udelay_val/5000)%100,
+ cpu_data[2].udelay_val/500000, (cpu_data[2].udelay_val/5000)%100,
+ cpu_data[3].udelay_val/500000, (cpu_data[3].udelay_val/5000)%100,
+#endif
+ mmu_info()
+#ifdef __SMP__
+ , smp_info()
+#endif
+ );
+
+}
diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
new file mode 100644
index 000000000..e1129dfd6
--- /dev/null
+++ b/arch/sparc64/kernel/signal32.c
@@ -0,0 +1,806 @@
+/* $Id: signal32.c,v 1.6 1997/04/16 10:27:17 jj Exp $
+ * arch/sparc64/kernel/signal32.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)
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#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 <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <asm/ptrace.h>
+#include <asm/svr4.h>
+#include <asm/pgtable.h>
+#include <asm/psrcompat.h>
+#include <asm/fpumacro.h>
+#include <asm/smp_lock.h>
+
+#define _S(nr) (1<<((nr)-1))
+
+#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
+
+#define synchronize_user_stack() do { } while (0)
+
+asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr,
+ int options, unsigned long *ru);
+
+asmlinkage int do_signal32(unsigned long oldmask, struct pt_regs * regs,
+ unsigned long orig_o0, int ret_from_syscall);
+
+/* This turned off for production... */
+/* #define DEBUG_SIGNALS 1 */
+
+/* Signal frames: the original one (compatible with SunOS):
+ *
+ * Set up a signal frame... Make the stack look the way SunOS
+ * expects it to look which is basically:
+ *
+ * ---------------------------------- <-- %sp at signal time
+ * Struct sigcontext
+ * Signal address
+ * Ptr to sigcontext area above
+ * Signal code
+ * The signal number itself
+ * One register window
+ * ---------------------------------- <-- New %sp
+ */
+struct signal_sframe32 {
+ struct reg_window32 sig_window;
+ int sig_num;
+ int sig_code;
+ /* struct sigcontext32 * */ u32 sig_scptr;
+ int sig_address;
+ struct sigcontext32 sig_context;
+};
+
+/*
+ * And the new one, intended to be used for Linux applications only
+ * (we have enough in there to work with clone).
+ * All the interesting bits are in the info field.
+ */
+
+struct new_signal_frame32 {
+ struct sparc_stackf32 ss;
+ __siginfo32_t info;
+ /* __siginfo_fpu32_t * */ u32 fpu_save;
+ unsigned int insns [2];
+ __siginfo_fpu32_t fpu_state;
+};
+
+/* Align macros */
+#define SF_ALIGNEDSZ (((sizeof(struct signal_sframe32) + 7) & (~7)))
+#define NF_ALIGNEDSZ (((sizeof(struct new_signal_frame32) + 7) & (~7)))
+
+/*
+ * atomically swap in the new signal mask, and wait for a signal.
+ * This is really tricky on the Sparc, watch out...
+ */
+asmlinkage void _sigpause32_common(unsigned int set, struct pt_regs *regs)
+{
+ unsigned int mask;
+
+ spin_lock_irq(&current->sigmask_lock);
+ mask = current->blocked;
+ current->blocked = set & _BLOCKABLE;
+ spin_unlock_irq(&current->sigmask_lock);
+
+ regs->tpc = regs->tnpc;
+ regs->tnpc += 4;
+
+ /* Condition codes and return value where set here for sigpause,
+ * and so got used by setup_frame, which again causes sigreturn()
+ * to return -EINTR.
+ */
+ while (1) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ /*
+ * Return -EINTR and set condition code here,
+ * so the interrupted system call actually returns
+ * these.
+ */
+ regs->tstate |= TSTATE_ICARRY;
+ regs->u_regs[UREG_I0] = EINTR;
+ if (do_signal32(mask, regs, 0, 0))
+ return;
+ }
+}
+
+asmlinkage void do_sigpause32(unsigned int set, struct pt_regs *regs)
+{
+ _sigpause32_common(set, regs);
+}
+
+asmlinkage void do_sigsuspend32(struct pt_regs *regs)
+{
+ _sigpause32_common(regs->u_regs[UREG_I0], regs);
+}
+
+
+static inline void
+restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu32_t *fpu)
+{
+#ifdef __SMP__
+ if (current->flags & PF_USEDFPU)
+ regs->tstate &= ~(TSTATE_PEF);
+#else
+ if (current == last_task_used_math) {
+ last_task_used_math = 0;
+ regs->tstate &= ~(TSTATE_PEF);
+ }
+#endif
+ current->used_math = 1;
+ current->flags &= ~PF_USEDFPU;
+
+ copy_from_user(&current->tss.float_regs[0],
+ &fpu->si_float_regs[0],
+ (sizeof(unsigned int) * 32));
+ __get_user(current->tss.fsr, &fpu->si_fsr);
+}
+
+void do_new_sigreturn32(struct pt_regs *regs)
+{
+ struct new_signal_frame32 *sf;
+ unsigned int psr, i;
+ unsigned pc, npc, fpu_save, mask;
+
+ sf = (struct new_signal_frame32 *) regs->u_regs [UREG_FP];
+ /* 1. Make sure we are not getting garbage from the user */
+ if (verify_area (VERIFY_READ, sf, sizeof (*sf))){
+ goto segv;
+ }
+ if (((unsigned long) sf) & 3){
+ goto segv;
+ }
+ get_user(pc, &sf->info.si_regs.pc);
+ __get_user(npc, &sf->info.si_regs.npc);
+ if ((pc | npc) & 3){
+ goto segv;
+ }
+ regs->tpc = pc;
+ regs->tnpc = npc;
+
+ /* 2. Restore the state */
+ __get_user(regs->y, &sf->info.si_regs.y);
+ __get_user(psr, &sf->info.si_regs.psr);
+ for (i = 0; i < 16; i++)
+ __get_user(regs->u_regs[i], &sf->info.si_regs.u_regs[i]);
+
+ /* User can only change condition codes and FPU enabling in %tstate. */
+ regs->tstate &= ~(TSTATE_ICC | TSTATE_PEF);
+ regs->tstate |= psr_to_tstate_icc(psr);
+ if (psr & PSR_EF) regs->tstate |= TSTATE_PEF;
+
+ __get_user(fpu_save, &sf->fpu_save);
+ if (fpu_save)
+ restore_fpu_state32(regs, &sf->fpu_state);
+ __get_user(mask, &sf->info.si_mask);
+ current->blocked = mask & _BLOCKABLE;
+ return;
+segv:
+ lock_kernel();
+ do_exit(SIGSEGV);
+}
+
+asmlinkage void do_sigreturn32(struct pt_regs *regs)
+{
+ struct sigcontext32 *scptr;
+ unsigned pc, npc, psr;
+ unsigned long mask;
+
+ synchronize_user_stack();
+ if (current->tss.new_signal)
+ return do_new_sigreturn32(regs);
+
+ scptr = (struct sigcontext32 *) regs->u_regs[UREG_I0];
+ /* Check sanity of the user arg. */
+ if(verify_area(VERIFY_READ, scptr, sizeof(struct sigcontext32)) ||
+ (((unsigned long) scptr) & 3)) {
+ goto segv;
+ }
+ __get_user(pc, &scptr->sigc_pc);
+ __get_user(npc, &scptr->sigc_npc);
+ if((pc | npc) & 3)
+ goto segv; /* Nice try. */
+
+ __get_user(mask, &scptr->sigc_mask);
+ current->blocked = (mask & _BLOCKABLE);
+ __get_user(current->tss.sstk_info.cur_status, &scptr->sigc_onstack);
+ current->tss.sstk_info.cur_status &= 1;
+ regs->tpc = pc;
+ regs->tnpc = npc;
+ __get_user(regs->u_regs[UREG_FP], &scptr->sigc_sp);
+ __get_user(regs->u_regs[UREG_I0], &scptr->sigc_o0);
+ __get_user(regs->u_regs[UREG_G1], &scptr->sigc_g1);
+
+ /* User can only change condition codes in %tstate. */
+ __get_user(psr, &scptr->sigc_psr);
+ regs->tstate &= ~(TSTATE_ICC);
+ regs->tstate |= psr_to_tstate_icc(psr);
+ return;
+segv:
+ lock_kernel ();
+ do_exit (SIGSEGV);
+}
+
+/* Checks if the fp is valid */
+static int invalid_frame_pointer(void *fp, int fplen)
+{
+ if ((((unsigned long) fp) & 7) || ((unsigned long)fp) > 0x100000000ULL - fplen)
+ return 1;
+ return 0;
+}
+
+static void
+setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
+ struct pt_regs *regs, int signr, unsigned long oldmask)
+{
+ struct signal_sframe32 *sframep;
+ struct sigcontext32 *sc;
+ int window = 0;
+ int old_status = current->tss.sstk_info.cur_status;
+ unsigned psr;
+ int i;
+ u32 temp;
+
+ synchronize_user_stack();
+ sframep = (struct signal_sframe32 *) regs->u_regs[UREG_FP];
+ sframep = (struct signal_sframe32 *) (((unsigned long) sframep)-SF_ALIGNEDSZ);
+ if (invalid_frame_pointer (sframep, sizeof(*sframep))){
+#ifdef DEBUG_SIGNALS /* fills up the console logs during crashme runs, yuck... */
+ printk("%s [%d]: User has trashed signal stack\n",
+ current->comm, current->pid);
+ printk("Sigstack ptr %p handler at pc<%016lx> for sig<%d>\n",
+ sframep, pc, signr);
+#endif
+ /* Don't change signal code and address, so that
+ * post mortem debuggers can have a look.
+ */
+ lock_kernel ();
+ do_exit(SIGILL);
+ }
+
+ sc = &sframep->sig_context;
+
+ /* We've already made sure frame pointer isn't in kernel space... */
+ __put_user(old_status, &sc->sigc_onstack);
+ __put_user(oldmask, &sc->sigc_mask);
+ __put_user(regs->u_regs[UREG_FP], &sc->sigc_sp);
+ __put_user(pc, &sc->sigc_pc);
+ __put_user(npc, &sc->sigc_npc);
+ psr = tstate_to_psr (regs->tstate);
+ __put_user(psr, &sc->sigc_psr);
+ __put_user(regs->u_regs[UREG_G1], &sc->sigc_g1);
+ __put_user(regs->u_regs[UREG_I0], &sc->sigc_o0);
+ __put_user(current->tss.w_saved, &sc->sigc_oswins);
+#if 0
+/* w_saved is not currently used... */
+ if(current->tss.w_saved)
+ for(window = 0; window < current->tss.w_saved; window++) {
+ sc->sigc_spbuf[window] =
+ (char *)current->tss.rwbuf_stkptrs[window];
+ copy_to_user(&sc->sigc_wbuf[window],
+ &current->tss.reg_window[window],
+ sizeof(struct reg_window));
+ }
+ else
+#endif
+ for (i = 0; i < 16; i++) {
+ get_user (temp, (((u32 *)(regs->u_regs[UREG_FP]))+i));
+ put_user (temp, (((u32 *)sframep)+i));
+ }
+
+ current->tss.w_saved = 0; /* So process is allowed to execute. */
+ __put_user(signr, &sframep->sig_num);
+ if(signr == SIGSEGV ||
+ signr == SIGILL ||
+ signr == SIGFPE ||
+ signr == SIGBUS ||
+ signr == SIGEMT) {
+ __put_user(current->tss.sig_desc, &sframep->sig_code);
+ __put_user(current->tss.sig_address, &sframep->sig_address);
+ } else {
+ __put_user(0, &sframep->sig_code);
+ __put_user(0, &sframep->sig_address);
+ }
+ __put_user((u64)sc, &sframep->sig_scptr);
+ regs->u_regs[UREG_FP] = (unsigned long) sframep;
+ regs->tpc = (unsigned long) sa->sa_handler;
+ regs->tnpc = (regs->tpc + 4);
+}
+
+
+static inline void
+save_fpu_state32(struct pt_regs *regs, __siginfo_fpu32_t *fpu)
+{
+#ifdef __SMP__
+ if (current->flags & PF_USEDFPU) {
+ fpsave32(&current->tss.float_regs[0], &current->tss.fsr);
+ regs->tstate &= ~(TSTATE_PEF);
+ current->flags &= ~(PF_USEDFPU);
+ }
+#else
+ if (current == last_task_used_math) {
+ fpsave32((unsigned long *)&current->tss.float_regs[0], &current->tss.fsr);
+ last_task_used_math = 0;
+ regs->tstate &= ~(TSTATE_PEF);
+ }
+#endif
+ copy_to_user(&fpu->si_float_regs[0], &current->tss.float_regs[0],
+ (sizeof(unsigned int) * 32));
+ __put_user(current->tss.fsr, &fpu->si_fsr);
+ current->used_math = 0;
+}
+
+static inline void
+new_setup_frame32(struct sigaction *sa, struct pt_regs *regs,
+ int signo, unsigned long oldmask)
+{
+ struct new_signal_frame32 *sf;
+ int sigframe_size;
+ u32 psr, tmp;
+ int i;
+
+ /* 1. Make sure everything is clean */
+ synchronize_user_stack();
+ sigframe_size = NF_ALIGNEDSZ;
+ if (!current->used_math)
+ sigframe_size -= sizeof(__siginfo_fpu32_t);
+
+ sf = (struct new_signal_frame32 *)(regs->u_regs[UREG_FP] - sigframe_size);
+
+ if (invalid_frame_pointer (sf, sigframe_size)){
+ lock_kernel ();
+ do_exit(SIGILL);
+ }
+
+ if (current->tss.w_saved != 0){
+ printk ("%s[%d]: Invalid user stack frame for "
+ "signal delivery.\n", current->comm, current->pid);
+ lock_kernel ();
+ do_exit (SIGILL);
+ }
+
+ /* 2. Save the current process state */
+ put_user(regs->tpc, &sf->info.si_regs.pc);
+ __put_user(regs->tnpc, &sf->info.si_regs.npc);
+ __put_user(regs->y, &sf->info.si_regs.y);
+ psr = tstate_to_psr (regs->tstate);
+ __put_user(psr, &sf->info.si_regs.psr);
+ for (i = 0; i < 16; i++)
+ __put_user(regs->u_regs[i], &sf->info.si_regs.u_regs[i]);
+
+ if (current->used_math) {
+ save_fpu_state32(regs, &sf->fpu_state);
+ __put_user((u64)&sf->fpu_state, &sf->fpu_save);
+ } else {
+ __put_user(0, &sf->fpu_save);
+ }
+
+ __put_user(oldmask, &sf->info.si_mask);
+ for (i = 0; i < sizeof(struct reg_window32)/4; i++) {
+ __get_user(tmp, (((u32 *)regs->u_regs[UREG_FP])+i));
+ __put_user(tmp, (((u32 *)sf)+i));
+ }
+
+ /* 3. return to kernel instructions */
+ __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */
+ __put_user(0x91d02010, &sf->insns[1]); /* t 0x10 */
+
+ /* 4. 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_I7] = (unsigned long) (&(sf->insns[0]) - 2);
+
+ /* 5. signal handler */
+ regs->tpc = (unsigned long) sa->sa_handler;
+ regs->tnpc = (regs->tpc + 4);
+
+ /* Flush instruction space. */
+ __asm__ __volatile__ ("flush %0; flush %0 + 4" : : "r" (&(sf->insns[0])));
+
+}
+
+/* Setup a Solaris stack frame */
+static inline void
+setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
+ struct pt_regs *regs, int signr, unsigned long oldmask)
+{
+ svr4_signal_frame_t *sfp;
+ svr4_gregset_t *gr;
+ svr4_siginfo_t *si;
+ svr4_mcontext_t *mc;
+ svr4_gwindows_t *gw;
+ svr4_ucontext_t *uc;
+ int window = 0;
+ unsigned psr;
+ int i;
+
+ synchronize_user_stack();
+ sfp = (svr4_signal_frame_t *) regs->u_regs[UREG_FP] - REGWIN_SZ;
+ sfp = (svr4_signal_frame_t *) (((unsigned long) sfp)-SVR4_SF_ALIGNED);
+
+ if (invalid_frame_pointer (sfp, sizeof (*sfp))){
+#ifdef DEBUG_SIGNALS
+ printk ("Invalid stack frame\n");
+#endif
+ lock_kernel ();
+ do_exit(SIGILL);
+ }
+
+ /* Start with a clean frame pointer and fill it */
+ clear_user(sfp, sizeof (*sfp));
+
+ /* Setup convenience variables */
+ si = &sfp->si;
+ uc = &sfp->uc;
+ gw = &sfp->gw;
+ mc = &uc->mcontext;
+ gr = &mc->greg;
+
+ /* FIXME: where am I supposed to put this?
+ * sc->sigc_onstack = old_status;
+ * anyways, it does not look like it is used for anything at all.
+ */
+ __put_user(oldmask, &uc->sigmask.sigbits [0]);
+
+ /* Store registers */
+ __put_user(regs->tpc, &((*gr) [SVR4_PC]));
+ __put_user(regs->tnpc, &((*gr) [SVR4_NPC]));
+ psr = tstate_to_psr (regs->tstate);
+ __put_user(psr, &((*gr) [SVR4_PSR]));
+ __put_user(regs->y, &((*gr) [SVR4_Y]));
+
+ /* Copy g [1..7] and o [0..7] registers */
+ for (i = 0; i < 7; i++)
+ __put_user(regs->u_regs[UREG_G1+i], (&(*gr)[SVR4_G1])+i);
+ for (i = 0; i < 8; i++)
+ __put_user(regs->u_regs[UREG_I0+i], (&(*gr)[SVR4_O0])+i);
+
+ /* Setup sigaltstack, FIXME */
+ __put_user(0xdeadbeef, &uc->stack.sp);
+ __put_user(0, &uc->stack.size);
+ __put_user(0, &uc->stack.flags); /* Possible: ONSTACK, DISABLE */
+
+ /* Save the currently window file: */
+
+ /* 1. Link sfp->uc->gwins to our windows */
+ __put_user(gw, &mc->gwin);
+
+ /* 2. Number of windows to restore at setcontext (): */
+ __put_user(current->tss.w_saved, &gw->count);
+
+ /* 3. Save each valid window
+ * Currently, it makes a copy of the windows from the kernel copy.
+ * David's code for SunOS, makes the copy but keeps the pointer to
+ * the kernel. My version makes the pointer point to a userland
+ * copy of those. Mhm, I wonder if I shouldn't just ignore those
+ * on setcontext and use those that are on the kernel, the signal
+ * handler should not be modyfing those, mhm.
+ *
+ * These windows are just used in case synchronize_user_stack failed
+ * to flush the user windows.
+ */
+#if 0
+ for(window = 0; window < current->tss.w_saved; window++) {
+ __put_user((int *) &(gw->win [window]), &gw->winptr [window]);
+ copy_to_user(&gw->win [window], &current->tss.reg_window [window], sizeof (svr4_rwindow_t));
+ __put_user(0, gw->winptr [window]);
+ }
+#endif
+
+ /* 4. We just pay attention to the gw->count field on setcontext */
+ current->tss.w_saved = 0; /* So process is allowed to execute. */
+
+ /* Setup the signal information. Solaris expects a bunch of
+ * information to be passed to the signal handler, we don't provide
+ * that much currently, should use those that David already
+ * is providing with tss.sig_desc
+ */
+ __put_user(signr, &si->siginfo.signo);
+ __put_user(SVR4_SINOINFO, &si->siginfo.code);
+
+ regs->u_regs[UREG_FP] = (unsigned long) sfp;
+ regs->tpc = (unsigned long) sa->sa_handler;
+ regs->tnpc = (regs->tpc + 4);
+
+#ifdef DEBUG_SIGNALS
+ printk ("Solaris-frame: %x %x\n", (int) regs->tpc, (int) regs->tnpc);
+#endif
+ /* Arguments passed to signal handler */
+ if (regs->u_regs [14]){
+ struct reg_window32 *rw = (struct reg_window32 *) regs->u_regs [14];
+
+ __put_user(signr, &rw->ins [0]);
+ __put_user((u64)si, &rw->ins [1]);
+ __put_user((u64)uc, &rw->ins [2]);
+ __put_user((u64)sfp, &rw->ins [6]); /* frame pointer */
+ regs->u_regs[UREG_I0] = signr;
+ regs->u_regs[UREG_I1] = (u32)(u64) si;
+ regs->u_regs[UREG_I2] = (u32)(u64) uc;
+ }
+}
+
+asmlinkage int
+svr4_getcontext32(svr4_ucontext_t *uc, struct pt_regs *regs)
+{
+ svr4_gregset_t *gr;
+ svr4_mcontext_t *mc;
+ int i;
+
+ synchronize_user_stack();
+ if (current->tss.w_saved){
+ printk ("Uh oh, w_saved is not zero (%ld)\n", current->tss.w_saved);
+ do_exit (SIGSEGV);
+ }
+ if(clear_user(uc, sizeof (*uc)))
+ return -EFAULT;
+
+ /* Setup convenience variables */
+ mc = &uc->mcontext;
+ gr = &mc->greg;
+
+ /* We only have < 32 signals, fill the first slot only */
+ __put_user(current->blocked, &uc->sigmask.sigbits [0]);
+
+ /* Store registers */
+ __put_user(regs->tpc, &uc->mcontext.greg [SVR4_PC]);
+ __put_user(regs->tnpc, &uc->mcontext.greg [SVR4_NPC]);
+ __put_user(tstate_to_psr(regs->tstate), &uc->mcontext.greg [SVR4_PSR]);
+ __put_user(regs->y, &uc->mcontext.greg [SVR4_Y]);
+
+ /* Copy g [1..7] and o [0..7] registers */
+ for (i = 0; i < 7; i++)
+ __put_user(regs->u_regs[UREG_G1+i], (&(*gr)[SVR4_G1])+i);
+ for (i = 0; i < 8; i++)
+ __put_user(regs->u_regs[UREG_I0+i], (&(*gr)[SVR4_O0])+i);
+
+ /* Setup sigaltstack, FIXME */
+ __put_user(0xdeadbeef, &uc->stack.sp);
+ __put_user(0, &uc->stack.size);
+ __put_user(0, &uc->stack.flags); /* Possible: ONSTACK, DISABLE */
+
+ /* The register file is not saved
+ * we have already stuffed all of it with sync_user_stack
+ */
+ return 0;
+}
+
+
+/* Set the context for a svr4 application, this is Solaris way to sigreturn */
+asmlinkage int svr4_setcontext32(svr4_ucontext_t *c, struct pt_regs *regs)
+{
+ struct thread_struct *tp = &current->tss;
+ svr4_gregset_t *gr;
+ u32 pc, npc, psr;
+ int i;
+
+ /* Fixme: restore windows, or is this already taken care of in
+ * svr4_setup_frame when sync_user_windows is done?
+ */
+ flush_user_windows();
+
+ if (tp->w_saved){
+ printk ("Uh oh, w_saved is: 0x%lx\n", tp->w_saved);
+ do_exit(SIGSEGV);
+ }
+ if (((unsigned long) c) & 3){
+ printk ("Unaligned structure passed\n");
+ do_exit (SIGSEGV);
+ }
+
+ if(!__access_ok((unsigned long)c, sizeof(*c))) {
+ /* Miguel, add nice debugging msg _here_. ;-) */
+ do_exit(SIGSEGV);
+ }
+
+ /* Check for valid PC and nPC */
+ gr = &c->mcontext.greg;
+ __get_user(pc, &((*gr)[SVR4_PC]));
+ __get_user(npc, &((*gr)[SVR4_NPC]));
+ if((pc | npc) & 3) {
+ printk ("setcontext, PC or nPC were bogus\n");
+ do_exit (SIGSEGV);
+ }
+ /* Retrieve information from passed ucontext */
+ /* note that nPC is ored a 1, this is used to inform entry.S */
+ /* that we don't want it to mess with our PC and nPC */
+ __get_user(current->blocked, &c->sigmask.sigbits [0]);
+ current->blocked &= _BLOCKABLE;
+ regs->tpc = pc;
+ regs->tnpc = npc | 1;
+ __get_user(regs->y, &((*gr) [SVR4_Y]));
+ __get_user(psr, &((*gr) [SVR4_PSR]));
+ regs->tstate &= ~(TSTATE_ICC);
+ regs->tstate |= psr_to_tstate_icc(psr);
+
+ /* Restore g[1..7] and o[0..7] registers */
+ for (i = 0; i < 7; i++)
+ __put_user(regs->u_regs[UREG_G1+i], (&(*gr)[SVR4_G1])+i);
+ for (i = 0; i < 8; i++)
+ __put_user(regs->u_regs[UREG_I0+i], (&(*gr)[SVR4_O0])+i);
+
+ return -EINTR;
+}
+
+static inline void handle_signal32(unsigned long signr, struct sigaction *sa,
+ unsigned long oldmask, struct pt_regs *regs,
+ int svr4_signal)
+{
+ if(svr4_signal)
+ setup_svr4_frame32(sa, regs->tpc, regs->tnpc, regs, signr, oldmask);
+ else {
+ if (current->tss.new_signal)
+ new_setup_frame32(sa, regs, signr, oldmask);
+ else
+ setup_frame32(sa, regs->tpc, regs->tnpc, regs, signr, oldmask);
+ }
+ if(sa->sa_flags & SA_ONESHOT)
+ sa->sa_handler = NULL;
+ if(!(sa->sa_flags & SA_NOMASK))
+ current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE;
+}
+
+static inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs,
+ struct sigaction *sa)
+{
+ switch(regs->u_regs[UREG_I0]) {
+ case ERESTARTNOHAND:
+ no_system_call_restart:
+ regs->u_regs[UREG_I0] = EINTR;
+ regs->tstate |= TSTATE_ICARRY;
+ 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->tpc -= 4;
+ regs->tnpc -= 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.
+ */
+asmlinkage int do_signal32(unsigned long oldmask, struct pt_regs * regs,
+ unsigned long orig_i0, int restart_syscall)
+{
+ unsigned long signr, mask = ~current->blocked;
+ struct sigaction *sa;
+ int svr4_signal = current->personality == PER_SVR4;
+
+ while ((signr = current->signal & mask) != 0) {
+ signr = ffz(~signr);
+ clear_bit(signr, &current->signal);
+ sa = current->sig->action + signr;
+ signr++;
+ if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
+ current->exit_code = signr;
+ current->state = TASK_STOPPED;
+ notify_parent(current);
+ schedule();
+ if (!(signr = current->exit_code))
+ continue;
+ current->exit_code = 0;
+ if (signr == SIGSTOP)
+ continue;
+ if (_S(signr) & current->blocked) {
+ current->signal |= _S(signr);
+ continue;
+ }
+ sa = current->sig->action + signr - 1;
+ }
+ if(sa->sa_handler == SIG_IGN) {
+ if(signr != SIGCHLD)
+ continue;
+
+ /* sys_wait4() grabs the master kernel lock, so
+ * we need not do so, that sucker should be
+ * threaded and would not be that difficult to
+ * do anyways.
+ */
+ while(sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
+ ;
+ continue;
+ }
+ if(sa->sa_handler == SIG_DFL) {
+ if(current->pid == 1)
+ continue;
+ switch(signr) {
+ case SIGCONT: case SIGCHLD: case SIGWINCH:
+ continue;
+
+ case SIGTSTP: case SIGTTIN: case SIGTTOU:
+ if (is_orphaned_pgrp(current->pgrp))
+ continue;
+
+ case SIGSTOP:
+ if (current->flags & PF_PTRACED)
+ continue;
+ current->state = TASK_STOPPED;
+ current->exit_code = signr;
+ if(!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
+ SA_NOCLDSTOP))
+ notify_parent(current);
+ schedule();
+ continue;
+
+ case SIGQUIT: case SIGILL: case SIGTRAP:
+ case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS:
+ if(current->binfmt && current->binfmt->core_dump) {
+ if(current->binfmt->core_dump(signr, regs))
+ signr |= 0x80;
+ }
+#ifdef DEBUG_SIGNALS
+ /* Very useful to debug dynamic linker problems */
+ printk ("Sig ILL going...\n");
+ show_regs (regs);
+#endif
+ /* fall through */
+ default:
+ current->signal |= _S(signr & 0x7f);
+ current->flags |= PF_SIGNALED;
+ do_exit(signr);
+ }
+ }
+ if(restart_syscall)
+ syscall_restart32(orig_i0, regs, sa);
+ handle_signal32(signr, sa, oldmask, regs, svr4_signal);
+ return 1;
+ }
+ 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->tpc -= 4;
+ regs->tnpc -= 4;
+ }
+ return 0;
+}
+
+struct sigstack32 {
+ u32 the_stack;
+ int cur_status;
+};
+
+asmlinkage int
+sys32_sigstack(struct sigstack32 *ssptr, struct sigstack32 *ossptr)
+{
+ int ret = -EFAULT;
+
+ lock_kernel();
+ /* First see if old state is wanted. */
+ if(ossptr) {
+ if (put_user ((u64)current->tss.sstk_info.the_stack, &ossptr->the_stack) ||
+ __put_user (current->tss.sstk_info.cur_status, &ossptr->cur_status))
+ goto out;
+ }
+
+ /* Now see if we want to update the new state. */
+ if(ssptr) {
+ if (get_user ((u64)current->tss.sstk_info.the_stack, &ssptr->the_stack) ||
+ __put_user (current->tss.sstk_info.cur_status, &ssptr->cur_status))
+ goto out;
+ }
+ ret = 0;
+out:
+ unlock_kernel();
+ return ret;
+}
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
new file mode 100644
index 000000000..91426c814
--- /dev/null
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -0,0 +1,178 @@
+/* $Id: sparc64_ksyms.c,v 1.4 1997/04/14 17:04:43 jj Exp $
+ * 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)
+ */
+
+#define PROMLIB_INTERNAL
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+
+#include <asm/oplib.h>
+#include <asm/delay.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/idprom.h>
+#include <asm/svr4.h>
+#include <asm/head.h>
+#include <asm/smp.h>
+#include <asm/mostek.h>
+#include <asm/ptrace.h>
+#include <asm/user.h>
+#include <asm/uaccess.h>
+#ifdef CONFIG_SBUS
+#include <asm/sbus.h>
+#include <asm/dma.h>
+#endif
+#include <asm/a.out.h>
+
+struct poll {
+ int fd;
+ short events;
+ short revents;
+};
+
+extern int svr4_getcontext (svr4_ucontext_t *, struct pt_regs *);
+extern int svr4_setcontext (svr4_ucontext_t *, struct pt_regs *);
+extern unsigned long sunos_mmap(unsigned long, unsigned long, unsigned long,
+ unsigned long, unsigned long, unsigned long);
+void _sigpause_common (unsigned int set, struct pt_regs *);
+extern void __copy_1page(void *, const void *);
+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 unsigned int __csum_partial_copy_sparc_generic (const char *, char *);
+
+extern void bcopy (const char *, char *, int);
+extern int __ashrdi3(int, int);
+
+extern void dump_thread(struct pt_regs *, struct user *);
+
+/* One thing to note is that the way the symbols of the mul/div
+ * support routines are named is a mess, they all start with
+ * a '.' which makes it a bitch to export, here is the trick:
+ */
+
+#define EXPORT_SYMBOL_PRIVATE(sym) \
+extern int __sparc_priv_ ## sym (int) __asm__("__" ## #sym); \
+const struct module_symbol __export_priv_##sym \
+__attribute__((section("__ksymtab"))) = \
+{ (unsigned long) &__sparc_priv_ ## sym, "__" ## #sym }
+
+/* used by various drivers */
+#ifdef __SMP__
+EXPORT_SYMBOL(klock_info);
+#endif
+EXPORT_SYMBOL_PRIVATE(_lock_kernel);
+EXPORT_SYMBOL_PRIVATE(_unlock_kernel);
+
+EXPORT_SYMBOL(mstk48t02_regs);
+EXPORT_SYMBOL(request_fast_irq);
+EXPORT_SYMBOL(sparc_alloc_io);
+EXPORT_SYMBOL(sparc_free_io);
+#if 0
+EXPORT_SYMBOL(io_remap_page_range);
+EXPORT_SYMBOL(mmu_unlockarea);
+EXPORT_SYMBOL(mmu_lockarea);
+EXPORT_SYMBOL(mmu_get_scsi_sgl);
+EXPORT_SYMBOL(mmu_get_scsi_one);
+EXPORT_SYMBOL(mmu_release_scsi_sgl);
+EXPORT_SYMBOL(mmu_release_scsi_one);
+#endif
+EXPORT_SYMBOL(sparc_dvma_malloc);
+#if 0
+EXPORT_SYMBOL(sun4c_unmapioaddr);
+EXPORT_SYMBOL(srmmu_unmapioaddr);
+#endif
+#if CONFIG_SBUS
+EXPORT_SYMBOL(SBus_chain);
+EXPORT_SYMBOL(dma_chain);
+#endif
+
+/* Solaris/SunOS binary compatibility */
+EXPORT_SYMBOL(svr4_setcontext);
+EXPORT_SYMBOL(svr4_getcontext);
+EXPORT_SYMBOL(_sigpause_common);
+EXPORT_SYMBOL(sunos_mmap);
+
+/* Should really be in linux/kernel/ksyms.c */
+EXPORT_SYMBOL(dump_thread);
+
+/* 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(prom_getbootargs);
+EXPORT_SYMBOL(prom_getname);
+EXPORT_SYMBOL(prom_feval);
+EXPORT_SYMBOL(prom_getstring);
+EXPORT_SYMBOL(prom_apply_sbus_ranges);
+EXPORT_SYMBOL(prom_getint);
+EXPORT_SYMBOL(prom_getintdefault);
+EXPORT_SYMBOL(__prom_getchild);
+EXPORT_SYMBOL(__prom_getsibling);
+
+/* sparc library symbols */
+EXPORT_SYMBOL(bcopy);
+EXPORT_SYMBOL(memscan);
+EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(strnlen);
+EXPORT_SYMBOL(strcpy);
+EXPORT_SYMBOL(strncpy);
+EXPORT_SYMBOL(strcat);
+EXPORT_SYMBOL(strncat);
+EXPORT_SYMBOL(strcmp);
+EXPORT_SYMBOL(strncmp);
+EXPORT_SYMBOL(strchr);
+EXPORT_SYMBOL(strrchr);
+EXPORT_SYMBOL(strpbrk);
+EXPORT_SYMBOL(strtok);
+EXPORT_SYMBOL(strstr);
+EXPORT_SYMBOL(strspn);
+
+/* 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);
+
+EXPORT_SYMBOL(__csum_partial_copy_sparc_generic);
+
+/* Moving data to/from userspace. */
+EXPORT_SYMBOL(__copy_to_user);
+EXPORT_SYMBOL(__copy_from_user);
+EXPORT_SYMBOL(__strncpy_from_user);
+
+/* No version information on this, heavily used in inline asm,
+ * and will always be 'void __ret_efault(void)'.
+ */
+EXPORT_SYMBOL_NOVERS(__ret_efault);
+
+/* No version information on these, as gcc produces such symbols. */
+EXPORT_SYMBOL_NOVERS(memcmp);
+EXPORT_SYMBOL_NOVERS(memcpy);
+EXPORT_SYMBOL_NOVERS(memset);
+EXPORT_SYMBOL_NOVERS(memmove);
diff --git a/arch/sparc64/kernel/sparcelf32.c b/arch/sparc64/kernel/sparcelf32.c
new file mode 100644
index 000000000..855c636e4
--- /dev/null
+++ b/arch/sparc64/kernel/sparcelf32.c
@@ -0,0 +1,1281 @@
+/* sparcelf32.c: Support 32-bit Sparc ELF binaries on Ultra.
+ *
+ * This is just binfmt_elf.c with hooks so that the types are those
+ * for a 32-bit ELF binaries.
+ */
+
+/* This makes it work. */
+#define ELF_ARCH EM_SPARC
+#define ELF_CLASS ELFCLASS32
+#define ELF_DATA ELFDATA2MSB;
+
+/*
+ * linux/fs/binfmt_elf.c
+ *
+ * These are the functions used to load ELF format executables as used
+ * on SVr4 machines. Information on the format may be found in the book
+ * "UNIX SYSTEM V RELEASE 4 Programmers Guide: Ansi C and Programming Support
+ * Tools".
+ *
+ * Copyright 1993, 1994: Eric Youngdale (ericy@cais.com).
+ */
+
+#include <linux/module.h>
+
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/a.out.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/binfmts.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/shm.h>
+#include <linux/personality.h>
+#include <linux/elfcore.h>
+#include <linux/init.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+
+#include <linux/config.h>
+
+#define DLINFO_ITEMS 12
+
+#include <linux/elf.h>
+
+static int load_elf32_binary(struct linux_binprm * bprm, struct pt_regs * regs);
+static int load_elf32_library(int fd);
+extern int dump_fpu (struct pt_regs *, elf_fpregset_t *);
+extern void dump_thread(struct pt_regs *, struct user *);
+
+extern unsigned long get_unmapped_area(unsigned long addr, unsigned long len);
+
+/*
+ * If we don't support core dumping, then supply a NULL so we
+ * don't even try.
+ */
+#ifdef USE_ELF_CORE_DUMP
+static int elf32_core_dump(long signr, struct pt_regs * regs);
+#else
+#define elf32_core_dump NULL
+#endif
+
+#define ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_EXEC_PAGESIZE-1))
+#define ELF_PAGEOFFSET(_v) ((_v) & (ELF_EXEC_PAGESIZE-1))
+
+static struct linux_binfmt elf32_format = {
+#ifndef MODULE
+ NULL, NULL, load_elf32_binary, load_elf32_library, elf32_core_dump
+#else
+ NULL, &__this_module, load_elf32_binary, load_elf32_library, elf32_core_dump
+#endif
+};
+
+static void set_brk(unsigned long start, unsigned long end)
+{
+ start = PAGE_ALIGN(start);
+ end = PAGE_ALIGN(end);
+ if (end <= start)
+ return;
+ do_mmap(NULL, start, end - start,
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_FIXED | MAP_PRIVATE, 0);
+}
+
+
+/* We need to explicitly zero any fractional pages
+ after the data section (i.e. bss). This would
+ contain the junk from the file that should not
+ be in memory */
+
+
+static void padzero(unsigned long elf_bss)
+{
+ unsigned long nbyte;
+
+ nbyte = elf_bss & (PAGE_SIZE-1);
+ if (nbyte) {
+ nbyte = PAGE_SIZE - nbyte;
+ clear_user((void *) elf_bss, nbyte);
+ }
+}
+
+__u32 *create_elf32_tables(char *p, int argc, int envc,
+ struct elfhdr * exec,
+ unsigned long load_addr,
+ unsigned long interp_load_addr, int ibcs)
+{
+ __u32 *argv, *envp;
+ __u32 *sp, *csp;
+
+ /*
+ * Force 16 byte alignment here for generality.
+ */
+ sp = (__u32 *) (~15UL & (unsigned long) p);
+ csp = sp;
+ csp -= exec ? DLINFO_ITEMS*2 : 2;
+ csp -= envc+1;
+ csp -= argc+1;
+ if (!(((unsigned long) csp) & 4))
+ sp--;
+
+ /*
+ * Put the ELF interpreter info on the stack
+ */
+#define NEW_AUX_ENT(nr, id, val) \
+ __put_user ((id), sp+(nr*2)); \
+ __put_user ((val), sp+(nr*2+1)); \
+
+ sp -= 2;
+ NEW_AUX_ENT(0, AT_NULL, 0);
+
+ if (exec) {
+ sp -= 11*2;
+
+ NEW_AUX_ENT (0, AT_PHDR, load_addr + exec->e_phoff);
+ NEW_AUX_ENT (1, AT_PHENT, sizeof (struct elf_phdr));
+ NEW_AUX_ENT (2, AT_PHNUM, exec->e_phnum);
+ NEW_AUX_ENT (3, AT_PAGESZ, PAGE_SIZE);
+ NEW_AUX_ENT (4, AT_BASE, interp_load_addr);
+ NEW_AUX_ENT (5, AT_FLAGS, 0);
+ NEW_AUX_ENT (6, AT_ENTRY, (__u32) exec->e_entry);
+ NEW_AUX_ENT (7, AT_UID, (__u32) current->uid);
+ NEW_AUX_ENT (8, AT_EUID, (__u32) current->euid);
+ NEW_AUX_ENT (9, AT_GID, (__u32) current->gid);
+ NEW_AUX_ENT (10, AT_EGID, (__u32) current->egid);
+ }
+#undef NEW_AUX_ENT
+
+ sp -= envc+1;
+ envp = (__u32 *) sp;
+ sp -= argc+1;
+ argv = (__u32 *) sp;
+ if (!ibcs) {
+ __put_user(((__u32)(long) envp),--sp);
+ __put_user(((__u32)(long) argv),--sp);
+ }
+
+ __put_user((__u32)argc,--sp);
+ current->mm->arg_start = (unsigned long) p;
+ while (argc-->0) {
+ __put_user(((__u32)(long)p),argv++);
+ p += strlen_user(p);
+ }
+ __put_user(NULL, argv);
+ current->mm->arg_end = current->mm->env_start = (unsigned long) p;
+ while (envc-->0) {
+ __put_user(((__u32)(long)p),envp++);
+ p += strlen_user(p);
+ }
+ __put_user(NULL, envp);
+ current->mm->env_end = (unsigned long) p;
+ return sp;
+}
+
+
+/* This is much more generalized than the library routine read function,
+ so we keep this separate. Technically the library read function
+ is only provided so that we can read a.out libraries that have
+ an ELF header */
+
+static unsigned long load_elf32_interp(struct elfhdr * interp_elf_ex,
+ struct inode * interpreter_inode,
+ unsigned long *interp_load_addr)
+{
+ struct file * file;
+ struct elf_phdr *elf_phdata = NULL;
+ struct elf_phdr *eppnt;
+ unsigned long load_addr;
+ int load_addr_set = 0;
+ int elf_exec_fileno;
+ int retval;
+ unsigned long last_bss, elf_bss;
+ unsigned long error;
+ int i;
+
+ elf_bss = 0;
+ last_bss = 0;
+ error = load_addr = 0;
+
+ /* First of all, some simple consistency checks */
+ if ((interp_elf_ex->e_type != ET_EXEC &&
+ interp_elf_ex->e_type != ET_DYN) ||
+ !elf_check_arch(interp_elf_ex->e_machine) ||
+ (!interpreter_inode->i_op ||
+ !interpreter_inode->i_op->default_file_ops->mmap)){
+ return ~0UL;
+ }
+
+ /* Now read in all of the header information */
+
+ if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE)
+ return ~0UL;
+
+ elf_phdata = (struct elf_phdr *)
+ kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum,
+ GFP_KERNEL);
+ if (!elf_phdata)
+ return ~0UL;
+
+ /*
+ * If the size of this structure has changed, then punt, since
+ * we will be doing the wrong thing.
+ */
+ if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr))
+ {
+ kfree(elf_phdata);
+ return ~0UL;
+ }
+
+ retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff,
+ (char *) elf_phdata,
+ sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, 1);
+
+ if (retval < 0) {
+ kfree (elf_phdata);
+ return retval;
+ }
+
+ elf_exec_fileno = open_inode(interpreter_inode, O_RDONLY);
+ if (elf_exec_fileno < 0) {
+ kfree(elf_phdata);
+ return ~0UL;
+ }
+
+ file = current->files->fd[elf_exec_fileno];
+
+ eppnt = elf_phdata;
+ for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
+ if (eppnt->p_type == PT_LOAD) {
+ int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
+ int elf_prot = 0;
+ unsigned long vaddr = 0;
+ unsigned long k;
+
+ if (eppnt->p_flags & PF_R) elf_prot = PROT_READ;
+ if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
+ if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
+ if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
+ elf_type |= MAP_FIXED;
+ vaddr = eppnt->p_vaddr;
+ } else {
+ load_addr = get_unmapped_area(0, eppnt->p_filesz +
+ ELF_PAGEOFFSET(eppnt->p_vaddr));
+ }
+
+ error = do_mmap(file,
+ load_addr + ELF_PAGESTART(vaddr),
+ eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr),
+ elf_prot,
+ elf_type,
+ eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr));
+
+ if (error > -1024UL) {
+ /* Real error */
+ sys_close(elf_exec_fileno);
+ kfree(elf_phdata);
+ return ~0UL;
+ }
+
+ if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
+ load_addr = error;
+ load_addr_set = 1;
+ }
+
+ /*
+ * Find the end of the file mapping for this phdr, and keep
+ * track of the largest address we see for this.
+ */
+ k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
+ if (k > elf_bss) elf_bss = k;
+
+ /*
+ * Do the same thing for the memory mapping - between
+ * elf_bss and last_bss is the bss section.
+ */
+ k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
+ if (k > last_bss) last_bss = k;
+ }
+
+ /* Now use mmap to map the library into memory. */
+
+ sys_close(elf_exec_fileno);
+
+ /*
+ * Now fill out the bss section. First pad the last page up
+ * to the page boundary, and then perform a mmap to make sure
+ * that there are zeromapped pages up to and including the last
+ * bss page.
+ */
+ padzero(elf_bss);
+ elf_bss = ELF_PAGESTART(elf_bss + ELF_EXEC_PAGESIZE - 1); /* What we have mapped so far */
+
+ /* Map the last of the bss segment */
+ if (last_bss > elf_bss)
+ do_mmap(NULL, elf_bss, last_bss-elf_bss,
+ PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_FIXED|MAP_PRIVATE, 0);
+ kfree(elf_phdata);
+
+ *interp_load_addr = load_addr;
+ return ((unsigned long) interp_elf_ex->e_entry) + load_addr;
+}
+
+static unsigned long load_aout32_interp(struct exec * interp_ex,
+ struct inode * interpreter_inode)
+{
+ int retval;
+ unsigned long elf_entry;
+
+ current->mm->brk = interp_ex->a_bss +
+ (current->mm->end_data = interp_ex->a_data +
+ (current->mm->end_code = interp_ex->a_text));
+ elf_entry = interp_ex->a_entry;
+
+
+ if (N_MAGIC(*interp_ex) == OMAGIC) {
+ do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data,
+ PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_FIXED|MAP_PRIVATE, 0);
+ retval = read_exec(interpreter_inode, 32, (char *) 0,
+ interp_ex->a_text+interp_ex->a_data, 0);
+ } else if (N_MAGIC(*interp_ex) == ZMAGIC || N_MAGIC(*interp_ex) == QMAGIC) {
+ do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data,
+ PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_FIXED|MAP_PRIVATE, 0);
+ retval = read_exec(interpreter_inode,
+ N_TXTOFF(*interp_ex) ,
+ (char *) N_TXTADDR(*interp_ex),
+ interp_ex->a_text+interp_ex->a_data, 0);
+ } else
+ retval = -1;
+
+ if (retval >= 0)
+ do_mmap(NULL, ELF_PAGESTART(interp_ex->a_text + interp_ex->a_data + ELF_EXEC_PAGESIZE - 1),
+ interp_ex->a_bss,
+ PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_FIXED|MAP_PRIVATE, 0);
+ if (retval < 0) return ~0UL;
+ return elf_entry;
+}
+
+/*
+ * These are the functions used to load ELF style executables and shared
+ * libraries. There is no binary dependent code anywhere else.
+ */
+
+#define INTERPRETER_NONE 0
+#define INTERPRETER_AOUT 1
+#define INTERPRETER_ELF 2
+
+
+static inline int
+do_load_elf32_binary(struct linux_binprm * bprm, struct pt_regs * regs)
+{
+ struct elfhdr elf_ex;
+ struct elfhdr interp_elf_ex;
+ struct file * file;
+ struct exec interp_ex;
+ struct inode *interpreter_inode;
+ unsigned long load_addr;
+ int load_addr_set = 0;
+ unsigned int interpreter_type = INTERPRETER_NONE;
+ unsigned char ibcs2_interpreter;
+ int i;
+ int old_fs;
+ int error;
+ struct elf_phdr * elf_ppnt, *elf_phdata;
+ int elf_exec_fileno;
+ unsigned long elf_bss, k, elf_brk;
+ int retval;
+ char * elf_interpreter;
+ unsigned long elf_entry, interp_load_addr = 0;
+ int status;
+ unsigned long start_code, end_code, end_data;
+ unsigned long elf_stack;
+ char passed_fileno[6];
+
+ ibcs2_interpreter = 0;
+ status = 0;
+ load_addr = 0;
+ elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
+
+ if (elf_ex.e_ident[0] != 0x7f ||
+ strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) {
+ return -ENOEXEC;
+ }
+
+
+ /* First of all, some simple consistency checks */
+ if ((elf_ex.e_type != ET_EXEC &&
+ elf_ex.e_type != ET_DYN) ||
+ (! elf_check_arch(elf_ex.e_machine)) ||
+ (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops ||
+ !bprm->inode->i_op->default_file_ops->mmap)){
+ return -ENOEXEC;
+ }
+
+ /* Now read in all of the header information */
+
+ elf_phdata = (struct elf_phdr *) kmalloc(elf_ex.e_phentsize *
+ elf_ex.e_phnum, GFP_KERNEL);
+ if (elf_phdata == NULL) {
+ return -ENOMEM;
+ }
+
+ retval = read_exec(bprm->inode, elf_ex.e_phoff, (char *) elf_phdata,
+ elf_ex.e_phentsize * elf_ex.e_phnum, 1);
+ if (retval < 0) {
+ kfree (elf_phdata);
+ return retval;
+ }
+
+ elf_ppnt = elf_phdata;
+
+ elf_bss = 0;
+ elf_brk = 0;
+
+ elf_exec_fileno = open_inode(bprm->inode, O_RDONLY);
+
+ if (elf_exec_fileno < 0) {
+ kfree (elf_phdata);
+ return elf_exec_fileno;
+ }
+
+ file = current->files->fd[elf_exec_fileno];
+
+ elf_stack = ~0UL;
+ elf_interpreter = NULL;
+ start_code = ~0UL;
+ end_code = 0;
+ end_data = 0;
+
+ for(i=0;i < elf_ex.e_phnum; i++){
+ if (elf_ppnt->p_type == PT_INTERP) {
+ if ( elf_interpreter != NULL )
+ {
+ kfree (elf_phdata);
+ kfree(elf_interpreter);
+ sys_close(elf_exec_fileno);
+ return -EINVAL;
+ }
+
+ /* This is the program interpreter used for
+ * shared libraries - for now assume that this
+ * is an a.out format binary
+ */
+
+ elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz,
+ GFP_KERNEL);
+ if (elf_interpreter == NULL) {
+ kfree (elf_phdata);
+ sys_close(elf_exec_fileno);
+ return -ENOMEM;
+ }
+
+ retval = read_exec(bprm->inode,elf_ppnt->p_offset,
+ elf_interpreter,
+ elf_ppnt->p_filesz, 1);
+ /* If the program interpreter is one of these two,
+ then assume an iBCS2 image. Otherwise assume
+ a native linux image. */
+ if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
+ strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0)
+ ibcs2_interpreter = 1;
+#if 0
+ printk("Using ELF interpreter %s\n", elf_interpreter);
+#endif
+ if (retval >= 0) {
+ old_fs = get_fs(); /* This could probably be optimized */
+ set_fs(get_ds());
+ retval = open_namei(elf_interpreter, 0, 0,
+ &interpreter_inode, NULL);
+ set_fs(old_fs);
+ }
+
+ if (retval >= 0)
+ retval = read_exec(interpreter_inode,0,bprm->buf,128, 1);
+
+ if (retval >= 0) {
+ interp_ex = *((struct exec *) bprm->buf); /* exec-header */
+ interp_elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
+
+ }
+ if (retval < 0) {
+ kfree (elf_phdata);
+ kfree(elf_interpreter);
+ sys_close(elf_exec_fileno);
+ return retval;
+ }
+ }
+ elf_ppnt++;
+ }
+
+ /* Some simple consistency checks for the interpreter */
+ if (elf_interpreter){
+ interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
+
+ /* Now figure out which format our binary is */
+ if ((N_MAGIC(interp_ex) != OMAGIC) &&
+ (N_MAGIC(interp_ex) != ZMAGIC) &&
+ (N_MAGIC(interp_ex) != QMAGIC))
+ interpreter_type = INTERPRETER_ELF;
+
+ if (interp_elf_ex.e_ident[0] != 0x7f ||
+ strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0)
+ interpreter_type &= ~INTERPRETER_ELF;
+
+ if (!interpreter_type)
+ {
+ kfree(elf_interpreter);
+ kfree(elf_phdata);
+ sys_close(elf_exec_fileno);
+ return -ELIBBAD;
+ }
+ }
+
+ /* OK, we are done with that, now set up the arg stuff,
+ and then start this sucker up */
+
+ if (!bprm->sh_bang) {
+ char * passed_p;
+
+ if (interpreter_type == INTERPRETER_AOUT) {
+ sprintf(passed_fileno, "%d", elf_exec_fileno);
+ passed_p = passed_fileno;
+
+ if (elf_interpreter) {
+ bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p,2);
+ bprm->argc++;
+ }
+ }
+ if (!bprm->p) {
+ if (elf_interpreter) {
+ kfree(elf_interpreter);
+ }
+ kfree (elf_phdata);
+ sys_close(elf_exec_fileno);
+ return -E2BIG;
+ }
+ }
+
+ /* OK, This is the point of no return */
+ flush_old_exec(bprm);
+
+ current->mm->end_data = 0;
+ current->mm->end_code = 0;
+ current->mm->start_mmap = ELF_START_MMAP;
+ current->mm->mmap = NULL;
+ elf_entry = (unsigned long) elf_ex.e_entry;
+
+ /* Do this so that we can load the interpreter, if need be. We will
+ change some of these later */
+ current->mm->rss = 0;
+ bprm->p = setup_arg_pages(bprm->p, bprm);
+ current->mm->start_stack = bprm->p;
+
+ /* Now we do a little grungy work by mmaping the ELF image into
+ the correct location in memory. At this point, we assume that
+ the image should be loaded at fixed address, not at a variable
+ address. */
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
+ if (elf_ppnt->p_type == PT_LOAD) {
+ int elf_prot = 0;
+ if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
+ if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
+ if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
+
+ error = do_mmap(file,
+ ELF_PAGESTART(elf_ppnt->p_vaddr),
+ (elf_ppnt->p_filesz +
+ ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
+ elf_prot,
+ (MAP_FIXED | MAP_PRIVATE |
+ MAP_DENYWRITE | MAP_EXECUTABLE),
+ (elf_ppnt->p_offset -
+ ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
+
+#ifdef LOW_ELF_STACK
+ if (ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
+ elf_stack = ELF_PAGESTART(elf_ppnt->p_vaddr);
+#endif
+
+ if (!load_addr_set) {
+ load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
+ load_addr_set = 1;
+ }
+ k = elf_ppnt->p_vaddr;
+ if (k < start_code) start_code = k;
+ k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
+ if (k > elf_bss) elf_bss = k;
+#if 1
+ if ((elf_ppnt->p_flags & PF_X) && end_code < k)
+#else
+ if ( !(elf_ppnt->p_flags & PF_W) && end_code < k)
+#endif
+ end_code = k;
+ if (end_data < k) end_data = k;
+ k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
+ if (k > elf_brk) elf_brk = k;
+ }
+ }
+ set_fs(old_fs);
+
+ if (elf_interpreter) {
+ if (interpreter_type & 1)
+ elf_entry = load_aout32_interp(&interp_ex,
+ interpreter_inode);
+ else if (interpreter_type & 2)
+ elf_entry = load_elf32_interp(&interp_elf_ex,
+ interpreter_inode,
+ &interp_load_addr);
+
+ iput(interpreter_inode);
+ kfree(elf_interpreter);
+
+ if (elf_entry == ~0UL) {
+ printk("Unable to load interpreter\n");
+ kfree(elf_phdata);
+ send_sig(SIGSEGV, current, 0);
+ return 0;
+ }
+ }
+
+ kfree(elf_phdata);
+
+ if (interpreter_type != INTERPRETER_AOUT) sys_close(elf_exec_fileno);
+ current->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
+
+ if (current->exec_domain && current->exec_domain->module)
+ __MOD_DEC_USE_COUNT(current->exec_domain->module);
+ if (current->binfmt && current->binfmt->module)
+ __MOD_DEC_USE_COUNT(current->binfmt->module);
+ current->exec_domain = lookup_exec_domain(current->personality);
+ current->binfmt = &elf32_format;
+ if (current->exec_domain && current->exec_domain->module)
+ __MOD_INC_USE_COUNT(current->exec_domain->module);
+ if (current->binfmt && current->binfmt->module)
+ __MOD_INC_USE_COUNT(current->binfmt->module);
+
+#ifndef VM_STACK_FLAGS
+ current->executable = bprm->inode;
+ bprm->inode->i_count++;
+#endif
+#ifdef LOW_ELF_STACK
+ current->start_stack = bprm->p = elf_stack - 4;
+#endif
+ current->suid = current->euid = current->fsuid = bprm->e_uid;
+ current->sgid = current->egid = current->fsgid = bprm->e_gid;
+ current->flags &= ~PF_FORKNOEXEC;
+ bprm->p = (unsigned long)
+ create_elf32_tables((char *)bprm->p,
+ bprm->argc,
+ bprm->envc,
+ (interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL),
+ load_addr,
+ interp_load_addr,
+ (interpreter_type == INTERPRETER_AOUT ? 0 : 1));
+ if (interpreter_type == INTERPRETER_AOUT)
+ current->mm->arg_start += strlen(passed_fileno) + 1;
+ current->mm->start_brk = current->mm->brk = elf_brk;
+ current->mm->end_code = end_code;
+ current->mm->start_code = start_code;
+ current->mm->end_data = end_data;
+ current->mm->start_stack = bprm->p;
+
+ /* Calling set_brk effectively mmaps the pages that we need for the bss and break
+ sections */
+ set_brk(elf_bss, elf_brk);
+
+ padzero(elf_bss);
+
+#if 0
+ printk("(start_brk) %x\n" , current->mm->start_brk);
+ printk("(end_code) %x\n" , current->mm->end_code);
+ printk("(start_code) %x\n" , current->mm->start_code);
+ printk("(end_data) %x\n" , current->mm->end_data);
+ printk("(start_stack) %x\n" , current->mm->start_stack);
+ printk("(brk) %x\n" , current->mm->brk);
+#endif
+
+ if ( current->personality == PER_SVR4 )
+ {
+ /* Why this, you ask??? Well SVr4 maps page 0 as read-only,
+ and some applications "depend" upon this behavior.
+ Since we do not have the power to recompile these, we
+ emulate the SVr4 behavior. Sigh. */
+ error = do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC,
+ MAP_FIXED | MAP_PRIVATE, 0);
+ }
+
+#ifdef ELF_PLAT_INIT
+ /*
+ * The ABI may specify that certain registers be set up in special
+ * ways (on i386 %edx is the address of a DT_FINI function, for
+ * example. This macro performs whatever initialization to
+ * the regs structure is required.
+ */
+ ELF_PLAT_INIT(regs);
+#endif
+
+
+ start_thread32(regs, elf_entry, bprm->p);
+ if (current->flags & PF_PTRACED)
+ send_sig(SIGTRAP, current, 0);
+ return 0;
+}
+
+static int
+load_elf32_binary(struct linux_binprm * bprm, struct pt_regs * regs)
+{
+ int retval;
+
+ MOD_INC_USE_COUNT;
+ retval = do_load_elf32_binary(bprm, regs);
+ MOD_DEC_USE_COUNT;
+ return retval;
+}
+
+/* This is really simpleminded and specialized - we are loading an
+ a.out library that is given an ELF header. */
+
+static inline int
+do_load_elf32_library(int fd){
+ struct file * file;
+ struct elfhdr elf_ex;
+ struct elf_phdr *elf_phdata = NULL;
+ struct inode * inode;
+ unsigned long len;
+ int elf_bss;
+ int retval;
+ unsigned long bss;
+ int error;
+ int i,j, k;
+
+ len = 0;
+ file = current->files->fd[fd];
+ inode = file->f_inode;
+ elf_bss = 0;
+
+ if (!file || !file->f_op)
+ return -EACCES;
+
+ /* seek to the beginning of the file */
+ if (file->f_op->llseek) {
+ if ((error = file->f_op->llseek(inode, file, 0, 0)) != 0)
+ return -ENOEXEC;
+ } else
+ file->f_pos = 0;
+
+ set_fs(KERNEL_DS);
+ error = file->f_op->read(inode, file, (char *) &elf_ex, sizeof(elf_ex));
+ set_fs(USER_DS);
+ if (error != sizeof(elf_ex))
+ return -ENOEXEC;
+
+ if (elf_ex.e_ident[0] != 0x7f ||
+ strncmp(&elf_ex.e_ident[1], "ELF",3) != 0)
+ return -ENOEXEC;
+
+ /* First of all, some simple consistency checks */
+ if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
+ !elf_check_arch(elf_ex.e_machine) ||
+ (!inode->i_op || !inode->i_op->default_file_ops->mmap))
+ return -ENOEXEC;
+
+ /* Now read in all of the header information */
+
+ if (sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE)
+ return -ENOEXEC;
+
+ elf_phdata = (struct elf_phdr *)
+ kmalloc(sizeof(struct elf_phdr) * elf_ex.e_phnum, GFP_KERNEL);
+ if (elf_phdata == NULL)
+ return -ENOMEM;
+
+ retval = read_exec(inode, elf_ex.e_phoff, (char *) elf_phdata,
+ sizeof(struct elf_phdr) * elf_ex.e_phnum, 1);
+
+ j = 0;
+ for(i=0; i<elf_ex.e_phnum; i++)
+ if ((elf_phdata + i)->p_type == PT_LOAD) j++;
+
+ if (j != 1) {
+ kfree(elf_phdata);
+ return -ENOEXEC;
+ }
+
+ while(elf_phdata->p_type != PT_LOAD) elf_phdata++;
+
+ /* Now use mmap to map the library into memory. */
+ error = do_mmap(file,
+ ELF_PAGESTART(elf_phdata->p_vaddr),
+ (elf_phdata->p_filesz +
+ ELF_PAGEOFFSET(elf_phdata->p_vaddr)),
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
+ (elf_phdata->p_offset -
+ ELF_PAGEOFFSET(elf_phdata->p_vaddr)));
+
+ k = elf_phdata->p_vaddr + elf_phdata->p_filesz;
+ if (k > elf_bss) elf_bss = k;
+
+ if (error != ELF_PAGESTART(elf_phdata->p_vaddr)) {
+ kfree(elf_phdata);
+ return error;
+ }
+
+ padzero(elf_bss);
+
+ len = ELF_PAGESTART(elf_phdata->p_filesz + elf_phdata->p_vaddr+ ELF_EXEC_PAGESIZE - 1);
+ bss = elf_phdata->p_memsz + elf_phdata->p_vaddr;
+ if (bss > len)
+ do_mmap(NULL, len, bss-len,
+ PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_FIXED|MAP_PRIVATE, 0);
+ kfree(elf_phdata);
+ return 0;
+}
+
+static int load_elf32_library(int fd)
+{
+ int retval;
+
+ MOD_INC_USE_COUNT;
+ retval = do_load_elf32_library(fd);
+ MOD_DEC_USE_COUNT;
+ return retval;
+}
+
+/*
+ * Note that some platforms still use traditional core dumps and not
+ * the ELF core dump. Each platform can select it as appropriate.
+ */
+#ifdef USE_ELF_CORE_DUMP
+
+/*
+ * ELF core dumper
+ *
+ * Modelled on fs/exec.c:aout_core_dump()
+ * Jeremy Fitzhardinge <jeremy@sw.oz.au>
+ */
+/*
+ * These are the only things you should do on a core-file: use only these
+ * functions to write out all the necessary info.
+ */
+static int dump_write(struct file *file, const void *addr, int nr)
+{
+ return file->f_op->write(file->f_inode, file, addr, nr) == nr;
+}
+
+static int dump_seek(struct file *file, off_t off)
+{
+ if (file->f_op->llseek) {
+ if (file->f_op->llseek(file->f_inode, file, off, 0) != off)
+ return 0;
+ } else
+ file->f_pos = off;
+ return 1;
+}
+
+/*
+ * Decide whether a segment is worth dumping; default is yes to be
+ * sure (missing info is worse than too much; etc).
+ * Personally I'd include everything, and use the coredump limit...
+ *
+ * I think we should skip something. But I am not sure how. H.J.
+ */
+static inline int maydump(struct vm_area_struct *vma)
+{
+ if (!(vma->vm_flags & (VM_READ|VM_WRITE|VM_EXEC)))
+ return 0;
+#if 1
+ if (vma->vm_flags & (VM_WRITE|VM_GROWSUP|VM_GROWSDOWN))
+ return 1;
+ if (vma->vm_flags & (VM_READ|VM_EXEC|VM_EXECUTABLE|VM_SHARED))
+ return 0;
+#endif
+ return 1;
+}
+
+#define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
+
+/* An ELF note in memory */
+struct memelfnote
+{
+ const char *name;
+ int type;
+ unsigned int datasz;
+ void *data;
+};
+
+static int notesize(struct memelfnote *en)
+{
+ int sz;
+
+ sz = sizeof(struct elf_note);
+ sz += roundup(strlen(en->name), 4);
+ sz += roundup(en->datasz, 4);
+
+ return sz;
+}
+
+/* #define DEBUG */
+
+#define DUMP_WRITE(addr, nr) \
+ do { if (!dump_write(file, (addr), (nr))) return 0; } while(0)
+#define DUMP_SEEK(off) \
+ do { if (!dump_seek(file, (off))) return 0; } while(0)
+
+static int writenote(struct memelfnote *men, struct file *file)
+{
+ struct elf_note en;
+
+ en.n_namesz = strlen(men->name);
+ en.n_descsz = men->datasz;
+ en.n_type = men->type;
+
+ DUMP_WRITE(&en, sizeof(en));
+ DUMP_WRITE(men->name, en.n_namesz);
+ /* XXX - cast from long long to long to avoid need for libgcc.a */
+ DUMP_SEEK(roundup((unsigned long)file->f_pos, 4)); /* XXX */
+ DUMP_WRITE(men->data, men->datasz);
+ DUMP_SEEK(roundup((unsigned long)file->f_pos, 4)); /* XXX */
+
+ return 1;
+}
+#undef DUMP_WRITE
+#undef DUMP_SEEK
+
+#define DUMP_WRITE(addr, nr) \
+ if (!dump_write(&file, (addr), (nr))) \
+ goto close_coredump;
+#define DUMP_SEEK(off) \
+ if (!dump_seek(&file, (off))) \
+ goto close_coredump;
+/*
+ * Actual dumper
+ *
+ * This is a two-pass process; first we find the offsets of the bits,
+ * and then they are actually written out. If we run out of core limit
+ * we just truncate.
+ */
+static int elf32_core_dump(long signr, struct pt_regs * regs)
+{
+ int has_dumped = 0;
+ struct file file;
+ struct inode *inode;
+ unsigned short fs;
+ char corefile[6+sizeof(current->comm)];
+ int segs;
+ int i;
+ size_t size;
+ struct vm_area_struct *vma;
+ struct elfhdr elf;
+ off_t offset = 0, dataoff;
+ int limit = current->rlim[RLIMIT_CORE].rlim_cur;
+ int numnote = 4;
+ struct memelfnote notes[4];
+ struct elf_prstatus prstatus; /* NT_PRSTATUS */
+ elf_fpregset_t fpu; /* NT_PRFPREG */
+ struct elf_prpsinfo psinfo; /* NT_PRPSINFO */
+
+ if (!current->dumpable || limit < PAGE_SIZE || current->mm->count != 1)
+ return 0;
+ current->dumpable = 0;
+
+#ifndef CONFIG_BINFMT_ELF32
+ MOD_INC_USE_COUNT;
+#endif
+
+ /* Count what's needed to dump, up to the limit of coredump size */
+ segs = 0;
+ size = 0;
+ for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
+ if (maydump(vma))
+ {
+ int sz = vma->vm_end-vma->vm_start;
+
+ if (size+sz >= limit)
+ break;
+ else
+ size += sz;
+ }
+
+ segs++;
+ }
+#ifdef DEBUG
+ printk("elf_core_dump: %d segs taking %d bytes\n", segs, size);
+#endif
+
+ /* Set up header */
+ memcpy(elf.e_ident, ELFMAG, SELFMAG);
+ elf.e_ident[EI_CLASS] = ELF_CLASS;
+ elf.e_ident[EI_DATA] = ELF_DATA;
+ elf.e_ident[EI_VERSION] = EV_CURRENT;
+ memset(elf.e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
+
+ elf.e_type = ET_CORE;
+ elf.e_machine = ELF_ARCH;
+ elf.e_version = EV_CURRENT;
+ elf.e_entry = 0;
+ elf.e_phoff = sizeof(elf);
+ elf.e_shoff = 0;
+ elf.e_flags = 0;
+ elf.e_ehsize = sizeof(elf);
+ elf.e_phentsize = sizeof(struct elf_phdr);
+ elf.e_phnum = segs+1; /* Include notes */
+ elf.e_shentsize = 0;
+ elf.e_shnum = 0;
+ elf.e_shstrndx = 0;
+
+ fs = get_fs();
+ set_fs(KERNEL_DS);
+ memcpy(corefile,"core.",5);
+#if 0
+ memcpy(corefile+5,current->comm,sizeof(current->comm));
+#else
+ corefile[4] = '\0';
+#endif
+ if (open_namei(corefile,O_CREAT | 2 | O_TRUNC,0600,&inode,NULL)) {
+ inode = NULL;
+ goto end_coredump;
+ }
+ if (!S_ISREG(inode->i_mode))
+ goto end_coredump;
+ if (!inode->i_op || !inode->i_op->default_file_ops)
+ goto end_coredump;
+ file.f_mode = 3;
+ file.f_flags = 0;
+ file.f_count = 1;
+ file.f_inode = inode;
+ file.f_pos = 0;
+ file.f_reada = 0;
+ file.f_op = inode->i_op->default_file_ops;
+ if (file.f_op->open)
+ if (file.f_op->open(inode,&file))
+ goto end_coredump;
+ if (!file.f_op->write)
+ goto close_coredump;
+ has_dumped = 1;
+ current->flags |= PF_DUMPCORE;
+
+ DUMP_WRITE(&elf, sizeof(elf));
+ offset += sizeof(elf); /* Elf header */
+ offset += (segs+1) * sizeof(struct elf_phdr); /* Program headers */
+
+ /*
+ * Set up the notes in similar form to SVR4 core dumps made
+ * with info from their /proc.
+ */
+ memset(&psinfo, 0, sizeof(psinfo));
+ memset(&prstatus, 0, sizeof(prstatus));
+
+ notes[0].name = "CORE";
+ notes[0].type = NT_PRSTATUS;
+ notes[0].datasz = sizeof(prstatus);
+ notes[0].data = &prstatus;
+ prstatus.pr_info.si_signo = prstatus.pr_cursig = signr;
+ prstatus.pr_sigpend = current->signal;
+ prstatus.pr_sighold = current->blocked;
+ psinfo.pr_pid = prstatus.pr_pid = current->pid;
+ psinfo.pr_ppid = prstatus.pr_ppid = current->p_pptr->pid;
+ psinfo.pr_pgrp = prstatus.pr_pgrp = current->pgrp;
+ psinfo.pr_sid = prstatus.pr_sid = current->session;
+ prstatus.pr_utime.tv_sec = CT_TO_SECS(current->utime);
+ prstatus.pr_utime.tv_usec = CT_TO_USECS(current->utime);
+ prstatus.pr_stime.tv_sec = CT_TO_SECS(current->stime);
+ prstatus.pr_stime.tv_usec = CT_TO_USECS(current->stime);
+ prstatus.pr_cutime.tv_sec = CT_TO_SECS(current->cutime);
+ prstatus.pr_cutime.tv_usec = CT_TO_USECS(current->cutime);
+ prstatus.pr_cstime.tv_sec = CT_TO_SECS(current->cstime);
+ prstatus.pr_cstime.tv_usec = CT_TO_USECS(current->cstime);
+
+ /*
+ * This transfers the registers from regs into the standard
+ * coredump arrangement, whatever that is.
+ */
+#ifdef ELF_CORE_COPY_REGS
+ ELF_CORE_COPY_REGS(prstatus.pr_reg, regs)
+#else
+ if (sizeof(elf_gregset_t) != sizeof(struct pt_regs))
+ {
+ printk("sizeof(elf_gregset_t) (%ld) != sizeof(struct pt_regs) (%ld)\n",
+ sizeof(elf_gregset_t), sizeof(struct pt_regs));
+ }
+ else
+ *(struct pt_regs *)&prstatus.pr_reg = *regs;
+#endif
+
+ notes[1].name = "CORE";
+ notes[1].type = NT_PRPSINFO;
+ notes[1].datasz = sizeof(psinfo);
+ notes[1].data = &psinfo;
+ psinfo.pr_state = current->state;
+ psinfo.pr_sname = (current->state < 0 || current->state > 5) ? '.' : "RSDZTD"[current->state];
+ psinfo.pr_zomb = psinfo.pr_sname == 'Z';
+ psinfo.pr_nice = current->priority-15;
+ psinfo.pr_flag = current->flags;
+ psinfo.pr_uid = current->uid;
+ psinfo.pr_gid = current->gid;
+ {
+ int i, len;
+
+ set_fs(fs);
+
+ len = current->mm->arg_end - current->mm->arg_start;
+ len = len >= ELF_PRARGSZ ? ELF_PRARGSZ : len;
+ copy_from_user(&psinfo.pr_psargs,
+ (const char *)current->mm->arg_start, len);
+ for(i = 0; i < len; i++)
+ if (psinfo.pr_psargs[i] == 0)
+ psinfo.pr_psargs[i] = ' ';
+ psinfo.pr_psargs[len] = 0;
+
+ set_fs(KERNEL_DS);
+ }
+ strncpy(psinfo.pr_fname, current->comm, sizeof(psinfo.pr_fname));
+
+ notes[2].name = "CORE";
+ notes[2].type = NT_TASKSTRUCT;
+ notes[2].datasz = sizeof(*current);
+ notes[2].data = current;
+
+ /* Try to dump the fpu. */
+ prstatus.pr_fpvalid = dump_fpu (regs, &fpu);
+ if (!prstatus.pr_fpvalid)
+ {
+ numnote--;
+ }
+ else
+ {
+ notes[3].name = "CORE";
+ notes[3].type = NT_PRFPREG;
+ notes[3].datasz = sizeof(fpu);
+ notes[3].data = &fpu;
+ }
+
+ /* Write notes phdr entry */
+ {
+ struct elf_phdr phdr;
+ int sz = 0;
+
+ for(i = 0; i < numnote; i++)
+ sz += notesize(&notes[i]);
+
+ phdr.p_type = PT_NOTE;
+ phdr.p_offset = offset;
+ phdr.p_vaddr = 0;
+ phdr.p_paddr = 0;
+ phdr.p_filesz = sz;
+ phdr.p_memsz = 0;
+ phdr.p_flags = 0;
+ phdr.p_align = 0;
+
+ offset += phdr.p_filesz;
+ DUMP_WRITE(&phdr, sizeof(phdr));
+ }
+
+ /* Page-align dumped data */
+ dataoff = offset = roundup(offset, PAGE_SIZE);
+
+ /* Write program headers for segments dump */
+ for(vma = current->mm->mmap, i = 0;
+ i < segs && vma != NULL; vma = vma->vm_next) {
+ struct elf_phdr phdr;
+ size_t sz;
+
+ i++;
+
+ sz = vma->vm_end - vma->vm_start;
+
+ phdr.p_type = PT_LOAD;
+ phdr.p_offset = offset;
+ phdr.p_vaddr = vma->vm_start;
+ phdr.p_paddr = 0;
+ phdr.p_filesz = maydump(vma) ? sz : 0;
+ phdr.p_memsz = sz;
+ offset += phdr.p_filesz;
+ phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0;
+ if (vma->vm_flags & VM_WRITE) phdr.p_flags |= PF_W;
+ if (vma->vm_flags & VM_EXEC) phdr.p_flags |= PF_X;
+ phdr.p_align = PAGE_SIZE;
+
+ DUMP_WRITE(&phdr, sizeof(phdr));
+ }
+
+ for(i = 0; i < numnote; i++)
+ if (!writenote(&notes[i], &file))
+ goto close_coredump;
+
+ set_fs(fs);
+
+ DUMP_SEEK(dataoff);
+
+ for(i = 0, vma = current->mm->mmap;
+ i < segs && vma != NULL;
+ vma = vma->vm_next) {
+ unsigned long addr = vma->vm_start;
+ unsigned long len = vma->vm_end - vma->vm_start;
+
+ i++;
+ if (!maydump(vma))
+ continue;
+#ifdef DEBUG
+ printk("elf_core_dump: writing %08lx %lx\n", addr, len);
+#endif
+ DUMP_WRITE((void *)addr, len);
+ }
+
+ if ((off_t) file.f_pos != offset) {
+ /* Sanity check */
+ printk("elf_core_dump: file.f_pos (%ld) != offset (%ld)\n",
+ (off_t) file.f_pos, offset);
+ }
+
+ close_coredump:
+ if (file.f_op->release)
+ file.f_op->release(inode,&file);
+
+ end_coredump:
+ set_fs(fs);
+ iput(inode);
+#ifndef CONFIG_BINFMT_ELF32
+ MOD_DEC_USE_COUNT;
+#endif
+ return has_dumped;
+}
+#endif /* USE_ELF_CORE_DUMP */
+
+__initfunc(int init_elf32_binfmt(void))
+{
+ return register_binfmt(&elf32_format);
+}
+
+#ifdef MODULE
+
+int init_module(void)
+{
+ /* Install the COFF, ELF and XOUT loaders.
+ * N.B. We *rely* on the table being the right size with the
+ * right number of free slots...
+ */
+ return init_elf32_binfmt();
+}
+
+
+void cleanup_module( void)
+{
+ /* Remove the COFF and ELF loaders. */
+ unregister_binfmt(&elf32_format);
+}
+#endif
diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c
new file mode 100644
index 000000000..851d1550c
--- /dev/null
+++ b/arch/sparc64/kernel/sys_sparc.c
@@ -0,0 +1,270 @@
+/* $Id: sys_sparc.c,v 1.1 1997/04/09 08:25:18 jj Exp $
+ * linux/arch/sparc64/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/config.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/stat.h>
+#include <linux/mman.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+
+#include <asm/uaccess.h>
+#include <asm/ipc.h>
+
+/* 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;
+}
+
+extern asmlinkage unsigned long sys_brk(unsigned long brk);
+
+asmlinkage unsigned long sparc_brk(unsigned long brk)
+{
+ unsigned long ret;
+
+ lock_kernel();
+ if(brk >= 0x80000000000ULL) { /* VM hole */
+ ret = current->mm->brk;
+ goto out;
+ }
+ ret = sys_brk(brk);
+out:
+ unlock_kernel();
+ return ret;
+}
+
+/*
+ * 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;
+
+ lock_kernel();
+ error = do_pipe(fd);
+ if (error)
+ goto out;
+ regs->u_regs[UREG_I1] = fd[1];
+ error = fd[0];
+out:
+ unlock_kernel();
+ return error;
+}
+
+/*
+ * sys_ipc() is the de-multiplexer for the SysV IPC calls..
+ *
+ * This is really horribly ugly.
+ */
+
+asmlinkage int sys_ipc (unsigned call, int first, int second, unsigned long third, void *ptr, long fifth)
+{
+ int err;
+
+ lock_kernel();
+ /* No need for backward compatibility. We can start fresh... */
+
+ if (call <= SEMCTL)
+ switch (call) {
+ case SEMOP:
+ err = sys_semop (first, (struct sembuf *)ptr, second);
+ goto out;
+ case SEMGET:
+ err = sys_semget (first, second, (int)third);
+ goto out;
+ case SEMCTL: {
+ union semun fourth;
+ err = -EINVAL;
+ if (!ptr)
+ goto out;
+ err = -EFAULT;
+ if(get_user(fourth.__pad, (void **)ptr))
+ goto out;
+ err = sys_semctl (first, second, (int)third, fourth);
+ goto out;
+ }
+ default:
+ err = -EINVAL;
+ goto out;
+ }
+ if (call <= MSGCTL)
+ switch (call) {
+ case MSGSND:
+ err = sys_msgsnd (first, (struct msgbuf *) ptr,
+ second, (int)third);
+ goto out;
+ case MSGRCV:
+ err = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, (int)third);
+ goto out;
+ case MSGGET:
+ err = sys_msgget ((key_t) first, second);
+ goto out;
+ case MSGCTL:
+ err = sys_msgctl (first, second, (struct msqid_ds *) ptr);
+ goto out;
+ default:
+ err = -EINVAL;
+ goto out;
+ }
+ if (call <= SHMCTL)
+ switch (call) {
+ case SHMAT:
+ err = sys_shmat (first, (char *) ptr, second, (ulong *) third);
+ goto out;
+ case SHMDT:
+ err = sys_shmdt ((char *)ptr);
+ goto out;
+ case SHMGET:
+ err = sys_shmget (first, second, (int)third);
+ goto out;
+ case SHMCTL:
+ err = sys_shmctl (first, second, (struct shmid_ds *) ptr);
+ goto out;
+ default:
+ err = -EINVAL;
+ goto out;
+ }
+ else
+ err = -EINVAL;
+out:
+ unlock_kernel();
+ return err;
+}
+
+extern unsigned long get_unmapped_area(unsigned long addr, unsigned long len);
+
+/* Linux version of mmap */
+asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
+ unsigned long prot, unsigned long flags, unsigned long fd,
+ unsigned long off)
+{
+ struct file * file = NULL;
+ unsigned long retval = -EBADF;
+
+ lock_kernel();
+ if (!(flags & MAP_ANONYMOUS)) {
+ if (fd >= NR_OPEN || !(file = current->files->fd[fd])){
+ goto out;
+ }
+ }
+ retval = -ENOMEM;
+ if(!(flags & MAP_FIXED) && !addr) {
+ addr = get_unmapped_area(addr, len);
+ if(!addr){
+ goto out;
+ }
+ }
+
+ /* See asm-sparc64/uaccess.h */
+ retval = -EINVAL;
+ if((len > (TASK_SIZE - PAGE_SIZE)) || (addr > (TASK_SIZE-len-PAGE_SIZE)))
+ goto out;
+
+ if(addr >= 0x80000000000ULL) {
+ retval = current->mm->brk;
+ goto out;
+ }
+
+ retval = do_mmap(file, addr, len, prot, flags, off);
+out:
+ unlock_kernel();
+ return retval;
+}
+
+/* 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)
+{
+ lock_kernel();
+ printk ("Unimplemented SPARC system call %ld\n",regs->u_regs[1]);
+ show_regs (regs);
+ unlock_kernel();
+ return -ENOSYS;
+}
+
+/* #define DEBUG_SPARC_BREAKPOINT */
+
+asmlinkage void
+sparc_breakpoint (struct pt_regs *regs)
+{
+ lock_kernel();
+#ifdef DEBUG_SPARC_BREAKPOINT
+ printk ("TRAP: Entering kernel PC=%lx, nPC=%lx\n", regs->tpc, regs->tnpc);
+#endif
+ force_sig(SIGTRAP, current);
+#ifdef DEBUG_SPARC_BREAKPOINT
+ printk ("TRAP: Returning to space: PC=%lx nPC=%lx\n", regs->tpc, regs->tnpc);
+#endif
+ unlock_kernel();
+}
+
+extern void check_pending(int signum);
+
+asmlinkage int
+sparc_sigaction (int signum, const struct sigaction *action, struct sigaction *oldaction)
+{
+ struct sigaction new_sa, *p;
+ int err = -EINVAL;
+
+ lock_kernel();
+ if(signum < 0) {
+ current->tss.new_signal = 1;
+ signum = -signum;
+ }
+
+ if (signum<1 || signum>32)
+ goto out;
+ p = signum - 1 + current->sig->action;
+ if (action) {
+ err = -EINVAL;
+ if (signum==SIGKILL || signum==SIGSTOP)
+ goto out;
+ err = -EFAULT;
+ if(copy_from_user(&new_sa, action, sizeof(struct sigaction)))
+ goto out;
+ if (new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) {
+ err = verify_area(VERIFY_READ, new_sa.sa_handler, 1);
+ if (err)
+ goto out;
+ }
+ }
+
+ if (oldaction) {
+ err = -EFAULT;
+ if (copy_to_user(oldaction, p, sizeof(struct sigaction)))
+ goto out;
+ }
+
+ if (action) {
+ *p = new_sa;
+ check_pending(signum);
+ }
+
+ err = 0;
+out:
+ unlock_kernel();
+ return err;
+}
+
+/* only AP+ systems have sys_aplib */
+asmlinkage int sys_aplib(void)
+{
+ return -ENOSYS;
+}
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
new file mode 100644
index 000000000..e9911daed
--- /dev/null
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -0,0 +1,1741 @@
+/* $Id: sys_sparc32.c,v 1.9 1997/04/21 08:34:24 jj Exp $
+ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *
+ * These routines maintain argument size conversion between 32bit and 64bit
+ * environment.
+ */
+
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/signal.h>
+#include <linux/utime.h>
+#include <linux/resource.h>
+#include <linux/sched.h>
+#include <linux/times.h>
+#include <linux/utime.h>
+#include <linux/utsname.h>
+#include <linux/timex.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/malloc.h>
+#include <linux/uio.h>
+#include <linux/nfs_fs.h>
+#include <linux/smb_fs.h>
+#include <linux/ncp_fs.h>
+
+#include <asm/types.h>
+#include <asm/poll.h>
+#include <asm/ipc.h>
+#include <asm/uaccess.h>
+
+/* As gcc will warn about casting u32 to some ptr, we have to cast it to unsigned long first, and that's what is A() for.
+ * You just do (void *)A(x), instead of having to type (void *)((unsigned long)x) or instead of just (void *)x, which will
+ * produce warnings */
+#define A(x) ((unsigned long)x)
+
+extern asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on);
+extern asmlinkage unsigned long sys_brk(unsigned long brk);
+extern asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long off);
+extern asmlinkage int sys_bdflush(int func, long data);
+extern asmlinkage int sys_uselib(const char * library);
+extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg);
+extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
+extern asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev);
+extern asmlinkage int sys_mkdir(const char * pathname, int mode);
+extern asmlinkage int sys_rmdir(const char * pathname);
+extern asmlinkage int sys_unlink(const char * pathname);
+extern asmlinkage int sys_symlink(const char * oldname, const char * newname);
+extern asmlinkage int sys_link(const char * oldname, const char * newname);
+extern asmlinkage int sys_rename(const char * oldname, const char * newname);
+extern asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr);
+extern asmlinkage int sys_statfs(const char * path, struct statfs * buf);
+extern asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf);
+extern asmlinkage int sys_truncate(const char * path, unsigned long length);
+extern asmlinkage int sys_ftruncate(unsigned int fd, unsigned long length);
+extern asmlinkage int sys_utime(char * filename, struct utimbuf * times);
+extern asmlinkage int sys_utimes(char * filename, struct timeval * utimes);
+extern asmlinkage int sys_access(const char * filename, int mode);
+extern asmlinkage int sys_chdir(const char * filename);
+extern asmlinkage int sys_chroot(const char * filename);
+extern asmlinkage int sys_chmod(const char * filename, mode_t mode);
+extern asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group);
+extern asmlinkage int sys_open(const char * filename,int flags,int mode);
+extern asmlinkage int sys_creat(const char * pathname, int mode);
+extern asmlinkage long sys_lseek(unsigned int fd, off_t offset, unsigned int origin);
+extern asmlinkage int sys_llseek(unsigned int fd, unsigned long offset_high, unsigned long offset_low, loff_t *result, unsigned int origin);
+extern asmlinkage long sys_read(unsigned int fd, char * buf, unsigned long count);
+extern asmlinkage long sys_write(unsigned int fd, const char * buf, unsigned long count);
+extern asmlinkage long sys_readv(unsigned long fd, const struct iovec * vector, unsigned long count);
+extern asmlinkage long sys_writev(unsigned long fd, const struct iovec * vector, unsigned long count);
+extern asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp);
+extern asmlinkage int sys_poll(struct pollfd * ufds, unsigned int nfds, int timeout);
+extern asmlinkage int sys_newstat(char * filename, struct stat * statbuf);
+extern asmlinkage int sys_newlstat(char * filename, struct stat * statbuf);
+extern asmlinkage int sys_newfstat(unsigned int fd, struct stat * statbuf);
+extern asmlinkage int sys_readlink(const char * path, char * buf, int bufsiz);
+extern asmlinkage int sys_sysfs(int option, ...);
+extern asmlinkage int sys_ustat(dev_t dev, struct ustat * ubuf);
+extern asmlinkage int sys_umount(char * name);
+extern asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type, unsigned long new_flags, void *data);
+extern asmlinkage int sys_syslog(int type, char * bug, int count);
+extern asmlinkage int sys_personality(unsigned long personality);
+extern asmlinkage int sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru);
+extern asmlinkage int sys_waitpid(pid_t pid,unsigned int * stat_addr, int options);
+extern asmlinkage int sys_sysinfo(struct sysinfo *info);
+extern asmlinkage int sys_getitimer(int which, struct itimerval *value);
+extern asmlinkage int sys_setitimer(int which, struct itimerval *value, struct itimerval *ovalue);
+extern asmlinkage int sys_sched_setscheduler(pid_t pid, int policy, struct sched_param *param);
+extern asmlinkage int sys_sched_setparam(pid_t pid, struct sched_param *param);
+extern asmlinkage int sys_sched_getparam(pid_t pid, struct sched_param *param);
+extern asmlinkage int sys_sched_rr_get_interval(pid_t pid, struct timespec *interval);
+extern asmlinkage int sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp);
+extern asmlinkage int sys_sigprocmask(int how, sigset_t *set, sigset_t *oset);
+extern asmlinkage int sys_sigpending(sigset_t *set);
+extern asmlinkage unsigned long sys_signal(int signum, __sighandler_t handler);
+extern asmlinkage int sys_reboot(int magic1, int magic2, int cmd, void * arg);
+extern asmlinkage int sys_acct(const char *name);
+extern asmlinkage int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
+extern asmlinkage long sys_times(struct tms * tbuf);
+extern asmlinkage int sys_getgroups(int gidsetsize, gid_t *grouplist);
+extern asmlinkage int sys_setgroups(int gidsetsize, gid_t *grouplist);
+extern asmlinkage int sys_newuname(struct new_utsname * name);
+extern asmlinkage int sys_olduname(struct oldold_utsname * name);
+extern asmlinkage int sys_sethostname(char *name, int len);
+extern asmlinkage int sys_gethostname(char *name, int len);
+extern asmlinkage int sys_setdomainname(char *name, int len);
+extern asmlinkage int sys_getrlimit(unsigned int resource, struct rlimit *rlim);
+extern asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim);
+extern asmlinkage int sys_getrusage(int who, struct rusage *ru);
+extern asmlinkage int sys_time(int * tloc);
+extern asmlinkage int sys_gettimeofday(struct timeval *tv, struct timezone *tz);
+extern asmlinkage int sys_settimeofday(struct timeval *tv, struct timezone *tz);
+extern asmlinkage int sys_adjtimex(struct timex *txc_p);
+extern asmlinkage int sys_msync(unsigned long start, size_t len, int flags);
+extern asmlinkage int sys_mlock(unsigned long start, size_t len);
+extern asmlinkage int sys_munlock(unsigned long start, size_t len);
+extern asmlinkage int sys_munmap(unsigned long addr, size_t len);
+extern asmlinkage int sys_mprotect(unsigned long start, size_t len, unsigned long prot);
+extern asmlinkage unsigned long sys_mremap(unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flags);
+extern asmlinkage int sys_swapoff(const char * specialfile);
+extern asmlinkage int sys_swapon(const char * specialfile, int swap_flags);
+extern asmlinkage int sys_bind(int fd, struct sockaddr *umyaddr, int addrlen);
+extern asmlinkage int sys_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrlen);
+extern asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen);
+extern asmlinkage int sys_getsockname(int fd, struct sockaddr *usockaddr, int *usockaddr_len);
+extern asmlinkage int sys_getpeername(int fd, struct sockaddr *usockaddr, int *usockaddr_len);
+extern asmlinkage int sys_send(int fd, void * buff, size_t len, unsigned flags);
+extern asmlinkage int sys_sendto(int fd, void * buff, size_t len, unsigned flags, struct sockaddr *addr, int addr_len);
+extern asmlinkage int sys_recv(int fd, void * ubuf, size_t size, unsigned flags);
+extern asmlinkage int sys_recvfrom(int fd, void * ubuf, size_t size, unsigned flags, struct sockaddr *addr, int *addr_len);
+extern asmlinkage int sys_setsockopt(int fd, int level, int optname, char *optval, int optlen);
+extern asmlinkage int sys_getsockopt(int fd, int level, int optname, char *optval, int *optlen);
+extern asmlinkage int sys_sendmsg(int fd, struct msghdr *msg, unsigned flags);
+extern asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags);
+extern asmlinkage int sys_socketcall(int call, unsigned long *args);
+extern asmlinkage int sys_nfsservctl(int cmd, void *argp, void *resp);
+
+asmlinkage int sys32_ioperm(u32 from, u32 num, int on)
+{
+ return sys_ioperm((unsigned long)from, (unsigned long)num, on);
+}
+
+struct msgbuf32 { s32 mtype; char mtext[1]; };
+
+struct ipc_perm32
+{
+ key_t key;
+ __kernel_uid_t32 uid;
+ __kernel_gid_t32 gid;
+ __kernel_uid_t32 cuid;
+ __kernel_gid_t32 cgid;
+ __kernel_mode_t32 mode;
+ unsigned short seq;
+};
+
+struct msqid_ds32
+{
+ struct ipc_perm32 msg_perm;
+ u32 msg_first;
+ u32 msg_last;
+ __kernel_time_t32 msg_stime;
+ __kernel_time_t32 msg_rtime;
+ __kernel_time_t32 msg_ctime;
+ u32 wwait;
+ u32 rwait;
+ unsigned short msg_cbytes;
+ unsigned short msg_qnum;
+ unsigned short msg_qbytes;
+ __kernel_ipc_pid_t32 msg_lspid;
+ __kernel_ipc_pid_t32 msg_lrpid;
+};
+
+struct shmid_ds32 {
+ struct ipc_perm32 shm_perm;
+ int shm_segsz;
+ __kernel_time_t32 shm_atime;
+ __kernel_time_t32 shm_dtime;
+ __kernel_time_t32 shm_ctime;
+ __kernel_ipc_pid_t32 shm_cpid;
+ __kernel_ipc_pid_t32 shm_lpid;
+ unsigned short shm_nattch;
+ unsigned short shm_npages;
+ u32 shm_pages;
+ u32 attaches;
+};
+
+/*
+ * sys32_ipc() is the de-multiplexer for the SysV IPC calls in 32bit emulation..
+ *
+ * This is really horribly ugly.
+ */
+
+asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth)
+{
+ int version, err;
+
+ lock_kernel();
+ version = call >> 16; /* hack for backward compatibility */
+ call &= 0xffff;
+
+ if (call <= SEMCTL)
+ switch (call) {
+ case SEMOP:
+ /* struct sembuf is the same on 32 and 64bit :)) */
+ err = sys_semop (first, (struct sembuf *)A(ptr), second);
+ goto out;
+ case SEMGET:
+ err = sys_semget (first, second, third);
+ goto out;
+ case SEMCTL: {
+ /* XXX union semun32 to union semun64 and back conversion */
+ union semun fourth;
+ err = -EINVAL;
+ if (!ptr)
+ goto out;
+ err = -EFAULT;
+ if(get_user(fourth.__pad, (void **)A(ptr)))
+ goto out;
+ err = sys_semctl (first, second, third, fourth);
+ goto out;
+ }
+ default:
+ err = -EINVAL;
+ goto out;
+ }
+ if (call <= MSGCTL)
+ switch (call) {
+ case MSGSND:
+ {
+ struct msgbuf *p = kmalloc (second + sizeof (struct msgbuf), GFP_KERNEL);
+
+ if (!p) err = -ENOMEM;
+ else {
+ if (get_user(p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) ||
+ __copy_from_user(p->mtext, &(((struct msgbuf32 *)A(ptr))->mtext), second))
+ err = -EFAULT;
+ else {
+ unsigned long old_fs = get_fs();
+ set_fs (KERNEL_DS);
+ err = sys_msgsnd (first, p, second, third);
+ set_fs (old_fs);
+ }
+ kfree (p);
+ }
+ }
+ goto out;
+ case MSGRCV:
+ {
+ struct msgbuf *p;
+ unsigned long old_fs;
+
+ if (!version) {
+ struct ipc_kludge tmp;
+ err = -EINVAL;
+ if (!ptr)
+ goto out;
+ err = -EFAULT;
+ if(copy_from_user(&tmp,(struct ipc_kludge *)A(ptr), sizeof (tmp)))
+ goto out;
+ ptr = tmp.msgp;
+ fifth = tmp.msgtyp;
+ }
+ p = kmalloc (second + sizeof (struct msgbuf), GFP_KERNEL);
+ if (!p) {
+ err = -EFAULT;
+ goto out;
+ }
+ old_fs = get_fs();
+ set_fs (KERNEL_DS);
+ err = sys_msgrcv (first, p, second, fifth, third);
+ set_fs (old_fs);
+ if (put_user (p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) ||
+ __copy_to_user(&(((struct msgbuf32 *)A(ptr))->mtext), p->mtext, second))
+ err = -EFAULT;
+ kfree (p);
+ goto out;
+ }
+ case MSGGET:
+ err = sys_msgget ((key_t) first, second);
+ goto out;
+ case MSGCTL:
+ {
+ struct msqid_ds m;
+ unsigned long old_fs;
+
+ switch (second) {
+ case IPC_INFO:
+ case MSG_INFO:
+ /* struct msginfo is the same */
+ case IPC_RMID:
+ /* and this doesn't care about ptr */
+ err = sys_msgctl (first, second, (struct msqid_ds *)A(ptr));
+ goto out;
+
+ case IPC_SET:
+ if (get_user (m.msg_perm.uid, &(((struct msqid_ds32 *)A(ptr))->msg_perm.uid)) ||
+ __get_user (m.msg_perm.gid, &(((struct msqid_ds32 *)A(ptr))->msg_perm.gid)) ||
+ __get_user (m.msg_perm.mode, &(((struct msqid_ds32 *)A(ptr))->msg_perm.mode)) ||
+ __get_user (m.msg_qbytes, &(((struct msqid_ds32 *)A(ptr))->msg_qbytes))) {
+ err = -EFAULT;
+ goto out;
+ }
+ default:
+ break;
+ }
+ old_fs = get_fs();
+ set_fs (KERNEL_DS);
+ err = sys_msgctl (first, second, &m);
+ set_fs (old_fs);
+ switch (second) {
+ case MSG_STAT:
+ case IPC_STAT:
+ if (put_user (m.msg_perm.key, &(((struct msqid_ds32 *)A(ptr))->msg_perm.key)) ||
+ __put_user (m.msg_perm.uid, &(((struct msqid_ds32 *)A(ptr))->msg_perm.uid)) ||
+ __put_user (m.msg_perm.gid, &(((struct msqid_ds32 *)A(ptr))->msg_perm.gid)) ||
+ __put_user (m.msg_perm.cuid, &(((struct msqid_ds32 *)A(ptr))->msg_perm.cuid)) ||
+ __put_user (m.msg_perm.cgid, &(((struct msqid_ds32 *)A(ptr))->msg_perm.cgid)) ||
+ __put_user (m.msg_perm.mode, &(((struct msqid_ds32 *)A(ptr))->msg_perm.mode)) ||
+ __put_user (m.msg_perm.seq, &(((struct msqid_ds32 *)A(ptr))->msg_perm.seq)) ||
+ __put_user (m.msg_stime, &(((struct msqid_ds32 *)A(ptr))->msg_stime)) ||
+ __put_user (m.msg_rtime, &(((struct msqid_ds32 *)A(ptr))->msg_rtime)) ||
+ __put_user (m.msg_ctime, &(((struct msqid_ds32 *)A(ptr))->msg_ctime)) ||
+ __put_user (m.msg_cbytes, &(((struct msqid_ds32 *)A(ptr))->msg_cbytes)) ||
+ __put_user (m.msg_qnum, &(((struct msqid_ds32 *)A(ptr))->msg_qnum)) ||
+ __put_user (m.msg_qbytes, &(((struct msqid_ds32 *)A(ptr))->msg_qbytes)) ||
+ __put_user (m.msg_lspid, &(((struct msqid_ds32 *)A(ptr))->msg_lspid)) ||
+ __put_user (m.msg_lrpid, &(((struct msqid_ds32 *)A(ptr))->msg_lrpid)))
+ err = -EFAULT;
+ break;
+ default:
+ break;
+ }
+ }
+ goto out;
+ default:
+ err = -EINVAL;
+ goto out;
+ }
+ if (call <= SHMCTL)
+ switch (call) {
+ case SHMAT:
+ switch (version) {
+ case 0: default: {
+ unsigned long raddr;
+ err = sys_shmat (first, (char *)A(ptr), second, &raddr);
+ if (err)
+ goto out;
+ err = -EFAULT;
+ if(put_user (raddr, ((u32 *)A(third))))
+ goto out;
+ err = 0;
+ goto out;
+ }
+ case 1: /* If iBCS2 should ever run, then for sure in 64bit mode, not 32bit... */
+ err = -EINVAL;
+ goto out;
+ }
+ case SHMDT:
+ err = sys_shmdt ((char *)A(ptr));
+ goto out;
+ case SHMGET:
+ err = sys_shmget (first, second, third);
+ goto out;
+ case SHMCTL:
+ {
+ struct shmid_ds s;
+ unsigned long old_fs;
+
+ switch (second) {
+ case IPC_INFO:
+ /* struct shminfo is the same */
+ case SHM_LOCK:
+ case SHM_UNLOCK:
+ case IPC_RMID:
+ /* and these three aren't using ptr at all */
+ err = sys_shmctl (first, second, (struct shmid_ds *)A(ptr));
+ goto out;
+
+ case IPC_SET:
+ if (get_user (s.shm_perm.uid, &(((struct shmid_ds32 *)A(ptr))->shm_perm.uid)) ||
+ __get_user (s.shm_perm.gid, &(((struct shmid_ds32 *)A(ptr))->shm_perm.gid)) ||
+ __get_user (s.shm_perm.mode, &(((struct shmid_ds32 *)A(ptr))->shm_perm.mode))) {
+ err = -EFAULT;
+ goto out;
+ }
+ default:
+ break;
+ }
+ old_fs = get_fs();
+ set_fs (KERNEL_DS);
+ err = sys_shmctl (first, second, &s);
+ set_fs (old_fs);
+ switch (second) {
+ case SHM_INFO:
+ {
+ struct shm_info32 { int used_ids; u32 shm_tot; u32 shm_rss; u32 shm_swp; u32 swap_attempts; u32 swap_successes; };
+ struct shm_info *si = (struct shm_info *)&s;
+
+ if (put_user (si->used_ids, &(((struct shm_info32 *)A(ptr))->used_ids)) ||
+ __put_user (si->shm_tot, &(((struct shm_info32 *)A(ptr))->shm_tot)) ||
+ __put_user (si->shm_rss, &(((struct shm_info32 *)A(ptr))->shm_rss)) ||
+ __put_user (si->shm_swp, &(((struct shm_info32 *)A(ptr))->shm_swp)) ||
+ __put_user (si->swap_attempts, &(((struct shm_info32 *)A(ptr))->swap_attempts)) ||
+ __put_user (si->swap_successes, &(((struct shm_info32 *)A(ptr))->swap_successes)))
+ err = -EFAULT;
+ }
+ break;
+ case SHM_STAT:
+ case IPC_STAT:
+ if (put_user (s.shm_perm.key, &(((struct shmid_ds32 *)A(ptr))->shm_perm.key)) ||
+ __put_user (s.shm_perm.uid, &(((struct shmid_ds32 *)A(ptr))->shm_perm.uid)) ||
+ __put_user (s.shm_perm.gid, &(((struct shmid_ds32 *)A(ptr))->shm_perm.gid)) ||
+ __put_user (s.shm_perm.cuid, &(((struct shmid_ds32 *)A(ptr))->shm_perm.cuid)) ||
+ __put_user (s.shm_perm.cgid, &(((struct shmid_ds32 *)A(ptr))->shm_perm.cgid)) ||
+ __put_user (s.shm_perm.mode, &(((struct shmid_ds32 *)A(ptr))->shm_perm.mode)) ||
+ __put_user (s.shm_perm.seq, &(((struct shmid_ds32 *)A(ptr))->shm_perm.seq)) ||
+ __put_user (s.shm_atime, &(((struct shmid_ds32 *)A(ptr))->shm_atime)) ||
+ __put_user (s.shm_dtime, &(((struct shmid_ds32 *)A(ptr))->shm_dtime)) ||
+ __put_user (s.shm_ctime, &(((struct shmid_ds32 *)A(ptr))->shm_ctime)) ||
+ __put_user (s.shm_segsz, &(((struct shmid_ds32 *)A(ptr))->shm_segsz)) ||
+ __put_user (s.shm_nattch, &(((struct shmid_ds32 *)A(ptr))->shm_nattch)) ||
+ __put_user (s.shm_lpid, &(((struct shmid_ds32 *)A(ptr))->shm_cpid)) ||
+ __put_user (s.shm_cpid, &(((struct shmid_ds32 *)A(ptr))->shm_lpid)))
+ err = -EFAULT;
+ break;
+ default:
+ break;
+ }
+ }
+ goto out;
+ default:
+ err = -EINVAL;
+ goto out;
+ }
+ else
+ err = -EINVAL;
+out:
+ unlock_kernel();
+ return err;
+}
+
+asmlinkage unsigned long sys32_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 off)
+{
+ return sys_mmap((unsigned long)addr, (unsigned long)len, (unsigned long)prot, (unsigned long)flags,
+ (unsigned long)fd, (unsigned long)off);
+}
+
+asmlinkage int sys32_bdflush(int func, s32 data)
+{
+ return sys_bdflush(func, (long)data);
+}
+
+asmlinkage int sys32_uselib(u32 library)
+{
+ return sys_uselib((const char *)A(library));
+}
+
+asmlinkage long sys32_fcntl(unsigned int fd, unsigned int cmd, u32 arg)
+{
+ switch (cmd) {
+ case F_GETLK:
+ case F_SETLK:
+ case F_SETLKW:
+ {
+ struct flock f;
+ unsigned long old_fs;
+ long ret;
+
+ if (get_user (f.l_type, &(((struct flock32 *)A(arg))->l_type)) ||
+ __get_user (f.l_whence, &(((struct flock32 *)A(arg))->l_whence)) ||
+ __get_user (f.l_start, &(((struct flock32 *)A(arg))->l_start)) ||
+ __get_user (f.l_len, &(((struct flock32 *)A(arg))->l_len)) ||
+ __get_user (f.l_pid, &(((struct flock32 *)A(arg))->l_pid)))
+ return -EFAULT;
+ old_fs = get_fs(); set_fs (KERNEL_DS);
+ ret = sys_fcntl(fd, cmd, (unsigned long)&f);
+ set_fs (old_fs);
+ if (__put_user (f.l_type, &(((struct flock32 *)A(arg))->l_type)) ||
+ __put_user (f.l_whence, &(((struct flock32 *)A(arg))->l_whence)) ||
+ __put_user (f.l_start, &(((struct flock32 *)A(arg))->l_start)) ||
+ __put_user (f.l_len, &(((struct flock32 *)A(arg))->l_len)) ||
+ __put_user (f.l_pid, &(((struct flock32 *)A(arg))->l_pid)))
+ return -EFAULT;
+ return ret;
+ }
+ default:
+ return sys_fcntl(fd, cmd, (unsigned long)arg);
+ }
+}
+
+/* Conversion of args should be probably done in all the locations where it is handled,
+ using if (current->tss.flags & SPARC_FLAG_32BIT */
+asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
+{
+ return sys_ioctl(fd, cmd, (unsigned long)arg);
+}
+
+asmlinkage int sys32_mknod(u32 filename, int mode, __kernel_dev_t32 dev)
+{
+ return sys_mknod((const char *)A(filename), mode, dev);
+}
+
+asmlinkage int sys32_mkdir(u32 pathname, int mode)
+{
+ return sys_mkdir((const char *)A(pathname), mode);
+}
+
+asmlinkage int sys32_rmdir(u32 pathname)
+{
+ return sys_rmdir((const char *)A(pathname));
+}
+
+asmlinkage int sys32_unlink(u32 pathname)
+{
+ return sys_unlink((const char *)A(pathname));
+}
+
+asmlinkage int sys32_symlink(u32 oldname, u32 newname)
+{
+ return sys_symlink((const char *)A(oldname), (const char *)A(newname));
+}
+
+asmlinkage int sys32_link(u32 oldname, u32 newname)
+{
+ return sys_link((const char *)A(oldname), (const char *)A(newname));
+}
+
+asmlinkage int sys32_rename(u32 oldname, u32 newname)
+{
+ return sys_rename((const char *)A(oldname), (const char *)A(newname));
+}
+
+/* XXX: Play with the addr, it will be ugly :(( */
+asmlinkage int sys32_quotactl(int cmd, u32 special, int id, u32 addr)
+{
+ return sys_quotactl(cmd, (const char *)A(special), id, (caddr_t)A(addr));
+}
+
+static int put_statfs (u32 buf, struct statfs *s)
+{
+ if (put_user (s->f_type, &(((struct statfs32 *)A(buf))->f_type)) ||
+ __put_user (s->f_bsize, &(((struct statfs32 *)A(buf))->f_bsize)) ||
+ __put_user (s->f_blocks, &(((struct statfs32 *)A(buf))->f_blocks)) ||
+ __put_user (s->f_bfree, &(((struct statfs32 *)A(buf))->f_bfree)) ||
+ __put_user (s->f_bavail, &(((struct statfs32 *)A(buf))->f_bavail)) ||
+ __put_user (s->f_files, &(((struct statfs32 *)A(buf))->f_files)) ||
+ __put_user (s->f_ffree, &(((struct statfs32 *)A(buf))->f_ffree)) ||
+ __put_user (s->f_namelen, &(((struct statfs32 *)A(buf))->f_namelen)) ||
+ __put_user (s->f_fsid.val[0], &(((struct statfs32 *)A(buf))->f_fsid.val[0])) ||
+ __put_user (s->f_fsid.val[1], &(((struct statfs32 *)A(buf))->f_fsid.val[1])))
+ return -EFAULT;
+ return 0;
+}
+
+asmlinkage int sys32_statfs(u32 path, u32 buf)
+{
+ int ret;
+ struct statfs s;
+ unsigned long old_fs = get_fs();
+
+ set_fs (KERNEL_DS);
+ ret = sys_statfs((const char *)A(path), &s);
+ set_fs (old_fs);
+ if (put_statfs(buf, &s)) return -EFAULT;
+ return ret;
+}
+
+asmlinkage int sys32_fstatfs(unsigned int fd, u32 buf)
+{
+ int ret;
+ struct statfs s;
+ unsigned long old_fs = get_fs();
+
+ set_fs (KERNEL_DS);
+ ret = sys_fstatfs(fd, &s);
+ set_fs (old_fs);
+ if (put_statfs(buf, &s)) return -EFAULT;
+ return ret;
+}
+
+asmlinkage int sys32_truncate(u32 path, u32 length)
+{
+ return sys_truncate((const char *)A(path), (unsigned long)length);
+}
+
+asmlinkage int sys32_ftruncate(unsigned int fd, u32 length)
+{
+ return sys_ftruncate(fd, (unsigned long)length);
+}
+
+asmlinkage int sys32_utime(u32 filename, u32 times)
+{
+ struct utimbuf32 { __kernel_time_t32 actime, modtime; };
+ struct utimbuf t;
+ unsigned long old_fs;
+ int ret;
+
+ if (get_user (t.actime, &(((struct utimbuf32 *)A(times))->actime)) ||
+ __get_user (t.modtime, &(((struct utimbuf32 *)A(times))->modtime)))
+ return -EFAULT;
+ old_fs = get_fs();
+ set_fs (KERNEL_DS);
+ ret = sys_utime((char *)A(filename), &t);
+ set_fs (old_fs);
+ return ret;
+}
+
+asmlinkage int sys32_utimes(u32 filename, u32 utimes)
+{
+ /* struct timeval is the same :)) */
+ return sys_utimes((char *)A(filename), (struct timeval *)A(utimes));
+}
+
+asmlinkage int sys32_access(u32 filename, int mode)
+{
+ return sys_access((const char *)A(filename), mode);
+}
+
+asmlinkage int sys32_chdir(u32 filename)
+{
+ return sys_chdir((const char *)A(filename));
+}
+
+asmlinkage int sys32_chroot(u32 filename)
+{
+ return sys_chroot((const char *)A(filename));
+}
+
+asmlinkage int sys32_chmod(u32 filename, __kernel_mode_t32 mode)
+{
+ return sys_chmod((const char *)A(filename), mode);
+}
+
+asmlinkage int sys32_chown(u32 filename, __kernel_uid_t32 user, __kernel_gid_t32 group)
+{
+ return sys_chown((const char *)A(filename), user, group);
+}
+
+asmlinkage int sys32_open(u32 filename, int flags, int mode)
+{
+ return sys_open((const char *)A(filename), flags, mode);
+}
+
+asmlinkage int sys32_creat(u32 pathname, int mode)
+{
+ return sys_creat((const char *)A(pathname), mode);
+}
+
+asmlinkage long sys32_lseek(unsigned int fd, s32 offset, unsigned int origin)
+{
+ return sys_lseek(fd, (off_t)offset, origin);
+}
+
+asmlinkage int sys32_llseek(unsigned int fd, u32 offset_high, u32 offset_low, u32 result, unsigned int origin)
+{
+ /* loff_t is the same :)) */
+ return sys_llseek(fd, (unsigned long)offset_high, (unsigned long)offset_low, (loff_t *)A(result), origin);
+}
+
+asmlinkage long sys32_read(unsigned int fd, u32 buf, u32 count)
+{
+ return sys_read(fd, (char *)A(buf), (unsigned long)count);
+}
+
+asmlinkage long sys32_write(unsigned int fd, u32 buf, u32 count)
+{
+ return sys_write(fd, (const char *)A(buf), (unsigned long)count);
+}
+
+struct iovec32 { u32 iov_base; __kernel_size_t32 iov_len; };
+
+asmlinkage long sys32_readv(u32 fd, u32 vector, u32 count)
+{
+ struct iovec *v;
+ struct iovec vf[UIO_FASTIOV];
+ u32 i;
+ long ret;
+ unsigned long old_fs;
+
+ if (!count) return 0; if (count > UIO_MAXIOV) return -EINVAL;
+ if (count <= UIO_FASTIOV)
+ v = vf;
+ else {
+ lock_kernel ();
+ v = kmalloc (count * sizeof (struct iovec), GFP_KERNEL);
+ if (!v) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ }
+ for (i = 0; i < count; i++) {
+ if (__get_user ((unsigned long)(v[i].iov_base), &((((struct iovec32 *)A(vector))+i)->iov_base)) ||
+ __get_user (v[i].iov_len, &((((struct iovec32 *)A(vector))+i)->iov_len))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ }
+ old_fs = get_fs();
+ set_fs (KERNEL_DS);
+ ret = sys_readv((unsigned long)fd, v, (unsigned long)count);
+ set_fs (old_fs);
+out:
+ if (count > UIO_FASTIOV) {
+ kfree (v);
+ unlock_kernel ();
+ }
+ return ret;
+}
+
+asmlinkage long sys32_writev(u32 fd, u32 vector, u32 count)
+{
+ struct iovec *v;
+ struct iovec vf[UIO_FASTIOV];
+ u32 i;
+ long ret;
+ unsigned long old_fs;
+
+ if (!count) return 0; if (count > UIO_MAXIOV) return -EINVAL;
+ if (count <= UIO_FASTIOV)
+ v = vf;
+ else {
+ lock_kernel ();
+ v = kmalloc (count * sizeof (struct iovec), GFP_KERNEL);
+ if (!v) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ }
+ for (i = 0; i < count; i++) {
+ if (__get_user ((unsigned long)(v[i].iov_base), &((((struct iovec32 *)A(vector))+i)->iov_base)) ||
+ __get_user (v[i].iov_len, &((((struct iovec32 *)A(vector))+i)->iov_len))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ }
+ old_fs = get_fs();
+ set_fs (KERNEL_DS);
+ ret = sys_writev((unsigned long)fd, v, (unsigned long)count);
+ set_fs (old_fs);
+out:
+ if (count > UIO_FASTIOV) {
+ kfree (v);
+ unlock_kernel ();
+ }
+ return ret;
+}
+
+/* readdir & getdents */
+
+#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
+#define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1))
+
+struct old_linux_dirent32 {
+ u32 d_ino;
+ u32 d_offset;
+ unsigned short d_namlen;
+ char d_name[1];
+};
+
+struct readdir_callback32 {
+ struct old_linux_dirent32 * dirent;
+ int count;
+};
+
+static int fillonedir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino)
+{
+ struct readdir_callback32 * buf = (struct readdir_callback32 *) __buf;
+ struct old_linux_dirent32 * dirent;
+
+ if (buf->count)
+ return -EINVAL;
+ buf->count++;
+ dirent = buf->dirent;
+ put_user(ino, &dirent->d_ino);
+ put_user(offset, &dirent->d_offset);
+ put_user(namlen, &dirent->d_namlen);
+ copy_to_user(dirent->d_name, name, namlen);
+ put_user(0, dirent->d_name + namlen);
+ return 0;
+}
+
+asmlinkage int old32_readdir(unsigned int fd, u32 dirent, unsigned int count)
+{
+ int error = -EBADF;
+ struct file * file;
+ struct readdir_callback32 buf;
+
+ lock_kernel();
+ if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+ goto out;
+ error = -ENOTDIR;
+ if (!file->f_op || !file->f_op->readdir)
+ goto out;
+ error = verify_area(VERIFY_WRITE, (void *)A(dirent), sizeof(struct old_linux_dirent32));
+ if (error)
+ goto out;
+ buf.count = 0;
+ buf.dirent = (struct old_linux_dirent32 *)A(dirent);
+ error = file->f_op->readdir(file->f_inode, file, &buf, fillonedir);
+ if (error < 0)
+ goto out;
+ error = buf.count;
+out:
+ unlock_kernel();
+ return error;
+}
+
+struct linux_dirent32 {
+ u32 d_ino;
+ u32 d_off;
+ unsigned short d_reclen;
+ char d_name[1];
+};
+
+struct getdents_callback32 {
+ struct linux_dirent32 * current_dir;
+ struct linux_dirent32 * previous;
+ int count;
+ int error;
+};
+
+static int filldir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino)
+{
+ struct linux_dirent32 * dirent;
+ struct getdents_callback32 * buf = (struct getdents_callback32 *) __buf;
+ int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
+
+ buf->error = -EINVAL; /* only used if we fail.. */
+ if (reclen > buf->count)
+ return -EINVAL;
+ dirent = buf->previous;
+ if (dirent)
+ put_user(offset, &dirent->d_off);
+ dirent = buf->current_dir;
+ buf->previous = dirent;
+ put_user(ino, &dirent->d_ino);
+ put_user(reclen, &dirent->d_reclen);
+ copy_to_user(dirent->d_name, name, namlen);
+ put_user(0, dirent->d_name + namlen);
+ ((char *) dirent) += reclen;
+ buf->current_dir = dirent;
+ buf->count -= reclen;
+ return 0;
+}
+
+asmlinkage int sys32_getdents(unsigned int fd, u32 dirent, unsigned int count)
+{
+ struct file * file;
+ struct linux_dirent32 * lastdirent;
+ struct getdents_callback32 buf;
+ int error = -EBADF;
+
+ lock_kernel();
+ if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+ goto out;
+ error = -ENOTDIR;
+ if (!file->f_op || !file->f_op->readdir)
+ goto out;
+ error = verify_area(VERIFY_WRITE, (void *)A(dirent), count);
+ if (error)
+ goto out;
+ buf.current_dir = (struct linux_dirent32 *) A(dirent);
+ buf.previous = NULL;
+ buf.count = count;
+ buf.error = 0;
+ error = file->f_op->readdir(file->f_inode, file, &buf, filldir);
+ if (error < 0)
+ goto out;
+ lastdirent = buf.previous;
+ if (!lastdirent) {
+ error = buf.error;
+ } else {
+ put_user(file->f_pos, &lastdirent->d_off);
+ error = count - buf.count;
+ }
+out:
+ unlock_kernel();
+ return error;
+}
+
+/* end of readdir & getdents */
+
+asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp)
+{
+ unsigned long old_fs;
+ char *p;
+ u32 *q;
+ int i, ret = -EINVAL, nn;
+ u32 *Inp, *Outp, *Exp;
+
+ if (n < 0 || n > PAGE_SIZE*2) return -EINVAL;
+ lock_kernel ();
+ p = (char *)__get_free_page (GFP_KERNEL);
+ if (!p) goto out;
+ q = (u32 *)p;
+ nn = (n + 8 * sizeof(unsigned long) - 1) / (8 * sizeof (unsigned long));
+ Inp = (u32 *)A(inp); Outp = (u32 *)A(outp); Exp = (u32 *)A(exp);
+ ret = -EFAULT;
+ for (i = 0; i < ret; i++, Inp += 2, Outp += 2, Exp += 2, q += 2) {
+ if (__get_user (q[1], Inp) ||
+ __get_user (q[0], Inp+1) ||
+ __get_user (q[1+PAGE_SIZE/4], Outp) ||
+ __get_user (q[PAGE_SIZE/4], Outp+1) ||
+ __get_user (q[1+PAGE_SIZE/2], Exp) ||
+ __get_user (q[PAGE_SIZE/2], Exp+1))
+ goto out;
+ }
+ old_fs = get_fs ();
+ set_fs (KERNEL_DS);
+ ret = sys_select(n, (fd_set *)p, (fd_set *)(p + PAGE_SIZE/4), (fd_set *)(p + PAGE_SIZE/2), (struct timeval *)A(tvp));
+ set_fs (old_fs);
+ q = (u32 *)p;
+ Inp = (u32 *)A(inp); Outp = (u32 *)A(outp); Exp = (u32 *)A(exp);
+ for (i = 0; i < ret; i++, Inp += 2, Outp += 2, Exp += 2, q += 2) {
+ if (__put_user (q[1], Inp) ||
+ __put_user (q[0], Inp+1) ||
+ __put_user (q[1+PAGE_SIZE/4], Outp) ||
+ __put_user (q[PAGE_SIZE/4], Outp+1) ||
+ __put_user (q[1+PAGE_SIZE/2], Exp) ||
+ __put_user (q[PAGE_SIZE/2], Exp+1)) {
+ ret = -EFAULT;
+ goto out;
+ }
+ }
+out:
+ free_page ((unsigned long)p);
+ return ret;
+}
+
+asmlinkage int sys32_poll(u32 ufds, unsigned int nfds, int timeout)
+{
+ return sys_poll((struct pollfd *)A(ufds), nfds, timeout);
+}
+
+static inline int putstat(u32 statbuf, struct stat *s)
+{
+ if (put_user (s->st_dev, &(((struct stat32 *)A(statbuf))->st_dev)) ||
+ __put_user (s->st_ino, &(((struct stat32 *)A(statbuf))->st_ino)) ||
+ __put_user (s->st_mode, &(((struct stat32 *)A(statbuf))->st_mode)) ||
+ __put_user (s->st_nlink, &(((struct stat32 *)A(statbuf))->st_nlink)) ||
+ __put_user (s->st_uid, &(((struct stat32 *)A(statbuf))->st_uid)) ||
+ __put_user (s->st_gid, &(((struct stat32 *)A(statbuf))->st_gid)) ||
+ __put_user (s->st_rdev, &(((struct stat32 *)A(statbuf))->st_rdev)) ||
+ __put_user (s->st_size, &(((struct stat32 *)A(statbuf))->st_size)) ||
+ __put_user (s->st_atime, &(((struct stat32 *)A(statbuf))->st_atime)) ||
+ __put_user (s->st_mtime, &(((struct stat32 *)A(statbuf))->st_mtime)) ||
+ __put_user (s->st_ctime, &(((struct stat32 *)A(statbuf))->st_ctime)) ||
+ __put_user (s->st_blksize, &(((struct stat32 *)A(statbuf))->st_blksize)) ||
+ __put_user (s->st_blocks, &(((struct stat32 *)A(statbuf))->st_blocks)))
+ return -EFAULT;
+ return 0;
+}
+
+asmlinkage int sys32_newstat(u32 filename, u32 statbuf)
+{
+ int ret;
+ struct stat s;
+ unsigned long old_fs = get_fs();
+
+ set_fs (KERNEL_DS);
+ ret = sys_newstat((char *)A(filename), &s);
+ set_fs (old_fs);
+ if (putstat (statbuf, &s)) return -EFAULT;
+ return ret;
+}
+
+asmlinkage int sys32_newlstat(u32 filename, u32 statbuf)
+{
+ int ret;
+ struct stat s;
+ unsigned long old_fs = get_fs();
+
+ set_fs (KERNEL_DS);
+ ret = sys_newlstat((char *)A(filename), &s);
+ set_fs (old_fs);
+ if (putstat (statbuf, &s)) return -EFAULT;
+ return ret;
+}
+
+asmlinkage int sys32_newfstat(unsigned int fd, u32 statbuf)
+{
+ int ret;
+ struct stat s;
+ unsigned long old_fs = get_fs();
+
+ set_fs (KERNEL_DS);
+ ret = sys_newfstat(fd, &s);
+ set_fs (old_fs);
+ if (putstat (statbuf, &s)) return -EFAULT;
+ return ret;
+}
+
+asmlinkage int sys32_readlink(u32 path, u32 buf, int bufsiz)
+{
+ return sys_readlink((const char *)A(path), (char *)A(buf), bufsiz);
+}
+
+asmlinkage int sys32_sysfs(int option, ...)
+{
+ va_list args;
+ unsigned int x;
+ int ret = -EINVAL;
+
+ va_start(args, option);
+ switch (option) {
+ case 1:
+ ret = sys_sysfs(option, (const char *)A(va_arg(args, u32)));
+ break;
+ case 2:
+ x = va_arg(args, unsigned int);
+ ret = sys_sysfs(option, x, (char *)A(va_arg(args, u32)));
+ break;
+ case 3:
+ ret = sys_sysfs(option);
+ break;
+ }
+ va_end(args);
+ return ret;
+}
+
+asmlinkage int sys32_ustat(dev_t dev, u32 ubuf)
+{
+ /* ustat is the same :)) */
+ return sys_ustat(dev, (struct ustat *)A(ubuf));
+}
+
+asmlinkage int sys32_umount(u32 name)
+{
+ return sys_umount((char *)A(name));
+}
+
+asmlinkage int sys32_mount(u32 dev_name, u32 dir_name, u32 type, u32 new_flags, u32 data)
+{
+ return sys_mount((char *)A(dev_name), (char *)A(dir_name), (char *)A(type),
+ (unsigned long)new_flags, (void *)A(data));
+}
+
+asmlinkage int sys32_syslog(int type, u32 bug, int count)
+{
+ return sys_syslog(type, (char *)A(bug), count);
+}
+
+asmlinkage int sys32_personality(u32 personality)
+{
+ return sys_personality((unsigned long)personality);
+}
+
+struct rusage32 {
+ struct timeval ru_utime;
+ struct timeval ru_stime;
+ s32 ru_maxrss;
+ s32 ru_ixrss;
+ s32 ru_idrss;
+ s32 ru_isrss;
+ s32 ru_minflt;
+ s32 ru_majflt;
+ s32 ru_nswap;
+ s32 ru_inblock;
+ s32 ru_oublock;
+ s32 ru_msgsnd;
+ s32 ru_msgrcv;
+ s32 ru_nsignals;
+ s32 ru_nvcsw;
+ s32 ru_nivcsw;
+};
+
+static int put_rusage (u32 ru, struct rusage *r)
+{
+ if (put_user (r->ru_utime.tv_sec, &(((struct rusage32 *)A(ru))->ru_utime.tv_sec)) ||
+ __put_user (r->ru_utime.tv_usec, &(((struct rusage32 *)A(ru))->ru_utime.tv_usec)) ||
+ __put_user (r->ru_stime.tv_sec, &(((struct rusage32 *)A(ru))->ru_stime.tv_sec)) ||
+ __put_user (r->ru_stime.tv_usec, &(((struct rusage32 *)A(ru))->ru_stime.tv_usec)) ||
+ __put_user (r->ru_maxrss, &(((struct rusage32 *)A(ru))->ru_maxrss)) ||
+ __put_user (r->ru_ixrss, &(((struct rusage32 *)A(ru))->ru_ixrss)) ||
+ __put_user (r->ru_idrss, &(((struct rusage32 *)A(ru))->ru_idrss)) ||
+ __put_user (r->ru_isrss, &(((struct rusage32 *)A(ru))->ru_isrss)) ||
+ __put_user (r->ru_minflt, &(((struct rusage32 *)A(ru))->ru_minflt)) ||
+ __put_user (r->ru_majflt, &(((struct rusage32 *)A(ru))->ru_majflt)) ||
+ __put_user (r->ru_nswap, &(((struct rusage32 *)A(ru))->ru_nswap)) ||
+ __put_user (r->ru_inblock, &(((struct rusage32 *)A(ru))->ru_inblock)) ||
+ __put_user (r->ru_oublock, &(((struct rusage32 *)A(ru))->ru_oublock)) ||
+ __put_user (r->ru_msgsnd, &(((struct rusage32 *)A(ru))->ru_msgsnd)) ||
+ __put_user (r->ru_msgrcv, &(((struct rusage32 *)A(ru))->ru_msgrcv)) ||
+ __put_user (r->ru_nsignals, &(((struct rusage32 *)A(ru))->ru_nsignals)) ||
+ __put_user (r->ru_nvcsw, &(((struct rusage32 *)A(ru))->ru_nvcsw)) ||
+ __put_user (r->ru_nivcsw, &(((struct rusage32 *)A(ru))->ru_nivcsw)))
+ return -EFAULT;
+ return 0;
+}
+
+asmlinkage int sys32_wait4(__kernel_pid_t32 pid, u32 stat_addr, int options, u32 ru)
+{
+ if (!ru)
+ return sys_wait4(pid, (unsigned int *)A(stat_addr), options, NULL);
+ else {
+ struct rusage r;
+ int ret;
+ unsigned long old_fs = get_fs();
+
+ set_fs (KERNEL_DS);
+ ret = sys_wait4(pid, (unsigned int *)A(stat_addr), options, &r);
+ set_fs (old_fs);
+ if (put_rusage (ru, &r)) return -EFAULT;
+ return ret;
+ }
+}
+
+asmlinkage int sys32_waitpid(__kernel_pid_t32 pid, u32 stat_addr, int options)
+{
+ return sys_waitpid(pid, (unsigned int *)A(stat_addr), options);
+}
+
+struct sysinfo32 {
+ s32 uptime;
+ u32 loads[3];
+ u32 totalram;
+ u32 freeram;
+ u32 sharedram;
+ u32 bufferram;
+ u32 totalswap;
+ u32 freeswap;
+ unsigned short procs;
+ char _f[22];
+};
+
+asmlinkage int sys32_sysinfo(u32 info)
+{
+ struct sysinfo s;
+ int ret;
+ unsigned long old_fs = get_fs ();
+
+ set_fs (KERNEL_DS);
+ ret = sys_sysinfo(&s);
+ set_fs (old_fs);
+ if (put_user (s.uptime, &(((struct sysinfo32 *)A(info))->uptime)) ||
+ __put_user (s.loads[0], &(((struct sysinfo32 *)A(info))->loads[0])) ||
+ __put_user (s.loads[1], &(((struct sysinfo32 *)A(info))->loads[1])) ||
+ __put_user (s.loads[2], &(((struct sysinfo32 *)A(info))->loads[2])) ||
+ __put_user (s.totalram, &(((struct sysinfo32 *)A(info))->totalram)) ||
+ __put_user (s.freeram, &(((struct sysinfo32 *)A(info))->freeram)) ||
+ __put_user (s.sharedram, &(((struct sysinfo32 *)A(info))->sharedram)) ||
+ __put_user (s.bufferram, &(((struct sysinfo32 *)A(info))->bufferram)) ||
+ __put_user (s.totalswap, &(((struct sysinfo32 *)A(info))->totalswap)) ||
+ __put_user (s.freeswap, &(((struct sysinfo32 *)A(info))->freeswap)) ||
+ __put_user (s.procs, &(((struct sysinfo32 *)A(info))->procs)))
+ return -EFAULT;
+ return ret;
+}
+
+asmlinkage int sys32_getitimer(int which, u32 value)
+{
+ /* itimerval is the same :)) */
+ return sys_getitimer(which, (struct itimerval *)A(value));
+}
+
+asmlinkage int sys32_setitimer(int which, u32 value, u32 ovalue)
+{
+ return sys_setitimer(which, (struct itimerval *)A(value), (struct itimerval *)A(ovalue));
+}
+
+asmlinkage int sys32_sched_setscheduler(__kernel_pid_t32 pid, int policy, u32 param)
+{
+ /* sched_param is the same :)) */
+ return sys_sched_setscheduler(pid, policy, (struct sched_param *)A(param));
+}
+
+asmlinkage int sys32_sched_setparam(__kernel_pid_t32 pid, u32 param)
+{
+ return sys_sched_setparam(pid, (struct sched_param *)A(param));
+}
+
+asmlinkage int sys32_sched_getparam(__kernel_pid_t32 pid, u32 param)
+{
+ return sys_sched_getparam(pid, (struct sched_param *)A(param));
+}
+
+struct timespec32 {
+ s32 tv_sec;
+ s32 tv_nsec;
+};
+
+asmlinkage int sys32_sched_rr_get_interval(__kernel_pid_t32 pid, u32 interval)
+{
+ struct timespec t;
+ int ret;
+ unsigned long old_fs = get_fs ();
+
+ set_fs (KERNEL_DS);
+ ret = sys_sched_rr_get_interval(pid, &t);
+ set_fs (old_fs);
+ if (put_user (t.tv_sec, &(((struct timespec32 *)A(interval))->tv_sec)) ||
+ __put_user (t.tv_nsec, &(((struct timespec32 *)A(interval))->tv_nsec)))
+ return -EFAULT;
+ return ret;
+}
+
+asmlinkage int sys32_nanosleep(u32 rqtp, u32 rmtp)
+{
+ struct timespec t;
+ int ret;
+ unsigned long old_fs = get_fs ();
+
+ if (get_user (t.tv_sec, &(((struct timespec32 *)A(rqtp))->tv_sec)) ||
+ __get_user (t.tv_nsec, &(((struct timespec32 *)A(rqtp))->tv_nsec)))
+ return -EFAULT;
+ set_fs (KERNEL_DS);
+ ret = sys_nanosleep(&t, rmtp ? &t : NULL);
+ set_fs (old_fs);
+ if (rmtp && ret == -EINTR) {
+ if (__put_user (t.tv_sec, &(((struct timespec32 *)A(rmtp))->tv_sec)) ||
+ __put_user (t.tv_nsec, &(((struct timespec32 *)A(rmtp))->tv_nsec)))
+ return -EFAULT;
+ }
+ return ret;
+}
+
+asmlinkage int sys32_sigprocmask(int how, u32 set, u32 oset)
+{
+ sigset_t s;
+ int ret;
+ unsigned long old_fs = get_fs();
+
+ if (set && get_user (s, (sigset_t32 *)A(set))) return -EFAULT;
+ set_fs (KERNEL_DS);
+ ret = sys_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL);
+ set_fs (old_fs);
+ if (oset && put_user (s, (sigset_t32 *)A(oset))) return -EFAULT;
+ return ret;
+}
+
+asmlinkage int sys32_sigpending(u32 set)
+{
+ sigset_t s;
+ int ret;
+ unsigned long old_fs = get_fs();
+
+ set_fs (KERNEL_DS);
+ ret = sys_sigpending(&s);
+ set_fs (old_fs);
+ if (put_user (s, (sigset_t32 *)A(set))) return -EFAULT;
+ return ret;
+}
+
+asmlinkage unsigned long sys32_signal(int signum, u32 handler)
+{
+ return sys_signal(signum, (__sighandler_t)A(handler));
+}
+
+asmlinkage int sys32_reboot(int magic1, int magic2, int cmd, u32 arg)
+{
+ return sys_reboot(magic1, magic2, cmd, (void *)A(arg));
+}
+
+asmlinkage int sys32_acct(u32 name)
+{
+ return sys_acct((const char *)A(name));
+}
+
+asmlinkage int sys32_getresuid(u32 ruid, u32 euid, u32 suid)
+{
+ uid_t a, b, c;
+ int ret;
+ unsigned long old_fs = get_fs();
+
+ set_fs (KERNEL_DS);
+ ret = sys_getresuid(&a, &b, &c);
+ set_fs (old_fs);
+ if (put_user (a, (__kernel_uid_t32 *)A(ruid)) ||
+ put_user (b, (__kernel_uid_t32 *)A(euid)) ||
+ put_user (c, (__kernel_uid_t32 *)A(suid)))
+ return -EFAULT;
+ return ret;
+}
+
+struct tms32 {
+ __kernel_clock_t32 tms_utime;
+ __kernel_clock_t32 tms_stime;
+ __kernel_clock_t32 tms_cutime;
+ __kernel_clock_t32 tms_cstime;
+};
+
+asmlinkage long sys32_times(u32 tbuf)
+{
+ struct tms t;
+ long ret;
+ unsigned long old_fs = get_fs ();
+
+ set_fs (KERNEL_DS);
+ ret = sys_times(tbuf ? &t : NULL);
+ set_fs (old_fs);
+ if (tbuf && (
+ put_user (t.tms_utime, &(((struct tms32 *)A(tbuf))->tms_utime)) ||
+ __put_user (t.tms_stime, &(((struct tms32 *)A(tbuf))->tms_stime)) ||
+ __put_user (t.tms_cutime, &(((struct tms32 *)A(tbuf))->tms_cutime)) ||
+ __put_user (t.tms_cstime, &(((struct tms32 *)A(tbuf))->tms_cstime))))
+ return -EFAULT;
+ return ret;
+}
+
+asmlinkage int sys32_getgroups(int gidsetsize, u32 grouplist)
+{
+ gid_t gl[NGROUPS];
+ int ret, i;
+ unsigned long old_fs = get_fs ();
+
+ set_fs (KERNEL_DS);
+ ret = sys_getgroups(gidsetsize, gl);
+ set_fs (old_fs);
+ if (ret > 0 && ret <= NGROUPS)
+ for (i = 0; i < ret; i++, grouplist += sizeof(__kernel_gid_t32))
+ if (__put_user (gl[i], (__kernel_gid_t32 *)A(grouplist)))
+ return -EFAULT;
+ return ret;
+}
+
+asmlinkage int sys32_setgroups(int gidsetsize, u32 grouplist)
+{
+ gid_t gl[NGROUPS];
+ int ret, i;
+ unsigned long old_fs = get_fs ();
+
+ if ((unsigned) gidsetsize > NGROUPS)
+ return -EINVAL;
+ for (i = 0; i < gidsetsize; i++, grouplist += sizeof(__kernel_gid_t32))
+ if (__get_user (gl[i], (__kernel_gid_t32 *)A(grouplist)))
+ return -EFAULT;
+ set_fs (KERNEL_DS);
+ ret = sys_setgroups(gidsetsize, gl);
+ set_fs (old_fs);
+ return ret;
+}
+
+asmlinkage int sys32_newuname(u32 name)
+{
+ /* utsname is the same :)) */
+ return sys_newuname((struct new_utsname *)A(name));
+}
+
+asmlinkage int sys32_olduname(u32 name)
+{
+ return sys_olduname((struct oldold_utsname *)A(name));
+}
+
+asmlinkage int sys32_sethostname(u32 name, int len)
+{
+ return sys_sethostname((char *)A(name), len);
+}
+
+asmlinkage int sys32_gethostname(u32 name, int len)
+{
+ return sys_gethostname((char *)A(name), len);
+}
+
+asmlinkage int sys32_setdomainname(u32 name, int len)
+{
+ return sys_setdomainname((char *)A(name), len);
+}
+
+struct rlimit32 {
+ s32 rlim_cur;
+ s32 rlim_max;
+};
+
+asmlinkage int sys32_getrlimit(unsigned int resource, u32 rlim)
+{
+ struct rlimit r;
+ int ret;
+ unsigned long old_fs = get_fs ();
+
+ set_fs (KERNEL_DS);
+ ret = sys_getrlimit(resource, &r);
+ set_fs (old_fs);
+ if (!ret && (
+ put_user (r.rlim_cur, &(((struct rlimit32 *)A(rlim))->rlim_cur)) ||
+ __put_user (r.rlim_max, &(((struct rlimit32 *)A(rlim))->rlim_max))))
+ return -EFAULT;
+ return ret;
+}
+
+asmlinkage int sys32_setrlimit(unsigned int resource, u32 rlim)
+{
+ struct rlimit r;
+ int ret;
+ unsigned long old_fs = get_fs ();
+
+ if (resource >= RLIM_NLIMITS) return -EINVAL;
+ if (get_user (r.rlim_cur, &(((struct rlimit32 *)A(rlim))->rlim_cur)) ||
+ __get_user (r.rlim_max, &(((struct rlimit32 *)A(rlim))->rlim_max)))
+ return -EFAULT;
+ set_fs (KERNEL_DS);
+ ret = sys_setrlimit(resource, &r);
+ set_fs (old_fs);
+ return ret;
+}
+
+asmlinkage int sys32_getrusage(int who, u32 ru)
+{
+ struct rusage r;
+ int ret;
+ unsigned long old_fs = get_fs();
+
+ set_fs (KERNEL_DS);
+ ret = sys_getrusage(who, &r);
+ set_fs (old_fs);
+ if (put_rusage (ru, &r)) return -EFAULT;
+ return ret;
+}
+
+asmlinkage int sys32_time(u32 tloc)
+{
+ return sys_time((int *)A(tloc));
+}
+
+asmlinkage int sys32_gettimeofday(u32 tv, u32 tz)
+{
+ /* both timeval and timezone are ok :)) */
+ return sys_gettimeofday((struct timeval *)A(tv), (struct timezone *)A(tz));
+}
+
+asmlinkage int sys32_settimeofday(u32 tv, u32 tz)
+{
+ return sys_settimeofday((struct timeval *)A(tv), (struct timezone *)A(tz));
+}
+
+struct timex32 {
+ unsigned int modes;
+ s32 offset;
+ s32 freq;
+ s32 maxerror;
+ s32 esterror;
+ int status;
+ s32 constant;
+ s32 precision;
+ s32 tolerance;
+ struct timeval time;
+ s32 tick;
+ s32 ppsfreq;
+ s32 jitter;
+ int shift;
+ s32 stabil;
+ s32 jitcnt;
+ s32 calcnt;
+ s32 errcnt;
+ s32 stbcnt;
+ int :32; int :32; int :32; int :32;
+ int :32; int :32; int :32; int :32;
+ int :32; int :32; int :32; int :32;
+};
+
+asmlinkage int sys32_adjtimex(u32 txc_p)
+{
+ struct timex t;
+ int ret;
+ unsigned long old_fs = get_fs ();
+
+ if (get_user (t.modes, &(((struct timex32 *)A(txc_p))->modes)) ||
+ __get_user (t.offset, &(((struct timex32 *)A(txc_p))->offset)) ||
+ __get_user (t.freq, &(((struct timex32 *)A(txc_p))->freq)) ||
+ __get_user (t.maxerror, &(((struct timex32 *)A(txc_p))->maxerror)) ||
+ __get_user (t.esterror, &(((struct timex32 *)A(txc_p))->esterror)) ||
+ __get_user (t.status, &(((struct timex32 *)A(txc_p))->status)) ||
+ __get_user (t.constant, &(((struct timex32 *)A(txc_p))->constant)) ||
+ __get_user (t.tick, &(((struct timex32 *)A(txc_p))->tick)) ||
+ __get_user (t.shift, &(((struct timex32 *)A(txc_p))->shift)))
+ return -EFAULT;
+ set_fs (KERNEL_DS);
+ ret = sys_adjtimex(&t);
+ set_fs (old_fs);
+ if ((unsigned)ret >= 0 && (
+ __put_user (t.modes, &(((struct timex32 *)A(txc_p))->modes)) ||
+ __put_user (t.offset, &(((struct timex32 *)A(txc_p))->offset)) ||
+ __put_user (t.freq, &(((struct timex32 *)A(txc_p))->freq)) ||
+ __put_user (t.maxerror, &(((struct timex32 *)A(txc_p))->maxerror)) ||
+ __put_user (t.esterror, &(((struct timex32 *)A(txc_p))->esterror)) ||
+ __put_user (t.status, &(((struct timex32 *)A(txc_p))->status)) ||
+ __put_user (t.constant, &(((struct timex32 *)A(txc_p))->constant)) ||
+ __put_user (t.precision, &(((struct timex32 *)A(txc_p))->precision)) ||
+ __put_user (t.tolerance, &(((struct timex32 *)A(txc_p))->tolerance)) ||
+ __put_user (t.time.tv_sec, &(((struct timex32 *)A(txc_p))->time.tv_sec)) ||
+ __put_user (t.time.tv_usec, &(((struct timex32 *)A(txc_p))->time.tv_usec)) ||
+ __put_user (t.tick, &(((struct timex32 *)A(txc_p))->tick)) ||
+ __put_user (t.ppsfreq, &(((struct timex32 *)A(txc_p))->ppsfreq)) ||
+ __put_user (t.jitter, &(((struct timex32 *)A(txc_p))->jitter)) ||
+ __put_user (t.shift, &(((struct timex32 *)A(txc_p))->shift)) ||
+ __put_user (t.stabil, &(((struct timex32 *)A(txc_p))->stabil)) ||
+ __put_user (t.jitcnt, &(((struct timex32 *)A(txc_p))->jitcnt)) ||
+ __put_user (t.calcnt, &(((struct timex32 *)A(txc_p))->calcnt)) ||
+ __put_user (t.errcnt, &(((struct timex32 *)A(txc_p))->errcnt)) ||
+ __put_user (t.stbcnt, &(((struct timex32 *)A(txc_p))->stbcnt))))
+ return -EFAULT;
+ return ret;
+}
+
+asmlinkage int sys32_msync(u32 start, __kernel_size_t32 len, int flags)
+{
+ return sys_msync((unsigned long)start, (size_t)len, flags);
+}
+
+asmlinkage int sys32_mlock(u32 start, __kernel_size_t32 len)
+{
+ return sys_mlock((unsigned long)start, (size_t)len);
+}
+
+asmlinkage int sys32_munlock(u32 start, __kernel_size_t32 len)
+{
+ return sys_munlock((unsigned long)start, (size_t)len);
+}
+
+asmlinkage unsigned long sparc32_brk(u32 brk)
+{
+ return sys_brk((unsigned long)brk);
+}
+
+asmlinkage int sys32_munmap(u32 addr, __kernel_size_t32 len)
+{
+ return sys_munmap((unsigned long)addr, (size_t)len);
+}
+
+asmlinkage int sys32_mprotect(u32 start, __kernel_size_t32 len, u32 prot)
+{
+ return sys_mprotect((unsigned long)start, (size_t)len, (unsigned long)prot);
+}
+
+asmlinkage unsigned long sys32_mremap(u32 addr, u32 old_len, u32 new_len, u32 flags)
+{
+ return sys_mremap((unsigned long)addr, (unsigned long)old_len, (unsigned long)new_len, (unsigned long)flags);
+}
+
+asmlinkage int sys32_swapoff(u32 specialfile)
+{
+ return sys_swapoff((const char *)A(specialfile));
+}
+
+asmlinkage int sys32_swapon(u32 specialfile, int swap_flags)
+{
+ return sys_swapon((const char *)A(specialfile), swap_flags);
+}
+
+asmlinkage int sys32_bind(int fd, u32 umyaddr, int addrlen)
+{
+ /* sockaddr is the same :)) */
+ return sys_bind(fd, (struct sockaddr *)A(umyaddr), addrlen);
+}
+
+asmlinkage int sys32_accept(int fd, u32 upeer_sockaddr, u32 upeer_addrlen)
+{
+ return sys_accept(fd, (struct sockaddr *)A(upeer_sockaddr), (int *)A(upeer_addrlen));
+}
+
+asmlinkage int sys32_connect(int fd, u32 uservaddr, int addrlen)
+{
+ return sys_connect(fd, (struct sockaddr *)A(uservaddr), addrlen);
+}
+
+asmlinkage int sys32_getsockname(int fd, u32 usockaddr, u32 usockaddr_len)
+{
+ return sys_getsockname(fd, (struct sockaddr *)A(usockaddr), (int *)A(usockaddr_len));
+}
+
+asmlinkage int sys32_getpeername(int fd, u32 usockaddr, u32 usockaddr_len)
+{
+ return sys_getpeername(fd, (struct sockaddr *)A(usockaddr), (int *)A(usockaddr_len));
+}
+
+asmlinkage int sys32_send(int fd, u32 buff, __kernel_size_t32 len, unsigned flags)
+{
+ return sys_send(fd, (void *)A(buff), (size_t)len, flags);
+}
+
+asmlinkage int sys32_sendto(int fd, u32 buff, __kernel_size_t32 len, unsigned flags, u32 addr, int addr_len)
+{
+ return sys_sendto(fd, (void *)A(buff), (size_t)len, flags, (struct sockaddr *)A(addr), addr_len);
+}
+
+asmlinkage int sys32_recv(int fd, u32 ubuf, __kernel_size_t32 size, unsigned flags)
+{
+ return sys_recv(fd, (void *)A(ubuf), (size_t)size, flags);
+}
+
+asmlinkage int sys32_recvfrom(int fd, u32 ubuf, __kernel_size_t32 size, unsigned flags, u32 addr, u32 addr_len)
+{
+ return sys_recvfrom(fd, (void *)A(ubuf), (size_t)size, flags, (struct sockaddr *)A(addr), (int *)A(addr_len));
+}
+
+asmlinkage int sys32_setsockopt(int fd, int level, int optname, u32 optval, int optlen)
+{
+ /* XXX handle ip_fw32->ip_fw conversion for IP firewalling and accounting.
+ Do it using some macro in ip_sockglue.c
+ Other optval arguments are mostly just ints or 32<->64bit transparent */
+ return sys_setsockopt(fd, level, optname, (char *)A(optval), optlen);
+}
+
+asmlinkage int sys32_getsockopt(int fd, int level, int optname, u32 optval, u32 optlen)
+{
+ return sys_getsockopt(fd, level, optname, (char *)A(optval), (int *)A(optlen));
+}
+
+/* Continue here */
+asmlinkage int sys32_sendmsg(int fd, u32 msg, unsigned flags)
+{
+ return sys_sendmsg(fd, (struct msghdr *)A(msg), flags);
+}
+
+asmlinkage int sys32_recvmsg(int fd, u32 msg, unsigned int flags)
+{
+ return sys_recvmsg(fd, (struct msghdr *)A(msg), flags);
+}
+
+asmlinkage int sys32_socketcall(int call, u32 args)
+{
+ return sys_socketcall(call, (unsigned long *)A(args));
+}
+
+extern void check_pending(int signum);
+
+asmlinkage int sparc32_sigaction (int signum, u32 action, u32 oldaction)
+{
+ struct sigaction32 new_sa, old_sa;
+ struct sigaction *p;
+ int err = -EINVAL;
+
+ lock_kernel();
+ if(signum < 0) {
+ current->tss.new_signal = 1;
+ signum = -signum;
+ }
+
+ if (signum<1 || signum>32)
+ goto out;
+ p = signum - 1 + current->sig->action;
+ if (action) {
+ err = -EINVAL;
+ if (signum==SIGKILL || signum==SIGSTOP)
+ goto out;
+ err = -EFAULT;
+ if(copy_from_user(&new_sa, A(action), sizeof(struct sigaction32)))
+ goto out;
+ if (((__sighandler_t)A(new_sa.sa_handler)) != SIG_DFL &&
+ ((__sighandler_t)A(new_sa.sa_handler)) != SIG_IGN) {
+ err = verify_area(VERIFY_READ, (__sighandler_t)A(new_sa.sa_handler), 1);
+ if (err)
+ goto out;
+ }
+ }
+
+ if (oldaction) {
+ err = -EFAULT;
+ old_sa.sa_handler = (unsigned)(u64)(p->sa_handler);
+ old_sa.sa_mask = (sigset_t32)(p->sa_mask);
+ old_sa.sa_flags = (unsigned)(p->sa_flags);
+ old_sa.sa_restorer = (unsigned)(u64)(p->sa_restorer);
+ if (copy_to_user(A(oldaction), p, sizeof(struct sigaction32)))
+ goto out;
+ }
+
+ if (action) {
+ p->sa_handler = (__sighandler_t)A(new_sa.sa_handler);
+ p->sa_mask = (sigset_t)(new_sa.sa_mask);
+ p->sa_flags = new_sa.sa_flags;
+ p->sa_restorer = (void (*)(void))A(new_sa.sa_restorer);
+ check_pending(signum);
+ }
+
+ err = 0;
+out:
+ unlock_kernel();
+ return err;
+}
+
+asmlinkage int sys32_nfsservctl(int cmd, u32 argp, u32 resp)
+{
+ /* XXX handle argp and resp args */
+ return sys_nfsservctl(cmd, (void *)A(argp), (void *)A(resp));
+}
+
+struct ncp_mount_data32 {
+ int version;
+ unsigned int ncp_fd;
+ __kernel_uid_t32 mounted_uid;
+ __kernel_pid_t32 wdog_pid;
+ unsigned char mounted_vol[NCP_VOLNAME_LEN + 1];
+ unsigned int time_out;
+ unsigned int retry_count;
+ unsigned int flags;
+ __kernel_uid_t32 uid;
+ __kernel_gid_t32 gid;
+ __kernel_mode_t32 file_mode;
+ __kernel_mode_t32 dir_mode;
+};
+
+void *do_ncp_super_data_conv(void *raw_data)
+{
+ struct ncp_mount_data *n = (struct ncp_mount_data *)raw_data;
+ struct ncp_mount_data32 *n32 = (struct ncp_mount_data32 *)raw_data;
+
+ n->dir_mode = n32->dir_mode;
+ n->file_mode = n32->file_mode;
+ n->gid = n32->gid;
+ n->uid = n32->uid;
+ memmove (n->mounted_vol, n32->mounted_vol, (sizeof (n32->mounted_vol) + 3 * sizeof (unsigned int)));
+ n->wdog_pid = n32->wdog_pid;
+ n->mounted_uid = n32->mounted_uid;
+ return raw_data;
+}
+
+struct smb_mount_data32 {
+ int version;
+ unsigned int fd;
+ __kernel_uid_t32 mounted_uid;
+ struct sockaddr_in addr;
+ char server_name[17];
+ char client_name[17];
+ char service[64];
+ char root_path[64];
+ char username[64];
+ char password[64];
+ char domain[64];
+ unsigned short max_xmit;
+ __kernel_uid_t32 uid;
+ __kernel_gid_t32 gid;
+ __kernel_mode_t32 file_mode;
+ __kernel_mode_t32 dir_mode;
+};
+
+void *do_smb_super_data_conv(void *raw_data)
+{
+ struct smb_mount_data *s = (struct smb_mount_data *)raw_data;
+ struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data;
+
+ s->dir_mode = s32->dir_mode;
+ s->file_mode = s32->file_mode;
+ s->gid = s32->gid;
+ s->uid = s32->uid;
+ memmove (&s->addr, &s32->addr, (((long)&s->uid) - ((long)&s->addr)));
+ s->mounted_uid = s32->mounted_uid;
+ return raw_data;
+}
diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
new file mode 100644
index 000000000..8ff04f02a
--- /dev/null
+++ b/arch/sparc64/kernel/systbls.S
@@ -0,0 +1,222 @@
+/* $Id: systbls.S,v 1.8 1997/04/21 08:34:23 jj Exp $
+ * systbls.S: System call entry point tables for OS compatibility.
+ * The native Linux system call table lives here also.
+ *
+ * Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *
+ * Based upon preliminary work which is:
+ *
+ * Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu)
+ */
+
+ .data
+ .align 8
+
+ /* First, the 32-bit Linux native syscall table. */
+
+ .globl sys_call_table32
+sys_call_table32:
+/*0*/ .xword sys_setup, sys_exit, sys_fork, sys32_read, sys32_write
+/*5*/ .xword sys32_open, sys_close, sys32_wait4, sys32_creat, sys32_link
+/*10*/ .xword sys32_unlink, sunos_execv, sys32_chdir, sys_nis_syscall, sys32_mknod
+/*15*/ .xword sys32_chmod, sys32_chown, sparc32_brk, sys_nis_syscall, sys32_lseek
+/*20*/ .xword sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid
+/*25*/ .xword sys32_time, sys32_ptrace, sys_alarm, sys_nis_syscall, sys_pause
+/*30*/ .xword sys32_utime, sys_stty, sys_gtty, sys32_access, sys_nice
+ .xword sys_ftime, sys_sync, sys_kill, sys32_newstat, sys_nis_syscall
+/*40*/ .xword sys32_newlstat, sys_dup, sys_pipe, sys32_times, sys_profil
+ .xword sys_nis_syscall, sys_setgid, sys_getgid, sys32_signal, sys_geteuid
+/*50*/ .xword sys_getegid, sys32_acct, sys_nis_syscall, sys_nis_syscall, sys32_ioctl
+ .xword sys32_reboot, sys_nis_syscall, sys32_symlink, sys32_readlink, sys_execve
+/*60*/ .xword sys_umask, sys32_chroot, sys32_newfstat, sys_nis_syscall, sys_getpagesize
+ .xword sys_nis_syscall, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*70*/ .xword sys_nis_syscall, sys32_mmap, sys_nis_syscall, sys32_munmap, sys32_mprotect
+ .xword sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys32_getgroups
+/*80*/ .xword sys32_setgroups, sys_getpgrp, sys_nis_syscall, sys32_setitimer, sys_nis_syscall
+ .xword sys32_swapon, sys32_getitimer, sys_nis_syscall, sys32_sethostname, sys_nis_syscall
+/*90*/ .xword sys_dup2, sys_nis_syscall, sys32_fcntl, sys32_select, sys_nis_syscall
+ .xword sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*100*/ .xword sys_getpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*110*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+ .xword sys_nis_syscall, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_nis_syscall
+/*120*/ .xword sys32_readv, sys32_writev, sys32_settimeofday, sys_fchown, sys_fchmod
+ .xword sys_nis_syscall, sys_setreuid, sys_setregid, sys32_rename, sys32_truncate
+/*130*/ .xword sys32_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+ .xword sys_nis_syscall, sys32_mkdir, sys32_rmdir, sys_nis_syscall, sys_nis_syscall
+/*140*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getrlimit
+ .xword sys32_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*150*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+ .xword sys_nis_syscall, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys32_umount
+/*160*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_setdomainname, sys_nis_syscall
+ .xword sys32_quotactl, sys_nis_syscall, sys32_mount, sys32_ustat, sys_nis_syscall
+/*170*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getdents
+ .xword sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*180*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_sigpending, sys_nis_syscall
+ .xword sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_newuname
+/*190*/ .xword sys_nis_syscall, sys32_personality, sys_prof, sys_break, sys_lock
+ .xword sys_mpx, sys_ulimit, sys_getppid, sparc32_sigaction, sys_sgetmask
+/*200*/ .xword sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys32_uselib, old32_readdir
+ .xword sys_nis_syscall, sys32_socketcall, sys32_syslog, sys32_olduname, sys_nis_syscall
+/*210*/ .xword sys_idle, sys_nis_syscall, sys32_waitpid, sys32_swapoff, sys32_sysinfo
+ .xword sys32_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex
+/*220*/ .xword sys_sigprocmask, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getpgid
+ .xword sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
+/*230*/ .xword sys32_llseek, sys32_time, sys_nis_syscall, sys_stime, sys_nis_syscall
+ .xword sys_nis_syscall, sys32_llseek, sys32_mlock, sys32_munlock, sys_mlockall
+/*240*/ .xword sys_munlockall, sys32_sched_setparam, sys32_sched_getparam, sys_nis_syscall, sys_nis_syscall
+ .xword sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys_nanosleep
+/*250*/ .xword sys32_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl
+ .xword sys_aplib, sys_nis_syscall
+
+ /* Now the 64-bit native Linux syscall table. */
+
+ .globl sys_call_table64, sys_call_table
+sys_call_table64:
+sys_call_table:
+/*0*/ .xword sys_setup, sys_exit, sys_fork, sys_read, sys_write
+/*5*/ .xword sys_open, sys_close, sys_wait4, sys_creat, sys_link
+/*10*/ .xword sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys_mknod
+/*15*/ .xword sys_chmod, sys_chown, sparc_brk, sys_nis_syscall, sys_lseek
+/*20*/ .xword sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid
+/*25*/ .xword sys_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_pause
+/*30*/ .xword sys_utime, sys_stty, sys_gtty, sys_access, sys_nice
+ .xword sys_ftime, sys_sync, sys_kill, sys_newstat, sys_nis_syscall
+/*40*/ .xword sys_newlstat, sys_dup, sys_pipe, sys_times, sys_profil
+ .xword sys_nis_syscall, sys_setgid, sys_getgid, sys_signal, sys_geteuid
+/*50*/ .xword sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys_ioctl
+ .xword sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve
+/*60*/ .xword sys_umask, sys_chroot, sys_newfstat, sys_nis_syscall, sys_getpagesize
+ .xword sys_nis_syscall, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*70*/ .xword sys_nis_syscall, sys_mmap, sys_nis_syscall, sys_munmap, sys_mprotect
+ .xword sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys_getgroups
+/*80*/ .xword sys_setgroups, sys_getpgrp, sys_nis_syscall, sys_setitimer, sys_nis_syscall
+ .xword sys_swapon, sys_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall
+/*90*/ .xword sys_dup2, sys_nis_syscall, sys_fcntl, sys_select, sys_nis_syscall
+ .xword sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*100*/ .xword sys_getpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*110*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+ .xword sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_nis_syscall, sys_nis_syscall
+/*120*/ .xword sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod
+ .xword sys_nis_syscall, sys_setreuid, sys_setregid, sys_rename, sys_truncate
+/*130*/ .xword sys_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+ .xword sys_nis_syscall, sys_mkdir, sys_rmdir, sys_nis_syscall, sys_nis_syscall
+/*140*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getrlimit
+ .xword sys_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*150*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+ .xword sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_umount
+/*160*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_setdomainname, sys_nis_syscall
+ .xword sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall
+/*170*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
+ .xword sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*180*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_sigpending, sys_nis_syscall
+ .xword sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_newuname
+/*190*/ .xword sys_init_module, sys_personality, sys_prof, sys_break, sys_lock
+ .xword sys_mpx, sys_ulimit, sys_getppid, sparc_sigaction, sys_sgetmask
+/*200*/ .xword sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, sys_nis_syscall
+ .xword sys_nis_syscall, sys_socketcall, sys_syslog, sys_nis_syscall, sys_nis_syscall
+/*210*/ .xword sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo
+ .xword sys_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys_adjtimex
+/*220*/ .xword sys_sigprocmask, sys_create_module, sys_delete_module, sys_get_kernel_syms, sys_getpgid
+ .xword sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
+/*230*/ .xword sys_llseek, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall
+ .xword sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
+/*240*/ .xword sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_nis_syscall, sys_nis_syscall
+ .xword sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
+/*250*/ .xword sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
+ .xword sys_aplib, sys_nis_syscall
+
+ /* Now the 32-bit SunOS syscall table. */
+
+ .align 4
+ .globl sunos_sys_table
+sunos_sys_table:
+/*0*/ .xword sunos_indir, sys_exit, sys_fork
+ .xword sunos_read, sunos_write, sunos_open
+ .xword sys_close, sunos_wait4, sys_creat
+ .xword sys_link, sys_unlink, sunos_execv
+ .xword sys_chdir, sunos_nosys, sys_mknod
+ .xword sys_chmod, sys_chown, sunos_brk
+ .xword sunos_nosys, sys_lseek, sunos_getpid
+ .xword sunos_nosys, sunos_nosys, sunos_nosys
+ .xword sunos_getuid, sunos_nosys, sys_ptrace
+ .xword sunos_nosys, sunos_nosys, sunos_nosys
+ .xword sunos_nosys, sunos_nosys, sunos_nosys
+ .xword sys_access, sunos_nosys, sunos_nosys
+ .xword sys_sync, sys_kill, sys_newstat
+ .xword sunos_nosys, sys_newlstat, sys_dup
+ .xword sys_pipe, sunos_nosys, sys_profil
+ .xword sunos_nosys, sunos_nosys, sunos_getgid
+ .xword sunos_nosys, sunos_nosys
+/*50*/ .xword sunos_nosys, sys_acct, sunos_nosys
+ .xword sunos_mctl, sunos_ioctl, sys_reboot
+ .xword sunos_nosys, sys_symlink, sys_readlink
+ .xword sys_execve, sys_umask, sys_chroot
+ .xword sys_newfstat, sunos_nosys, sys_getpagesize
+ .xword sys_msync, sys_vfork, sunos_nosys
+ .xword sunos_nosys, sunos_sbrk, sunos_sstk
+ .xword sunos_mmap, sunos_vadvise, sys_munmap
+ .xword sys_mprotect, sunos_madvise, sys_vhangup
+ .xword sunos_nosys, sunos_mincore, sys_getgroups
+ .xword sys_setgroups, sys_getpgrp, sunos_setpgrp
+ .xword sys_setitimer, sunos_nosys, sys_swapon
+ .xword sys_getitimer, sys_gethostname, sys_sethostname
+ .xword sunos_getdtablesize, sys_dup2, sunos_nop
+ .xword sys_fcntl, sunos_select, sunos_nop
+ .xword sys_fsync, sys_setpriority, sys_socket
+ .xword sys_connect, sunos_accept
+/*100*/ .xword sys_getpriority, sunos_send, sunos_recv
+ .xword sunos_nosys, sys_bind, sunos_setsockopt
+ .xword sys_listen, sunos_nosys, sunos_sigaction
+ .xword sunos_sigblock, sunos_sigsetmask, sys_sigpause
+ .xword sys_sigstack, sys_recvmsg, sys_sendmsg
+ .xword sunos_nosys, sys_gettimeofday, sys_getrusage
+ .xword sunos_getsockopt, sunos_nosys, sunos_readv
+ .xword sunos_writev, sys_settimeofday, sys_fchown
+ .xword sys_fchmod, sys_recvfrom, sys_setreuid
+ .xword sys_setregid, sys_rename, sys_truncate
+ .xword sys_ftruncate, sys_flock, sunos_nosys
+ .xword sys_sendto, sys_shutdown, sys_socketpair
+ .xword sys_mkdir, sys_rmdir, sys_utimes
+ .xword sys_sigreturn, sunos_nosys, sys_getpeername
+ .xword sunos_gethostid, sunos_nosys, sys_getrlimit
+ .xword sys_setrlimit, sunos_killpg, sunos_nosys
+ .xword sunos_nosys, sunos_nosys
+/*150*/ .xword sys_getsockname, sunos_nosys, sunos_nosys
+ .xword sunos_poll, sunos_nosys, sunos_nosys
+ .xword sunos_getdirentries, sys_statfs, sys_fstatfs
+ .xword sys_umount, sunos_nosys, sunos_nosys
+ .xword sunos_getdomainname, sys_setdomainname
+ .xword sunos_nosys, sys_quotactl, sunos_nosys
+ .xword sunos_mount, sys_ustat, sunos_semsys
+ .xword sunos_nosys, sunos_shmsys, sunos_audit
+ .xword sunos_nosys, sunos_getdents, sys_setsid
+ .xword sys_fchdir, sunos_nosys, sunos_nosys
+ .xword sunos_nosys, sunos_nosys, sunos_nosys
+ .xword sunos_nosys, sys_sigpending, sunos_nosys
+ .xword sys_setpgid, sunos_pathconf, sunos_fpathconf
+ .xword sunos_sysconf, sunos_uname, sunos_nosys
+ .xword sunos_nosys, sunos_nosys, sunos_nosys
+ .xword sunos_nosys, sunos_nosys, sunos_nosys
+ .xword sunos_nosys, sunos_nosys, sunos_nosys
+/*200*/ .xword sunos_nosys, sunos_nosys, sunos_nosys
+ .xword sunos_nosys, sunos_nosys, sunos_nosys
+ .xword sunos_nosys, sunos_nosys, sunos_nosys
+ .xword sunos_nosys, sunos_nosys, sunos_nosys
+ .xword sunos_nosys, sunos_nosys, sunos_nosys
+ .xword sunos_nosys, sunos_nosys, sunos_nosys
+ .xword sunos_nosys, sunos_nosys, sunos_nosys
+ .xword sunos_nosys, sunos_nosys, sunos_nosys
+ .xword sunos_nosys, sunos_nosys, sunos_nosys
+ .xword sunos_nosys, sunos_nosys, sunos_nosys
+ .xword sunos_nosys, sunos_nosys, sunos_nosys
+ .xword sunos_nosys, sunos_nosys, sunos_nosys
+ .xword sunos_nosys, sunos_nosys, sunos_nosys
+ .xword sunos_nosys, sunos_nosys, sunos_nosys
+ .xword sunos_nosys, sunos_nosys, sunos_nosys
+ .xword sunos_nosys, sunos_nosys, sunos_nosys
+ .xword sunos_nosys, sunos_nosys
+/*250*/ .xword sunos_nosys, sunos_nosys, sunos_nosys
+ .xword sunos_nosys, sunos_nosys, sys_aplib
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
new file mode 100644
index 000000000..3f15fcb54
--- /dev/null
+++ b/arch/sparc64/kernel/time.c
@@ -0,0 +1,352 @@
+/* $Id: time.c,v 1.2 1997/04/10 03:02:35 davem Exp $
+ * time.c: UltraSparc timer and TOD clock support.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ *
+ * Based largely on code which is:
+ *
+ * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
+ */
+
+#include <linux/errno.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/timex.h>
+#include <linux/init.h>
+
+#include <asm/oplib.h>
+#include <asm/mostek.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+struct mostek48t02 *mstk48t02_regs = 0;
+struct mostek48t08 *mstk48t08_regs = 0;
+struct mostek48t59 *mstk48t59_regs = 0;
+
+static int set_rtc_mmss(unsigned long);
+
+/* timer_interrupt() needs to keep up the real-time clock,
+ * as well as call the "do_timer()" routine every clocktick
+ *
+ * NOTE: On SUN5 systems the ticker interrupt comes in using 2
+ * interrupts, one at level14 and one with softint bit 0.
+ */
+void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+ /* last time the cmos clock got updated */
+ static long last_rtc_update=0;
+
+ do_timer(regs);
+
+ /* Determine when to update the Mostek clock. */
+ if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
+ xtime.tv_usec > 500000 - (tick >> 1) &&
+ xtime.tv_usec < 500000 + (tick >> 1))
+ 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 */
+}
+
+/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
+ * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
+ * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
+ *
+ * [For the Julian calendar (which was used in Russia before 1917,
+ * Britain & colonies before 1752, anywhere else before 1582,
+ * and is still in use by some communities) leave out the
+ * -year/100+year/400 terms, and add 10.]
+ *
+ * This algorithm was first published by Gauss (I think).
+ *
+ * WARNING: this function will overflow on 2106-02-07 06:28:16 on
+ * machines were long is 32-bit! (However, as time_t is signed, we
+ * will already get problems at other places on 2038-01-19 03:14:08)
+ */
+static inline unsigned long mktime(unsigned int year, unsigned int mon,
+ unsigned int day, unsigned int hour,
+ unsigned int min, unsigned int sec)
+{
+ if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */
+ mon += 12; /* Puts Feb last since it has leap day */
+ year -= 1;
+ }
+ return (((
+ (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
+ year*365 - 719499
+ )*24 + hour /* now have hours */
+ )*60 + min /* now have minutes */
+ )*60 + sec; /* finally seconds */
+}
+
+/* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */
+static void kick_start_clock(void)
+{
+ register struct mostek48t02 *regs = mstk48t02_regs;
+ unsigned char sec;
+ int i, count;
+
+ prom_printf("CLOCK: Clock was stopped. Kick start ");
+
+ /* Turn on the kick start bit to start the oscillator. */
+ regs->creg |= MSTK_CREG_WRITE;
+ regs->sec &= ~MSTK_STOP;
+ regs->hour |= MSTK_KICK_START;
+ regs->creg &= ~MSTK_CREG_WRITE;
+
+ /* Delay to allow the clock oscillator to start. */
+ sec = MSTK_REG_SEC(regs);
+ for (i = 0; i < 3; i++) {
+ while (sec == MSTK_REG_SEC(regs))
+ for (count = 0; count < 100000; count++)
+ /* nothing */ ;
+ prom_printf(".");
+ sec = regs->sec;
+ }
+ prom_printf("\n");
+
+ /* Turn off kick start and set a "valid" time and date. */
+ regs->creg |= MSTK_CREG_WRITE;
+ regs->hour &= ~MSTK_KICK_START;
+ MSTK_SET_REG_SEC(regs,0);
+ MSTK_SET_REG_MIN(regs,0);
+ MSTK_SET_REG_HOUR(regs,0);
+ MSTK_SET_REG_DOW(regs,5);
+ MSTK_SET_REG_DOM(regs,1);
+ MSTK_SET_REG_MONTH(regs,8);
+ MSTK_SET_REG_YEAR(regs,1996 - MSTK_YEAR_ZERO);
+ regs->creg &= ~MSTK_CREG_WRITE;
+
+ /* Ensure the kick start bit is off. If it isn't, turn it off. */
+ while (regs->hour & MSTK_KICK_START) {
+ prom_printf("CLOCK: Kick start still on!\n");
+ regs->creg |= MSTK_CREG_WRITE;
+ regs->hour &= ~MSTK_KICK_START;
+ regs->creg &= ~MSTK_CREG_WRITE;
+ }
+
+ prom_printf("CLOCK: Kick start procedure successful.\n");
+}
+
+/* Return nonzero if the clock chip battery is low. */
+static int has_low_battery(void)
+{
+ register struct mostek48t02 *regs = mstk48t02_regs;
+ unsigned char data1, data2;
+
+ data1 = regs->eeprom[0]; /* Read some data. */
+ regs->eeprom[0] = ~data1; /* Write back the complement. */
+ data2 = regs->eeprom[0]; /* Read back the complement. */
+ regs->eeprom[0] = data1; /* Restore the original value. */
+
+ return (data1 == data2); /* Was the write blocked? */
+}
+
+/* XXX HACK HACK HACK, delete me soon */
+static struct linux_prom_ranges XXX_sbus_ranges[PROMREG_MAX];
+static int XXX_sbus_nranges;
+
+/* Probe for the real time clock chip. */
+__initfunc(static void clock_probe(void))
+{
+ struct linux_prom_registers clk_reg[2];
+ char model[128];
+ int node, sbusnd, err;
+
+ node = prom_getchild(prom_root_node);
+ sbusnd = prom_searchsiblings(node, "sbus");
+ node = prom_getchild(sbusnd);
+
+ if(node == 0 || node == -1) {
+ prom_printf("clock_probe: Serious problem can't find sbus PROM node.\n");
+ prom_halt();
+ }
+
+ /* XXX FIX ME */
+ err = prom_getproperty(sbusnd, "ranges", (char *) XXX_sbus_ranges,
+ sizeof(XXX_sbus_ranges));
+ if(err == -1) {
+ prom_printf("clock_probe: Cannot get XXX sbus ranges\n");
+ prom_halt();
+ }
+ XXX_sbus_nranges = (err / sizeof(struct linux_prom_ranges));
+
+ while(1) {
+ prom_getstring(node, "model", model, sizeof(model));
+ if(strcmp(model, "mk48t02") &&
+ strcmp(model, "mk48t08") &&
+ strcmp(model, "mk48t59")) {
+ node = prom_getsibling(node);
+ if(node == 0) {
+ prom_printf("clock_probe: Cannot find timer chip\n");
+ prom_halt();
+ }
+ continue;
+ }
+
+ err = prom_getproperty(node, "reg", (char *)clk_reg,
+ sizeof(clk_reg));
+ if(err == -1) {
+ prom_printf("clock_probe: Cannot make Mostek\n");
+ prom_halt();
+ }
+
+ /* XXX fix me badly */
+ prom_adjust_regs(clk_reg, 1, XXX_sbus_ranges, XXX_sbus_nranges);
+
+ if(model[5] == '0' && model[6] == '2') {
+ mstk48t02_regs = (struct mostek48t02 *)
+ sparc_alloc_io(clk_reg[0].phys_addr,
+ (void *) 0, sizeof(*mstk48t02_regs),
+ "clock", clk_reg[0].which_io, 0x0);
+ } else if(model[5] == '0' && model[6] == '8') {
+ mstk48t08_regs = (struct mostek48t08 *)
+ sparc_alloc_io(clk_reg[0].phys_addr,
+ (void *) 0, sizeof(*mstk48t08_regs),
+ "clock", clk_reg[0].which_io, 0x0);
+ mstk48t02_regs = &mstk48t08_regs->regs;
+ } else {
+ mstk48t59_regs = (struct mostek48t59 *)
+ sparc_alloc_io(clk_reg[0].phys_addr,
+ (void *) 0, sizeof(*mstk48t59_regs),
+ "clock", clk_reg[0].which_io, 0x0);
+ mstk48t02_regs = &mstk48t59_regs->regs;
+ }
+ break;
+ }
+
+ /* Report a low battery voltage condition. */
+ if (has_low_battery())
+ prom_printf("NVRAM: Low battery voltage!\n");
+
+ /* Kick start the clock if it is completely stopped. */
+ if (mstk48t02_regs->sec & MSTK_STOP)
+ kick_start_clock();
+}
+
+#ifndef BCD_TO_BIN
+#define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10)
+#endif
+
+#ifndef BIN_TO_BCD
+#define BIN_TO_BCD(val) ((((val)/10)<<4) + (val)%10)
+#endif
+
+__initfunc(void time_init(void))
+{
+ extern void init_timers(void (*func)(int, void *, struct pt_regs *));
+ unsigned int year, mon, day, hour, min, sec;
+ struct mostek48t02 *mregs;
+
+ do_get_fast_time = do_gettimeofday;
+
+ clock_probe();
+ init_timers(timer_interrupt);
+
+ mregs = mstk48t02_regs;
+ if(!mregs) {
+ prom_printf("Something wrong, clock regs not mapped yet.\n");
+ prom_halt();
+ }
+
+ mregs->creg |= MSTK_CREG_READ;
+ sec = MSTK_REG_SEC(mregs);
+ min = MSTK_REG_MIN(mregs);
+ hour = MSTK_REG_HOUR(mregs);
+ day = MSTK_REG_DOM(mregs);
+ mon = MSTK_REG_MONTH(mregs);
+ year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );
+ xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
+ xtime.tv_usec = 0;
+ mregs->creg &= ~MSTK_CREG_READ;
+}
+
+static __inline__ unsigned long do_gettimeoffset(void)
+{
+ unsigned long offset = 0;
+ unsigned int count;
+
+ /* XXX -DaveM */
+#if 0
+ count = (*master_l10_counter >> 10) & 0x1fffff;
+#else
+ count = 0;
+#endif
+
+ if(test_bit(TIMER_BH, &bh_active))
+ offset = 1000000;
+
+ return offset + count;
+}
+
+void do_gettimeofday(struct timeval *tv)
+{
+ unsigned long flags;
+
+ save_and_cli(flags);
+ *tv = xtime;
+ tv->tv_usec += do_gettimeoffset();
+ if(tv->tv_usec >= 1000000) {
+ tv->tv_usec -= 1000000;
+ tv->tv_sec++;
+ }
+ restore_flags(flags);
+}
+
+void do_settimeofday(struct timeval *tv)
+{
+ cli();
+
+ tv->tv_usec -= do_gettimeoffset();
+ if(tv->tv_usec < 0) {
+ tv->tv_usec += 1000000;
+ tv->tv_sec--;
+ }
+
+ xtime = *tv;
+ time_state = TIME_BAD;
+ time_maxerror = 0x70000000;
+ time_esterror = 0x70000000;
+ sti();
+}
+
+static int set_rtc_mmss(unsigned long nowtime)
+{
+ int real_seconds, real_minutes, mostek_minutes;
+ struct mostek48t02 *regs = mstk48t02_regs;
+
+ /* Not having a register set can lead to trouble. */
+ if (!regs)
+ return -1;
+
+ /* Read the current RTC minutes. */
+ regs->creg |= MSTK_CREG_READ;
+ mostek_minutes = MSTK_REG_MIN(regs);
+ regs->creg &= ~MSTK_CREG_READ;
+
+ /*
+ * since we're only adjusting minutes and seconds,
+ * don't interfere with hour overflow. This avoids
+ * messing with unknown time zones but requires your
+ * RTC not to be off by more than 15 minutes
+ */
+ real_seconds = nowtime % 60;
+ real_minutes = nowtime / 60;
+ if (((abs(real_minutes - mostek_minutes) + 15)/30) & 1)
+ real_minutes += 30; /* correct for half hour time zone */
+ real_minutes %= 60;
+
+ if (abs(real_minutes - mostek_minutes) < 30) {
+ regs->creg |= MSTK_CREG_WRITE;
+ MSTK_SET_REG_SEC(regs,real_seconds);
+ MSTK_SET_REG_MIN(regs,real_minutes);
+ regs->creg &= ~MSTK_CREG_WRITE;
+ } else
+ return -1;
+
+ return 0;
+}
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
new file mode 100644
index 000000000..48648c39d
--- /dev/null
+++ b/arch/sparc64/kernel/traps.c
@@ -0,0 +1,185 @@
+/* $Id: traps.c,v 1.5 1997/04/14 06:56:55 davem Exp $
+ * arch/sparc/kernel/traps.c
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+/*
+ * 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 <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>
+
+/* #define TRAP_DEBUG */
+
+struct trap_trace_entry {
+ unsigned long pc;
+ unsigned long type;
+};
+
+int trap_curbuf = 0;
+struct trap_trace_entry trapbuf[1024];
+
+void syscall_trace_entry(struct pt_regs *regs)
+{
+ printk("%s[%d]: ", current->comm, current->pid);
+ printk("scall<%ld> (could be %ld)\n", (long) regs->u_regs[UREG_G1],
+ (long) regs->u_regs[UREG_I0]);
+}
+
+void syscall_trace_exit(struct pt_regs *regs)
+{
+}
+
+void sparc64_dtlb_fault_handler (void)
+{
+ printk ("sparc64_dtlb_fault_handler\n");
+ while (1);
+ /* Die for now... */
+}
+
+void sparc64_dtlb_refbit_handler (struct pt_regs *regs)
+{
+ printk ("sparc64_dtlb_refbit_handler[%016lx]\n", regs->tpc);
+ while (1);
+ /* Die for now... */
+}
+
+void sparc64_itlb_refbit_handler (void)
+{
+ printk ("sparc64_itlb_refbit_handler\n");
+ while (1);
+ /* Die for now... */
+}
+
+void bad_trap (struct pt_regs *regs, long lvl)
+{
+ printk ("Bad trap %d (tstate %016lx tpc %016lx tnpc %016lx)\n", lvl, regs->tstate, regs->tpc, regs->tnpc);
+ while (1);
+ /* Die for now... */
+}
+
+void bad_trap_tl1 (struct pt_regs *regs, long lvl)
+{
+ printk ("Bad trap %d at tl1+ (tstate %016lx tpc %016lx tnpc %016lx)\n", lvl, regs->tstate, regs->tpc, regs->tnpc);
+ while (1);
+ /* Die for now... */
+}
+
+void data_access_exception (struct pt_regs *regs)
+{
+ printk ("Unhandled data access exception sfsr %016lx sfar %016lx\n", spitfire_get_dsfsr(), spitfire_get_sfar());
+ die_if_kernel("Data access exception", regs);
+}
+
+void instruction_access_exception (struct pt_regs *regs)
+{
+ printk ("Unhandled instruction access exception sfsr %016lx\n", spitfire_get_isfsr());
+ die_if_kernel("Instruction access exception", regs);
+}
+
+void instruction_dump (unsigned int *pc)
+{
+ int i;
+
+ if((((unsigned long) pc) & 3))
+ return;
+
+ for(i = -3; i < 6; i++)
+ printk("%c%08x%c",i?' ':'<',pc[i],i?' ':'>');
+ printk("\n");
+}
+
+void die_if_kernel(char *str, struct pt_regs *regs)
+{
+ /* Amuse the user. */
+ printk(
+" \\|/ ____ \\|/\n"
+" \"@'/ .` \\`@\"\n"
+" /_| \\__/ |_\\\n"
+" \\__U_/\n");
+
+ printk("%s(%d): %s\n", current->comm, current->pid, str);
+ show_regs(regs);
+ printk("Instruction DUMP:");
+ instruction_dump ((unsigned int *) regs->tpc);
+ if(regs->tstate & TSTATE_PRIV)
+ do_exit(SIGKILL);
+ do_exit(SIGSEGV);
+}
+
+void do_illegal_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+ unsigned long tstate)
+{
+ lock_kernel();
+ if(tstate & TSTATE_PRIV)
+ die_if_kernel("Kernel illegal instruction", regs);
+#ifdef TRAP_DEBUG
+ printk("Ill instr. at pc=%016lx instruction is %08x\n",
+ regs->tpc, *(unsigned int *)regs->tpc);
+#endif
+ current->tss.sig_address = pc;
+ current->tss.sig_desc = SUBSIG_ILLINST;
+ send_sig(SIGILL, current, 1);
+ unlock_kernel();
+}
+
+void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+ unsigned long tstate)
+{
+ lock_kernel();
+ if(tstate & TSTATE_PRIV)
+ die_if_kernel("Penguin instruction from Penguin mode??!?!", regs);
+ current->tss.sig_address = pc;
+ current->tss.sig_desc = SUBSIG_PRIVINST;
+ send_sig(SIGILL, current, 1);
+ unlock_kernel();
+}
+
+/* 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 tstate)
+{
+ lock_kernel();
+ if(regs->tstate & TSTATE_PRIV) {
+ printk("KERNEL MNA at pc %016lx npc %016lx called by %016lx\n", pc, npc,
+ regs->u_regs[UREG_RETPC]);
+ die_if_kernel("BOGUS", regs);
+ /* die_if_kernel("Kernel MNA access", regs); */
+ }
+ current->tss.sig_address = pc;
+ current->tss.sig_desc = SUBSIG_PRIVINST;
+#if 0
+ show_regs (regs);
+ instruction_dump ((unsigned long *) regs->tpc);
+ printk ("do_MNA!\n");
+#endif
+ send_sig(SIGBUS, current, 1);
+ unlock_kernel();
+}
+
+void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+ unsigned long psr)
+{
+ lock_kernel();
+ send_sig(SIGILL, current, 1);
+ unlock_kernel();
+}
+
+void trap_init(void)
+{
+}
diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S
new file mode 100644
index 000000000..f22d85014
--- /dev/null
+++ b/arch/sparc64/kernel/ttable.S
@@ -0,0 +1,252 @@
+/* $Id: ttable.S,v 1.11 1997/03/25 09:47:21 davem Exp $
+ * ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+ .globl sparc64_ttable_tl0, sparc64_ttable_tl1
+
+sparc64_ttable_tl0:
+tl0_resv000: BOOT_KERNEL BTRAP(0x1) BTRAP(0x2) BTRAP(0x3)
+tl0_resv004: BTRAP(0x4) BTRAP(0x5) BTRAP(0x6) BTRAP(0x7)
+tl0_iax: ACCESS_EXCEPTION_TRAP(instruction_access_exception)
+tl0_resv009: BTRAP(0x9)
+tl0_iae: TRAP(do_iae)
+tl0_resv00b: BTRAP(0xb) BTRAP(0xc) BTRAP(0xd) BTRAP(0xe) BTRAP(0xf)
+tl0_ill: TRAP(do_ill)
+tl0_privop: TRAP(do_privop)
+tl0_resv012: BTRAP(0x12) BTRAP(0x13) BTRAP(0x14) BTRAP(0x15) BTRAP(0x16) BTRAP(0x17)
+tl0_resv018: BTRAP(0x18) BTRAP(0x19) BTRAP(0x1a) BTRAP(0x1b) BTRAP(0x1c) BTRAP(0x1d)
+tl0_resv01e: BTRAP(0x1e) BTRAP(0x1f)
+tl0_fpdis: TRAP(do_fpdis)
+tl0_fpieee: TRAP(do_fpieee)
+tl0_fpother: TRAP(do_fpother)
+tl0_tof: TRAP(do_tof)
+tl0_cwin: CLEAN_WINDOW
+tl0_div0: TRAP(do_div0)
+tl0_resv029: BTRAP(0x29) BTRAP(0x2a) BTRAP(0x2b) BTRAP(0x2c) BTRAP(0x2d) BTRAP(0x2e)
+tl0_resv02f: BTRAP(0x2f)
+tl0_dax: ACCESS_EXCEPTION_TRAP(data_access_exception)
+tl0_resv031: BTRAP(0x31)
+tl0_dae: TRAP(do_dae)
+tl0_resv033: BTRAP(0x33)
+tl0_mna: TRAP(do_mna)
+tl0_lddfmna: TRAP(do_lddfmna)
+tl0_stdfmna: TRAP(do_stdfmna)
+tl0_privact: TRAP(do_privact)
+tl0_resv038: BTRAP(0x38) BTRAP(0x39) BTRAP(0x3a) BTRAP(0x3b) BTRAP(0x3c) BTRAP(0x3d)
+tl0_resv03e: BTRAP(0x3e) BTRAP(0x3f) BTRAP(0x40)
+tl0_irq1: TRAP_IRQ(handler_irq, 1) TRAP_IRQ(handler_irq, 2)
+tl0_irq3: TRAP_IRQ(handler_irq, 3) TRAP_IRQ(handler_irq, 4)
+tl0_irq5: TRAP_IRQ(handler_irq, 5) TRAP_IRQ(handler_irq, 6)
+tl0_irq7: TRAP_IRQ(handler_irq, 7) TRAP_IRQ(handler_irq, 8)
+tl0_irq9: TRAP_IRQ(handler_irq, 9) TRAP_IRQ(handler_irq, 10)
+tl0_irq11: TRAP_IRQ(handler_irq, 11) TRAP_IRQ(handler_irq, 12)
+tl0_irq13: TRAP_IRQ(handler_irq, 13) TRAP_IRQ(handler_irq, 14)
+tl0_irq15: TRAP_IRQ(handler_irq, 15)
+tl0_resv050: BTRAP(0x50) BTRAP(0x51) BTRAP(0x52) BTRAP(0x53) BTRAP(0x54) BTRAP(0x55)
+tl0_resv056: BTRAP(0x56) BTRAP(0x57) BTRAP(0x58) BTRAP(0x59) BTRAP(0x5a) BTRAP(0x5b)
+tl0_resv05c: BTRAP(0x5c) BTRAP(0x5d) BTRAP(0x5e) BTRAP(0x5f)
+tl0_ivec: TRAP_IVEC
+tl0_paw: TRAP(do_paw)
+tl0_vaw: TRAP(do_vaw)
+tl0_cee: TRAP(do_cee)
+tl0_iamiss:
+#include "itlb_miss.S"
+tl0_damiss:
+#include "dtlb_miss.S"
+tl0_daprot:
+#include "dtlb_prot.S"
+tl0_resv070: BTRAP(0x70) BTRAP(0x71) BTRAP(0x72) BTRAP(0x73) BTRAP(0x74) BTRAP(0x75)
+tl0_resv076: BTRAP(0x76) BTRAP(0x77) BTRAP(0x78) BTRAP(0x79) BTRAP(0x7a) BTRAP(0x7b)
+tl0_resv07c: BTRAP(0x7c) BTRAP(0x7d) BTRAP(0x7e) BTRAP(0x7f)
+tl0_s0n: SPILL_0_NORMAL
+tl0_s1n: SPILL_1_NORMAL
+tl0_s2n: SPILL_2_NORMAL
+tl0_s3n: SPILL_3_NORMAL
+tl0_s4n: SPILL_4_NORMAL
+tl0_s5n: SPILL_5_NORMAL
+tl0_s6n: SPILL_6_NORMAL
+tl0_s7n: SPILL_7_NORMAL
+tl0_s0o: SPILL_0_OTHER
+tl0_s1o: SPILL_1_OTHER
+tl0_s2o: SPILL_2_OTHER
+tl0_s3o: SPILL_3_OTHER
+tl0_s4o: SPILL_4_OTHER
+tl0_s5o: SPILL_5_OTHER
+tl0_s6o: SPILL_6_OTHER
+tl0_s7o: SPILL_7_OTHER
+tl0_f0n: FILL_0_NORMAL
+tl0_f1n: FILL_1_NORMAL
+tl0_f2n: FILL_2_NORMAL
+tl0_f3n: FILL_3_NORMAL
+tl0_f4n: FILL_4_NORMAL
+tl0_f5n: FILL_5_NORMAL
+tl0_f6n: FILL_6_NORMAL
+tl0_f7n: FILL_7_NORMAL
+tl0_f0o: FILL_0_OTHER
+tl0_f1o: FILL_1_OTHER
+tl0_f2o: FILL_2_OTHER
+tl0_f3o: FILL_3_OTHER
+tl0_f4o: FILL_4_OTHER
+tl0_f5o: FILL_5_OTHER
+tl0_f6o: FILL_6_OTHER
+tl0_f7o: FILL_7_OTHER
+tl0_sunos: SUNOS_SYSCALL_TRAP
+tl0_bkpt: BREAKPOINT_TRAP
+tl0_resv102: BTRAP(0x102)
+tl0_flushw: FLUSH_WINDOW_TRAP
+tl0_resv104: BTRAP(0x104) BTRAP(0x105) BTRAP(0x106) BTRAP(0x107)
+tl0_solaris: SOLARIS_SYSCALL_TRAP
+tl0_netbsd: NETBSD_SYSCALL_TRAP
+tl0_resv10a: BTRAP(0x10a) BTRAP(0x10b) BTRAP(0x10c) BTRAP(0x10d) BTRAP(0x10e)
+tl0_resv10f: BTRAP(0x10f)
+tl0_linux32: LINUX_32BIT_SYSCALL_TRAP
+tl0_linux64: LINUX_64BIT_SYSCALL_TRAP
+tl0_resv112: BTRAP(0x112) BTRAP(0x113) BTRAP(0x114) BTRAP(0x115) BTRAP(0x116)
+tl0_resv117: BTRAP(0x117) BTRAP(0x118) BTRAP(0x119) BTRAP(0x11a) BTRAP(0x11b)
+tl0_resv11c: BTRAP(0x11c) BTRAP(0x11d) BTRAP(0x11e) BTRAP(0x11f)
+tl0_getcc: GETCC_TRAP
+tl0_setcc: SETCC_TRAP
+tl0_resv122: BTRAP(0x122) BTRAP(0x123) BTRAP(0x124) BTRAP(0x125) BTRAP(0x126)
+tl0_solindir: INDIRECT_SOLARIS_SYSCALL(156)
+tl0_resv128: BTRAP(0x128) BTRAP(0x129) BTRAP(0x12a) BTRAP(0x12b) BTRAP(0x12c)
+tl0_resv12d: BTRAP(0x12d) BTRAP(0x12e) BTRAP(0x12f) BTRAP(0x130) BTRAP(0x131)
+tl0_resv132: BTRAP(0x132) BTRAP(0x133) BTRAP(0x134) BTRAP(0x135) BTRAP(0x136)
+tl0_resv137: BTRAP(0x137) BTRAP(0x138) BTRAP(0x139) BTRAP(0x13a) BTRAP(0x13b)
+tl0_resv13c: BTRAP(0x13c) BTRAP(0x13d) BTRAP(0x13e) BTRAP(0x13f) BTRAP(0x140)
+tl0_resv141: BTRAP(0x141) BTRAP(0x142) BTRAP(0x143) BTRAP(0x144) BTRAP(0x145)
+tl0_resv146: BTRAP(0x146) BTRAP(0x147) BTRAP(0x148) BTRAP(0x149) BTRAP(0x14a)
+tl0_resv14b: BTRAP(0x14b) BTRAP(0x14c) BTRAP(0x14d) BTRAP(0x14e) BTRAP(0x14f)
+tl0_resv150: BTRAP(0x150) BTRAP(0x151) BTRAP(0x152) BTRAP(0x153) BTRAP(0x154)
+tl0_resv155: BTRAP(0x155) BTRAP(0x156) BTRAP(0x157) BTRAP(0x158) BTRAP(0x159)
+tl0_resv15a: BTRAP(0x15a) BTRAP(0x15b) BTRAP(0x15c) BTRAP(0x15d) BTRAP(0x15e)
+tl0_resv15f: BTRAP(0x15f) BTRAP(0x160) BTRAP(0x161) BTRAP(0x162) BTRAP(0x163)
+tl0_resv164: BTRAP(0x164) BTRAP(0x165) BTRAP(0x166) BTRAP(0x167) BTRAP(0x168)
+tl0_resv169: BTRAP(0x169) BTRAP(0x16a) BTRAP(0x16b) BTRAP(0x16c) BTRAP(0x16d)
+tl0_resv16e: BTRAP(0x16e) BTRAP(0x16f) BTRAP(0x170) BTRAP(0x171) BTRAP(0x172)
+tl0_resv173: BTRAP(0x173) BTRAP(0x174) BTRAP(0x175) BTRAP(0x176) BTRAP(0x177)
+tl0_resv178: BTRAP(0x178) BTRAP(0x179) BTRAP(0x17a) BTRAP(0x17b) BTRAP(0x17c)
+tl0_resv17d: BTRAP(0x17d) BTRAP(0x17e) BTRAP(0x17f)
+#define BTRAPS(x) BTRAP(x) BTRAP(x+1) BTRAP(x+2) BTRAP(x+3) BTRAP(x+4) BTRAP(x+5) BTRAP(x+6) BTRAP(x+7)
+tl0_resv180: BTRAPS(0x180) BTRAPS(0x188)
+tl0_resv190: BTRAPS(0x190) BTRAPS(0x198)
+tl0_resv1a0: BTRAPS(0x1a0) BTRAPS(0x1a8)
+tl0_resv1b0: BTRAPS(0x1b0) BTRAPS(0x1b8)
+tl0_resv1c0: BTRAPS(0x1c0) BTRAPS(0x1c8)
+tl0_resv1d0: BTRAPS(0x1d0) BTRAPS(0x1d8)
+tl0_resv1e0: BTRAPS(0x1e0) BTRAPS(0x1e8)
+tl0_resv1f0: BTRAPS(0x1f0) BTRAPS(0x1f8)
+
+sparc64_ttable_tl1:
+tl1_resv000: BOOT_KERNEL BTRAPTL1(0x1) BTRAPTL1(0x2) BTRAPTL1(0x3)
+tl1_resv004: BTRAPTL1(0x4) BTRAPTL1(0x5) BTRAPTL1(0x6) BTRAPTL1(0x7)
+tl1_iax: ACCESS_EXCEPTION_TRAPTL1(instruction_access_exception)
+tl1_resv009: BTRAPTL1(0x9)
+tl1_iae: TRAPTL1(do_iae_tl1)
+tl1_resv00b: BTRAPTL1(0xb) BTRAPTL1(0xc) BTRAPTL1(0xd) BTRAPTL1(0xe) BTRAPTL1(0xf)
+tl1_ill: TRAPTL1(do_ill_tl1)
+tl1_privop: BTRAPTL1(0x11)
+tl1_resv012: BTRAPTL1(0x12) BTRAPTL1(0x13) BTRAPTL1(0x14) BTRAPTL1(0x15)
+tl1_resv016: BTRAPTL1(0x16) BTRAPTL1(0x17) BTRAPTL1(0x18) BTRAPTL1(0x19)
+tl1_resv01a: BTRAPTL1(0x1a) BTRAPTL1(0x1b) BTRAPTL1(0x1c) BTRAPTL1(0x1d)
+tl1_resv01e: BTRAPTL1(0x1e) BTRAPTL1(0x1f)
+tl1_fpdis: TRAPTL1(do_fpdis_tl1)
+tl1_fpieee: TRAPTL1(do_fpieee_tl1)
+tl1_fpother: TRAPTL1(do_fpother_tl1)
+tl1_tof: TRAPTL1(do_tof_tl1)
+tl1_cwin: CLEAN_WINDOW
+tl1_div0: TRAPTL1(do_div0_tl1)
+tl1_resv029: BTRAPTL1(0x29) BTRAPTL1(0x2a) BTRAPTL1(0x2b) BTRAPTL1(0x2c)
+tl1_resv02d: BTRAPTL1(0x2d) BTRAPTL1(0x2e) BTRAPTL1(0x2f)
+tl1_dax: ACCESS_EXCEPTION_TRAPTL1(data_access_exception)
+tl1_resv031: BTRAPTL1(0x31)
+tl1_dae: TRAPTL1(do_dae_tl1)
+tl1_resv033: BTRAPTL1(0x33)
+tl1_mna: TRAPTL1(do_mna_tl1)
+tl1_lddfmna: TRAPTL1(do_lddfmna_tl1)
+tl1_stdfmna: TRAPTL1(do_stdfmna_tl1)
+tl1_privact: BTRAPTL1(0x37)
+tl1_resv038: BTRAPTL1(0x38) BTRAPTL1(0x39) BTRAPTL1(0x3a) BTRAPTL1(0x3b)
+tl1_resv03c: BTRAPTL1(0x3c) BTRAPTL1(0x3d) BTRAPTL1(0x3e) BTRAPTL1(0x3f)
+tl1_resv040: BTRAPTL1(0x40)
+tl1_irq1: TRAP_IRQ(do_irq_tl1, 1) TRAP_IRQ(do_irq_tl1, 2) TRAP_IRQ(do_irq_tl1, 3)
+tl1_irq4: TRAP_IRQ(do_irq_tl1, 4) TRAP_IRQ(do_irq_tl1, 5) TRAP_IRQ(do_irq_tl1, 6)
+tl1_irq7: TRAP_IRQ(do_irq_tl1, 7) TRAP_IRQ(do_irq_tl1, 8) TRAP_IRQ(do_irq_tl1, 9)
+tl1_irq10: TRAP_IRQ(do_irq_tl1, 10) TRAP_IRQ(do_irq_tl1, 11)
+tl1_irq12: TRAP_IRQ(do_irq_tl1, 12) TRAP_IRQ(do_irq_tl1, 13)
+tl1_irq14: TRAP_IRQ(do_irq_tl1, 14) TRAP_IRQ(do_irq_tl1, 15)
+tl1_resv050: BTRAPTL1(0x50) BTRAPTL1(0x51) BTRAPTL1(0x52) BTRAPTL1(0x53)
+tl1_resv054: BTRAPTL1(0x54) BTRAPTL1(0x55) BTRAPTL1(0x56) BTRAPTL1(0x57)
+tl1_resv058: BTRAPTL1(0x58) BTRAPTL1(0x59) BTRAPTL1(0x5a) BTRAPTL1(0x5b)
+tl1_resv05c: BTRAPTL1(0x5c) BTRAPTL1(0x5d) BTRAPTL1(0x5e) BTRAPTL1(0x5f)
+tl1_ivec: TRAP_IVEC
+tl1_paw: TRAPTL1(do_paw_tl1)
+tl1_vaw: TRAPTL1(do_vaw_tl1)
+tl1_cee: TRAPTL1(do_cee_tl1)
+tl1_iamiss:
+#include "itlb_miss.S"
+tl1_damiss:
+#include "dtlb_miss.S"
+tl1_daprot:
+#include "dtlb_prot.S"
+tl1_resv070: BTRAPTL1(0x70) BTRAPTL1(0x71) BTRAPTL1(0x72) BTRAPTL1(0x73)
+tl1_resv074: BTRAPTL1(0x74) BTRAPTL1(0x75) BTRAPTL1(0x76) BTRAPTL1(0x77)
+tl1_resv078: BTRAPTL1(0x78) BTRAPTL1(0x79) BTRAPTL1(0x7a) BTRAPTL1(0x7b)
+tl1_resv07c: BTRAPTL1(0x7c) BTRAPTL1(0x7d) BTRAPTL1(0x7e) BTRAPTL1(0x7f)
+tl1_s0n: SPILL_0_NORMAL
+tl1_s1n: SPILL_1_NORMAL
+tl1_s2n: SPILL_2_NORMAL
+tl1_s3n: SPILL_3_NORMAL
+tl1_s4n: SPILL_4_NORMAL
+tl1_s5n: SPILL_5_NORMAL
+tl1_s6n: SPILL_6_NORMAL
+tl1_s7n: SPILL_7_NORMAL
+tl1_s0o: SPILL_0_OTHER
+tl1_s1o: SPILL_1_OTHER
+tl1_s2o: SPILL_2_OTHER
+tl1_s3o: SPILL_3_OTHER
+tl1_s4o: SPILL_4_OTHER
+tl1_s5o: SPILL_5_OTHER
+tl1_s6o: SPILL_6_OTHER
+tl1_s7o: SPILL_7_OTHER
+tl1_f0n: FILL_0_NORMAL
+tl1_f1n: FILL_1_NORMAL
+tl1_f2n: FILL_2_NORMAL
+tl1_f3n: FILL_3_NORMAL
+tl1_f4n: FILL_4_NORMAL
+tl1_f5n: FILL_5_NORMAL
+tl1_f6n: FILL_6_NORMAL
+tl1_f7n: FILL_7_NORMAL
+tl1_f0o: FILL_0_OTHER
+tl1_f1o: FILL_1_OTHER
+tl1_f2o: FILL_2_OTHER
+tl1_f3o: FILL_3_OTHER
+tl1_f4o: FILL_4_OTHER
+tl1_f5o: FILL_5_OTHER
+tl1_f6o: FILL_6_OTHER
+tl1_f7o: FILL_7_OTHER
+
+#if 0
+/* Unless we are going to have software trap insns in the kernel code, we
+ * don't need this. For now we just save 8KB.
+ */
+
+#define BTRAPSTL1(x) BTRAPTL1(x) BTRAPTL1(x+1) BTRAPTL1(x+2) BTRAPTL1(x+3) BTRAPTL1(x+4) BTRAPTL1(x+5) BTRAPTL1(x+6) BTRAPTL1(x+7)
+
+tl1_sunos: BTRAPTL1(0x100)
+tl1_bkpt: BREAKPOINT_TRAP
+tl1_resv102: BTRAPTL1(0x102)
+tl1_flushw: FLUSH_WINDOW_TRAP
+tl1_resv104: BTRAPTL1(0x104) BTRAPTL1(0x105) BTRAPTL1(0x106)
+tl1_resv107: BTRAPTL1(0x107) BTRAPTL1(0x108) BTRAPTL1(0x109) BTRAPTL1(0x10a)
+tl1_resv10b: BTRAPTL1(0x10b) BTRAPTL1(0x10c) BTRAPTL1(0x10d) BTRAPTL1(0x10e)
+tl1_resv10f: BTRAPTL1(0x10f)
+tl1_resv110: BTRAPSTL1(0x110) BTRAPSTL1(0x118)
+tl1_resv120: BTRAPSTL1(0x120) BTRAPSTL1(0x128)
+tl1_resv130: BTRAPSTL1(0x130) BTRAPSTL1(0x138)
+tl1_resv140: BTRAPSTL1(0x140) BTRAPSTL1(0x148)
+tl1_resv150: BTRAPSTL1(0x150) BTRAPSTL1(0x158)
+tl1_resv160: BTRAPSTL1(0x160) BTRAPSTL1(0x168)
+tl1_resv170: BTRAPSTL1(0x170) BTRAPSTL1(0x178)
+#endif