diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-06-01 03:16:17 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1997-06-01 03:16:17 +0000 |
commit | d8d9b8f76f22b7a16a83e261e64f89ee611f49df (patch) | |
tree | 3067bc130b80d52808e6390c9fc7fc087ec1e33c /arch/sparc64 | |
parent | 19c9bba94152148523ba0f7ef7cffe3d45656b11 (diff) |
Initial revision
Diffstat (limited to 'arch/sparc64')
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 = ¤t->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 = ¤t->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(¤t->sigmask_lock); + mask = current->blocked; + current->blocked = set & _BLOCKABLE; + spin_unlock_irq(¤t->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(¤t->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(¤t->tss.float_regs[0], ¤t->tss.fsr); + regs->tstate &= ~(TSTATE_PEF); + current->flags &= ~(PF_USEDFPU); + } +#else + if (current == last_task_used_math) { + fpsave((unsigned long *)¤t->tss.float_regs[0], ¤t->tss.fsr); + last_task_used_math = 0; + regs->tstate &= ~(TSTATE_PEF); + } +#endif + copy_to_user(&fpu->si_float_regs[0], ¤t->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, ¤t->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(¬es[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(¬es[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); } } |