summaryrefslogtreecommitdiffstats
path: root/arch/sparc64
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-06-01 03:16:17 +0000
committerRalf Baechle <ralf@linux-mips.org>1997-06-01 03:16:17 +0000
commitd8d9b8f76f22b7a16a83e261e64f89ee611f49df (patch)
tree3067bc130b80d52808e6390c9fc7fc087ec1e33c /arch/sparc64
parent19c9bba94152148523ba0f7ef7cffe3d45656b11 (diff)
Initial revision
Diffstat (limited to 'arch/sparc64')
-rw-r--r--arch/sparc64/Makefile4
-rw-r--r--arch/sparc64/defconfig9
-rw-r--r--arch/sparc64/kernel/Makefile13
-rw-r--r--arch/sparc64/kernel/binfmt_elf32.c34
-rw-r--r--arch/sparc64/kernel/dtlb_prot.S28
-rw-r--r--arch/sparc64/kernel/entry.S124
-rw-r--r--arch/sparc64/kernel/etrap.S109
-rw-r--r--arch/sparc64/kernel/hack.S16
-rw-r--r--arch/sparc64/kernel/head.S31
-rw-r--r--arch/sparc64/kernel/init_task.c18
-rw-r--r--arch/sparc64/kernel/process.c81
-rw-r--r--arch/sparc64/kernel/rtrap.S15
-rw-r--r--arch/sparc64/kernel/setup.c4
-rw-r--r--arch/sparc64/kernel/signal.c438
-rw-r--r--arch/sparc64/kernel/signal32.c19
-rw-r--r--arch/sparc64/kernel/sparcelf32.c1281
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c334
-rw-r--r--arch/sparc64/kernel/traps.c35
-rw-r--r--arch/sparc64/kernel/ttable.S28
-rw-r--r--arch/sparc64/kernel/winfixup.S101
-rw-r--r--arch/sparc64/lib/blockops.S66
-rw-r--r--arch/sparc64/lib/checksum.S25
-rw-r--r--arch/sparc64/lib/copy_from_user.S15
-rw-r--r--arch/sparc64/lib/copy_to_user.S15
-rw-r--r--arch/sparc64/lib/strlen_user.S12
-rw-r--r--arch/sparc64/lib/strncpy_from_user.S4
-rw-r--r--arch/sparc64/mm/asyncd.c7
-rw-r--r--arch/sparc64/mm/fault.c23
-rw-r--r--arch/sparc64/mm/init.c44
29 files changed, 1373 insertions, 1560 deletions
diff --git a/arch/sparc64/Makefile b/arch/sparc64/Makefile
index bacf9b095..a70f9ebf8 100644
--- a/arch/sparc64/Makefile
+++ b/arch/sparc64/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.15 1997/04/14 17:04:49 jj Exp $
+# $Id: Makefile,v 1.16 1997/05/04 07:21:08 davem Exp $
# sparc64/Makefile
#
# Makefile for the architecture dependent flags and dependencies on the
@@ -29,7 +29,7 @@ CFLAGS := $(CFLAGS) -pipe \
LINKFLAGS = -T arch/sparc64/vmlinux.lds
-HEAD := arch/sparc64/kernel/head.o
+HEAD := arch/sparc64/kernel/head.o arch/sparc64/kernel/init_task.o
SUBDIRS := $(SUBDIRS) arch/sparc64/kernel arch/sparc64/lib arch/sparc64/mm \
arch/sparc64/prom
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index 9ecbf90b4..fbc4a5073 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -40,6 +40,7 @@ SUN_FB_CGFOURTEEN=y
SUN_FB_BWTWO=y
SUN_FB_LEO=y
TADPOLE_FB_WEITEK=y
+SUN_FB_CREATOR=y
#
# Misc Linux/SPARC drivers
@@ -132,8 +133,8 @@ CONFIG_SUNLANCE=y
#
# Filesystems
#
-CONFIG_QUOTA=y
-CONFIG_MINIX_FS=y
+# CONFIG_QUOTA is not set
+# CONFIG_MINIX_FS is not set
CONFIG_EXT2_FS=y
# CONFIG_FAT_FS is not set
# CONFIG_MSDOS_FS is not set
@@ -141,7 +142,9 @@ CONFIG_EXT2_FS=y
# CONFIG_UMSDOS_FS is not set
CONFIG_PROC_FS=y
CONFIG_NFS_FS=y
-# CONFIG_ROOT_NFS is not set
+CONFIG_ROOT_NFS=y
+CONFIG_RNFS_BOOTP=y
+# CONFIG_RNFS_RARP is not set
# CONFIG_NFSD is not set
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index d66fa06e7..4a07295e1 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.16 1997/04/17 20:35:37 jj Exp $
+# $Id: Makefile,v 1.20 1997/05/18 08:42:11 davem Exp $
# Makefile for the linux kernel.
#
# Note! Dependencies are done automagically by 'make dep', which also
@@ -13,12 +13,12 @@
.S.o:
$(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
-all: kernel.o head.o
+all: kernel.o head.o init_task.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
+ irq.o time.o sys_sparc.o signal.o winfixup.o
OX_OBJS := sparc64_ksyms.o
ifdef CONFIG_SPARC32_COMPAT
@@ -26,12 +26,17 @@ ifdef CONFIG_SPARC32_COMPAT
endif
ifdef CONFIG_BINFMT_ELF32
- O_OBJS += sparcelf32.o
+ O_OBJS += binfmt_elf32.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
+#
+# This is just to get the dependencies...
+#
+binfmt_elf32.o: $(TOPDIR)/fs/binfmt_elf.c
+
check_asm: dummy
@echo "#include <linux/sched.h>" > tmp.c
$(CC) -E tmp.c -o tmp.i
diff --git a/arch/sparc64/kernel/binfmt_elf32.c b/arch/sparc64/kernel/binfmt_elf32.c
new file mode 100644
index 000000000..05d50fe56
--- /dev/null
+++ b/arch/sparc64/kernel/binfmt_elf32.c
@@ -0,0 +1,34 @@
+/* binfmt_elf32.c: Support 32-bit Sparc ELF binaries on Ultra.
+ *
+ */
+
+#define ELF_ARCH EM_SPARC
+#define ELF_CLASS ELFCLASS32
+#define ELF_DATA ELFDATA2MSB;
+
+#include <asm/processor.h>
+#include <linux/module.h>
+#include <linux/config.h>
+
+#define elf_addr_t u32
+#define elf_caddr_t u32
+#undef start_thread
+#define start_thread start_thread32
+#define init_elf_binfmt init_elf32_binfmt
+#undef CONFIG_BINFMT_ELF
+#ifdef CONFIG_BINFMT_ELF32
+#define CONFIG_BINFMT_ELF CONFIG_BINFMT_ELF32
+#endif
+#undef CONFIG_BINFMT_ELF_MODULE
+#ifdef CONFIG_BINFMT_ELF32_MODULE
+#define CONFIG_BINFMT_ELF_MODULE CONFIG_BINFMT_ELF32_MODULE
+#endif
+#define ELF_FLAGS_INIT current->tss.flags |= SPARC_FLAG_32BIT
+
+MODULE_DESCRIPTION("Binary format loader for compatibility with 32bit SparcLinux binaries on the Ultra");
+MODULE_AUTHOR("Eric Youngdale, David S. Miller, Jakub Jelinek");
+
+#undef MODULE_DESCRIPTION
+#undef MODULE_AUTHOR
+
+#include "../../../fs/binfmt_elf.c"
diff --git a/arch/sparc64/kernel/dtlb_prot.S b/arch/sparc64/kernel/dtlb_prot.S
index 8eec19260..2cf372ca9 100644
--- a/arch/sparc64/kernel/dtlb_prot.S
+++ b/arch/sparc64/kernel/dtlb_prot.S
@@ -1,4 +1,4 @@
-/* $Id: dtlb_prot.S,v 1.10 1997/03/25 09:47:13 davem Exp $
+/* $Id: dtlb_prot.S,v 1.12 1997/05/18 10:04:43 davem Exp $
* dtlb_prot.S: Data TLB protection code, this is included directly
* into the trap table.
*
@@ -18,30 +18,30 @@
/*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
+ /*0x10*/ and %g4, %g2, %g4 ! 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
+ /*0x18*/ ldxa [%g5 + %g4] 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...
+ /*0x2c*/ be,pt %xcc, sparc64_dtlb_prot_catch ! 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
+ /*0x38*/ add %g1, %g4, %g1 ! to get a tmpreg
+ /*0x3c*/ ldxa [%g5] ASI_DMMU, %g4 ! From MMU
/* 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
+ /*0x40*/ add %g2, 7, %g5 ! Compute mask
+ /*0x44*/ andn %g4, %g5, %g4 ! Mask page
+ /*0x48*/ or %g4, 0x10, %g4 ! 2ndary Context
+ /*0x4c*/ stxa %g0, [%g4] ASI_DMMU_DEMAP ! TLB flush page
+ /*0x50*/ membar #Sync ! Synchronize
+ /*0x54*/ stxa %g3, [%g1] ASI_PHYS_USE_EC ! Update sw PTE
+ /*0x58*/ stxa %g3, [%g0] ASI_DTLB_DATA_IN ! TLB load
+ /*0x5c*/ retry ! Trap return
/* ICACHE line 4 */
/*0x60*/ nop
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
index 16fe5c8a0..589d1661a 100644
--- a/arch/sparc64/kernel/entry.S
+++ b/arch/sparc64/kernel/entry.S
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.14 1997/04/14 06:56:54 davem Exp $
+/* $Id: entry.S,v 1.21 1997/05/18 10:04:44 davem Exp $
* arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -24,31 +24,70 @@
.text
.align 4
-/* FIXME: This is still debugging hack */
- .globl sparc64_dtlb_fault, sparc64_dtlb_refbit_catch, sparc64_itlb_refbit_catch
-sparc64_dtlb_fault:
+ .globl sparc64_dtlb_prot_catch, sparc64_dtlb_refbit_catch
+ .globl sparc64_itlb_refbit_catch
+
+ /* Note, DMMU SFAR not updated for fast tlb data access miss
+ * traps, so we must use tag access to find the right page.
+ * However for DMMU fast protection traps it is updated so
+ * we use, but we must also clear it _before_ we enable interrupts
+ * and save state because there is a race where we can push a user
+ * window right now in etrap, a protection fault happens (for example
+ * to update the dirty bit) and since we left crap in the sfsr
+ * it will not get updated properly.
+ */
+sparc64_dtlb_prot_catch:
+ wr %g0, ASI_DMMU, %asi
rdpr %pstate, %g1
wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate
+ rdpr %tl, %g2
+ ldxa [%g0 + TLB_TAG_ACCESS] %asi, %g5
+ ldxa [%g0 + TLB_SFSR] %asi, %g4
+ cmp %g2, 1
+ stxa %g0, [%g0 + TLB_SFSR] %asi
+ bgu,a %icc, winfix_trampoline
+ rdpr %tpc, %g5
ba,pt %xcc, etrap
rd %pc, %g7
- call sparc64_dtlb_fault_handler
- nop
+ b,a,pt %xcc, 1f
sparc64_dtlb_refbit_catch:
+ wr %g0, ASI_DMMU, %asi
rdpr %pstate, %g1
wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate
+ rdpr %tl, %g2
+ ldxa [%g0 + TLB_TAG_ACCESS] %asi, %g5
+ cmp %g2, 1
+ clr %g4 ! sfsr not updated for tlb misses
+ bgu,a %icc, winfix_trampoline
+ rdpr %tpc, %g5
ba,pt %xcc, etrap
rd %pc, %g7
- call sparc64_dtlb_refbit_handler
- add %sp, STACK_BIAS + REGWIN_SZ, %o0
+1:
+ mov %l5, %o4 ! raw tag access
+ mov %l4, %o5 ! raw sfsr
+ srlx %l5, PAGE_SHIFT, %o3
+ clr %o1 ! text_fault == 0
+ sllx %o3, PAGE_SHIFT, %o3 ! address
+ and %l4, 0x4, %o2 ! write == sfsr.W
+ call do_sparc64_fault
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0 ! pt_regs ptr
+ ba,a,pt %xcc, rtrap
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
+
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC], %o3
+ mov 1, %o1 ! text_fault == 1
+ clr %o2 ! write == 0
+ clr %o4 ! tag access (N/A)
+ clr %o5 ! raw sfsr (N/A)
+ call do_sparc64_fault
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0 ! pt_regs ptr
+ ba,a,pt %xcc, rtrap
/* Note check out head.h, this code isn't even used for UP,
* for SMP things will be different. In particular the data
@@ -121,6 +160,7 @@ breakpoint_trap:
ba,a,pt %xcc, rtrap
.globl sys_pipe, sys_execve, sys_sigpause, sys_nis_syscall
+ .globl sys_sigsuspend, sys_sigreturn
sys_pipe:
sethi %hi(sparc_pipe), %g1
@@ -147,12 +187,35 @@ sys_sigpause:
ld [%curptr + AOFF_task_flags], %l5
andcc %l5, 0x20, %g0
+ be,pt %icc, rtrap
+ nop
+ call syscall_trace
+ nop
+ ba,a,pt %xcc, rtrap
+
+sys_sigsuspend:
+ call do_sigsuspend
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+
+ ld [%curptr + AOFF_task_flags], %l5
+ andcc %l5, 0x20, %g0
be,pt %icc, ret_sys_call
- clr %o0
+ nop
call syscall_trace
nop
- ba,pt %xcc, ret_sys_call
- clr %o0
+ ba,a,pt %xcc, rtrap
+
+sys_sigreturn:
+ call do_sigreturn
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+
+ ld [%curptr + AOFF_task_flags], %l5
+ andcc %l5, 0x20, %g0
+ be,pt %icc, ret_sys_call
+ nop
+ call syscall_trace
+ nop
+ ba,a,pt %xcc, rtrap
/* This is how fork() was meant to be done, 11 instruction entry. -DaveM */
.globl sys_fork, sys_vfork, sys_clone
@@ -200,7 +263,7 @@ linux_syscall_trace:
.globl ret_from_syscall
ret_from_syscall:
ba,pt %xcc, ret_sys_call
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_I0], %o0
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0
/* Linux native and SunOS system calls enter here... */
.align 4
@@ -232,13 +295,18 @@ syscall_is_too_hard:
call %l7
mov %i5, %o5
- stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_I0]
-
+ stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
+#if 0
+ /* Debugging... */
+ call syscall_trace_exit
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0
+#endif
.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
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %g3
cmp %o0, -ENOIOCTLCMD
sllx %g2, 32, %g2
bgeu,pn %xcc, 1f
@@ -247,34 +315,34 @@ ret_sys_call:
/* System call success, clear Carry condition code. */
andn %g3, %g2, %g3
clr %l6
- stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_TSTATE]
+ stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE]
bne,pn %icc, linux_syscall_trace2
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC], %l1 /* pc = npc */
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 /* pc = npc */
add %l1, 0x4, %l2 /* npc = npc+4 */
- stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_TPC]
+ stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
ba,pt %xcc, rtrap
- stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC]
+ stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_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]
+ stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
mov 1, %l6
- stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_TSTATE]
+ stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE]
bne,pn %icc, linux_syscall_trace2
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC], %l1 /* pc = npc */
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 /* pc = npc */
add %l1, 0x4, %l2 /* npc = npc+4 */
- stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_TPC]
+ stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
ba,pt %xcc, rtrap
- stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC]
+ stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
linux_syscall_trace2:
call syscall_trace
add %l1, 0x4, %l2 /* npc = npc+4 */
- stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_TPC]
+ stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
ba,pt %xcc, rtrap
- stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC]
+ stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
/* End of entry.S */
diff --git a/arch/sparc64/kernel/etrap.S b/arch/sparc64/kernel/etrap.S
index 7d293a88b..f936b3071 100644
--- a/arch/sparc64/kernel/etrap.S
+++ b/arch/sparc64/kernel/etrap.S
@@ -1,34 +1,39 @@
-/* $Id: etrap.S,v 1.11 1997/04/14 17:04:45 jj Exp $
+/* $Id: etrap.S,v 1.17 1997/05/18 22:52:09 davem Exp $
* etrap.S: Preparing for entry into the kernel on Sparc V9.
*
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996, 1997 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/page.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 */
+ /* We assume that pstate, when entering this, has AG and
+ * IE bits set, MG and IG clear.
+ *
+ * We also guarentee for caller that AG %g4 and %g5 will have
+ * their values preserved and left in %l4 and %l5 respectively
+ * for him (fault handling needs this).
+ */
.text
.align 32
.globl etrap, etrap_irq
etrap:
- rdpr %pil, %g4
+ rdpr %pil, %g2
etrap_irq:
rdpr %tstate, %g1
- sllx %g4, 20, %g4
- rdpr %tpc, %g2
- or %g1, %g4, %g1
- rdpr %tnpc, %g3
+ sllx %g2, 20, %g2
+ or %g1, %g2, %g1
/* 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
+ sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2
/* Just when going from userland to privileged mode,
* we have to change this stuff.
@@ -38,41 +43,48 @@ etrap_irq:
* 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
+ mov PRIMARY_CONTEXT, %g1
+ ldxa [%g1] ASI_DMMU, %g2
+ stxa %g0, [%g1] ASI_DMMU
- 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
+ mov SECONDARY_CONTEXT, %g1
+ stxa %g2, [%g1] ASI_DMMU
+
+ rd %pic, %g1
+ sethi %hi((PAGE_SIZE<<1)-TRACEREG_SZ-REGWIN_SZ), %g2
+ or %g2, %lo((PAGE_SIZE<<1)-TRACEREG_SZ-REGWIN_SZ), %g2
+ add %g1, %g2, %g2
+ rdpr %tstate, %g1
1:
+ stx %g1, [%g2 + REGWIN_SZ + PT_V9_TSTATE]
+ rdpr %tpc, %g1
+ rdpr %tnpc, %g3
+ stx %g1, [%g2 + REGWIN_SZ + PT_V9_TPC]
+ rd %y, %g1
+ stx %g3, [%g2 + REGWIN_SZ + PT_V9_TNPC]
+ stx %g1, [%g2 + REGWIN_SZ + PT_V9_Y]
+
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
+ save %g2, -STACK_BIAS, %sp
+
+ /* Must guarentee that here andcc of TSTATE_PRIV at the top is
+ * still valid in %ccr register. Don't show this trick to your
+ * mom. -DaveM
+ */
+ bne,pn %xcc, 1f
+ rdpr %canrestore, %g3
+ wrpr %g0, 0, %canrestore
+ wrpr %g3, 0, %otherwin
+
+ rdpr %wstate, %g6
+ sll %g6, 3, %g6
+ wrpr %g6, %wstate
+
+1:
mov %g1, %l1
+ mov %g4, %l4
+ mov %g5, %l5
mov %g7, %l2
wrpr %l1, PSTATE_AG, %pstate
stx %g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1]
@@ -91,24 +103,13 @@ etrap_irq:
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
+ srlx %sp, 43, %g4
+ rd %pic, %g6
jmpl %l2 + 0x4, %g0
- ldx [%g6 + %g4], %g6
-#ifdef __SMP__
-/* FIXME: Fix the above insn for SMP */
-#endif
+ sllx %g4, 43, %g4
.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
+ sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2
diff --git a/arch/sparc64/kernel/hack.S b/arch/sparc64/kernel/hack.S
index 0aca22a77..034bda2d0 100644
--- a/arch/sparc64/kernel/hack.S
+++ b/arch/sparc64/kernel/hack.S
@@ -4,8 +4,6 @@
to compile... */
.text
.align 8
- .globl _sigpause_common
-_sigpause_common: retl;nop
.globl breakpoint
breakpoint: retl;nop
.globl do_cee
@@ -36,8 +34,6 @@ do_fpother_tl1: retl;nop
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
@@ -48,8 +44,6 @@ do_irq_tl1: retl;nop
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
@@ -60,8 +54,6 @@ do_paw_tl1: retl;nop
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
@@ -200,15 +192,7 @@ sunos_write: retl;nop
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
index fdbe87aa3..4babe3eb4 100644
--- a/arch/sparc64/kernel/head.S
+++ b/arch/sparc64/kernel/head.S
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.27 1997/04/04 00:49:49 davem Exp $
+/* $Id: head.S,v 1.30 1997/05/18 22:52:12 davem Exp $
* head.S: Initial boot code for the Sparc64 port of Linux.
*
* Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -262,16 +262,22 @@ sun4u_init:
stx %g6, [%g2 + %g4]
stx %g5, [%g3 + %g4]
- sethi %hi(init_task), %g6
- or %g6, %lo(init_task), %g6
+ sethi %hi(init_task_union), %g6
+ or %g6, %lo(init_task_union), %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
+ /* Setup "Linux Current Register", thanks Sun 8-) */
+ wr %g0, 0x1, %pcr
+ wr %g6, 0x0, %pic
+
+ mov 1, %g5
+ sllx %g5, (PAGE_SHIFT + 1), %g5
+ sub %g5, (REGWIN_SZ + STACK_BIAS), %g5
+ add %g6, %g5, %sp
mov 0, %fp
+
wrpr %g0, 0, %wstate
wrpr %g0, 0x0, %tl
@@ -287,14 +293,20 @@ sun4u_init:
add %l2, 1, %l2
add %l0, %g4, %o0
1:
- call bzero_1page
+ clr %o1
+ sethi %hi(PAGE_SIZE), %o2
+ or %o2, %lo(PAGE_SIZE), %o2
+ call __memset
add %l0, %l2, %l0
cmp %l0, %l1
blu,pt %xcc, 1b
add %l0, %g4, %o0
/* Now clear empty_zero_page */
- call bzero_1page
+ clr %o1
+ sethi %hi(PAGE_SIZE), %o2
+ or %o2, %lo(PAGE_SIZE), %o2
+ call __memset
mov %g4, %o0
mov %l6, %o1 ! OpenPROM stack
@@ -361,6 +373,9 @@ bootup_kernel_stack:
#include "ttable.S"
+ /* This is just anal retentiveness on my part... */
+ .align 16384
+
.data
.align 8
.globl nwindows, nwindowsm1
diff --git a/arch/sparc64/kernel/init_task.c b/arch/sparc64/kernel/init_task.c
new file mode 100644
index 000000000..d0fc09346
--- /dev/null
+++ b/arch/sparc64/kernel/init_task.c
@@ -0,0 +1,18 @@
+#include <linux/mm.h>
+#include <linux/sched.h>
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+
+static struct vm_area_struct init_mmap = INIT_MMAP;
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS;
+struct mm_struct init_mm = INIT_MM;
+
+/* .text section in head.S is aligned at 2 page boundry and this gets linked
+ * right after that so that the init_task_union is aligned properly as well.
+ * We really don't need this special alignment like the Intel does, but
+ * I do it anyways for completeness.
+ */
+union task_union init_task_union __attribute__((__section__(".text"))) = { INIT_TASK };
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index 5ec62a6b6..4e2bbe016 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.6 1997/04/07 18:57:07 jj Exp $
+/* $Id: process.c,v 1.11 1997/05/18 22:52:19 davem Exp $
* arch/sparc64/kernel/process.c
*
* Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -346,7 +346,14 @@ void flush_thread(void)
}
/* Now, this task is no longer a kernel thread. */
- current->tss.flags &= ~SPARC_FLAG_KTHREAD;
+ if(current->tss.flags & SPARC_FLAG_KTHREAD) {
+ current->tss.flags &= ~SPARC_FLAG_KTHREAD;
+
+ /* exec_mmap() set context to NO_CONTEXT, here is
+ * where we grab a new one.
+ */
+ get_mmu_context(current);
+ }
current->tss.current_ds = USER_DS;
}
@@ -416,6 +423,64 @@ clone_stackframe(struct sparc_stackf *dst, struct sparc_stackf *src)
return sp;
}
+/* Standard stuff. */
+static inline void shift_window_buffer(int first_win, int last_win,
+ struct thread_struct *tp)
+{
+ int i;
+
+ for(i = first_win; i < last_win; i++) {
+ tp->rwbuf_stkptrs[i] = tp->rwbuf_stkptrs[i+1];
+ memcpy(&tp->reg_window[i], &tp->reg_window[i+1],
+ sizeof(struct reg_window));
+ }
+}
+
+void synchronize_user_stack(void)
+{
+ struct thread_struct *tp = &current->tss;
+ unsigned long window = tp->w_saved;
+
+ flush_user_windows();
+ if(window) {
+ int winsize = REGWIN_SZ;
+
+ if(tp->flags & SPARC_FLAG_32BIT)
+ winsize = REGWIN32_SZ;
+
+ window -= 1;
+ do {
+ unsigned long sp = tp->rwbuf_stkptrs[window];
+ struct reg_window *rwin = &tp->reg_window[window];
+
+ if(!copy_to_user((char *)sp, rwin, winsize)) {
+ shift_window_buffer(window, tp->w_saved - 1, tp);
+ tp->w_saved--;
+ }
+ } while(window--);
+ }
+}
+
+void fault_in_user_windows(struct pt_regs *regs)
+{
+ struct thread_struct *tp = &current->tss;
+ unsigned long window = tp->w_saved;
+ int winsize = REGWIN_SZ;
+
+ if(tp->flags & SPARC_FLAG_32BIT)
+ winsize = REGWIN32_SZ;
+ if(window) {
+ window -= 1;
+ do {
+ unsigned long sp = tp->rwbuf_stkptrs[window];
+ struct reg_window *rwin = &tp->reg_window[window];
+
+ if(copy_to_user((char *)sp, rwin, winsize))
+ do_exit(SIGILL);
+ } while(window--);
+ }
+ current->tss.w_saved = 0;
+}
/* Copy a Sparc thread. The fork() return value conventions
* under SunOS are nothing short of bletcherous:
@@ -453,19 +518,18 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
#endif
/* Calculate offset to stack_frame & pt_regs */
- stack_offset = (PAGE_SIZE - TRACEREG_SZ);
+ stack_offset = ((PAGE_SIZE<<1) - TRACEREG_SZ);
if(regs->tstate & TSTATE_PRIV)
stack_offset -= REGWIN_SZ;
- childregs = ((struct pt_regs *) (p->kernel_stack_page + stack_offset));
+ childregs = ((struct pt_regs *) (((unsigned long)p) + 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.ksp = ((unsigned long) new_stack) - STACK_BIAS;
p->tss.kpc = ((unsigned long) ret_from_syscall) - 0x8;
p->tss.kregs = childregs;
@@ -485,7 +549,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
p->tss.current_ds = USER_DS;
#if 0
- if (sp != current->tss.kregs->u_regs[UREG_FP]) {
+ if (sp != regs->u_regs[UREG_FP]) {
struct sparc_stackf *childstack;
struct sparc_stackf *parentstack;
@@ -494,8 +558,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
* 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];
+ parentstack = (struct sparc_stackf *)regs->u_regs[UREG_FP];
#if 0
printk("clone: parent stack:\n");
diff --git a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S
index dfebd7ad8..1c4c4df04 100644
--- a/arch/sparc64/kernel/rtrap.S
+++ b/arch/sparc64/kernel/rtrap.S
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.11 1997/04/03 13:03:50 davem Exp $
+/* $Id: rtrap.S,v 1.14 1997/05/18 08:42:14 davem Exp $
* rtrap.S: Preparing for return from trap on Sparc V9.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -71,12 +71,11 @@ rtrap:
/* 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
+ membar #Sync /* XXX flushi would be better -DaveM */
rdpr %wstate, %g1
rdpr %otherwin, %g2
@@ -84,7 +83,6 @@ rtrap:
wrpr %g2, %g0, %canrestore
wrpr %g1, %g0, %wstate
wrpr %g0, %g0, %otherwin
- retry
1:
restore
retry
@@ -101,9 +99,14 @@ to_user:
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
+ be,pt %xcc, check_user_wins
mov %l5, %o2
mov %l6, %o3
- add %sp, STACK_BIAS + REGWIN_SZ, %o1
call do_signal
+ add %sp, STACK_BIAS + REGWIN_SZ, %o1
+check_user_wins:
+ ldx [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
+ brz,pt %o2, 3b
+ add %sp, STACK_BIAS + REGWIN_SZ, %o1
+ call fault_in_user_windows
add %o7, 3b-.-4, %o7
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
index 170e5563e..47d900977 100644
--- a/arch/sparc64/kernel/setup.c
+++ b/arch/sparc64/kernel/setup.c
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.5 1997/04/04 00:49:52 davem Exp $
+/* $Id: setup.c,v 1.6 1997/05/04 07:21:04 davem Exp $
* linux/arch/sparc64/kernel/setup.c
*
* Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
@@ -261,6 +261,8 @@ __initfunc(void setup_arch(char **cmdline_p,
*cmdline_p = prom_getbootargs();
strcpy(saved_command_line, *cmdline_p);
+ prom_printf("BOOT: args[%s] saved[%s]\n", *cmdline_p, saved_command_line);
+
printk("ARCH: SUN4U\n");
boot_flags_init(*cmdline_p);
diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c
new file mode 100644
index 000000000..1a595491a
--- /dev/null
+++ b/arch/sparc64/kernel/signal.c
@@ -0,0 +1,438 @@
+/* $Id: signal.c,v 1.2 1997/05/18 08:42:15 davem Exp $
+ * arch/sparc64/kernel/signal.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
+ * 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/fpumacro.h>
+#include <asm/smp_lock.h>
+
+#define _S(nr) (1<<((nr)-1))
+
+#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
+
+asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr,
+ int options, unsigned long *ru);
+
+asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
+ unsigned long orig_o0, int ret_from_syscall);
+
+/* This turned off for production... */
+/* #define DEBUG_SIGNALS 1 */
+
+/*
+ * The new signal frame, 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_frame {
+ struct sparc_stackf ss;
+ __siginfo_t info;
+ __siginfo_fpu_t * fpu_save;
+ unsigned int insns [2];
+ __siginfo_fpu_t fpu_state;
+};
+
+/* Align macros */
+#define NF_ALIGNEDSZ (((sizeof(struct new_signal_frame) + 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 _sigpause_common(unsigned int set, struct pt_regs *regs)
+{
+ unsigned int mask;
+
+#ifdef CONFIG_SPARC32_COMPAT
+ if (current->tss.flags & SPARC_FLAG_32BIT) {
+ extern asmlinkage void _sigpause32_common(unsigned int, struct pt_regs *);
+ _sigpause32_common(set, regs);
+ return;
+ }
+#endif
+ 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|TSTATE_XCARRY);
+ regs->u_regs[UREG_I0] = EINTR;
+ if (do_signal(mask, regs, 0, 0))
+ return;
+ }
+}
+
+asmlinkage void do_sigpause(unsigned int set, struct pt_regs *regs)
+{
+ _sigpause_common(set, regs);
+}
+
+asmlinkage void do_sigsuspend(struct pt_regs *regs)
+{
+ _sigpause_common(regs->u_regs[UREG_I0], regs);
+}
+
+
+static inline void
+restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_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) * 64));
+ __get_user(current->tss.fsr, &fpu->si_fsr);
+}
+
+void do_sigreturn(struct pt_regs *regs)
+{
+ struct new_signal_frame *sf;
+ unsigned long tpc, tnpc, tstate;
+ __siginfo_fpu_t *fpu_save;
+ int mask;
+
+#ifdef CONFIG_SPARC32_COMPAT
+ if (current->tss.flags & SPARC_FLAG_32BIT) {
+ extern asmlinkage void do_sigreturn32(struct pt_regs *);
+ do_sigreturn32(regs);
+ return;
+ }
+#endif
+ synchronize_user_stack ();
+ sf = (struct new_signal_frame *) 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(tpc, &sf->info.si_regs.tpc);
+ __get_user(tnpc, &sf->info.si_regs.tnpc);
+ if ((tpc | tnpc) & 3){
+ goto segv;
+ }
+ regs->tpc = tpc;
+ regs->tnpc = tnpc;
+
+ /* 2. Restore the state */
+ __get_user(regs->y, &sf->info.si_regs.y);
+ __get_user(tstate, &sf->info.si_regs.tstate);
+ copy_from_user(regs->u_regs, sf->info.si_regs.u_regs, sizeof(regs->u_regs));
+
+ /* User can only change condition codes and FPU enabling in %tstate. */
+ regs->tstate &= ~(TSTATE_ICC | TSTATE_PEF);
+ regs->tstate |= (tstate & (TSTATE_ICC | TSTATE_PEF));
+
+ __get_user(fpu_save, &sf->fpu_save);
+ if (fpu_save)
+ restore_fpu_state(regs, &sf->fpu_state);
+ __get_user(mask, &sf->info.si_mask);
+ current->blocked = mask & _BLOCKABLE;
+ 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) > 0x80000000000ULL - fplen)
+ return 1;
+ return 0;
+}
+
+static inline void
+save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
+{
+#ifdef __SMP__
+ if (current->flags & PF_USEDFPU) {
+ fpsave(&current->tss.float_regs[0], &current->tss.fsr);
+ regs->tstate &= ~(TSTATE_PEF);
+ current->flags &= ~(PF_USEDFPU);
+ }
+#else
+ if (current == last_task_used_math) {
+ fpsave((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) * 64));
+ __put_user(current->tss.fsr, &fpu->si_fsr);
+ current->used_math = 0;
+}
+
+static inline void
+new_setup_frame(struct sigaction *sa, struct pt_regs *regs,
+ int signo, unsigned long oldmask)
+{
+ struct new_signal_frame *sf;
+ int sigframe_size;
+ unsigned long tmp;
+ int i;
+
+ /* 1. Make sure everything is clean */
+ synchronize_user_stack();
+ sigframe_size = NF_ALIGNEDSZ;
+ if (!current->used_math)
+ sigframe_size -= sizeof(__siginfo_fpu_t);
+
+ sf = (struct new_signal_frame *)(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 */
+ copy_to_user(&sf->info.si_regs, regs, sizeof (*regs));
+
+ if (current->used_math) {
+ save_fpu_state(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_window)/8; i++) {
+ __get_user(tmp, (((u64 *)regs->u_regs[UREG_FP])+i));
+ __put_user(tmp, (((u64 *)sf)+i));
+ }
+
+ /* 3. return to kernel instructions */
+ __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */
+ __put_user(0x91d02011, &sf->insns[1]); /* t 0x11 */
+
+ /* 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])));
+
+}
+
+static inline void handle_signal(unsigned long signr, struct sigaction *sa,
+ unsigned long oldmask, struct pt_regs *regs)
+{
+ new_setup_frame(sa, 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_restart(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|TSTATE_XCARRY);
+ 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_signal(unsigned long oldmask, struct pt_regs * regs,
+ unsigned long orig_i0, int restart_syscall)
+{
+ unsigned long signr, mask = ~current->blocked;
+ struct sigaction *sa;
+
+#ifdef CONFIG_SPARC32_COMPAT
+ if (current->tss.flags & SPARC_FLAG_32BIT) {
+ extern asmlinkage int do_signal32(unsigned long, struct pt_regs *,
+ unsigned long, int);
+ return do_signal32(oldmask, regs, orig_i0, restart_syscall);
+ }
+#endif
+ 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_restart(orig_i0, regs, sa);
+ handle_signal(signr, sa, oldmask, regs);
+ 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;
+}
+
+asmlinkage int
+sys_sigstack(struct sigstack *ssptr, struct sigstack *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/signal32.c b/arch/sparc64/kernel/signal32.c
index e1129dfd6..d8e61511d 100644
--- a/arch/sparc64/kernel/signal32.c
+++ b/arch/sparc64/kernel/signal32.c
@@ -1,4 +1,4 @@
-/* $Id: signal32.c,v 1.6 1997/04/16 10:27:17 jj Exp $
+/* $Id: signal32.c,v 1.8 1997/05/18 08:42:15 davem Exp $
* arch/sparc64/kernel/signal32.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
@@ -30,8 +30,6 @@
#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);
@@ -117,17 +115,6 @@ asmlinkage void _sigpause32_common(unsigned int set, struct pt_regs *regs)
}
}
-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)
{
@@ -248,7 +235,9 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
{
struct signal_sframe32 *sframep;
struct sigcontext32 *sc;
+#if 0
int window = 0;
+#endif
int old_status = current->tss.sstk_info.cur_status;
unsigned psr;
int i;
@@ -424,7 +413,9 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
svr4_mcontext_t *mc;
svr4_gwindows_t *gw;
svr4_ucontext_t *uc;
+#if 0
int window = 0;
+#endif
unsigned psr;
int i;
diff --git a/arch/sparc64/kernel/sparcelf32.c b/arch/sparc64/kernel/sparcelf32.c
deleted file mode 100644
index 855c636e4..000000000
--- a/arch/sparc64/kernel/sparcelf32.c
+++ /dev/null
@@ -1,1281 +0,0 @@
-/* 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_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index e9911daed..147b60c34 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.9 1997/04/21 08:34:24 jj Exp $
+/* $Id: sys_sparc32.c,v 1.13 1997/05/18 04:16:44 davem Exp $
* sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -27,15 +27,19 @@
#include <linux/nfs_fs.h>
#include <linux/smb_fs.h>
#include <linux/ncp_fs.h>
+#include <linux/quota.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 */
+/* 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);
@@ -138,6 +142,10 @@ 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);
+extern asmlinkage int sys_listen(int fd, int backlog);
+extern asmlinkage int sys_socket(int family, int type, int protocol);
+extern asmlinkage int sys_socketpair(int family, int type, int protocol, int usockvec[2]);
+extern asmlinkage int sys_shutdown(int fd, int how);
asmlinkage int sys32_ioperm(u32 from, u32 num, int on)
{
@@ -157,6 +165,17 @@ struct ipc_perm32
unsigned short seq;
};
+struct semid_ds32 {
+ struct ipc_perm32 sem_perm; /* permissions .. see ipc.h */
+ __kernel_time_t32 sem_otime; /* last semop time */
+ __kernel_time_t32 sem_ctime; /* last change time */
+ u32 sem_base; /* ptr to first semaphore in array */
+ u32 sem_pending; /* pending operations to be processed */
+ u32 sem_pending_last; /* last pending operation */
+ u32 undo; /* undo requests on this array */
+ unsigned short sem_nsems; /* no. of semaphores in array */
+};
+
struct msqid_ds32
{
struct ipc_perm32 msg_perm;
@@ -212,15 +231,62 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u
err = sys_semget (first, second, third);
goto out;
case SEMCTL: {
- /* XXX union semun32 to union semun64 and back conversion */
union semun fourth;
+ void *pad;
+ unsigned long old_fs;
+ struct semid_ds s;
+
err = -EINVAL;
if (!ptr)
goto out;
err = -EFAULT;
- if(get_user(fourth.__pad, (void **)A(ptr)))
+ if(get_user(pad, (void **)A(ptr)))
goto out;
+ fourth.__pad = pad;
+ switch (third) {
+ case IPC_INFO:
+ case SEM_INFO:
+ case GETVAL:
+ case GETPID:
+ case GETNCNT:
+ case GETZCNT:
+ case GETALL:
+ case SETALL:
+ case IPC_RMID:
+ err = sys_semctl (first, second, third, fourth);
+ goto out;
+ case IPC_SET:
+ if (get_user (s.sem_perm.uid, &(((struct semid_ds32 *)A(pad))->sem_perm.uid)) ||
+ __get_user (s.sem_perm.gid, &(((struct semid_ds32 *)A(pad))->sem_perm.gid)) ||
+ __get_user (s.sem_perm.mode, &(((struct semid_ds32 *)A(pad))->sem_perm.mode))) {
+ err = -EFAULT;
+ goto out;
+ }
+ /* Fall through */
+ case SEM_STAT:
+ case IPC_STAT:
+ fourth.__pad = &s;
+ break;
+ }
+ old_fs = get_fs();
+ set_fs (KERNEL_DS);
err = sys_semctl (first, second, third, fourth);
+ set_fs (old_fs);
+ switch (third) {
+ case SEM_STAT:
+ case IPC_STAT:
+ if (put_user (s.sem_perm.key, &(((struct semid_ds32 *)A(pad))->sem_perm.key)) ||
+ __put_user (s.sem_perm.uid, &(((struct semid_ds32 *)A(pad))->sem_perm.uid)) ||
+ __put_user (s.sem_perm.gid, &(((struct semid_ds32 *)A(pad))->sem_perm.gid)) ||
+ __put_user (s.sem_perm.cuid, &(((struct semid_ds32 *)A(pad))->sem_perm.cuid)) ||
+ __put_user (s.sem_perm.cgid, &(((struct semid_ds32 *)A(pad))->sem_perm.cgid)) ||
+ __put_user (s.sem_perm.mode, &(((struct semid_ds32 *)A(pad))->sem_perm.mode)) ||
+ __put_user (s.sem_perm.seq, &(((struct semid_ds32 *)A(pad))->sem_perm.seq)) ||
+ __put_user (s.sem_otime, &(((struct semid_ds32 *)A(pad))->sem_otime)) ||
+ __put_user (s.sem_ctime, &(((struct semid_ds32 *)A(pad))->sem_ctime)) ||
+ __put_user (s.sem_nsems, &(((struct semid_ds32 *)A(pad))->sem_nsems)))
+ err = -EFAULT;
+ }
goto out;
}
default:
@@ -534,10 +600,50 @@ 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 :(( */
+struct dqblk32 {
+ __u32 dqb_bhardlimit;
+ __u32 dqb_bsoftlimit;
+ __u32 dqb_curblocks;
+ __u32 dqb_ihardlimit;
+ __u32 dqb_isoftlimit;
+ __u32 dqb_curinodes;
+ __kernel_time_t32 dqb_btime;
+ __kernel_time_t32 dqb_itime;
+};
+
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));
+ int cmds = cmd >> SUBCMDSHIFT;
+ int err;
+ struct dqblk d;
+ unsigned long old_fs;
+
+ switch (cmds) {
+ case Q_GETQUOTA:
+ break;
+ case Q_SETQUOTA:
+ case Q_SETUSE:
+ case Q_SETQLIM:
+ if (copy_from_user (&d, (struct dqblk32 *)A(addr), sizeof (struct dqblk32)))
+ return -EFAULT;
+ d.dqb_itime = ((struct dqblk32 *)&d)->dqb_itime;
+ d.dqb_btime = ((struct dqblk32 *)&d)->dqb_btime;
+ break;
+ default:
+ return sys_quotactl(cmd, (const char *)A(special), id, (caddr_t)A(addr));
+ }
+ old_fs = get_fs ();
+ set_fs (KERNEL_DS);
+ err = sys_quotactl(cmd, (const char *)A(special), id, (caddr_t)A(addr));
+ set_fs (old_fs);
+ if (cmds == Q_GETQUOTA) {
+ __kernel_time_t b = d.dqb_btime, i = d.dqb_itime;
+ ((struct dqblk32 *)&d)->dqb_itime = i;
+ ((struct dqblk32 *)&d)->dqb_btime = b;
+ if (copy_to_user ((struct dqblk32 *)A(addr), &d, sizeof (struct dqblk32)))
+ return -EFAULT;
+ }
+ return err;
}
static int put_statfs (u32 buf, struct statfs *s)
@@ -1599,20 +1705,224 @@ asmlinkage int sys32_getsockopt(int fd, int level, int optname, u32 optval, u32
return sys_getsockopt(fd, level, optname, (char *)A(optval), (int *)A(optlen));
}
-/* Continue here */
+struct msghdr32 {
+ u32 msg_name;
+ int msg_namelen;
+ u32 msg_iov;
+ __kernel_size_t32 msg_iovlen;
+ u32 msg_control;
+ __kernel_size_t32 msg_controllen;
+ unsigned msg_flags;
+};
+
+struct cmsghdr32 {
+ __kernel_size_t32 cmsg_len;
+ int cmsg_level;
+ int cmsg_type;
+ unsigned char cmsg_data[0];
+};
+
asmlinkage int sys32_sendmsg(int fd, u32 msg, unsigned flags)
{
- return sys_sendmsg(fd, (struct msghdr *)A(msg), flags);
+ struct msghdr m;
+ int count;
+ struct iovec *v;
+ struct iovec vf[UIO_FASTIOV];
+ u32 i, vector;
+ long ret;
+ unsigned long old_fs;
+
+ if (get_user ((long)m.msg_name, &(((struct msghdr32 *)A(msg))->msg_name)) ||
+ __get_user (m.msg_namelen, &(((struct msghdr32 *)A(msg))->msg_namelen)) ||
+ __get_user (vector, &(((struct msghdr32 *)A(msg))->msg_iov)) ||
+ __get_user (m.msg_iovlen, &(((struct msghdr32 *)A(msg))->msg_iovlen)) ||
+ __get_user ((long)m.msg_control, &(((struct msghdr32 *)A(msg))->msg_control)) ||
+ __get_user (m.msg_controllen, &(((struct msghdr32 *)A(msg))->msg_controllen)) ||
+ __get_user (m.msg_flags, &(((struct msghdr32 *)A(msg))->msg_flags)))
+ return -EFAULT;
+
+ count = m.msg_iovlen;
+ 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;
+ }
+ }
+
+ m.msg_iov = v;
+
+ if (m.msg_controllen) {
+ /* XXX Handle msg_control stuff... Or should that go into ip_sockglue.c etc.? */
+ }
+ old_fs = get_fs();
+ set_fs (KERNEL_DS);
+ ret = sys_sendmsg(fd, &m, flags);
+ set_fs (old_fs);
+out:
+ if (count > UIO_FASTIOV) {
+ kfree (v);
+ unlock_kernel ();
+ }
+ return ret;
}
asmlinkage int sys32_recvmsg(int fd, u32 msg, unsigned int flags)
{
- return sys_recvmsg(fd, (struct msghdr *)A(msg), flags);
+ struct msghdr m;
+ int count;
+ struct iovec *v;
+ struct iovec vf[UIO_FASTIOV];
+ u32 i, vector;
+ long ret;
+ unsigned long old_fs;
+
+ if (get_user ((long)m.msg_name, &(((struct msghdr32 *)A(msg))->msg_name)) ||
+ __get_user (m.msg_namelen, &(((struct msghdr32 *)A(msg))->msg_namelen)) ||
+ __get_user (vector, &(((struct msghdr32 *)A(msg))->msg_iov)) ||
+ __get_user (m.msg_iovlen, &(((struct msghdr32 *)A(msg))->msg_iovlen)) ||
+ __get_user ((long)m.msg_control, &(((struct msghdr32 *)A(msg))->msg_control)) ||
+ __get_user (m.msg_controllen, &(((struct msghdr32 *)A(msg))->msg_controllen)) ||
+ __get_user (m.msg_flags, &(((struct msghdr32 *)A(msg))->msg_flags)))
+ return -EFAULT;
+
+ count = m.msg_iovlen;
+ 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;
+ }
+ }
+
+ m.msg_iov = v;
+
+ if (m.msg_controllen) {
+ /* XXX Handle msg_control stuff... Or should that go into ip_sockglue.c etc.? */
+ }
+ old_fs = get_fs();
+ set_fs (KERNEL_DS);
+ ret = sys_recvmsg(fd, &m, flags);
+ set_fs (old_fs);
+ if (ret >= 0) {
+ /* XXX Handle msg_control stuff... */
+ if (put_user (m.msg_flags, &(((struct msghdr32 *)A(msg))->msg_flags)) ||
+ __put_user (m.msg_controllen, &(((struct msghdr32 *)A(msg))->msg_controllen)))
+ return -EFAULT;
+ }
+out:
+ if (count > UIO_FASTIOV) {
+ kfree (v);
+ unlock_kernel ();
+ }
+ return ret;
}
asmlinkage int sys32_socketcall(int call, u32 args)
{
- return sys_socketcall(call, (unsigned long *)A(args));
+ static unsigned char nargs[18]={0,3,3,3,2,3,3,3,
+ 4,4,4,6,6,2,5,5,3,3};
+ u32 a[6];
+ u32 a0,a1;
+ int err = -EINVAL;
+ int i;
+
+ lock_kernel();
+ if(call<1||call>SYS_RECVMSG)
+ goto out;
+ err = -EFAULT;
+
+ for (i = 0; i < nargs[call]; i++, args += sizeof (u32))
+ if (get_user(a[i], (u32 *)A(args)))
+ goto out;
+
+ a0=a[0];
+ a1=a[1];
+
+ switch(call)
+ {
+ case SYS_SOCKET:
+ err = sys_socket(a0, a1, a[2]);
+ break;
+ case SYS_BIND:
+ err = sys32_bind(a0, a1, a[2]);
+ break;
+ case SYS_CONNECT:
+ err = sys32_connect(a0, a1, a[2]);
+ break;
+ case SYS_LISTEN:
+ err = sys_listen(a0, a1);
+ break;
+ case SYS_ACCEPT:
+ err = sys32_accept(a0, a1, a[2]);
+ break;
+ case SYS_GETSOCKNAME:
+ err = sys32_getsockname(a0, a1, a[2]);
+ break;
+ case SYS_GETPEERNAME:
+ err = sys32_getpeername(a0, a1, a[2]);
+ break;
+ case SYS_SOCKETPAIR:
+ err = sys_socketpair(a0, a1, a[2], (int *)A(a[3]));
+ break;
+ case SYS_SEND:
+ err = sys32_send(a0, a1, a[2], a[3]);
+ break;
+ case SYS_SENDTO:
+ err = sys32_sendto(a0, a1, a[2], a[3], a[4], a[5]);
+ break;
+ case SYS_RECV:
+ err = sys32_recv(a0, a1, a[2], a[3]);
+ break;
+ case SYS_RECVFROM:
+ err = sys32_recvfrom(a0, a1, a[2], a[3], a[4], a[5]);
+ break;
+ case SYS_SHUTDOWN:
+ err = sys_shutdown(a0,a1);
+ break;
+ case SYS_SETSOCKOPT:
+ err = sys32_setsockopt(a0, a1, a[2], a[3], a[4]);
+ break;
+ case SYS_GETSOCKOPT:
+ err = sys32_getsockopt(a0, a1, a[2], a[3], a[4]);
+ break;
+ case SYS_SENDMSG:
+ err = sys32_sendmsg(a0, a1, a[2]);
+ break;
+ case SYS_RECVMSG:
+ err = sys32_recvmsg(a0, a1, a[2]);
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+out:
+ unlock_kernel();
+ return err;
}
extern void check_pending(int signum);
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index 48648c39d..c9774df06 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.5 1997/04/14 06:56:55 davem Exp $
+/* $Id: traps.c,v 1.10 1997/05/18 08:42:16 davem Exp $
* arch/sparc/kernel/traps.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -22,6 +22,7 @@
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/unistd.h>
+#include <asm/uaccess.h>
/* #define TRAP_DEBUG */
@@ -42,6 +43,8 @@ void syscall_trace_entry(struct pt_regs *regs)
void syscall_trace_exit(struct pt_regs *regs)
{
+ printk("Syscall return check, reg dump.\n");
+ show_regs(regs);
}
void sparc64_dtlb_fault_handler (void)
@@ -116,25 +119,45 @@ void die_if_kernel(char *str, struct pt_regs *regs)
show_regs(regs);
printk("Instruction DUMP:");
instruction_dump ((unsigned int *) regs->tpc);
+ while(1)
+ barrier();
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)
+void do_illegal_instruction(struct pt_regs *regs)
{
+ unsigned long pc = regs->tpc;
+ unsigned long tstate = regs->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);
+#if 1
+ {
+ unsigned int insn;
+
+ printk("Ill instr. at pc=%016lx ", pc);
+ get_user(insn, ((unsigned int *)pc));
+ printk("insn=[%08x]\n", insn);
+ }
#endif
current->tss.sig_address = pc;
current->tss.sig_desc = SUBSIG_ILLINST;
send_sig(SIGILL, current, 1);
unlock_kernel();
+
+ while(1)
+ barrier();
+}
+
+void do_mna(struct pt_regs *regs)
+{
+ printk("AIEEE: do_mna at %016lx\n", regs->tpc);
+ show_regs(regs);
+ while(1)
+ barrier();
}
void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S
index f22d85014..326382c3f 100644
--- a/arch/sparc64/kernel/ttable.S
+++ b/arch/sparc64/kernel/ttable.S
@@ -1,4 +1,4 @@
-/* $Id: ttable.S,v 1.11 1997/03/25 09:47:21 davem Exp $
+/* $Id: ttable.S,v 1.12 1997/05/17 08:22:30 davem Exp $
* ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -13,7 +13,7 @@ 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_ill: TRAP(do_illegal_instruction)
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)
@@ -226,27 +226,3 @@ 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
diff --git a/arch/sparc64/kernel/winfixup.S b/arch/sparc64/kernel/winfixup.S
new file mode 100644
index 000000000..a8293c453
--- /dev/null
+++ b/arch/sparc64/kernel/winfixup.S
@@ -0,0 +1,101 @@
+/* $Id: winfixup.S,v 1.3 1997/05/18 22:52:26 davem Exp $
+ *
+ * winfixup.S: Handle cases where user stack pointer is found to be bogus.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/asi.h>
+#include <asm/head.h>
+#include <asm/page.h>
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+#include <asm/asm_offsets.h>
+
+ .text
+ .align 32
+
+ /* Here are the rules, pay attention.
+ *
+ * The kernel is disallowed from touching user space while
+ * the trap level is greater than zero, except for from within
+ * the window spill/fill handlers. This must be followed
+ * so that we can easily detect the case where we tried to
+ * spill/fill with a bogus (or unmapped) user stack pointer.
+ *
+ * These are layed out in a special way for cache reasons,
+ * don't touch...
+ */
+ .globl winfix_trampoline, fill_fixup, spill_fixup
+fill_fixup:
+ ba,pt %xcc, etrap
+ rd %pc, %g7
+ mov %l5, %o4
+ mov %l4, %o5
+ srlx %l5, PAGE_SHIFT, %o3
+ clr %o1
+ sllx %o3, PAGE_SHIFT, %o3
+ and %l4, 0x4, %o2
+
+ call do_sparc64_fault
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ ba,a,pt %xcc, rtrap
+ nop
+winfix_trampoline:
+ andn %g5, 0x7f, %g5
+ add %g5, 0x7c, %g5
+ wrpr %g5, %tnpc
+ done
+
+spill_fixup:
+ rd %pic, %g1
+ ldx [%g1 + AOFF_task_tss + AOFF_thread_w_saved], %g2
+ sll %g2, 3, %g5
+ ldx [%g1 + AOFF_task_tss + AOFF_thread_flags], %g7
+ add %g1, %g5, %g5
+ andcc %g7, SPARC_FLAG_32BIT, %g0
+ stx %sp, [%g5 + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs]
+ sll %g2, 5, %g5
+
+ bne,pt %xcc, 1f
+ add %g1, %g5, %g5
+ stx %l0, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
+ stx %l1, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
+ stx %l2, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
+ stx %l3, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
+ stx %l4, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
+ stx %l5, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
+
+ stx %l6, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
+ stx %l7, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
+ stx %i0, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x40]
+ stx %i1, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x48]
+ stx %i2, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x50]
+ stx %i3, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x58]
+ stx %i4, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x60]
+ stx %i5, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x68]
+
+ stx %i6, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x70]
+ stx %i7, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x78]
+ b,a,pt %xcc, 2f
+ add %g2, 1, %g2
+1:
+ std %l0, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
+ std %l2, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
+ std %l4, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
+ std %l6, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
+
+ std %i0, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
+ std %i2, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
+ std %i4, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
+ std %i6, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
+ add %g2, 1, %g2
+2:
+ stx %g2, [%g1 + AOFF_task_tss + AOFF_thread_w_saved]
+ rdpr %tstate, %g1
+ nop
+
+ andcc %g1, TSTATE_PRIV, %g0
+ be,pn %xcc, fill_fixup
+ saved
+ retry
diff --git a/arch/sparc64/lib/blockops.S b/arch/sparc64/lib/blockops.S
index b3f06c18d..d0f023d1b 100644
--- a/arch/sparc64/lib/blockops.S
+++ b/arch/sparc64/lib/blockops.S
@@ -1,4 +1,4 @@
-/* $Id: blockops.S,v 1.5 1997/03/26 18:34:28 jj Exp $
+/* $Id: blockops.S,v 1.6 1997/05/18 04:16:49 davem Exp $
* arch/sparc64/lib/blockops.S: UltraSparc block zero optimized routines.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -31,37 +31,8 @@
.text
.align 4
- .globl bzero_2page, bzero_1page
-bzero_2page:
- /* %o0 = buf */
- mov %o0, %o1
- wr %g0, ASI_BLK_P, %asi
- mov 0x10, %g2
-
- membar #Sync|#StoreLoad
-
- fzero %f48
- fzero %f50
- fzero %f52
- fzero %f54
- fzero %f56
- fzero %f58
- fzero %f60
- fzero %f62
-1:
- BLAST_BLOCK(%o0, 0x000)
- BLAST_BLOCK(%o0, 0x100)
- BLAST_BLOCK(%o0, 0x200)
- BLAST_BLOCK(%o0, 0x300)
- subcc %g2, 1, %g2
- bne,pt %icc, 1b
- add %o0, 0x400, %o0
-
- membar #Sync|#LoadStore|#StoreStore
-
- retl
- mov %o1, %o0
-
+#if 0
+ .globl bzero_1page
bzero_1page:
/* %o0 = buf */
mov %o0, %o1
@@ -89,9 +60,36 @@ bzero_1page:
retl
mov %o1, %o0
+#endif
.globl __bfill64
__bfill64:
+#if 1
+ /* %o0 = buf, %o1 = 64-bit pattern */
+#define FILL_BLOCK(buf, offset) \
+ stx %o1, [buf + offset + 0x38]; \
+ stx %o1, [buf + offset + 0x30]; \
+ stx %o1, [buf + offset + 0x28]; \
+ stx %o1, [buf + offset + 0x20]; \
+ stx %o1, [buf + offset + 0x18]; \
+ stx %o1, [buf + offset + 0x10]; \
+ stx %o1, [buf + offset + 0x08]; \
+ stx %o1, [buf + offset + 0x00];
+
+ mov 0x20, %g2
+1:
+ FILL_BLOCK(%o0, 0x00)
+ FILL_BLOCK(%o0, 0x40)
+ FILL_BLOCK(%o0, 0x80)
+ FILL_BLOCK(%o0, 0xc0)
+ subcc %g2, 1, %g2
+ bne,pt %icc, 1b
+ add %o0, 0x100, %o0
+ retl
+ nop
+#undef FILL_BLOCK
+
+#else
/* %o0 = buf */
stx %o1, [%sp + 0x7ff + 128]
wr %g0, ASI_BLK_P, %asi
@@ -116,7 +114,9 @@ __bfill64:
retl
membar #Sync|#LoadStore|#StoreStore
+#endif
+#if 0
.globl __copy_1page
__copy_1page:
/* %o0 = dst, %o1 = src */
@@ -135,4 +135,4 @@ __copy_1page:
retl
membar #Sync|#LoadStore|#StoreStore
-
+#endif
diff --git a/arch/sparc64/lib/checksum.S b/arch/sparc64/lib/checksum.S
index 8a06003ee..b63f0d6e8 100644
--- a/arch/sparc64/lib/checksum.S
+++ b/arch/sparc64/lib/checksum.S
@@ -44,13 +44,13 @@
csum_partial_end_cruft:
andcc %o1, 8, %g0 ! check how much
be,pn %icc, 1f ! caller asks %o1 & 0x8
- and %o1, 4, %g3 ! nope, check for word remaining
+ and %o1, 4, %g5 ! nope, check for word remaining
ldd [%o0], %g2 ! load two
addcc %g2, %o2, %o2 ! add first word to sum
addccc %g3, %o2, %o2 ! add second word as well
add %o0, 8, %o0 ! advance buf ptr
addc %g0, %o2, %o2 ! add in final carry
-1: brz,pn %g3, 1f ! nope, skip this code
+1: brz,pn %g5, 1f ! nope, skip this code
andcc %o1, 3, %o1 ! check for trailing bytes
ld [%o0], %g2 ! load it
addcc %g2, %o2, %o2 ! add to sum
@@ -98,15 +98,17 @@ csum_partial: /* %o0=buf, %o1=len, %o2=sum */
srl %o2, 16, %g3
addc %g0, %g3, %g2
sll %o2, 16, %o2
+ and %o0, 0x4, %g7
sll %g2, 16, %g3
srl %o2, 16, %o2
or %g3, %o2, %o2
1: brz,pn %g7, csum_partial_fix_aligned
- nop
+ andn %o1, 0x7f, %o3
ld [%o0 + 0x00], %g2
sub %o1, 4, %o1
addcc %g2, %o2, %o2
add %o0, 4, %o0
+ andn %o1, 0x7f, %o3
addc %g0, %o2, %o2
csum_partial_fix_aligned:
brz,pt %o3, 3f ! none to do
@@ -115,9 +117,9 @@ csum_partial_fix_aligned:
CSUM_BIGCHUNK(%o0, 0x20, %o2, %o4, %o5, %g2, %g3, %g4, %g5)
CSUM_BIGCHUNK(%o0, 0x40, %o2, %o4, %o5, %g2, %g3, %g4, %g5)
CSUM_BIGCHUNK(%o0, 0x60, %o2, %o4, %o5, %g2, %g3, %g4, %g5)
- sub %o3, 128, %o3 ! detract from loop iters
addc %g0, %o2, %o2 ! sink in final carry
- brnz,pt %o3, 5b ! more to do
+ subcc %o3, 128, %o3 ! detract from loop iters
+ bne,pt %icc, 5b ! more to do
add %o0, 128, %o0 ! advance buf ptr
3: brz,pn %g1, cpte ! nope
andcc %o1, 0xf, %o3 ! anything left at all?
@@ -125,7 +127,7 @@ csum_partial_fix_aligned:
srl %g1, 1, %o4 ! compute offset
sub %g7, %g1, %g7 ! adjust jmp ptr
sub %g7, %o4, %g7 ! final jmp ptr adjust
- jmp %g7 + (cpte - 8 - 10b) ! enter the table
+ jmp %g7 + (11f-10b) ! enter the table
add %o0, %g1, %o0 ! advance buf ptr
cptbl: CSUM_LASTCHUNK(%o0, 0x68, %o2, %g2, %g3, %g4, %g5)
CSUM_LASTCHUNK(%o0, 0x58, %o2, %g2, %g3, %g4, %g5)
@@ -134,8 +136,8 @@ cptbl: CSUM_LASTCHUNK(%o0, 0x68, %o2, %g2, %g3, %g4, %g5)
CSUM_LASTCHUNK(%o0, 0x28, %o2, %g2, %g3, %g4, %g5)
CSUM_LASTCHUNK(%o0, 0x18, %o2, %g2, %g3, %g4, %g5)
CSUM_LASTCHUNK(%o0, 0x08, %o2, %g2, %g3, %g4, %g5)
- addc %g0, %o2, %o2 ! fetch final carry
- andcc %o1, 0xf, %g0 ! anything left at all?
+11: addc %g0, %o2, %o2 ! fetch final carry
+ andcc %o1, 0xf, %o3 ! anything left at all?
cpte: brnz,pn %o3, csum_partial_end_cruft ! yep, handle it
sethi %uhi(KERNBASE), %g4
mov %o2, %o0 ! return computed csum
@@ -322,13 +324,14 @@ __csum_partial_copy_sparc_generic:
andcc %o0, 0x4, %g0
or %g3, %g7, %g7
1: be,pt %icc, 3f
- andn %g1, 0x7f, %g0
+ andn %g1, 0x7f, %g2
EX(ld [%o0 + 0x00], %g4, add %g1, 0,#)
sub %g1, 4, %g1
EX2(st %g4, [%o1 + 0x00],#)
add %o0, 4, %o0
addcc %g4, %g7, %g7
add %o1, 4, %o1
+ andn %g1, 0x7f, %g2
addc %g0, %g7, %g7
cc_dword_aligned:
3: brz,pn %g2, 3f ! nope, less than one loop remains
@@ -365,7 +368,7 @@ cctbl: CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x68,%g2,%g3,%g4,%g5)
CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x08,%g2,%g3,%g4,%g5)
12: EXT(cctbl, 12b, 22f,#) ! note for exception table handling
addc %g0, %g7, %g7
- andcc %o3, 0xf, %g0 ! check for low bits set
+ andcc %g1, 0xf, %o3 ! check for low bits set
ccte: bne,pn %icc, cc_end_cruft ! something left, handle it out of band
sethi %uhi(KERNBASE), %g4 ! restore gfp
mov %g7, %o0 ! give em the computed checksum
@@ -555,7 +558,7 @@ __csum_partial_copy_end:
add %i1, %i2, %i1
2:
mov %i1, %o0
- wr %%g0, ASI_S, %%asi
+ wr %g0, ASI_S, %asi
call __bzero_noasi
mov %i3, %o1
1:
diff --git a/arch/sparc64/lib/copy_from_user.S b/arch/sparc64/lib/copy_from_user.S
index ba26a1c01..50ec7bb3d 100644
--- a/arch/sparc64/lib/copy_from_user.S
+++ b/arch/sparc64/lib/copy_from_user.S
@@ -15,12 +15,16 @@
#include <asm/ptrace.h>
#include <asm/asi.h>
+#include <asm/head.h>
+
+#define PRE_RETL sethi %uhi(KERNBASE), %g4; sllx %g4, 32, %g4;
#define EX(x,y,a,b,z) \
98: x,y; \
.section .fixup,z##alloc,z##execinstr; \
.align 4; \
-99: retl; \
+99: PRE_RETL \
+ retl; \
a, b, %o0; \
.section __ex_table,z##alloc; \
.align 4; \
@@ -33,6 +37,7 @@
.section .fixup,z##alloc,z##execinstr; \
.align 4; \
99: c, d, e; \
+ PRE_RETL \
retl; \
a, b, %o0; \
.section __ex_table,z##alloc; \
@@ -234,6 +239,7 @@ copy_user_last7:
EX(lduba [%o1] %asi, %g2, add %g0, 1,#)
stb %g2, [%o0]
1:
+ PRE_RETL
retl
clr %o0
@@ -332,6 +338,7 @@ short_table_end:
EX(lduba [%o1] %asi, %g2, add %g0, 1,#)
stb %g2, [%o0]
1:
+ PRE_RETL
retl
clr %o0
@@ -355,6 +362,7 @@ short_aligned_end:
.section .fixup,#alloc,#execinstr
.align 4
97:
+ PRE_RETL
retl
mov %o2, %o0
/* exception routine sets %g2 to (broken_insn - first_insn)>>2 */
@@ -388,6 +396,7 @@ short_aligned_end:
1:
and %g1, 0x7f, %o0
add %o0, %g7, %o0
+ PRE_RETL
retl
sub %o0, %g2, %o0
51:
@@ -413,6 +422,7 @@ short_aligned_end:
3:
sll %g2, 2, %g2
2:
+ PRE_RETL
retl
add %g1, %g2, %o0
52:
@@ -431,6 +441,7 @@ short_aligned_end:
add %g2, %g4, %g2
and %o2, 0xf, %o0
add %o0, %o3, %o0
+ PRE_RETL
retl
sub %o0, %g2, %o0
54:
@@ -441,6 +452,7 @@ short_aligned_end:
and %o2, 0xf, %o2
sub %o3, %o1, %o3
sub %o2, %o4, %o2
+ PRE_RETL
retl
add %o2, %o3, %o0
55:
@@ -452,5 +464,6 @@ short_aligned_end:
and %g2, 1, %g2
sll %o1, 1, %o1
add %o2, %g2, %o0
+ PRE_RETL
retl
add %o0, %o1, %o0
diff --git a/arch/sparc64/lib/copy_to_user.S b/arch/sparc64/lib/copy_to_user.S
index 47a6bd337..733953743 100644
--- a/arch/sparc64/lib/copy_to_user.S
+++ b/arch/sparc64/lib/copy_to_user.S
@@ -14,13 +14,17 @@
*/
#include <asm/ptrace.h>
+#include <asm/head.h>
#include <asm/asi.h>
+#define PRE_RETL sethi %uhi(KERNBASE), %g4; sllx %g4, 32, %g4;
+
#define EX(x,y,a,b,z) \
98: x,y; \
.section .fixup,z##alloc,z##execinstr; \
.align 4; \
-99: retl; \
+99: PRE_RETL \
+ retl; \
a, b, %o0; \
.section __ex_table,z##alloc; \
.align 4; \
@@ -33,6 +37,7 @@
.section .fixup,z##alloc,z##execinstr; \
.align 4; \
99: c, d, e; \
+ PRE_RETL \
retl; \
a, b, %o0; \
.section __ex_table,z##alloc; \
@@ -234,6 +239,7 @@ copy_user_last7:
ldub [%o1], %g2
EX(stba %g2, [%o0] %asi, add %g0, 1,#)
1:
+ PRE_RETL
retl
clr %o0
@@ -332,6 +338,7 @@ short_table_end:
ldub [%o1], %g2
EX(stba %g2, [%o0] %asi, add %g0, 1,#)
1:
+ PRE_RETL
retl
clr %o0
@@ -355,6 +362,7 @@ short_aligned_end:
.section .fixup,#alloc,#execinstr
.align 4
97:
+ PRE_RETL
retl
mov %o2, %o0
/* exception routine sets %g2 to (broken_insn - first_insn)>>2 */
@@ -388,6 +396,7 @@ short_aligned_end:
1:
and %g1, 0x7f, %o0
add %o0, %g7, %o0
+ PRE_RETL
retl
sub %o0, %g2, %o0
51:
@@ -413,6 +422,7 @@ short_aligned_end:
3:
sll %g2, 2, %g2
2:
+ PRE_RETL
retl
add %g1, %g2, %o0
52:
@@ -431,6 +441,7 @@ short_aligned_end:
add %g2, %g4, %g2
and %o2, 0xf, %o0
add %o0, %o3, %o0
+ PRE_RETL
retl
sub %o0, %g2, %o0
54:
@@ -441,6 +452,7 @@ short_aligned_end:
and %o2, 0xf, %o2
sub %o3, %o1, %o3
sub %o2, %o4, %o2
+ PRE_RETL
retl
add %o2, %o3, %o0
55:
@@ -452,5 +464,6 @@ short_aligned_end:
and %g2, 1, %g2
sll %o1, 1, %o1
add %o2, %g2, %o0
+ PRE_RETL
retl
add %o0, %o1, %o0
diff --git a/arch/sparc64/lib/strlen_user.S b/arch/sparc64/lib/strlen_user.S
index 24bea73fd..30beee3ff 100644
--- a/arch/sparc64/lib/strlen_user.S
+++ b/arch/sparc64/lib/strlen_user.S
@@ -8,6 +8,8 @@
* Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
+#include <asm/asi.h>
+
#define LO_MAGIC 0x01010101
#define HI_MAGIC 0x80808080
@@ -19,21 +21,21 @@ __strlen_user:
be,pt %icc, 9f
sethi %hi(HI_MAGIC), %o4
10:
- ldub [%o0], %o5
+ lduba [%o0] ASI_S, %o5
brz,pn %o5, 21f
add %o0, 1, %o0
andcc %o0, 3, %g0
be,pn %icc, 4f
or %o4, %lo(HI_MAGIC), %o3
11:
- ldub [%o0], %o5
+ lduba [%o0] ASI_S, %o5
brz,pn %o5, 22f
add %o0, 1, %o0
andcc %o0, 3, %g0
be,pt %icc, 5f
sethi %hi(LO_MAGIC), %o4
12:
- ldub [%o0], %o5
+ lduba [%o0] ASI_S, %o5
brz,pn %o5, 23f
add %o0, 1, %o0
ba,pt %icc, 13f
@@ -45,7 +47,7 @@ __strlen_user:
5:
or %o4, %lo(LO_MAGIC), %o2
13:
- ld [%o0], %o5
+ lda [%o0] ASI_S, %o5
2:
sub %o5, %o2, %o4
andcc %o4, %o3, %g0
@@ -68,7 +70,7 @@ __strlen_user:
andcc %o5, 0xff, %g0
bne,a,pt %icc, 2b
14:
- ld [%o0], %o5
+ lda [%o0] ASI_S, %o5
add %o4, 1, %o4
1:
retl
diff --git a/arch/sparc64/lib/strncpy_from_user.S b/arch/sparc64/lib/strncpy_from_user.S
index 05a48eb5a..e0fb0f09b 100644
--- a/arch/sparc64/lib/strncpy_from_user.S
+++ b/arch/sparc64/lib/strncpy_from_user.S
@@ -24,14 +24,14 @@ __strncpy_from_user:
sub %g0, %o2, %o3
add %o0, %o2, %o0
10:
- ldub [%o1 + %o3], %o4
+ lduba [%o1 + %o3] ASI_S, %o4
1:
brz,pn %o4, 2f
stb %o4, [%o0 + %o3]
addcc %o3, 1, %o3
bne,pt %xcc, 1b
11:
- ldub [%o1 + %o3], %o4
+ lduba [%o1 + %o3] ASI_S, %o4
retl
mov %o2, %o0
2:
diff --git a/arch/sparc64/mm/asyncd.c b/arch/sparc64/mm/asyncd.c
index 4e7de16fb..0272b09c2 100644
--- a/arch/sparc64/mm/asyncd.c
+++ b/arch/sparc64/mm/asyncd.c
@@ -1,4 +1,4 @@
-/* $Id: asyncd.c,v 1.1 1996/12/26 10:24:24 davem Exp $
+/* $Id: asyncd.c,v 1.2 1997/05/15 21:14:32 davem Exp $
* The asyncd kernel daemon. This handles paging on behalf of
* processes that receive page faults due to remote (async) memory
* accesses.
@@ -153,7 +153,7 @@ static int fault_in_page(int taskid,
if(!pte)
goto no_memory;
if(!pte_present(*pte)) {
- do_no_page(tsk, vma, address, write);
+ handle_mm_fault(tsk, vma, address, write);
goto finish_up;
}
set_pte(pte, pte_mkyoung(*pte));
@@ -165,12 +165,11 @@ static int fault_in_page(int taskid,
flush_tlb_page(vma, address);
goto finish_up;
}
- do_wp_page(tsk, vma, address, write);
+ handle_mm_fault(tsk, vma, address, write);
/* Fall through for do_wp_page */
finish_up:
stats.success++;
- update_mmu_cache(vma, address, *pte);
return 0;
no_memory:
diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c
index 0dd118c8e..dc28ac339 100644
--- a/arch/sparc64/mm/fault.c
+++ b/arch/sparc64/mm/fault.c
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.4 1997/03/11 17:37:07 jj Exp $
+/* $Id: fault.c,v 1.8 1997/05/18 04:16:52 davem Exp $
* arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -134,8 +134,11 @@ asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc,
return 0;
}
+/* #define FAULT_TRACER */
+
asmlinkage void do_sparc64_fault(struct pt_regs *regs, int text_fault, int write,
- unsigned long address)
+ unsigned long address, unsigned long tag,
+ unsigned long sfsr)
{
struct vm_area_struct *vma;
struct task_struct *tsk = current;
@@ -143,7 +146,19 @@ asmlinkage void do_sparc64_fault(struct pt_regs *regs, int text_fault, int write
unsigned long fixup;
unsigned long g2;
int from_user = !(regs->tstate & TSTATE_PRIV);
-
+#ifdef FAULT_TRACER
+ static unsigned long last_addr = 0;
+ static int rcnt = 0;
+
+ printk("do_sparc64_fault(PC[%016lx],t[%d],w[%d],addr[%016lx]tag[%016lx]"
+ "sfar[%016lx])\n", regs->tpc, text_fault, write, address, tag, sfsr);
+ if(address == last_addr && rcnt++ > 5) {
+ printk("Wheee lotsa bogus faults, something wrong, spinning\n");
+ while(1)
+ barrier();
+ }
+ last_addr = address;
+#endif
lock_kernel ();
down(&mm->mmap_sem);
vma = find_vma(mm, address);
@@ -168,7 +183,7 @@ good_area:
if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
goto bad_area;
}
- handle_mm_fault(vma, address, write);
+ handle_mm_fault(current, vma, address, write);
up(&mm->mmap_sem);
goto out;
/*
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index 57ca5eb92..cf378a266 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.24 1997/04/17 21:49:41 jj Exp $
+/* $Id: init.c,v 1.28 1997/05/18 04:16:53 davem Exp $
* arch/sparc64/mm/init.c
*
* Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -457,16 +457,18 @@ void sparc_ultra_unmapioaddr(unsigned long virt_addr)
pte_clear(ptep);
}
-#ifdef DEBUG_MMU
void sparc_ultra_dump_itlb(void)
{
int slot;
- prom_printf ("Contents of itlb:\n");
- for (slot = 0; slot < 64; slot+=2) {
- prom_printf ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
+ printk ("Contents of itlb: ");
+ for (slot = 0; slot < 14; slot++) printk (" ");
+ printk ("%2x:%016lx,%016lx\n", 0, spitfire_get_itlb_tag(0), spitfire_get_itlb_data(0));
+ for (slot = 1; slot < 64; slot+=3) {
+ printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx %2x:%016lx,%016lx\n",
slot, spitfire_get_itlb_tag(slot), spitfire_get_itlb_data(slot),
- slot+1, spitfire_get_itlb_tag(slot+1), spitfire_get_itlb_data(slot+1));
+ slot+1, spitfire_get_itlb_tag(slot+1), spitfire_get_itlb_data(slot+1),
+ slot+2, spitfire_get_itlb_tag(slot+2), spitfire_get_itlb_data(slot+2));
}
}
@@ -474,14 +476,16 @@ void sparc_ultra_dump_dtlb(void)
{
int slot;
- prom_printf ("Contents of dtlb:\n");
- for (slot = 0; slot < 64; slot+=2) {
- prom_printf ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
+ printk ("Contents of dtlb: ");
+ for (slot = 0; slot < 14; slot++) printk (" ");
+ printk ("%2x:%016lx,%016lx\n", 0, spitfire_get_dtlb_tag(0), spitfire_get_dtlb_data(0));
+ for (slot = 1; slot < 64; slot+=3) {
+ printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx %2x:%016lx,%016lx\n",
slot, spitfire_get_dtlb_tag(slot), spitfire_get_dtlb_data(slot),
- slot+1, spitfire_get_dtlb_tag(slot+1), spitfire_get_dtlb_data(slot+1));
+ slot+1, spitfire_get_dtlb_tag(slot+1), spitfire_get_dtlb_data(slot+1),
+ slot+2, spitfire_get_dtlb_tag(slot+2), spitfire_get_dtlb_data(slot+2));
}
}
-#endif
/* paging_init() sets up the page tables */
@@ -643,7 +647,7 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
high_memory = (void *) end_mem;
start_mem = PAGE_ALIGN(start_mem);
- num_physpages = (start_mem - phys_base - PAGE_OFFSET) >> PAGE_SHIFT;
+ num_physpages = (start_mem - PAGE_OFFSET) >> PAGE_SHIFT;
addr = PAGE_OFFSET;
while(addr < start_mem) {
@@ -694,6 +698,11 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
min_free_pages = 16;
free_pages_low = min_free_pages + (min_free_pages >> 1);
free_pages_high = min_free_pages + min_free_pages;
+
+#if 0
+ printk("Testing fault handling...\n");
+ *(char *)0x00000deadbef0000UL = 0;
+#endif
}
void free_initmem (void)
@@ -702,9 +711,14 @@ void free_initmem (void)
addr = (unsigned long)(&__init_begin);
for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
- mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
- atomic_set(&mem_map[MAP_NR(addr)].count, 1);
- free_page(addr);
+ unsigned long page = addr;
+
+ if(page < ((unsigned long)__va(phys_base)))
+ page += phys_base;
+
+ mem_map[MAP_NR(page)].flags &= ~(1 << PG_reserved);
+ atomic_set(&mem_map[MAP_NR(page)].count, 1);
+ free_page(page);
}
}