diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-03-17 22:05:47 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-03-17 22:05:47 +0000 |
commit | 27cfca1ec98e91261b1a5355d10a8996464b63af (patch) | |
tree | 8e895a53e372fa682b4c0a585b9377d67ed70d0e /arch/sparc64/kernel | |
parent | 6a76fb7214c477ccf6582bd79c5b4ccc4f9c41b1 (diff) |
Look Ma' what I found on my harddisk ...
o New faster syscalls for 2.1.x, too
o Upgrade to 2.1.89.
Don't try to run this. It's flaky as hell. But feel free to debug ...
Diffstat (limited to 'arch/sparc64/kernel')
28 files changed, 3484 insertions, 1638 deletions
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile index 2b07a0e15..7889c84a4 100644 --- a/arch/sparc64/kernel/Makefile +++ b/arch/sparc64/kernel/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.34 1997/08/12 04:12:36 ecd Exp $ +# $Id: Makefile,v 1.35 1997/09/20 21:48:58 davem Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also @@ -71,8 +71,8 @@ check_asm: dummy @rm -f tmp.[ci] #$(CC) -o check_asm check_asm.c # <hack> Until we can do this natively, a hack has to take place - $(CC) -mmedlow -S -o check_asm.s check_asm.c - $(HOSTCC) -o check_asm check_asm.s + $(CC) -mmedlow -ffixed-g4 -S -o check_asm.s check_asm.c + $(HOSTCC) -Wa,-Av9a -o check_asm check_asm.s @rm -f check_asm.s # </hack> ./check_asm > asm_offsets.h diff --git a/arch/sparc64/kernel/binfmt_aout32.c b/arch/sparc64/kernel/binfmt_aout32.c index 98066a321..55ccbc203 100644 --- a/arch/sparc64/kernel/binfmt_aout32.c +++ b/arch/sparc64/kernel/binfmt_aout32.c @@ -57,11 +57,12 @@ static void set_brk(unsigned long start, unsigned long end) * macros to write out all the necessary info. */ #define DUMP_WRITE(addr,nr) \ -while (file.f_op->write(inode,&file,(char *)(addr),(nr)) != (nr)) goto close_coredump +while (file.f_op->write(&file,(char *)(addr),(nr),&file.f_pos) != (nr)) \ + goto close_coredump #define DUMP_SEEK(offset) \ if (file.f_op->llseek) { \ - if (file.f_op->llseek(inode,&file,(offset),0) != (offset)) \ + if (file.f_op->llseek(&file,(offset),0) != (offset)) \ goto close_coredump; \ } else file.f_pos = (offset) @@ -81,7 +82,7 @@ do_aout32_core_dump(long signr, struct pt_regs * regs) struct dentry * dentry = NULL; struct inode * inode = NULL; struct file file; - unsigned short fs; + mm_segment_t fs; int has_dumped = 0; char corefile[6+sizeof(current->comm)]; unsigned long dump_start, dump_size; @@ -256,7 +257,7 @@ static inline int do_load_aout32_binary(struct linux_binprm * bprm, unsigned long p = bprm->p; unsigned long fd_offset; unsigned long rlim; - int retval; +int retval; ex = *((struct exec *) bprm->buf); /* exec-header */ if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC && @@ -285,8 +286,6 @@ static inline int do_load_aout32_binary(struct linux_binprm * bprm, return retval; /* OK, This is the point of no return */ - memcpy(¤t->tss.core_exec, &ex, sizeof(struct exec)); - current->mm->end_code = ex.a_text + (current->mm->start_code = N_TXTADDR(ex)); current->mm->end_data = ex.a_data + @@ -420,13 +419,13 @@ do_load_aout32_library(int fd) /* Seek into the file */ if (file->f_op->llseek) { - if ((error = file->f_op->llseek(inode, file, 0, 0)) != 0) + if ((error = file->f_op->llseek(file, 0, 0)) != 0) return -ENOEXEC; } else file->f_pos = 0; set_fs(KERNEL_DS); - error = file->f_op->read(inode, file, (char *) &ex, sizeof(ex)); + error = file->f_op->read(file, (char *) &ex, sizeof(ex), &file->f_pos); set_fs(USER_DS); if (error != sizeof(ex)) return -ENOEXEC; diff --git a/arch/sparc64/kernel/dtlb_miss.S b/arch/sparc64/kernel/dtlb_miss.S index 04efb1cec..4d71d967c 100644 --- a/arch/sparc64/kernel/dtlb_miss.S +++ b/arch/sparc64/kernel/dtlb_miss.S @@ -1,4 +1,4 @@ -/* $Id: dtlb_miss.S,v 1.13 1997/08/14 19:27:15 davem Exp $ +/* $Id: dtlb_miss.S,v 1.14 1997/10/14 01:48:28 davem Exp $ * dtlb_miss.S: Data TLB miss code, this is included directly * into the trap table. * @@ -53,10 +53,10 @@ /*0x24*/ srlx %g1, 1, %g1 ! PTE offset 2:/*0x28*/ ldxa [%g5 + %g4] ASI_PHYS_USE_EC, %g3 ! Load PMD /*0x2c*/ ldxa [%g3 + %g1] ASI_PHYS_USE_EC, %g5 ! Load PTE - /*0x30*/ brlz,a,pt %g5, 1f ! Valid set? - /*0x34*/ stxa %g5, [%g0] ASI_DTLB_DATA_IN ! TLB load - /*0x38*/ ba,a,pt %xcc, sparc64_dtlb_refbit_catch ! Nope... -1:/*0x3c*/ retry ! Trap return + /*0x30*/ brgez,pn %g5, sparc64_dtlb_refbit_catch ! Valid set? + /*0x34*/ nop ! delay + /*0x38*/ stxa %g5, [%g0] ASI_DTLB_DATA_IN ! TLB load + /*0x3c*/ retry ! Trap return 3: /* ICACHE line 3 */ /*0x40*/ sllx %g1, 22, %g5 ! This is now physical page + PAGE_OFFSET diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c index f484cfef8..02faf4e3c 100644 --- a/arch/sparc64/kernel/ebus.c +++ b/arch/sparc64/kernel/ebus.c @@ -1,4 +1,4 @@ -/* $Id: ebus.c,v 1.8 1997/09/05 22:59:39 ecd Exp $ +/* $Id: ebus.c,v 1.17 1998/01/10 18:26:13 ecd Exp $ * ebus.c: PCI to EBus bridge device. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -17,8 +17,15 @@ #include <asm/oplib.h> #include <asm/bpp.h> +#undef PROM_DEBUG #undef DEBUG_FILL_EBUS_DEV +#ifdef PROM_DEBUG +#define dprintf prom_printf +#else +#define dprintf printk +#endif + struct linux_ebus *ebus_chain = 0; extern void prom_ebus_ranges_init(struct linux_ebus *); @@ -36,8 +43,12 @@ extern int sparcaudio_init(void); #ifdef CONFIG_SUN_AUXIO extern void auxio_probe(void); #endif +#ifdef CONFIG_OBP_FLASH +extern int flash_init(void); +#endif -extern unsigned int psycho_irq_build(unsigned int full_ino); +extern unsigned int psycho_irq_build(struct linux_pbm_info *pbm, + unsigned int full_ino); static inline unsigned long ebus_alloc(unsigned long *memory_start, size_t size) @@ -47,6 +58,7 @@ ebus_alloc(unsigned long *memory_start, size_t size) *memory_start = (*memory_start + 7) & ~(7); mem = *memory_start; *memory_start += size; + memset((void *)mem, 0, size); return mem; } @@ -79,19 +91,19 @@ __initfunc(void fill_ebus_child(int node, struct linux_ebus_child *dev)) } else { dev->num_irqs = len / sizeof(irqs[0]); for (i = 0; i < dev->num_irqs; i++) - dev->irqs[i] = psycho_irq_build(irqs[i]); + dev->irqs[i] = psycho_irq_build(dev->bus->parent, irqs[i]); } #ifdef DEBUG_FILL_EBUS_DEV - printk("child '%s': address%s\n", dev->prom_name, + dprintf("child '%s': address%s\n", dev->prom_name, dev->num_addrs > 1 ? "es" : ""); for (i = 0; i < dev->num_addrs; i++) - printk(" %016lx\n", dev->base_address[i]); + dprintf(" %016lx\n", dev->base_address[i]); if (dev->num_irqs) { - printk(" IRQ%s", dev->num_irqs > 1 ? "s" : ""); + dprintf(" IRQ%s", dev->num_irqs > 1 ? "s" : ""); for (i = 0; i < dev->num_irqs; i++) - printk(" %08x", dev->irqs[i]); - printk("\n"); + dprintf(" %08x", dev->irqs[i]); + dprintf("\n"); } #endif } @@ -121,7 +133,7 @@ __initfunc(unsigned long fill_ebus_device(int node, struct linux_ebus_device *de for (i = 0; i < dev->num_addrs; i++) { n = (regs[i].which_io - 0x10) >> 2; - dev->base_address[i] = dev->parent->self->base_address[n]; + dev->base_address[i] = dev->bus->self->base_address[n]; dev->base_address[i] += (unsigned long)regs[i].phys_addr; } @@ -131,19 +143,19 @@ __initfunc(unsigned long fill_ebus_device(int node, struct linux_ebus_device *de } else { dev->num_irqs = len / sizeof(irqs[0]); for (i = 0; i < dev->num_irqs; i++) - dev->irqs[i] = psycho_irq_build(irqs[i]); + dev->irqs[i] = psycho_irq_build(dev->bus->parent, irqs[i]); } #ifdef DEBUG_FILL_EBUS_DEV - printk("'%s': address%s\n", dev->prom_name, + dprintf("'%s': address%s\n", dev->prom_name, dev->num_addrs > 1 ? "es" : ""); for (i = 0; i < dev->num_addrs; i++) - printk(" %016lx\n", dev->base_address[i]); + dprintf(" %016lx\n", dev->base_address[i]); if (dev->num_irqs) { - printk(" IRQ%s", dev->num_irqs > 1 ? "s" : ""); + dprintf(" IRQ%s", dev->num_irqs > 1 ? "s" : ""); for (i = 0; i < dev->num_irqs; i++) - printk(" %08x", dev->irqs[i]); - printk("\n"); + dprintf(" %08x", dev->irqs[i]); + dprintf("\n"); } #endif if ((node = prom_getchild(node))) { @@ -153,6 +165,7 @@ __initfunc(unsigned long fill_ebus_device(int node, struct linux_ebus_device *de child = dev->children; child->next = 0; child->parent = dev; + child->bus = dev->bus; fill_ebus_child(node, child); while ((node = prom_getsibling(node))) { @@ -162,6 +175,7 @@ __initfunc(unsigned long fill_ebus_device(int node, struct linux_ebus_device *de child = child->next; child->next = 0; child->parent = dev; + child->bus = dev->bus; fill_ebus_child(node, child); } } @@ -195,6 +209,9 @@ __initfunc(unsigned long ebus_init(unsigned long memory_start, } if (!pdev) { printk("ebus: No EBus's found.\n"); +#ifdef PROM_DEBUG + dprintf("ebus: No EBus's found.\n"); +#endif return memory_start; } @@ -206,7 +223,10 @@ __initfunc(unsigned long ebus_init(unsigned long memory_start, ebus->next = 0; while (ebusnd) { - printk("ebus%d:\n", num_ebus); + printk("ebus%d:", num_ebus); +#ifdef PROM_DEBUG + dprintf("ebus%d:", num_ebus); +#endif prom_getstring(ebusnd, "name", lbuf, sizeof(lbuf)); ebus->prom_node = ebusnd; @@ -250,20 +270,34 @@ __initfunc(unsigned long ebus_init(unsigned long memory_start, addr += (u64)rp->parent_phys_hi << 32UL; *base++ = (unsigned long)__va(addr); + printk(" %lx[%x]", (unsigned long)__va(addr), + regs[reg].size_lo); +#ifdef PROM_DEBUG + dprintf(" %lx[%x]", (unsigned long)__va(addr), + regs[reg].size_lo); +#endif break; } } + printk("\n"); +#ifdef PROM_DEBUG + dprintf("\n"); +#endif prom_ebus_ranges_init(ebus); nd = prom_getchild(ebusnd); + if (!nd) + goto next_ebus; + ebus->devices = (struct linux_ebus_device *) - ebus_alloc(&memory_start, sizeof(struct linux_ebus_device)); + ebus_alloc(&memory_start, + sizeof(struct linux_ebus_device)); dev = ebus->devices; dev->next = 0; dev->children = 0; - dev->parent = ebus; + dev->bus = ebus; memory_start = fill_ebus_device(nd, dev, memory_start); while ((nd = prom_getsibling(nd))) { @@ -273,10 +307,11 @@ __initfunc(unsigned long ebus_init(unsigned long memory_start, dev = dev->next; dev->next = 0; dev->children = 0; - dev->parent = ebus; + dev->bus = ebus; memory_start = fill_ebus_device(nd, dev, memory_start); } + next_ebus: for (pdev = pdev->next; pdev; pdev = pdev->next) { if ((pdev->vendor == PCI_VENDOR_ID_SUN) && (pdev->device == PCI_DEVICE_ID_SUN_EBUS)) @@ -313,6 +348,9 @@ __initfunc(unsigned long ebus_init(unsigned long memory_start, if (sparc_cpu_model == sun4u) auxio_probe(); #endif +#ifdef CONFIG_OBP_FLASH + flash_init(); +#endif #ifdef __sparc_v9__ if (sparc_cpu_model == sun4u) { extern void sun4u_start_timers(void); diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index a6e2d6da7..76f913ade 100644 --- a/arch/sparc64/kernel/entry.S +++ b/arch/sparc64/kernel/entry.S @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.65 1997/08/29 15:51:29 jj Exp $ +/* $Id: entry.S,v 1.76 1998/01/05 17:00:13 jj Exp $ * arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points. * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) @@ -121,7 +121,7 @@ sparc64_itlb_refbit_catch: .align 32 .globl do_fpdis do_fpdis: - ldx [%g6 + AOFF_task_tss + AOFF_thread_flags], %g5 ! Load Group + lduh [%g6 + AOFF_task_tss + AOFF_thread_flags], %g5 ! Load Group sethi %hi(TSTATE_PEF), %g4 ! IEU0 sethi %hi(FPDIS_OFF), %g3 ! IEU1 wr %g0, FPRS_FEF, %fprs ! LSU Group+4bubbles @@ -337,9 +337,28 @@ setcc: retl stx %o1, [%o0 + PT_V9_TSTATE] + .globl utrap, utrap_ill +utrap: brz,pn %g1, etrap + nop + save %sp, -128, %sp + rdpr %tstate, %l6 + rdpr %cwp, %l7 + andn %l6, TSTATE_CWP, %l6 + wrpr %l6, %l7, %tstate + rdpr %tpc, %l6 + rdpr %tnpc, %l7 + wrpr %g1, 0, %tnpc + done +utrap_ill: + call bad_trap + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + ba,pt %xcc, rtrap + clr %l6 + #ifdef CONFIG_BLK_DEV_FD .globl floppy_hardint floppy_hardint: + wr %g0, (1 << 11), %clear_softint sethi %hi(doing_pdma), %g1 ld [%g1 + %lo(doing_pdma)], %g2 brz,pn %g2, floppy_dosoftint @@ -404,8 +423,9 @@ floppy_fifo_emptied: sethi %hi(irq_action), %g1 or %g1, %lo(irq_action), %g1 ldx [%g1 + (11 << 3)], %g3 ! irqaction[floppy_irq] - ldx [%g3 + 0x10], %g4 ! action->mask - st %g0, [%g4] ! SYSIO_ICLR_IDLE + ldx [%g3 + 0x10], %g4 ! action->mask == ino_bucket ptr + ldx [%g4 + 0x18], %g4 ! bucket->iclr + stw %g0, [%g4] ! SYSIO_ICLR_IDLE membar #Sync ! probably not needed... retry @@ -446,14 +466,52 @@ do_mna: cmp %g3, 1 bgu,a,pn %icc, winfix_mna rdpr %tpc, %g3 + mov DMMU_SFAR, %g4 + mov TLB_SFSR, %g5 sethi %hi(109f), %g7 + ldxa [%g4] ASI_DMMU, %g4 + ldxa [%g5] ASI_DMMU, %g5 ba,pt %xcc, etrap 109: or %g7, %lo(109b), %g7 + mov %l4, %o1 + mov %l5, %o2 call mem_address_unaligned add %sp, STACK_BIAS + REGWIN_SZ, %o0 ba,pt %xcc, rtrap clr %l6 + .globl do_lddfmna +do_lddfmna: + mov DMMU_SFAR, %g4 + mov TLB_SFSR, %g5 + sethi %hi(109f), %g7 + ldxa [%g4] ASI_DMMU, %g4 + ldxa [%g5] ASI_DMMU, %g5 + ba,pt %xcc, etrap +109: or %g7, %lo(109b), %g7 + mov %l4, %o1 + mov %l5, %o2 + call handle_lddfmna + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + ba,pt %xcc, rtrap + clr %l6 + + .globl do_stdfmna +do_stdfmna: + mov DMMU_SFAR, %g4 + mov TLB_SFSR, %g5 + sethi %hi(109f), %g7 + ldxa [%g4] ASI_DMMU, %g4 + ldxa [%g5] ASI_DMMU, %g5 + ba,pt %xcc, etrap +109: or %g7, %lo(109b), %g7 + mov %l4, %o1 + mov %l5, %o2 + call handle_stdfmna + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + ba,pt %xcc, rtrap + clr %l6 + .globl breakpoint_trap breakpoint_trap: call sparc_breakpoint @@ -471,13 +529,13 @@ sunos_indir: mov %o7, %l4 cmp %o0, NR_SYSCALLS blu,a,pt %icc, 1f - sll %o0, 0x3, %o0 + sll %o0, 0x2, %o0 sethi %hi(sunos_nosys), %l6 b,pt %xcc, 2f or %l6, %lo(sunos_nosys), %l6 1: sethi %hi(sunos_sys_table), %l7 or %l7, %lo(sunos_sys_table), %l7 - ldx [%l7 + %o0], %l6 + lduw [%l7 + %o0], %l6 2: mov %o1, %o0 mov %o2, %o1 mov %o3, %o2 @@ -526,7 +584,9 @@ sunos_execv: add %sp, STACK_BIAS + REGWIN_SZ, %o0 .globl sys_pipe, sys_execve, sys_sigpause, sys_nis_syscall - .globl sys_sigsuspend, sys_sigreturn + .globl sys_sigsuspend, sys_rt_sigsuspend, sys32_rt_sigsuspend + .globl sys_sigreturn, sys_rt_sigreturn + .globl sys32_sigreturn, sys32_rt_sigreturn .globl sys32_execve, sys_ptrace .align 32 sys_pipe: sethi %hi(sparc_pipe), %g1 @@ -546,42 +606,57 @@ sys32_execve: sethi %hi(sparc32_execve), %g1 add %sp, STACK_BIAS + REGWIN_SZ, %o0 jmpl %g1 + %lo(sparc32_execve), %g0 nop - - /* NOTE: %o0 has a correct value already */ -sys_sigpause: call do_sigpause - add %sp, STACK_BIAS + REGWIN_SZ, %o1 - ldx [%curptr + AOFF_task_flags], %l5 - andcc %l5, 0x20, %g0 - be,pt %icc, rtrap - clr %l6 - call syscall_trace +sys_memory_ordering: + sethi %hi(sparc_memory_ordering), %g1 + add %sp, STACK_BIAS + REGWIN_SZ, %o1 + jmpl %g1 + %lo(sparc_memory_ordering), %g0 nop - ba,pt %xcc, rtrap - clr %l6 -linux_sparc_ni_syscall: - sethi %hi(sys_ni_syscall), %l7 - b,pt %xcc,syscall_is_too_hard - or %l7, %lo(sys_ni_syscall), %l7 - nop - .align 32 -sys_sigsuspend: call do_sigsuspend - add %sp, STACK_BIAS + REGWIN_SZ, %o0 - ldx [%curptr + AOFF_task_flags], %l5 - andcc %l5, 0x20, %g0 - be,pt %icc, rtrap - clr %l6 - call syscall_trace - nop - - ba,pt %xcc, rtrap - clr %l6 - +sys_sigsuspend: add %sp, STACK_BIAS + REGWIN_SZ, %o0 + call do_sigsuspend + add %o7, 1f-.-4, %o7 + nop +sys_rt_sigsuspend: /* NOTE: %o0,%o1 have a correct value already */ + add %sp, STACK_BIAS + REGWIN_SZ, %o2 + call do_rt_sigsuspend + add %o7, 1f-.-4, %o7 + nop +sys32_rt_sigsuspend: /* NOTE: %o0,%o1 have a correct value already */ + srl %o0, 0, %o0 + add %sp, STACK_BIAS + REGWIN_SZ, %o2 + call do_rt_sigsuspend32 + add %o7, 1f-.-4, %o7 + /* NOTE: %o0 has a correct value already */ +sys_sigpause: add %sp, STACK_BIAS + REGWIN_SZ, %o1 + call do_sigpause + add %o7, 1f-.-4, %o7 + nop +sys_sigreturn: add %sp, STACK_BIAS + REGWIN_SZ, %o0 + call do_sigreturn + add %o7, 1f-.-4, %o7 + nop +sys32_sigreturn: + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + call do_sigreturn32 + add %o7, 1f-.-4, %o7 + nop +sys_rt_sigreturn: + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + call do_rt_sigreturn + add %o7, 1f-.-4, %o7 + nop +sys32_rt_sigreturn: + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + call do_rt_sigreturn32 + add %o7, 1f-.-4, %o7 + nop +sys_ptrace: add %sp, STACK_BIAS + REGWIN_SZ, %o0 + call do_ptrace + add %o7, 1f-.-4, %o7 + nop .align 32 -sys_sigreturn: call do_sigreturn - add %sp, STACK_BIAS + REGWIN_SZ, %o0 - ldx [%curptr + AOFF_task_flags], %l5 +1: ldx [%curptr + AOFF_task_flags], %l5 andcc %l5, 0x20, %g0 be,pt %icc, rtrap clr %l6 @@ -591,19 +666,6 @@ sys_sigreturn: call do_sigreturn ba,pt %xcc, rtrap clr %l6 - .align 32 -sys_ptrace: call do_ptrace - add %sp, STACK_BIAS + REGWIN_SZ, %o0 - ldx [%curptr + AOFF_task_flags], %l5 - andcc %l5, 0x20, %g0 - be,pt %icc, rtrap - clr %l6 - call syscall_trace - nop - - ba,pt %xcc, rtrap - clr %l6 - /* This is how fork() was meant to be done, 12 instruction entry. * * I questioned the following code briefly, let me clear things @@ -648,42 +710,94 @@ ret_from_syscall: b,pt %xcc, ret_sys_call ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0 +linux_sparc_ni_syscall: + sethi %hi(sys_ni_syscall), %l7 + b,pt %xcc, 4f + or %l7, %lo(sys_ni_syscall), %l7 + +linux_syscall_trace32: + call syscall_trace + nop + srl %i0, 0, %o0 + mov %i4, %o4 + srl %i1, 0, %o1 + srl %i2, 0, %o2 + b,pt %xcc, 2f + srl %i3, 0, %o3 + linux_syscall_trace: - call syscall_trace - nop - mov %i0, %o0 - mov %i1, %o1 - mov %i2, %o2 - mov %i3, %o3 - b,pt %xcc, 2f - mov %i4, %o4 + call syscall_trace + nop + mov %i0, %o0 + mov %i1, %o1 + mov %i2, %o2 + mov %i3, %o3 + b,pt %xcc, 2f + mov %i4, %o4 + + + /* Linux 32-bit and SunOS system calls enter here... */ + .align 32 + .globl linux_sparc_syscall32 +linux_sparc_syscall32: + /* Direct access to user regs, must faster. */ + cmp %g1, NR_SYSCALLS ! IEU1 Group + bgeu,pn %xcc, linux_sparc_ni_syscall ! CTI + srl %i0, 0, %o0 ! IEU0 + sll %g1, 2, %l4 ! IEU0 Group +#ifdef SYSCALL_TRACING + add %sp, STACK_BIAS + REGWIN_SZ, %o1 + call syscall_trace_entry + mov %g1, %o0 + srl %i0, 0, %o0 +#endif + mov %i4, %o4 ! IEU1 + lduw [%l7 + %l4], %l7 ! Load + srl %i1, 0, %o1 ! IEU0 Group + ldx [%curptr + AOFF_task_flags], %l0 ! Load + + mov %i5, %o5 ! IEU1 + srl %i2, 0, %o2 ! IEU0 Group + mov %i0, %l5 ! IEU1 + andcc %l0, 0x20, %g0 ! IEU1 Group + bne,pn %icc, linux_syscall_trace32 ! CTI + srl %i3, 0, %o3 ! IEU0 + call %l7 ! CTI Group brk forced + add %o7, 3f-.-4, %o7 ! IEU0 /* Linux native and SunOS system calls enter here... */ .align 32 - .globl linux_sparc_syscall, syscall_is_too_hard, ret_sys_call + .globl linux_sparc_syscall, ret_sys_call linux_sparc_syscall: /* Direct access to user regs, must faster. */ cmp %g1, NR_SYSCALLS ! IEU1 Group bgeu,pn %xcc, linux_sparc_ni_syscall ! CTI mov %i0, %o0 ! IEU0 sll %g1, 2, %l4 ! IEU0 Group +#ifdef SYSCALL_TRACING + add %sp, STACK_BIAS + REGWIN_SZ, %o1 + call syscall_trace_entry + mov %g1, %o0 + mov %i0, %o0 +#endif mov %i1, %o1 ! IEU1 lduw [%l7 + %l4], %l7 ! Load -syscall_is_too_hard: - mov %i2, %o2 ! IEU0 Group - ldx [%curptr + AOFF_task_flags], %l5 ! Load +4: mov %i2, %o2 ! IEU0 Group + ldx [%curptr + AOFF_task_flags], %l0 ! Load - st %g0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_FPRS] mov %i3, %o3 ! IEU1 mov %i4, %o4 ! IEU0 Group - andcc %l5, 0x20, %g0 ! IEU1 2 bubbles + andcc %l0, 0x20, %g0 ! IEU1 Group+1 bubble bne,pn %icc, linux_syscall_trace ! CTI Group mov %i0, %l5 ! IEU0 2: call %l7 ! CTI Group brk forced mov %i5, %o5 ! IEU0 - stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] - +3: stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] ret_sys_call: +#ifdef SYSCALL_TRACING + call syscall_trace_exit + add %sp, STACK_BIAS + REGWIN_SZ, %o1 +#endif ldx [%curptr + AOFF_task_flags], %l6 sra %o0, 0, %o0 mov %ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2 diff --git a/arch/sparc64/kernel/etrap.S b/arch/sparc64/kernel/etrap.S index e10480454..9e7c9e374 100644 --- a/arch/sparc64/kernel/etrap.S +++ b/arch/sparc64/kernel/etrap.S @@ -1,4 +1,4 @@ -/* $Id: etrap.S,v 1.37 1997/08/21 09:13:18 davem Exp $ +/* $Id: etrap.S,v 1.39 1997/10/24 11:57:47 jj Exp $ * etrap.S: Preparing for entry into the kernel on Sparc V9. * * Copyright (C) 1996, 1997 David S. Miller (davem@caip.rutgers.edu) @@ -79,11 +79,11 @@ etrap_irq: rdpr %tstate, %g1 ! Single Group andcc %l0, FPRS_FEF, %g0 ! IEU1 Group be,pn %icc, 6f ! CTI st %l0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_FPRS] ! Store - ld [%g6 + AOFF_task_tss + AOFF_thread_flags], %l4 ! Load Group + lduh [%g6 + AOFF_task_tss + AOFF_thread_flags], %l4 ! Load Group stx %fsr, [%sp + FPU_OFF + 0x100] ! Single Group or %l4, %l0, %l4 ! IEU0 Group ba,pt %xcc, 3f ! CTI - st %l4, [%g6 + AOFF_task_tss + AOFF_thread_flags] ! Store + sth %l4, [%g6 + AOFF_task_tss + AOFF_thread_flags] ! Store 2: rd %fprs, %l0 ! Single Group+4bubbles andcc %l0, FPRS_FEF, %g0 ! IEU1 Group be,pn %icc, 6f ! CTI @@ -107,7 +107,7 @@ etrap_irq: rdpr %tstate, %g1 ! Single Group 5: membar #Sync ! Memory 6: wr %g0, 0x0, %fprs ! Single Group+4bubbles wrpr %g0, 0x0, %tl ! Single Group+4bubbles - mov %g1, %l1 ! IEU0 Group + andn %g1, PSTATE_MM, %l1 ! IEU0 Group mov %g4, %l4 ! IEU1 mov %g5, %l5 ! IEU0 Group mov %g7, %l2 ! IEU1 diff --git a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c index af88ca4b6..64465663d 100644 --- a/arch/sparc64/kernel/ioctl32.c +++ b/arch/sparc64/kernel/ioctl32.c @@ -1,4 +1,4 @@ -/* $Id: ioctl32.c,v 1.18 1997/09/06 02:25:13 davem Exp $ +/* $Id: ioctl32.c,v 1.26 1997/12/15 15:11:02 jj Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -19,11 +19,19 @@ #include <linux/md.h> #include <linux/kd.h> #include <linux/route.h> +#include <linux/skbuff.h> #include <linux/netlink.h> #include <linux/vt.h> #include <linux/fs.h> #include <linux/fd.h> #include <linux/if_ppp.h> +#include <linux/mtio.h> + +#include <scsi/scsi.h> +/* Ugly hack. */ +#undef __KERNEL__ +#include <scsi/scsi_ioctl.h> +#define __KERNEL__ #include <asm/types.h> #include <asm/uaccess.h> @@ -44,7 +52,7 @@ extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long static int w_long(unsigned int fd, unsigned int cmd, u32 arg) { - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); int err; unsigned long val; @@ -97,16 +105,24 @@ static inline int dev_ifconf(unsigned int fd, u32 arg) struct ifconf ifc; struct ifreq32 *ifr32; struct ifreq *ifr; - unsigned long old_fs; + mm_segment_t old_fs; unsigned int i, j; int err; if (copy_from_user(&ifc32, (struct ifconf32 *)A(arg), sizeof(struct ifconf32))) return -EFAULT; - ifc.ifc_len = ((ifc32.ifc_len / sizeof (struct ifreq32)) + 1) * sizeof (struct ifreq); - ifc.ifc_buf = kmalloc (ifc.ifc_len, GFP_KERNEL); - if (!ifc.ifc_buf) return -ENOMEM; + if(ifc32.ifcbuf == 0) { + ifc32.ifc_len = 0; + ifc.ifc_len = 0; + ifc.ifc_buf = NULL; + } else { + ifc.ifc_len = ((ifc32.ifc_len / sizeof (struct ifreq32)) + 1) * + sizeof (struct ifreq); + ifc.ifc_buf = kmalloc (ifc.ifc_len, GFP_KERNEL); + if (!ifc.ifc_buf) + return -ENOMEM; + } ifr = ifc.ifc_req; ifr32 = (struct ifreq32 *)A(ifc32.ifcbuf); for (i = 0; i < ifc32.ifc_len; i += sizeof (struct ifreq32)) { @@ -137,14 +153,15 @@ static inline int dev_ifconf(unsigned int fd, u32 arg) err = -EFAULT; } } - kfree (ifc.ifc_buf); + if(ifc.ifc_buf != NULL) + kfree (ifc.ifc_buf); return err; } static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, u32 arg) { struct ifreq ifr; - unsigned long old_fs; + mm_segment_t old_fs; int err; switch (cmd) { @@ -183,7 +200,7 @@ static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, u32 arg) case SIOCGIFMTU: case SIOCGIFMEM: case SIOCGIFHWADDR: - case SIOGIFINDEX: + case SIOCGIFINDEX: case SIOCGIFADDR: case SIOCGIFBRDADDR: case SIOCGIFDSTADDR: @@ -250,16 +267,10 @@ static inline int routing_ioctl(unsigned int fd, unsigned int cmd, u32 arg) char devname[16]; u32 rtdev; int ret; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); - if (get_user (r.rt_pad1, &(((struct rtentry32 *)A(arg))->rt_pad1)) || - copy_from_user (&r.rt_dst, &(((struct rtentry32 *)A(arg))->rt_dst), 3 * sizeof(struct sockaddr)) || + if (copy_from_user (&r.rt_dst, &(((struct rtentry32 *)A(arg))->rt_dst), 3 * sizeof(struct sockaddr)) || __get_user (r.rt_flags, &(((struct rtentry32 *)A(arg))->rt_flags)) || - __get_user (r.rt_pad2, &(((struct rtentry32 *)A(arg))->rt_pad2)) || - __get_user (r.rt_pad3, &(((struct rtentry32 *)A(arg))->rt_pad3)) || - __get_user (r.rt_tos, &(((struct rtentry32 *)A(arg))->rt_tos)) || - __get_user (r.rt_class, &(((struct rtentry32 *)A(arg))->rt_class)) || - __get_user (r.rt_pad4, &(((struct rtentry32 *)A(arg))->rt_pad4)) || __get_user (r.rt_metric, &(((struct rtentry32 *)A(arg))->rt_metric)) || __get_user (r.rt_mtu, &(((struct rtentry32 *)A(arg))->rt_mtu)) || __get_user (r.rt_window, &(((struct rtentry32 *)A(arg))->rt_window)) || @@ -277,116 +288,6 @@ static inline int routing_ioctl(unsigned int fd, unsigned int cmd, u32 arg) return ret; } -struct nlmsghdr32 { - u32 nlmsg_len; /* Length of message including header */ - u32 nlmsg_type; /* Message type */ - u32 nlmsg_seq; /* Sequence number */ - u32 nlmsg_pid; /* Sending process PID */ - unsigned char nlmsg_data[0]; -}; - -struct in_rtmsg32 { - struct in_addr rtmsg_prefix; - struct in_addr rtmsg_gateway; - unsigned rtmsg_flags; - u32 rtmsg_mtu; - u32 rtmsg_window; - unsigned short rtmsg_rtt; - short rtmsg_metric; - unsigned char rtmsg_tos; - unsigned char rtmsg_class; - unsigned char rtmsg_prefixlen; - unsigned char rtmsg_reserved; - int rtmsg_ifindex; -}; - -struct in_ifmsg32 { - struct sockaddr ifmsg_lladdr; - struct in_addr ifmsg_prefix; - struct in_addr ifmsg_brd; - unsigned ifmsg_flags; - u32 ifmsg_mtu; - short ifmsg_metric; - unsigned char ifmsg_prefixlen; - unsigned char ifmsg_reserved; - int ifmsg_index; - char ifmsg_name[16]; -}; - -static inline int rtmsg_ioctl(unsigned int fd, u32 arg) -{ - struct { - struct nlmsghdr n; - union { - struct in_rtmsg rt; - struct in_ifmsg iff; - struct in_rtctlmsg ctl; - struct in_rtrulemsg rule; - } u; - } nn; - char *p; - int ret; - unsigned long old_fs = get_fs(); - - if (get_user (nn.n.nlmsg_len, &(((struct nlmsghdr32 *)A(arg))->nlmsg_len)) || - __get_user (nn.n.nlmsg_type, &(((struct nlmsghdr32 *)A(arg))->nlmsg_type)) || - __get_user (nn.n.nlmsg_seq, &(((struct nlmsghdr32 *)A(arg))->nlmsg_seq)) || - __get_user (nn.n.nlmsg_pid, &(((struct nlmsghdr32 *)A(arg))->nlmsg_pid)) || - __get_user (nn.n.nlmsg_data[0], &(((struct nlmsghdr32 *)A(arg))->nlmsg_data[0]))) - return -EFAULT; - p = ((char *)(&nn.n)) + sizeof(struct nlmsghdr); - arg += sizeof(struct nlmsghdr32); - switch (nn.n.nlmsg_type) { - case RTMSG_NEWRULE: - case RTMSG_DELRULE: - if (nn.n.nlmsg_len < sizeof(struct nlmsghdr32) + sizeof(struct in_rtrulemsg) - - sizeof(struct in_rtmsg) + sizeof(struct in_rtmsg32)) - return -EINVAL; - if (copy_from_user (p, (struct in_rtrulemsg *)A(arg), sizeof(struct in_rtrulemsg) - sizeof(struct in_rtmsg))) - return -EFAULT; - nn.n.nlmsg_len = sizeof(struct nlmsghdr) + sizeof(struct in_rtrulemsg); - p += sizeof (struct in_rtrulemsg) - sizeof(struct in_rtmsg); - arg += sizeof (struct in_rtrulemsg) - sizeof(struct in_rtmsg); - goto newroute; - case RTMSG_NEWROUTE: - case RTMSG_DELROUTE: - if (nn.n.nlmsg_len < sizeof(struct nlmsghdr32) + sizeof(struct in_rtmsg)) - return -EINVAL; - nn.n.nlmsg_len = sizeof(struct nlmsghdr) + sizeof(struct in_rtmsg); -newroute: - if (copy_from_user (p, (struct in_rtmsg32 *)A(arg), 2*sizeof(struct in_addr) + sizeof(unsigned)) || - __get_user (((struct in_rtmsg *)p)->rtmsg_mtu, &((struct in_rtmsg32 *)A(arg))->rtmsg_mtu) || - __get_user (((struct in_rtmsg *)p)->rtmsg_window, &((struct in_rtmsg32 *)A(arg))->rtmsg_window) || - copy_from_user (&(((struct in_rtmsg *)p)->rtmsg_rtt), &((struct in_rtmsg32 *)A(arg))->rtmsg_rtt, - 2 * sizeof(short) + 4 + sizeof(int))) - return -EFAULT; - break; - case RTMSG_NEWDEVICE: - case RTMSG_DELDEVICE: - if (nn.n.nlmsg_len < sizeof(struct nlmsghdr32) + sizeof(struct in_ifmsg)) - return -EINVAL; - nn.n.nlmsg_len = sizeof(struct nlmsghdr) + sizeof(struct in_ifmsg); - if (copy_from_user (p, (struct in_ifmsg32 *)A(arg), - sizeof(struct sockaddr) + 2*sizeof(struct in_addr) + sizeof(unsigned)) || - __get_user (((struct in_ifmsg *)p)->ifmsg_mtu, &((struct in_ifmsg32 *)A(arg))->ifmsg_mtu) || - copy_from_user (&(((struct in_ifmsg *)p)->ifmsg_metric), &((struct in_ifmsg32 *)A(arg))->ifmsg_metric, - sizeof(short) + 2 + sizeof(int) + 16)) - return -EFAULT; - break; - case RTMSG_CONTROL: - if (nn.n.nlmsg_len < sizeof(struct nlmsghdr32) + sizeof(struct in_rtctlmsg)) - return -EINVAL; - nn.n.nlmsg_len = sizeof(struct nlmsghdr) + sizeof(struct in_rtctlmsg); - if (copy_from_user (p, (struct in_rtctlmsg *)A(arg), sizeof(struct in_rtctlmsg))) - return -EFAULT; - break; - } - set_fs (KERNEL_DS); - ret = sys_ioctl (fd, SIOCRTMSG, (long)&(nn.n)); - set_fs (old_fs); - return ret; -} - struct hd_geometry32 { unsigned char heads; unsigned char sectors; @@ -396,7 +297,7 @@ struct hd_geometry32 { static inline int hdio_getgeo(unsigned int fd, u32 arg) { - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); struct hd_geometry geo; int err; @@ -428,7 +329,7 @@ static inline int fbiogetputcmap(unsigned int fd, unsigned int cmd, u32 arg) int ret; char red[256], green[256], blue[256]; u32 r, g, b; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); if (get_user(f.index, &(((struct fbcmap32 *)A(arg))->index)) || __get_user(f.count, &(((struct fbcmap32 *)A(arg))->count)) || @@ -480,7 +381,7 @@ static inline int fbiogscursor(unsigned int fd, unsigned int cmd, u32 arg) char image[128], mask[128]; u32 r, g, b; u32 m, i; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); if (copy_from_user (&f, (struct fbcursor32 *)A(arg), 2 * sizeof (short) + 2 * sizeof(struct fbcurpos)) || __get_user(f.size.fbx, &(((struct fbcursor32 *)A(arg))->size.fbx)) || @@ -516,7 +417,7 @@ static inline int fbiogscursor(unsigned int fd, unsigned int cmd, u32 arg) static int hdio_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) { - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); unsigned long kval; unsigned int *uvp; int error; @@ -533,6 +434,328 @@ static int hdio_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) return error; } +struct floppy_struct32 { + unsigned int size; + unsigned int sect; + unsigned int head; + unsigned int track; + unsigned int stretch; + unsigned char gap; + unsigned char rate; + unsigned char spec1; + unsigned char fmt_gap; + const __kernel_caddr_t32 name; +}; + +struct floppy_drive_params32 { + char cmos; + u32 max_dtr; + u32 hlt; + u32 hut; + u32 srt; + u32 spinup; + u32 spindown; + unsigned char spindown_offset; + unsigned char select_delay; + unsigned char rps; + unsigned char tracks; + u32 timeout; + unsigned char interleave_sect; + struct floppy_max_errors max_errors; + char flags; + char read_track; + short autodetect[8]; + int checkfreq; + int native_format; +}; + +struct floppy_drive_struct32 { + signed char flags; + u32 spinup_date; + u32 select_date; + u32 first_read_date; + short probed_format; + short track; + short maxblock; + short maxtrack; + int generation; + int keep_data; + int fd_ref; + int fd_device; + int last_checked; + __kernel_caddr_t32 dmabuf; + int bufblocks; +}; + +struct floppy_fdc_state32 { + int spec1; + int spec2; + int dtr; + unsigned char version; + unsigned char dor; + u32 address; + unsigned int rawcmd:2; + unsigned int reset:1; + unsigned int need_configure:1; + unsigned int perp_mode:2; + unsigned int has_fifo:1; + unsigned int driver_version; + unsigned char track[4]; +}; + +struct floppy_write_errors32 { + unsigned int write_errors; + u32 first_error_sector; + int first_error_generation; + u32 last_error_sector; + int last_error_generation; + unsigned int badness; +}; + +#define FDSETPRM32 _IOW(2, 0x42, struct floppy_struct32) +#define FDDEFPRM32 _IOW(2, 0x43, struct floppy_struct32) +#define FDGETPRM32 _IOR(2, 0x04, struct floppy_struct32) +#define FDSETDRVPRM32 _IOW(2, 0x90, struct floppy_drive_params32) +#define FDGETDRVPRM32 _IOR(2, 0x11, struct floppy_drive_params32) +#define FDGETDRVSTAT32 _IOR(2, 0x12, struct floppy_drive_struct32) +#define FDPOLLDRVSTAT32 _IOR(2, 0x13, struct floppy_drive_struct32) +#define FDGETFDCSTAT32 _IOR(2, 0x15, struct floppy_fdc_state32) +#define FDWERRORGET32 _IOR(2, 0x17, struct floppy_write_errors32) + +static struct { + unsigned int cmd32; + unsigned int cmd; +} fd_ioctl_trans_table[] = { + { FDSETPRM32, FDSETPRM }, + { FDDEFPRM32, FDDEFPRM }, + { FDGETPRM32, FDGETPRM }, + { FDSETDRVPRM32, FDSETDRVPRM }, + { FDGETDRVPRM32, FDGETDRVPRM }, + { FDGETDRVSTAT32, FDGETDRVSTAT }, + { FDPOLLDRVSTAT32, FDPOLLDRVSTAT }, + { FDGETFDCSTAT32, FDGETFDCSTAT }, + { FDWERRORGET32, FDWERRORGET } +}; + +#define NR_FD_IOCTL_TRANS (sizeof(fd_ioctl_trans_table)/sizeof(fd_ioctl_trans_table[0])) + +static int fd_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) +{ + mm_segment_t old_fs = get_fs(); + void *karg; + unsigned int kcmd = 0; + int i, err; + + for (i = 0; i < NR_FD_IOCTL_TRANS; i++) + if (cmd == fd_ioctl_trans_table[i].cmd32) { + kcmd = fd_ioctl_trans_table[i].cmd; + break; + } + if (!kcmd) + return -EINVAL; + + switch (cmd) { + case FDSETPRM32: + case FDDEFPRM32: + case FDGETPRM32: + { + struct floppy_struct *f; + + f = karg = kmalloc(GFP_KERNEL, sizeof(struct floppy_struct)); + if (!karg) + return -ENOMEM; + if (cmd == FDGETPRM32) + break; + if (__get_user(f->size, &((struct floppy_struct32 *)A(arg))->size) || + __get_user(f->sect, &((struct floppy_struct32 *)A(arg))->sect) || + __get_user(f->head, &((struct floppy_struct32 *)A(arg))->head) || + __get_user(f->track, &((struct floppy_struct32 *)A(arg))->track) || + __get_user(f->stretch, &((struct floppy_struct32 *)A(arg))->stretch) || + __get_user(f->gap, &((struct floppy_struct32 *)A(arg))->gap) || + __get_user(f->rate, &((struct floppy_struct32 *)A(arg))->rate) || + __get_user(f->spec1, &((struct floppy_struct32 *)A(arg))->spec1) || + __get_user(f->fmt_gap, &((struct floppy_struct32 *)A(arg))->fmt_gap) || + __get_user((u64)f->name, &((struct floppy_struct32 *)A(arg))->name)) { + kfree(karg); + return -EFAULT; + } + break; + } + case FDSETDRVPRM32: + case FDGETDRVPRM32: + { + struct floppy_drive_params *f; + + f = karg = kmalloc(GFP_KERNEL, sizeof(struct floppy_drive_params)); + if (!karg) + return -ENOMEM; + if (cmd == FDGETDRVPRM32) + break; + if (__get_user(f->cmos, &((struct floppy_drive_params32 *)A(arg))->cmos) || + __get_user(f->max_dtr, &((struct floppy_drive_params32 *)A(arg))->max_dtr) || + __get_user(f->hlt, &((struct floppy_drive_params32 *)A(arg))->hlt) || + __get_user(f->hut, &((struct floppy_drive_params32 *)A(arg))->hut) || + __get_user(f->srt, &((struct floppy_drive_params32 *)A(arg))->srt) || + __get_user(f->spinup, &((struct floppy_drive_params32 *)A(arg))->spinup) || + __get_user(f->spindown, &((struct floppy_drive_params32 *)A(arg))->spindown) || + __get_user(f->spindown_offset, &((struct floppy_drive_params32 *)A(arg))->spindown_offset) || + __get_user(f->select_delay, &((struct floppy_drive_params32 *)A(arg))->select_delay) || + __get_user(f->rps, &((struct floppy_drive_params32 *)A(arg))->rps) || + __get_user(f->tracks, &((struct floppy_drive_params32 *)A(arg))->tracks) || + __get_user(f->timeout, &((struct floppy_drive_params32 *)A(arg))->timeout) || + __get_user(f->interleave_sect, &((struct floppy_drive_params32 *)A(arg))->interleave_sect) || + __copy_from_user(&f->max_errors, &((struct floppy_drive_params32 *)A(arg))->max_errors, sizeof(f->max_errors)) || + __get_user(f->flags, &((struct floppy_drive_params32 *)A(arg))->flags) || + __get_user(f->read_track, &((struct floppy_drive_params32 *)A(arg))->read_track) || + __copy_from_user(f->autodetect, ((struct floppy_drive_params32 *)A(arg))->autodetect, sizeof(f->autodetect)) || + __get_user(f->checkfreq, &((struct floppy_drive_params32 *)A(arg))->checkfreq) || + __get_user(f->native_format, &((struct floppy_drive_params32 *)A(arg))->native_format)) { + kfree(karg); + return -EFAULT; + } + break; + } + case FDGETDRVSTAT32: + case FDPOLLDRVSTAT32: + karg = kmalloc(GFP_KERNEL, sizeof(struct floppy_drive_struct)); + if (!karg) + return -ENOMEM; + break; + case FDGETFDCSTAT32: + karg = kmalloc(GFP_KERNEL, sizeof(struct floppy_fdc_state)); + if (!karg) + return -ENOMEM; + break; + case FDWERRORGET32: + karg = kmalloc(GFP_KERNEL, sizeof(struct floppy_write_errors)); + if (!karg) + return -ENOMEM; + break; + default: + return -EINVAL; + } + set_fs (KERNEL_DS); + err = sys_ioctl (fd, kcmd, (unsigned long)karg); + set_fs (old_fs); + if (err) { + kfree(karg); + return err; + } + switch (cmd) { + case FDGETPRM32: + { + struct floppy_struct *f = karg; + + if (__put_user(f->size, &((struct floppy_struct32 *)A(arg))->size) || + __put_user(f->sect, &((struct floppy_struct32 *)A(arg))->sect) || + __put_user(f->head, &((struct floppy_struct32 *)A(arg))->head) || + __put_user(f->track, &((struct floppy_struct32 *)A(arg))->track) || + __put_user(f->stretch, &((struct floppy_struct32 *)A(arg))->stretch) || + __put_user(f->gap, &((struct floppy_struct32 *)A(arg))->gap) || + __put_user(f->rate, &((struct floppy_struct32 *)A(arg))->rate) || + __put_user(f->spec1, &((struct floppy_struct32 *)A(arg))->spec1) || + __put_user(f->fmt_gap, &((struct floppy_struct32 *)A(arg))->fmt_gap) || + __put_user((u64)f->name, &((struct floppy_struct32 *)A(arg))->name)) { + kfree(karg); + return -EFAULT; + } + break; + } + case FDGETDRVPRM32: + { + struct floppy_drive_params *f = karg; + + if (__put_user(f->cmos, &((struct floppy_drive_params32 *)A(arg))->cmos) || + __put_user(f->max_dtr, &((struct floppy_drive_params32 *)A(arg))->max_dtr) || + __put_user(f->hlt, &((struct floppy_drive_params32 *)A(arg))->hlt) || + __put_user(f->hut, &((struct floppy_drive_params32 *)A(arg))->hut) || + __put_user(f->srt, &((struct floppy_drive_params32 *)A(arg))->srt) || + __put_user(f->spinup, &((struct floppy_drive_params32 *)A(arg))->spinup) || + __put_user(f->spindown, &((struct floppy_drive_params32 *)A(arg))->spindown) || + __put_user(f->spindown_offset, &((struct floppy_drive_params32 *)A(arg))->spindown_offset) || + __put_user(f->select_delay, &((struct floppy_drive_params32 *)A(arg))->select_delay) || + __put_user(f->rps, &((struct floppy_drive_params32 *)A(arg))->rps) || + __put_user(f->tracks, &((struct floppy_drive_params32 *)A(arg))->tracks) || + __put_user(f->timeout, &((struct floppy_drive_params32 *)A(arg))->timeout) || + __put_user(f->interleave_sect, &((struct floppy_drive_params32 *)A(arg))->interleave_sect) || + __copy_to_user(&((struct floppy_drive_params32 *)A(arg))->max_errors, &f->max_errors, sizeof(f->max_errors)) || + __put_user(f->flags, &((struct floppy_drive_params32 *)A(arg))->flags) || + __put_user(f->read_track, &((struct floppy_drive_params32 *)A(arg))->read_track) || + __copy_to_user(((struct floppy_drive_params32 *)A(arg))->autodetect, f->autodetect, sizeof(f->autodetect)) || + __put_user(f->checkfreq, &((struct floppy_drive_params32 *)A(arg))->checkfreq) || + __put_user(f->native_format, &((struct floppy_drive_params32 *)A(arg))->native_format)) { + kfree(karg); + return -EFAULT; + } + break; + } + case FDGETDRVSTAT32: + case FDPOLLDRVSTAT32: + { + struct floppy_drive_struct *f = karg; + + if (__put_user(f->flags, &((struct floppy_drive_struct32 *)A(arg))->flags) || + __put_user(f->spinup_date, &((struct floppy_drive_struct32 *)A(arg))->spinup_date) || + __put_user(f->select_date, &((struct floppy_drive_struct32 *)A(arg))->select_date) || + __put_user(f->first_read_date, &((struct floppy_drive_struct32 *)A(arg))->first_read_date) || + __put_user(f->probed_format, &((struct floppy_drive_struct32 *)A(arg))->probed_format) || + __put_user(f->track, &((struct floppy_drive_struct32 *)A(arg))->track) || + __put_user(f->maxblock, &((struct floppy_drive_struct32 *)A(arg))->maxblock) || + __put_user(f->maxtrack, &((struct floppy_drive_struct32 *)A(arg))->maxtrack) || + __put_user(f->generation, &((struct floppy_drive_struct32 *)A(arg))->generation) || + __put_user(f->keep_data, &((struct floppy_drive_struct32 *)A(arg))->keep_data) || + __put_user(f->fd_ref, &((struct floppy_drive_struct32 *)A(arg))->fd_ref) || + __put_user(f->fd_device, &((struct floppy_drive_struct32 *)A(arg))->fd_device) || + __put_user(f->last_checked, &((struct floppy_drive_struct32 *)A(arg))->last_checked) || + __put_user((u64)f->dmabuf, &((struct floppy_drive_struct32 *)A(arg))->dmabuf) || + __put_user((u64)f->bufblocks, &((struct floppy_drive_struct32 *)A(arg))->bufblocks)) { + kfree(karg); + return -EFAULT; + } + break; + } + case FDGETFDCSTAT32: + { + struct floppy_fdc_state *f = karg; + + if (__put_user(f->spec1, &((struct floppy_fdc_state32 *)A(arg))->spec1) || + __put_user(f->spec2, &((struct floppy_fdc_state32 *)A(arg))->spec2) || + __put_user(f->dtr, &((struct floppy_fdc_state32 *)A(arg))->dtr) || + __put_user(f->version, &((struct floppy_fdc_state32 *)A(arg))->version) || + __put_user(f->dor, &((struct floppy_fdc_state32 *)A(arg))->dor) || + __put_user(f->address, &((struct floppy_fdc_state32 *)A(arg))->address) || + __copy_to_user((char *)&((struct floppy_fdc_state32 *)A(arg))->address + + sizeof(((struct floppy_fdc_state32 *)A(arg))->address), + (char *)&f->address + sizeof(f->address), sizeof(int)) || + __put_user(f->driver_version, &((struct floppy_fdc_state32 *)A(arg))->driver_version) || + __copy_to_user(((struct floppy_fdc_state32 *)A(arg))->track, f->track, sizeof(f->track))) { + kfree(karg); + return -EFAULT; + } + break; + } + case FDWERRORGET32: + { + struct floppy_write_errors *f = karg; + + if (__put_user(f->write_errors, &((struct floppy_write_errors32 *)A(arg))->write_errors) || + __put_user(f->first_error_sector, &((struct floppy_write_errors32 *)A(arg))->first_error_sector) || + __put_user(f->first_error_generation, &((struct floppy_write_errors32 *)A(arg))->first_error_generation) || + __put_user(f->last_error_sector, &((struct floppy_write_errors32 *)A(arg))->last_error_sector) || + __put_user(f->last_error_generation, &((struct floppy_write_errors32 *)A(arg))->last_error_generation) || + __put_user(f->badness, &((struct floppy_write_errors32 *)A(arg))->badness)) { + kfree(karg); + return -EFAULT; + } + break; + } + default: + break; + } + kfree(karg); + return 0; +} + struct ppp_option_data32 { __kernel_caddr_t32 ptr; __u32 length; @@ -540,14 +763,28 @@ struct ppp_option_data32 { }; #define PPPIOCSCOMPRESS32 _IOW('t', 77, struct ppp_option_data32) -static int ppp_ioctl(unsigned int fd, unsigned int cmd, u32 arg) +struct ppp_idle32 { + __kernel_time_t32 xmit_idle; + __kernel_time_t32 recv_idle; +}; +#define PPPIOCGIDLE32 _IOR('t', 63, struct ppp_idle32) + +static int ppp_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) { - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); struct ppp_option_data32 data32; struct ppp_option_data data; - int err; + struct ppp_idle32 idle32; + struct ppp_idle idle; + unsigned int kcmd; + void *karg; + int err = 0; switch (cmd) { + case PPPIOCGIDLE32: + kcmd = PPPIOCGIDLE; + karg = &idle; + break; case PPPIOCSCOMPRESS32: if (copy_from_user(&data32, (struct ppp_option_data32 *)A(arg), sizeof(struct ppp_option_data32))) return -EFAULT; @@ -555,33 +792,163 @@ static int ppp_ioctl(unsigned int fd, unsigned int cmd, u32 arg) if (!data.ptr) return -ENOMEM; if (copy_from_user(data.ptr, (__u8 *)A(data32.ptr), data32.length)) { - err = -EFAULT; - goto out; + kfree(data.ptr); + return -EFAULT; } data.length = data32.length; data.transmit = data32.transmit; + kcmd = PPPIOCSCOMPRESS; + karg = &data; break; default: printk("ppp_ioctl: Unknown cmd fd(%d) cmd(%08x) arg(%08x)\n", (int)fd, (unsigned int)cmd, (unsigned int)arg); return -EINVAL; } - old_fs = get_fs(); set_fs (KERNEL_DS); - err = sys_ioctl (fd, cmd, (unsigned long)&data); + err = sys_ioctl (fd, kcmd, (unsigned long)karg); set_fs (old_fs); - if (err) - goto out; switch (cmd) { + case PPPIOCGIDLE32: + if (err) + return err; + idle32.xmit_idle = idle.xmit_idle; + idle32.recv_idle = idle.recv_idle; + if (copy_to_user((struct ppp_idle32 *)A(arg), &idle32, sizeof(struct ppp_idle32))) + return -EFAULT; + break; case PPPIOCSCOMPRESS32: + kfree(data.ptr); + break; default: break; } -out: - kfree(data.ptr); return err; } + +struct mtget32 { + __u32 mt_type; + __u32 mt_resid; + __u32 mt_dsreg; + __u32 mt_gstat; + __u32 mt_erreg; + __kernel_daddr_t32 mt_fileno; + __kernel_daddr_t32 mt_blkno; +}; +#define MTIOCGET32 _IOR('m', 2, struct mtget32) + +struct mtpos32 { + __u32 mt_blkno; +}; +#define MTIOCPOS32 _IOR('m', 3, struct mtpos32) + +struct mtconfiginfo32 { + __u32 mt_type; + __u32 ifc_type; + __u16 irqnr; + __u16 dmanr; + __u16 port; + __u32 debug; + __u32 have_dens:1; + __u32 have_bsf:1; + __u32 have_fsr:1; + __u32 have_bsr:1; + __u32 have_eod:1; + __u32 have_seek:1; + __u32 have_tell:1; + __u32 have_ras1:1; + __u32 have_ras2:1; + __u32 have_ras3:1; + __u32 have_qfa:1; + __u32 pad1:5; + char reserved[10]; +}; +#define MTIOCGETCONFIG32 _IOR('m', 4, struct mtconfiginfo32) +#define MTIOCSETCONFIG32 _IOW('m', 5, struct mtconfiginfo32) + +static int mt_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) +{ + mm_segment_t old_fs = get_fs(); + struct mtconfiginfo info; + struct mtget get; + struct mtpos pos; + unsigned long kcmd; + void *karg; + int err = 0; + + switch(cmd) { + case MTIOCPOS32: + kcmd = MTIOCPOS; + karg = &pos; + break; + case MTIOCGET32: + kcmd = MTIOCGET; + karg = &get; + break; + case MTIOCGETCONFIG32: + kcmd = MTIOCGETCONFIG; + karg = &info; + break; + case MTIOCSETCONFIG32: + kcmd = MTIOCSETCONFIG; + karg = &info; + if (__get_user(info.mt_type, &((struct mtconfiginfo32 *)A(arg))->mt_type) || + __get_user(info.ifc_type, &((struct mtconfiginfo32 *)A(arg))->ifc_type) || + __get_user(info.irqnr, &((struct mtconfiginfo32 *)A(arg))->irqnr) || + __get_user(info.dmanr, &((struct mtconfiginfo32 *)A(arg))->dmanr) || + __get_user(info.port, &((struct mtconfiginfo32 *)A(arg))->port) || + __get_user(info.debug, &((struct mtconfiginfo32 *)A(arg))->debug) || + __copy_from_user((char *)&info.debug + sizeof(info.debug), + (char *)&((struct mtconfiginfo32 *)A(arg))->debug + + sizeof(((struct mtconfiginfo32 *)A(arg))->debug), + sizeof(__u32))) + return -EFAULT; + break; + default: + printk("mt_ioctl: Unknown cmd fd(%d) cmd(%08x) arg(%08x)\n", + (int)fd, (unsigned int)cmd, (unsigned int)arg); + return -EINVAL; + } + set_fs (KERNEL_DS); + err = sys_ioctl (fd, kcmd, (unsigned long)karg); + set_fs (old_fs); + if (err) + return err; + switch (cmd) { + case MTIOCPOS32: + if (__put_user(pos.mt_blkno, &((struct mtpos32 *)A(arg))->mt_blkno)) + return -EFAULT; + break; + case MTIOCGET32: + if (__put_user(get.mt_type, &((struct mtget32 *)A(arg))->mt_type) || + __put_user(get.mt_resid, &((struct mtget32 *)A(arg))->mt_resid) || + __put_user(get.mt_dsreg, &((struct mtget32 *)A(arg))->mt_dsreg) || + __put_user(get.mt_gstat, &((struct mtget32 *)A(arg))->mt_gstat) || + __put_user(get.mt_erreg, &((struct mtget32 *)A(arg))->mt_erreg) || + __put_user(get.mt_fileno, &((struct mtget32 *)A(arg))->mt_fileno) || + __put_user(get.mt_blkno, &((struct mtget32 *)A(arg))->mt_blkno)) + return -EFAULT; + break; + case MTIOCGETCONFIG32: + if (__put_user(info.mt_type, &((struct mtconfiginfo32 *)A(arg))->mt_type) || + __put_user(info.ifc_type, &((struct mtconfiginfo32 *)A(arg))->ifc_type) || + __put_user(info.irqnr, &((struct mtconfiginfo32 *)A(arg))->irqnr) || + __put_user(info.dmanr, &((struct mtconfiginfo32 *)A(arg))->dmanr) || + __put_user(info.port, &((struct mtconfiginfo32 *)A(arg))->port) || + __put_user(info.debug, &((struct mtconfiginfo32 *)A(arg))->debug) || + __copy_to_user((char *)&((struct mtconfiginfo32 *)A(arg))->debug + + sizeof(((struct mtconfiginfo32 *)A(arg))->debug), + (char *)&info.debug + sizeof(info.debug), sizeof(__u32))) + return -EFAULT; + break; + case MTIOCSETCONFIG32: + break; + } + return 0; +} + + asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) { struct file * filp; @@ -617,7 +984,7 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) case SIOCSIFHWADDR: case SIOCADDMULTI: case SIOCDELMULTI: - case SIOGIFINDEX: + case SIOCGIFINDEX: case SIOCGIFMAP: case SIOCSIFMAP: case SIOCGIFADDR: @@ -628,6 +995,8 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) case SIOCSIFDSTADDR: case SIOCGIFNETMASK: case SIOCSIFNETMASK: + case SIOCSIFPFLAGS: + case SIOCGIFPFLAGS: case SIOCGPPPSTATS: case SIOCGPPPCSTATS: case SIOCGPPPVER: @@ -639,10 +1008,12 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) error = routing_ioctl(fd, cmd, arg); goto out; - case SIOCRTMSG: - error = rtmsg_ioctl(fd, arg); + case SIOCRTMSG: /* Note SIOCRTMSG is no longer, so this is safe and + * the user would have seen just an -EINVAL anyways. + */ + error = -EINVAL; goto out; - + case HDIO_GETGEO: error = hdio_getgeo(fd, arg); goto out; @@ -671,6 +1042,30 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) error = hdio_ioctl_trans(fd, cmd, arg); goto out; + case FDSETPRM32: + case FDDEFPRM32: + case FDGETPRM32: + case FDSETDRVPRM32: + case FDGETDRVPRM32: + case FDGETDRVSTAT32: + case FDPOLLDRVSTAT32: + case FDGETFDCSTAT32: + case FDWERRORGET32: + error = fd_ioctl_trans(fd, cmd, (unsigned long)arg); + goto out; + + case PPPIOCGIDLE32: + case PPPIOCSCOMPRESS32: + error = ppp_ioctl_trans(fd, cmd, arg); + goto out; + + case MTIOCGET32: + case MTIOCPOS32: + case MTIOCGETCONFIG32: + case MTIOCSETCONFIG32: + error = mt_ioctl_trans(fd, cmd, arg); + goto out; + /* List here exlicitly which ioctl's are known to have * compatable types passed or none at all... */ @@ -751,13 +1146,22 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) case BLKROGET: /* 0x02 -- Floppy ioctls */ + case FDMSGON: + case FDMSGOFF: case FDSETEMSGTRESH: case FDFLUSH: + case FDWERRORCLR: case FDSETMAXERRS: case FDGETMAXERRS: case FDGETDRVTYP: case FDEJECT: - /* XXX The rest need struct floppy_* translations. */ + case FDCLRPRM: + case FDFMTBEG: + case FDFMTEND: + case FDRESET: + case FDTWADDLE: + case FDFMTTRK: + case FDRAWCMD: /* 0x12 */ case BLKRRPART: @@ -807,6 +1211,15 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) case KIOCSRATE: case KIOCGRATE: + /* Big S */ + case SCSI_IOCTL_GET_IDLUN: + case SCSI_IOCTL_DOORLOCK: + case SCSI_IOCTL_DOORUNLOCK: + case SCSI_IOCTL_TEST_UNIT_READY: + case SCSI_IOCTL_TAGGED_ENABLE: + case SCSI_IOCTL_TAGGED_DISABLE: + case SCSI_IOCTL_GET_BUS_NUMBER: + /* Big V */ case VT_SETMODE: case VT_GETMODE: @@ -829,6 +1242,9 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) case RTCGET: case RTCSET: + /* Little m */ + case MTIOCTOP: + /* OPENPROMIO, SunOS/Solaris only, the NetBSD one's have * embedded pointers in the arg which we'd need to clean up... */ @@ -860,9 +1276,11 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) case SIOCSARP: case SIOCGARP: case SIOCDARP: +#if 0 /* XXX No longer exist in new routing code. XXX */ case OLD_SIOCSARP: case OLD_SIOCGARP: case OLD_SIOCDARP: +#endif case SIOCSRARP: case SIOCGRARP: case SIOCDRARP: @@ -887,14 +1305,9 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) case PPPIOCSNPMODE: case PPPIOCGDEBUG: case PPPIOCSDEBUG: - case PPPIOCGIDLE: error = sys_ioctl (fd, cmd, (unsigned long)arg); goto out; - case PPPIOCSCOMPRESS32: - error = ppp_ioctl (fd, cmd, (unsigned long)arg); - goto out; - default: printk("sys32_ioctl: Unknown cmd fd(%d) cmd(%08x) arg(%08x)\n", (int)fd, (unsigned int)cmd, (unsigned int)arg); diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index 6f4c9dfdf..a84fe8eaa 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.39 1997/08/31 03:11:18 davem Exp $ +/* $Id: irq.c,v 1.47 1998/01/10 18:26:17 ecd Exp $ * irq.c: UltraSparc IRQ handling/init/registry. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -57,6 +57,7 @@ struct ino_bucket { unsigned int ino; unsigned int *imap; unsigned int *iclr; + unsigned char *imap_refcnt; }; #define INO_HASHSZ (NUM_HARD_IVECS >> 2) @@ -114,9 +115,15 @@ int get_irq_list(char *buf) } #if 0 #ifdef CONFIG_PCI - len += sprintf(buf + len, "ISTAT: PCI[%016lx] OBIO[%016lx]\n", - psycho_root->psycho_regs->pci_istate, - psycho_root->psycho_regs->obio_istate); + { + struct linux_psycho *p; + for (p = psycho_root; p; p = p->next) + len += sprintf(buf + len, + "ISTAT[%d]: PCI[%016lx] OBIO[%016lx]\n", + p->index, + p->psycho_regs->pci_istate, + p->psycho_regs->obio_istate); + } #endif #endif return len; @@ -229,10 +236,10 @@ unsigned char psycho_ino_to_pil[] = { 13, /* Audio Record */ 14, /* Audio Playback */ 15, /* PowerFail */ - 12, /* Keyboard/Mouse/Serial */ + 9, /* Keyboard/Mouse/Serial */ 11, /* Floppy */ 2, /* Spare Hardware */ - 12, /* Keyboard */ + 9, /* Keyboard */ 4, /* Mouse */ 12, /* Serial */ 10, /* Timer 0 */ @@ -411,7 +418,7 @@ static void get_irq_translations(int *cpu_irq, int *ivindex_fixup, offset += ((unsigned long)pregs); *imap = ((unsigned int *)offset) + 1; *iclr = (unsigned int *) - (((unsigned long)pregs) + psycho_imap_offset(irq)); + (((unsigned long)pregs) + psycho_iclr_offset(irq)); return; } #endif @@ -449,10 +456,17 @@ static void pci_irq_frobnicate(int *cpu_irq, int *ivindex_fixup, unsigned int **imap, unsigned int **iclr, unsigned int irq) { - struct linux_psycho *psycho = psycho_root; - struct psycho_regs *pregs = psycho->psycho_regs; + struct linux_psycho *psycho; + struct psycho_regs *pregs; unsigned long addr, imoff; + psycho = psycho_by_index((irq & PCI_IRQ_BUSNO) >> PCI_IRQ_BUSNO_SHFT); + if (!psycho) { + printk("get_irq_translations: BAD PSYCHO BUSNO[%x]\n", irq); + panic("Bad PSYCHO IRQ frobnication..."); + } + pregs = psycho->psycho_regs; + addr = (unsigned long) &pregs->imap_a_slot0; imoff = (irq & PCI_IRQ_IMAP_OFF) >> PCI_IRQ_IMAP_OFF_SHFT; addr = addr + imoff; @@ -515,7 +529,7 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *) unsigned long flags; unsigned int *imap, *iclr; void *bus_id = NULL; - int ivindex, ivindex_fixup, cpu_irq = -1; + int ivindex, ivindex_fixup, cpu_irq = -1, pending; if(!handler) return -EINVAL; @@ -605,7 +619,10 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *) return -ENOMEM; } + pending = ((ivector_to_mask[ivindex] & 0x80000000) != 0); ivector_to_mask[ivindex] = (1 << cpu_irq); + if(pending) + ivector_to_mask[ivindex] |= 0x80000000; if(dcookie) { dcookie->ret_ino = ivindex; @@ -625,6 +642,11 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *) *(cpu_irq + irq_action) = action; enable_irq(ivindex); + + /* We ate the IVEC already, this makes sure it does not get lost. */ + if(pending) + set_softint(1 << cpu_irq); + restore_flags(flags); #ifdef __SMP__ if(irqs_have_been_distributed) @@ -638,6 +660,7 @@ void free_irq(unsigned int irq, void *dev_id) struct irqaction *action; struct irqaction *tmp = NULL; unsigned long flags; + unsigned int *imap = NULL; unsigned int cpu_irq; int ivindex = -1; @@ -685,8 +708,8 @@ void free_irq(unsigned int irq, void *dev_id) if(action->flags & SA_IMAP_MASKED) { struct ino_bucket *bucket = (struct ino_bucket *)action->mask; - unsigned int *imap = bucket->imap; + imap = bucket->imap; if(imap != NULL) { ivindex = bucket->ino; ivector_to_mask[ivindex] = 0; @@ -696,8 +719,27 @@ void free_irq(unsigned int irq, void *dev_id) } kfree(action); - if(ivindex != -1) - disable_irq(ivindex); + + if(ivindex != -1) { + struct ino_bucket *bp; + int i, count = 0; + + /* The trick is that we can't turn the thing off when there + * are potentially other sub-irq level references. + */ + if(imap != NULL) { + for(i = 0; i < INO_HASHSZ; i++) { + bp = ino_hash[i]; + while(bp) { + if(bp->imap == imap) + count++; + bp = bp->next; + } + } + } + if(count < 2) + disable_irq(ivindex); + } restore_flags(flags); } @@ -863,12 +905,21 @@ void synchronize_irq(void) void report_spurious_ivec(struct pt_regs *regs) { extern unsigned long ivec_spurious_cookie; - static int times = 0; +#if 0 printk("IVEC: Spurious interrupt vector (%016lx) received at (%016lx)\n", ivec_spurious_cookie, regs->tpc); - if(times++ > 1) - prom_halt(); +#endif + + /* We can actually see this on Ultra/PCI PCI cards, which are bridges + * to other devices. Here a single IMAP enabled potentially multiple + * unique interrupt sources (which each do have a unique ICLR register. + * + * So what we do is just register that the IVEC arrived, when registered + * for real the request_irq() code will check the high bit and signal + * a local CPU interrupt for it. + */ + ivector_to_mask[ivec_spurious_cookie] |= (0x80000000); } void unexpected_irq(int irq, void *dev_cookie, struct pt_regs *regs) @@ -899,6 +950,7 @@ void unexpected_irq(int irq, void *dev_cookie, struct pt_regs *regs) void handler_irq(int irq, struct pt_regs *regs) { + struct ino_bucket *bucket = NULL; struct irqaction *action; int cpu = smp_processor_id(); @@ -911,20 +963,19 @@ void handler_irq(int irq, struct pt_regs *regs) unexpected_irq(irq, 0, regs); } else { do { - struct ino_bucket *bucket = NULL; - unsigned int ino = 0; + unsigned long *swmask = NULL; if(action->flags & SA_IMAP_MASKED) { bucket = (struct ino_bucket *)action->mask; - ino = bucket->ino; - if(!(ivector_to_mask[ino] & 0x80000000)) + swmask = &ivector_to_mask[bucket->ino]; + if(!(*swmask & 0x80000000)) continue; } action->handler(irq, action->dev_id, regs); - if(bucket) { - ivector_to_mask[ino] &= ~(0x80000000); + if(swmask) { + *swmask &= ~(0x80000000); *(bucket->iclr) = SYSIO_ICLR_IDLE; } } while((action = action->next) != NULL); @@ -938,12 +989,14 @@ extern void floppy_interrupt(int irq, void *dev_cookie, struct pt_regs *regs); void sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs) { struct irqaction *action = *(irq + irq_action); + struct ino_bucket *bucket; int cpu = smp_processor_id(); irq_enter(cpu, irq); + bucket = (struct ino_bucket *)action->mask; floppy_interrupt(irq, dev_cookie, regs); - if(action->flags & SA_IMAP_MASKED) - *((unsigned int *)action->mask) = SYSIO_ICLR_IDLE; + ivector_to_mask[bucket->ino] &= ~(0x80000000); + *(bucket->iclr) = SYSIO_ICLR_IDLE; irq_exit(cpu, irq); } #endif @@ -975,28 +1028,60 @@ static void install_fast_irq(unsigned int cpu_irq, int request_fast_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), - unsigned long irqflags, const char *name) + unsigned long irqflags, const char *name, void *dev_id) { struct irqaction *action; + struct devid_cookie *dcookie = NULL; + struct ino_bucket *bucket = NULL; unsigned long flags; - unsigned int cpu_irq, *imap, *iclr; - int ivindex = -1; - - /* XXX This really is not the way to do it, the "right way" - * XXX is to have drivers set SA_SBUS or something like that - * XXX in irqflags and we base our decision here on whether - * XXX that flag bit is set or not. - * - * In this case nobody can have a fast interrupt at the level - * where TICK interrupts live. - */ - if(irq == 14) - return -EINVAL; - cpu_irq = sysio_ino_to_pil[irq]; + unsigned int *imap, *iclr; + void *bus_id = NULL; + int ivindex, ivindex_fixup, cpu_irq = -1; if(!handler) return -EINVAL; - imap = sysio_irq_to_imap(irq); + + imap = iclr = NULL; + ivindex_fixup = 0; +#ifdef CONFIG_PCI + if(PCI_IRQ_P(irq)) { + pci_irq_frobnicate(&cpu_irq, &ivindex_fixup, &imap, &iclr, irq); + } else +#endif + if(irqflags & SA_DCOOKIE) { + if(!dev_id) { + printk("request_fast_irq: SA_DCOOKIE but dev_id is NULL!\n"); + panic("Bogus irq registry."); + } + dcookie = dev_id; + dev_id = dcookie->real_dev_id; + cpu_irq = dcookie->pil; + imap = dcookie->imap; + iclr = dcookie->iclr; + bus_id = dcookie->bus_cookie; + get_irq_translations(&cpu_irq, &ivindex_fixup, &imap, + &iclr, bus_id, irqflags, irq); + } else { + /* XXX NOTE: This code is maintained for compatability until I can + * XXX verify that all drivers sparc64 will use are updated + * XXX to use the new IRQ registry dcookie interface. -DaveM + */ + if(irq == 14) + cpu_irq = irq; + else + cpu_irq = sysio_ino_to_pil[irq]; + imap = sysio_irq_to_imap(irq); + if(!imap) { + printk("request_irq: BAD, null imap for old style " + "irq registry IRQ[%x].\n", irq); + panic("Bad IRQ registery..."); + } + iclr = sysio_imap_to_iclr(imap); + } + + ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)); + ivindex += ivindex_fixup; + action = *(cpu_irq + irq_action); if(action) { if(action->flags & SA_SHIRQ) @@ -1023,28 +1108,35 @@ int request_fast_irq(unsigned int irq, } install_fast_irq(cpu_irq, handler); - if(imap) { - ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)); - ivector_to_mask[ivindex] = (1 << cpu_irq); - iclr = sysio_imap_to_iclr(imap); - action->mask = (unsigned long) iclr; - irqflags |= SA_IMAP_MASKED; - add_ino_hash(ivindex, imap, iclr, irqflags); - } else - action->mask = 0; + bucket = add_ino_hash(ivindex, imap, iclr, irqflags); + if(!bucket) { + kfree(action); + restore_flags(flags); + return -ENOMEM; + } + + ivector_to_mask[ivindex] = (1 << cpu_irq); + + if(dcookie) { + dcookie->ret_ino = ivindex; + dcookie->ret_pil = cpu_irq; + } + action->mask = (unsigned long) bucket; action->handler = handler; - action->flags = irqflags; + action->flags = irqflags | SA_IMAP_MASKED; action->dev_id = NULL; action->name = name; action->next = NULL; *(cpu_irq + irq_action) = action; - - if(ivindex != -1) - enable_irq(ivindex); + enable_irq(ivindex); restore_flags(flags); +#ifdef __SMP__ + if(irqs_have_been_distributed) + distribute_irqs(); +#endif return 0; } diff --git a/arch/sparc64/kernel/itlb_miss.S b/arch/sparc64/kernel/itlb_miss.S index 61233125c..9317587a7 100644 --- a/arch/sparc64/kernel/itlb_miss.S +++ b/arch/sparc64/kernel/itlb_miss.S @@ -1,4 +1,4 @@ -/* $Id: itlb_miss.S,v 1.10 1997/03/26 12:24:18 davem Exp $ +/* $Id: itlb_miss.S,v 1.11 1997/10/14 01:48:25 davem Exp $ * itlb_miss.S: Instruction TLB miss code, this is included directly * into the trap table. * @@ -23,10 +23,10 @@ /*0x24*/ srlx %g1, 1, %g1 ! PTE offset /*0x28*/ ldxa [%g5 + %g4] ASI_PHYS_USE_EC, %g3 ! Load PMD 2:/*0x2c*/ ldxa [%g3 + %g1] ASI_PHYS_USE_EC, %g5 ! Load PTE - /*0x30*/ brlz,a,pt %g5, 1f ! Valid set? - /*0x34*/ stxa %g5, [%g0] ASI_ITLB_DATA_IN ! TLB load - /*0x38*/ ba,a,pt %xcc, sparc64_itlb_refbit_catch ! Nope... -1:/*0x3c*/ retry ! Trap return + /*0x30*/ brgez,pn %g5, sparc64_itlb_refbit_catch ! Valid set? + /*0x34*/ nop ! delay + /*0x38*/ stxa %g5, [%g0] ASI_ITLB_DATA_IN ! TLB load + /*0x3c*/ retry ! Trap return 3: /* ICACHE line 3 */ /*0x40*/ ldxa [%g6 + %g3] ASI_PHYS_USE_EC, %g5 ! Load kern PGD diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index 35d4d606d..4e5ead982 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c @@ -1,9 +1,9 @@ -/* $Id: process.c,v 1.42 1997/08/19 14:17:55 jj Exp $ +/* $Id: process.c,v 1.50 1998/01/09 16:39:33 jj Exp $ * arch/sparc64/kernel/process.c * * Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) - * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1997, 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ /* @@ -39,6 +39,8 @@ #include <asm/elf.h> #include <asm/fpumacro.h> +/* #define VERBOSE_SHOWREGS */ + #define PGTCACHE_HIGH_WATER 50 #define PGTCACHE_LOW_WATER 25 @@ -98,7 +100,7 @@ asmlinkage int cpu_idle(void) } barrier(); current->counter = -100; - if(resched_needed()) + if(need_resched) schedule(); barrier(); } @@ -166,7 +168,7 @@ static void show_regwindow32(struct pt_regs *regs) { struct reg_window32 *rw; struct reg_window32 r_w; - unsigned long old_fs; + mm_segment_t old_fs; __asm__ __volatile__ ("flushw"); rw = (struct reg_window32 *)((long)(unsigned)regs->u_regs[14]); @@ -192,7 +194,7 @@ static void show_regwindow(struct pt_regs *regs) { struct reg_window *rw; struct reg_window r_w; - unsigned long old_fs; + mm_segment_t old_fs; if ((regs->tstate & TSTATE_PRIV) || !(current->tss.flags & SPARC_FLAG_32BIT)) { __asm__ __volatile__ ("flushw"); @@ -311,8 +313,30 @@ void __show_regs(struct pt_regs * regs) #endif } +#ifdef VERBOSE_SHOWREGS +static void idump_from_user (unsigned int *pc) +{ + int i; + int code; + + if((((unsigned long) pc) & 3)) + return; + + pc -= 3; + for(i = -3; i < 6; i++) { + get_user(code, pc); + printk("%c%08x%c",i?' ':'<',code,i?' ':'>'); + pc++; + } + printk("\n"); +} +#endif + void show_regs(struct pt_regs *regs) { +#ifdef VERBOSE_SHOWREGS + extern long etrap, etraptl1; +#endif __show_regs(regs); #ifdef __SMP__ { @@ -321,6 +345,17 @@ void show_regs(struct pt_regs *regs) smp_report_regs(); } #endif + +#ifdef VERBOSE_SHOWREGS + if (regs->tpc >= &etrap && regs->tpc < &etraptl1 && + regs->u_regs[14] >= (long)current - PAGE_SIZE && + regs->u_regs[14] < (long)current + 6 * PAGE_SIZE) { + printk ("*********parent**********\n"); + __show_regs((struct pt_regs *)(regs->u_regs[14] + STACK_BIAS + REGWIN_SZ)); + idump_from_user(((struct pt_regs *)(regs->u_regs[14] + STACK_BIAS + REGWIN_SZ))->tpc); + printk ("*********endpar**********\n"); + } +#endif } void show_regs32(struct pt_regs32 *regs) @@ -352,29 +387,35 @@ void show_thread(struct thread_struct *tss) printk("sig_address: 0x%016lx\n", tss->sig_address); printk("sig_desc: 0x%016lx\n", tss->sig_desc); printk("ksp: 0x%016lx\n", tss->ksp); - printk("kpc: 0x%016lx\n", tss->kpc); - - for (i = 0; i < NSWINS; i++) { - if (!tss->rwbuf_stkptrs[i]) - continue; - printk("reg_window[%d]:\n", i); - printk("stack ptr: 0x%016lx\n", tss->rwbuf_stkptrs[i]); + printk("kpc: 0x%08x\n", tss->kpc); + + if (tss->w_saved) { + for (i = 0; i < NSWINS; i++) { + if (!tss->rwbuf_stkptrs[i]) + continue; + printk("reg_window[%d]:\n", i); + printk("stack ptr: 0x%016lx\n", tss->rwbuf_stkptrs[i]); + } + printk("w_saved: 0x%04x\n", tss->w_saved); } - printk("w_saved: 0x%08lx\n", tss->w_saved); printk("sstk_info.stack: 0x%016lx\n", (unsigned long)tss->sstk_info.the_stack); printk("sstk_info.status: 0x%016lx\n", (unsigned long)tss->sstk_info.cur_status); printk("flags: 0x%08x\n", tss->flags); - printk("current_ds: 0x%016lx\n", tss->current_ds); - - /* XXX missing: core_exec */ + printk("current_ds: 0x%016lx\n", tss->current_ds.seg); } /* Free current thread data structures etc.. */ void exit_thread(void) { + if (current->tss.utraps) { + if (current->tss.utraps[0] < 2) + kfree (current->tss.utraps); + else + current->tss.utraps[0]--; + } } void flush_thread(void) @@ -540,9 +581,9 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, memcpy(child_trap_frame, (((struct reg_window *)regs)-1), tframe_size); p->tss.ksp = ((unsigned long) child_trap_frame) - STACK_BIAS; #ifdef __SMP__ - p->tss.kpc = ((unsigned long) ret_from_smpfork) - 0x8; + p->tss.kpc = ((unsigned int) ((unsigned long) ret_from_smpfork)) - 0x8; #else - p->tss.kpc = ((unsigned long) ret_from_syscall) - 0x8; + p->tss.kpc = ((unsigned int) ((unsigned long) ret_from_syscall)) - 0x8; #endif p->tss.kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct reg_window)); p->tss.cwp = (regs->tstate + 1) & TSTATE_CWP; @@ -569,6 +610,8 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, return -EFAULT; p->tss.kregs->u_regs[UREG_FP] = csp; } + if (p->tss.utraps) + p->tss.utraps[0]++; } /* Set the return value for the child. */ @@ -595,7 +638,6 @@ void dump_thread(struct pt_regs * regs, struct user * dump) dump->regs.y = regs->y; /* fuck me plenty */ memcpy(&dump->regs.regs[0], ®s->u_regs[1], (sizeof(unsigned long) * 15)); - dump->uexec = current->tss.core_exec; dump->u_tsize = (((unsigned long) current->mm->end_code) - ((unsigned long) current->mm->start_code)) & ~(PAGE_SIZE - 1); dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))); diff --git a/arch/sparc64/kernel/psycho.c b/arch/sparc64/kernel/psycho.c index 8aa1c342b..b3b403e33 100644 --- a/arch/sparc64/kernel/psycho.c +++ b/arch/sparc64/kernel/psycho.c @@ -1,7 +1,8 @@ -/* $Id: psycho.c,v 1.22 1997/08/31 03:51:40 davem Exp $ +/* $Id: psycho.c,v 1.31 1998/01/10 18:26:15 ecd Exp $ * psycho.c: Ultra/AX U2P PCI controller support. * * Copyright (C) 1997 David S. Miller (davem@caipfs.rutgers.edu) + * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) */ #include <linux/config.h> @@ -11,6 +12,16 @@ #include <asm/ebus.h> #include <asm/sbus.h> /* for sanity check... */ +#undef PROM_DEBUG +#undef FIXUP_REGS_DEBUG +#undef FIXUP_IRQ_DEBUG + +#ifdef PROM_DEBUG +#define dprintf prom_printf +#else +#define dprintf printk +#endif + #ifndef CONFIG_PCI int pcibios_present(void) @@ -49,6 +60,28 @@ asmlinkage int sys_pciconfig_write(unsigned long bus, #include <asm/uaccess.h> struct linux_psycho *psycho_root = NULL; +struct linux_psycho **psycho_index_map; +int linux_num_psycho = 0; +static struct linux_pbm_info *bus2pbm[256]; + +static int pbm_read_config_byte(struct linux_pbm_info *pbm, + unsigned char bus, unsigned char devfn, + unsigned char where, unsigned char *value); +static int pbm_read_config_word(struct linux_pbm_info *pbm, + unsigned char bus, unsigned char devfn, + unsigned char where, unsigned short *value); +static int pbm_read_config_dword(struct linux_pbm_info *pbm, + unsigned char bus, unsigned char devfn, + unsigned char where, unsigned int *value); +static int pbm_write_config_byte(struct linux_pbm_info *pbm, + unsigned char bus, unsigned char devfn, + unsigned char where, unsigned char value); +static int pbm_write_config_word(struct linux_pbm_info *pbm, + unsigned char bus, unsigned char devfn, + unsigned char where, unsigned short value); +static int pbm_write_config_dword(struct linux_pbm_info *pbm, + unsigned char bus, unsigned char devfn, + unsigned char where, unsigned int value); /* This is used to make the scan_bus in the generic PCI code be * a nop, as we need to control the actual bus probing sequence. @@ -69,10 +102,22 @@ static unsigned long psycho_iommu_init(struct linux_psycho *psycho, unsigned long control, i; unsigned long *iopte; + /* + * Invalidate TLB Entries. + */ + control = psycho->psycho_regs->iommu_control; + control |= IOMMU_CTRL_DENAB; + psycho->psycho_regs->iommu_control = control; + for(i = 0; i < 16; i++) { + psycho->psycho_regs->iommu_data[i] = 0; + } + control &= ~(IOMMU_CTRL_DENAB); + psycho->psycho_regs->iommu_control = control; + memory_start = (tsbbase + ((32 * 1024) * 8)); iopte = (unsigned long *)tsbbase; - for(i = 0; i < (65536 / 2); i++) { + for(i = 0; i < (32 * 1024); i++) { *iopte = (IOPTE_VALID | IOPTE_64K | IOPTE_CACHE | IOPTE_WRITE); *iopte |= (i << 16); @@ -94,21 +139,26 @@ extern void prom_pbm_ranges_init(int node, struct linux_pbm_info *pbm); unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end) { struct linux_prom64_registers pr_regs[3]; + struct linux_psycho *psycho; char namebuf[128]; u32 portid; int node; printk("PSYCHO: Probing for controllers.\n"); +#ifdef PROM_DEBUG + dprintf("PSYCHO: Probing for controllers.\n"); +#endif memory_start = long_align(memory_start); node = prom_getchild(prom_root_node); while((node = prom_searchsiblings(node, "pci")) != 0) { - struct linux_psycho *psycho = (struct linux_psycho *)memory_start; struct linux_psycho *search; struct linux_pbm_info *pbm = NULL; u32 busrange[2]; int err, is_pbm_a; + psycho = (struct linux_psycho *)memory_start; + portid = prom_getintdefault(node, "upa-portid", 0xff); for(search = psycho_root; search; search = search->next) { if(search->upa_portid == portid) { @@ -123,7 +173,8 @@ unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end) } } - memory_start = long_align(memory_start + sizeof(struct linux_psycho)); + memory_start = long_align(memory_start + + sizeof(struct linux_psycho)); memset(psycho, 0, sizeof(*psycho)); @@ -131,8 +182,12 @@ unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end) psycho_root = psycho; psycho->upa_portid = portid; + psycho->index = linux_num_psycho++; - /* Map in PSYCHO register set and report the presence of this PSYCHO. */ + /* + * Map in PSYCHO register set and report the presence + * of this PSYCHO. + */ err = prom_getproperty(node, "reg", (char *)&pr_regs[0], sizeof(pr_regs)); if(err == 0 || err == -1) { @@ -141,7 +196,10 @@ unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end) prom_halt(); } - /* Third REG in property is base of entire PSYCHO register space. */ + /* + * Third REG in property is base of entire PSYCHO + * register space. + */ psycho->psycho_regs = sparc_alloc_io((pr_regs[2].phys_addr & 0xffffffff), NULL, sizeof(struct psycho_regs), "PSYCHO Registers", @@ -154,12 +212,19 @@ unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end) printk("PSYCHO: Found controller, main regs at %p\n", psycho->psycho_regs); -#if 0 - printk("PSYCHO: Interrupt retry [%016lx]\n", - psycho->psycho_regs->irq_retry); +#ifdef PROM_DEBUG + dprintf("PSYCHO: Found controller, main regs at %p\n", + psycho->psycho_regs); #endif + psycho->psycho_regs->irq_retry = 0xff; +#if 0 + psycho->psycho_regs->ecc_control |= 1; + psycho->psycho_regs->sbuf_a_control = 0; + psycho->psycho_regs->sbuf_b_control = 0; +#endif + /* Now map in PCI config space for entire PSYCHO. */ psycho->pci_config_space = sparc_alloc_io(((pr_regs[2].phys_addr & 0xffffffff)+0x01000000), @@ -172,7 +237,12 @@ unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end) } /* Report some more info. */ - printk("PSYCHO: PCI config space at %p\n", psycho->pci_config_space); + printk("PSYCHO: PCI config space at %p\n", + psycho->pci_config_space); +#ifdef PROM_DEBUG + dprintf("PSYCHO: PCI config space at %p\n", + psycho->pci_config_space); +#endif memory_start = psycho_iommu_init(psycho, memory_start); @@ -223,6 +293,13 @@ unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end) prom_halt(); } + psycho_index_map = (struct linux_psycho **)long_align(memory_start); + memory_start = long_align(memory_start + linux_num_psycho + * sizeof(struct linux_psycho *)); + + for (psycho = psycho_root; psycho; psycho = psycho->next) + psycho_index_map[psycho->index] = psycho; + return memory_start; } @@ -361,18 +438,118 @@ static inline struct pcidev_cookie *pci_devcookie_alloc(void) return pci_init_alloc(sizeof(struct pcidev_cookie)); } + +static void +pbm_reconfigure_bridges(struct linux_pbm_info *pbm, unsigned char bus) +{ + unsigned int devfn, l, class; + unsigned char hdr_type = 0; + + for (devfn = 0; devfn < 0xff; ++devfn) { + if (PCI_FUNC(devfn) == 0) { + pbm_read_config_byte(pbm, bus, devfn, + PCI_HEADER_TYPE, &hdr_type); + } else if (!(hdr_type & 0x80)) { + /* not a multi-function device */ + continue; + } + + /* Check if there is anything here. */ + pbm_read_config_dword(pbm, bus, devfn, PCI_VENDOR_ID, &l); + if (l == 0xffffffff || l == 0x00000000) { + hdr_type = 0; + continue; + } + + /* See if this is a bridge device. */ + pbm_read_config_dword(pbm, bus, devfn, + PCI_CLASS_REVISION, &class); + + if ((class >> 16) == PCI_CLASS_BRIDGE_PCI) { + unsigned int buses; + + pbm_read_config_dword(pbm, bus, devfn, + PCI_PRIMARY_BUS, &buses); + + /* + * First reconfigure everything underneath the bridge. + */ + pbm_reconfigure_bridges(pbm, (buses >> 8) & 0xff); + + /* + * Unconfigure this bridges bus numbers, + * pci_scan_bus() will fix this up properly. + */ + buses &= 0xff000000; + pbm_write_config_dword(pbm, bus, devfn, + PCI_PRIMARY_BUS, buses); + } + } +} + +static void pbm_fixup_busno(struct linux_pbm_info *pbm, unsigned char bus) +{ + unsigned int nbus; + + /* + * First, reconfigure all bridge devices underneath this pbm. + */ + pbm_reconfigure_bridges(pbm, pbm->pci_first_busno); + + /* + * Now reconfigure the pbm to it's new bus number and set up + * our bus2pbm mapping for this pbm. + */ + nbus = pbm->pci_last_busno - pbm->pci_first_busno; + + pbm_write_config_byte(pbm, pbm->pci_first_busno, 0, 0x40, bus); + + pbm->pci_first_busno = bus; + pbm_write_config_byte(pbm, bus, 0, 0x41, 0xff); + + do { + bus2pbm[bus++] = pbm; + } while (nbus--); +} + + static void pbm_probe(struct linux_pbm_info *pbm, unsigned long *mstart) { + static struct pci_bus *pchain = NULL; struct pci_bus *pbus = &pbm->pci_bus; + static unsigned char busno = 0; /* PSYCHO PBM's include child PCI bridges in bus-range property, * but we don't scan each of those ourselves, Linux generic PCI * probing code will find child bridges and link them into this * pbm's root PCI device hierarchy. */ - pbus->number = pbm->pci_first_busno; + + pbus->number = pbus->secondary = busno; pbus->sysdata = pbm; + + pbm_fixup_busno(pbm, busno); + pbus->subordinate = pci_scan_bus(pbus, mstart); + + /* + * Set the maximum subordinate bus of this pbm. + */ + pbm->pci_last_busno = pbus->subordinate; + pbm_write_config_byte(pbm, busno, 0, 0x41, pbm->pci_last_busno); + + busno = pbus->subordinate + 1; + + /* + * Fixup the chain of primary PCI busses. + */ + if (pchain) { + pchain->next = &pbm->pci_bus; + pchain = pchain->next; + } else { + pchain = &pci_root; + memcpy(pchain, &pbm->pci_bus, sizeof(pci_root)); + } } static int pdev_to_pnode_sibtraverse(struct linux_pbm_info *pbm, @@ -433,8 +610,6 @@ static void fill_in_pbm_cookies(struct linux_pbm_info *pbm) pdev_cookie_fillin(pbm, pdev); } -/* #define RECORD_ASSIGNMENTS_DEBUG */ - /* Walk PROM device tree under PBM, looking for 'assigned-address' * properties, and recording them in pci_vma's linked in via * PBM->assignments. @@ -534,8 +709,6 @@ static void record_assignments(struct linux_pbm_info *pbm) assignment_walk_siblings(pbm, prom_getchild(pbm->prom_node)); } -/* #define FIXUP_REGS_DEBUG */ - static void fixup_regs(struct pci_dev *pdev, struct linux_pbm_info *pbm, struct linux_prom_pci_registers *pregs, @@ -556,12 +729,14 @@ static void fixup_regs(struct pci_dev *pdev, if(bustype == 0) { /* Config space cookie, nothing to do. */ if(preg != 0) - prom_printf("fixup_doit: strange, config space not 0\n"); + printk("%s: strange, config space not 0\n", + __FUNCTION__); continue; } else if(bustype == 3) { /* XXX add support for this... */ - prom_printf("fixup_doit: Warning, ignoring 64-bit PCI " - "memory space, tell DaveM.\n"); + printk("%s: Warning, ignoring 64-bit PCI memory space, " + "tell Eddie C. Dost (ecd@skynet.be).\n", + __FUNCTION__); continue; } bsreg = (pregs[preg].phys_hi & 0xff); @@ -574,8 +749,13 @@ static void fixup_regs(struct pci_dev *pdev, if((bsreg < PCI_BASE_ADDRESS_0) || (bsreg > (PCI_BASE_ADDRESS_5 + 4)) || (bsreg & 3)) { - prom_printf("fixup_doit: Warning, ignoring bogus basereg [%x]\n", - bsreg); + printk("%s: [%04x:%04x]: " + "Warning, ignoring bogus basereg [%x]\n", + __FUNCTION__, pdev->vendor, pdev->device, bsreg); + printk(" PROM reg: %08x.%08x.%08x %08x.%08x\n", + pregs[preg].phys_hi, pregs[preg].phys_mid, + pregs[preg].phys_lo, pregs[preg].size_hi, + pregs[preg].size_lo); continue; } @@ -740,22 +920,22 @@ static void fixup_regs(struct pci_dev *pdev, pdev->devfn, PCI_COMMAND, &l); #ifdef FIXUP_REGS_DEBUG - prom_printf("["); + dprintf("["); #endif if(IO_seen) { #ifdef FIXUP_REGS_DEBUG - prom_printf("IO "); + dprintf("IO "); #endif l |= PCI_COMMAND_IO; } if(MEM_seen) { #ifdef FIXUP_REGS_DEBUG - prom_printf("MEM"); + dprintf("MEM"); #endif l |= PCI_COMMAND_MEMORY; } #ifdef FIXUP_REGS_DEBUG - prom_printf("]"); + dprintf("]"); #endif pcibios_write_config_dword(pdev->bus->number, pdev->devfn, @@ -763,7 +943,7 @@ static void fixup_regs(struct pci_dev *pdev, } #ifdef FIXUP_REGS_DEBUG - prom_printf("REG_FIXUP[%s]: ", pci_strdev(pdev->vendor, pdev->device)); + dprintf("REG_FIXUP[%04x,%04x]: ", pdev->vendor, pdev->device); for(preg = 0; preg < 6; preg++) { if(pdev->base_address[preg] != 0) prom_printf("%d[%016lx] ", preg, pdev->base_address[preg]); @@ -814,7 +994,7 @@ static unsigned long psycho_pcislot_imap_offset(unsigned long ino) } /* Exported for EBUS probing layer. */ -unsigned int psycho_irq_build(unsigned int full_ino) +unsigned int psycho_irq_build(struct linux_pbm_info *pbm, unsigned int full_ino) { unsigned long imap_off, ign, ino; @@ -906,11 +1086,9 @@ unsigned int psycho_irq_build(unsigned int full_ino) } imap_off -= imap_offset(imap_a_slot0); - return pci_irq_encode(imap_off, 0 /* XXX */, ign, ino); + return pci_irq_encode(imap_off, pbm->parent->index, ign, ino); } -/* #define FIXUP_IRQ_DEBUG */ - static void fixup_irq(struct pci_dev *pdev, struct linux_pbm_info *pbm, int node) @@ -920,24 +1098,30 @@ static void fixup_irq(struct pci_dev *pdev, int err; #ifdef FIXUP_IRQ_DEBUG - printk("fixup_irq[%s:%s]: ", - pci_strvendor(pdev->vendor), - pci_strdev(pdev->vendor, pdev->device)); + dprintf("fixup_irq[%04x:%04x]: ", pdev->vendor, pdev->device); #endif err = prom_getproperty(node, "interrupts", (void *)&prom_irq, sizeof(prom_irq)); if(err == 0 || err == -1) { - prom_printf("fixup_irq: No interrupts property for dev[%s:%s]\n", - pci_strvendor(pdev->vendor), - pci_strdev(pdev->vendor, pdev->device)); + prom_printf("fixup_irq: No interrupts property for dev[%04x:%04x]\n", + pdev->vendor, pdev->device); prom_halt(); } /* See if fully specified already (ie. for onboard devices like hme) */ if(((prom_irq & PSYCHO_IMAP_IGN) >> 6) == pbm->parent->upa_portid) { - pdev->irq = psycho_irq_build(prom_irq); + pdev->irq = psycho_irq_build(pbm, prom_irq); +#ifdef FIXUP_IRQ_DEBUG + dprintf("fully specified prom_irq[%x] pdev->irq[%x]", + prom_irq, pdev->irq); +#endif + /* See if onboard device interrupt (i.e. bit 5 set) */ + } else if((prom_irq & PSYCHO_IMAP_INO) & 0x20) { + pdev->irq = psycho_irq_build(pbm, + (pbm->parent->upa_portid << 6) + | prom_irq); #ifdef FIXUP_IRQ_DEBUG - printk("fully specified prom_irq[%x] pdev->irq[%x]", - prom_irq, pdev->irq); + dprintf("partially specified prom_irq[%x] pdev->irq[%x]", + prom_irq, pdev->irq); #endif } else { unsigned int bus, slot, line; @@ -952,20 +1136,25 @@ static void fixup_irq(struct pci_dev *pdev, if(pbm == &pbm->parent->pbm_A) slot = (pdev->devfn >> 3) - 1; else - slot = ((pdev->devfn >> 3) >> 1) - 1; + slot = (pdev->devfn >> 3) - 2; } else { /* Underneath a bridge, use slot number of parent * bridge. */ - slot = (pdev->bus->self->devfn >> 3) - 1; + if(pbm == &pbm->parent->pbm_A) + slot = (pdev->bus->self->devfn >> 3) - 1; + else + slot = (pdev->bus->self->devfn >> 3) - 2; /* Use low slot number bits of child as IRQ line. */ - line = ((pdev->devfn >> 3) & 3); + line = (line + ((pdev->devfn >> 3) - 4)) % 4; } slot = (slot << 2); - pdev->irq = psycho_irq_build((((portid << 6) & PSYCHO_IMAP_IGN) | - (bus | slot | line))); + pdev->irq = psycho_irq_build(pbm, + (((portid << 6) & PSYCHO_IMAP_IGN) + | (bus | slot | line))); + #ifdef FIXUP_IRQ_DEBUG do { unsigned char iline, ipin; @@ -978,15 +1167,24 @@ static void fixup_irq(struct pci_dev *pdev, pdev->devfn, PCI_INTERRUPT_LINE, &iline); - printk("FIXED portid[%x] bus[%x] slot[%x] line[%x] irq[%x] " - "iline[%x] ipin[%x] prom_irq[%x]", - portid, bus>>4, slot>>2, line, pdev->irq, - iline, ipin, prom_irq); + dprintf("FIXED portid[%x] bus[%x] slot[%x] line[%x] irq[%x] " + "iline[%x] ipin[%x] prom_irq[%x]", + portid, bus>>4, slot>>2, line, pdev->irq, + iline, ipin, prom_irq); } while(0); #endif } + + /* + * Write the INO to config space PCI_INTERRUPT_LINE. + */ + (void)pcibios_write_config_byte(pdev->bus->number, + pdev->devfn, + PCI_INTERRUPT_LINE, + pdev->irq & PCI_IRQ_INO); + #ifdef FIXUP_IRQ_DEBUG - printk("\n"); + dprintf("\n"); #endif } @@ -1093,15 +1291,11 @@ static void psycho_final_fixup(struct linux_psycho *psycho) /* Second, fixup base address registers and IRQ lines... */ fixup_addr_irq(&psycho->pbm_A); fixup_addr_irq(&psycho->pbm_B); - -#if 0 - prom_halt(); -#endif } unsigned long pcibios_fixup(unsigned long memory_start, unsigned long memory_end) { - struct linux_psycho *psycho = psycho_root; + struct linux_psycho *psycho; pci_probe_enable = 1; @@ -1117,11 +1311,13 @@ unsigned long pcibios_fixup(unsigned long memory_start, unsigned long memory_end * XXX apps that need to get at PCI configuration space. */ - /* Probe busses under PBM A. */ - pbm_probe(&psycho->pbm_A, &memory_start); + for (psycho = psycho_root; psycho; psycho = psycho->next) { + /* Probe busses under PBM B. */ + pbm_probe(&psycho->pbm_B, &memory_start); - /* Probe busses under PBM B. */ - pbm_probe(&psycho->pbm_B, &memory_start); + /* Probe busses under PBM A. */ + pbm_probe(&psycho->pbm_A, &memory_start); + } pci_init_alloc_init(&memory_start); @@ -1130,15 +1326,17 @@ unsigned long pcibios_fixup(unsigned long memory_start, unsigned long memory_end * sysdata with a pointer to the PBM (for pci_bus's) or * a pci_dev cookie (PBM+PROM_NODE, for pci_dev's). */ - fill_in_pbm_cookies(&psycho->pbm_A); - fill_in_pbm_cookies(&psycho->pbm_B); + for (psycho = psycho_root; psycho; psycho = psycho->next) { + fill_in_pbm_cookies(&psycho->pbm_A); + fill_in_pbm_cookies(&psycho->pbm_B); - /* See what OBP has taken care of already. */ - record_assignments(&psycho->pbm_A); - record_assignments(&psycho->pbm_B); + /* See what OBP has taken care of already. */ + record_assignments(&psycho->pbm_A); + record_assignments(&psycho->pbm_B); - /* Now, fix it all up. */ - psycho_final_fixup(psycho); + /* Now, fix it all up. */ + psycho_final_fixup(psycho); + } pci_init_alloc_fini(); @@ -1153,113 +1351,124 @@ volatile int pci_poke_faulted = 0; * XXX space exists, on Ultra we can have many of them, especially with * XXX 'dual-pci' boards on Sunfire/Starfire/Wildfire. */ -static char *pci_mkaddr(unsigned char bus, unsigned char device_fn, - unsigned char where) +static void * +pci_mkaddr(struct linux_pbm_info *pbm, unsigned char bus, + unsigned char devfn, unsigned char where) { - unsigned long ret = (unsigned long) psycho_root->pci_config_space; + unsigned long ret; + + if (!pbm) + return NULL; + + ret = (unsigned long) pbm->parent->pci_config_space; ret |= (1 << 24); - ret |= ((bus & 0xff) << 16); - ret |= ((device_fn & 0xff) << 8); - ret |= (where & 0xfc); - return (unsigned char *)ret; + ret |= (bus << 16); + ret |= (devfn << 8); + ret |= where; + + return (void *)ret; } -static inline int out_of_range(unsigned char bus, unsigned char device_fn) +static inline int +out_of_range(struct linux_pbm_info *pbm, unsigned char bus, unsigned char devfn) { - return ((bus == 0 && PCI_SLOT(device_fn) > 4) || - (bus == 1 && PCI_SLOT(device_fn) > 6) || + return (((pbm == &pbm->parent->pbm_B) && PCI_SLOT(devfn) > 4) || + ((pbm == &pbm->parent->pbm_A) && PCI_SLOT(devfn) > 6) || (pci_probe_enable == 0)); } -int pcibios_read_config_byte (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned char *value) +static int +pbm_read_config_byte(struct linux_pbm_info *pbm, + unsigned char bus, unsigned char devfn, + unsigned char where, unsigned char *value) { - unsigned char *addr = pci_mkaddr(bus, device_fn, where); - unsigned int word, trapped; + unsigned char *addr = pci_mkaddr(pbm, bus, devfn, where); + unsigned int trapped; + unsigned char byte; *value = 0xff; - if(out_of_range(bus, device_fn)) + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (out_of_range(pbm, bus, devfn)) return PCIBIOS_SUCCESSFUL; pci_poke_in_progress = 1; pci_poke_faulted = 0; __asm__ __volatile__("membar #Sync\n\t" - "lduwa [%1] %2, %0\n\t" + "lduba [%1] %2, %0\n\t" "membar #Sync" - : "=r" (word) + : "=r" (byte) : "r" (addr), "i" (ASI_PL)); pci_poke_in_progress = 0; trapped = pci_poke_faulted; pci_poke_faulted = 0; - if(!trapped) { - switch(where & 3) { - case 0: - *value = word & 0xff; - break; - case 1: - *value = (word >> 8) & 0xff; - break; - case 2: - *value = (word >> 16) & 0xff; - break; - case 3: - *value = (word >> 24) & 0xff; - break; - }; - } + if(!trapped) + *value = byte; return PCIBIOS_SUCCESSFUL; } -int pcibios_read_config_word (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned short *value) +static int +pbm_read_config_word(struct linux_pbm_info *pbm, + unsigned char bus, unsigned char devfn, + unsigned char where, unsigned short *value) { - unsigned short *addr = (unsigned short *)pci_mkaddr(bus, device_fn, where); - unsigned int word, trapped; + unsigned short *addr = pci_mkaddr(pbm, bus, devfn, where); + unsigned int trapped; + unsigned short word; *value = 0xffff; - if(out_of_range(bus, device_fn)) + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (out_of_range(pbm, bus, devfn)) return PCIBIOS_SUCCESSFUL; + if (where & 0x01) { + printk("pcibios_read_config_word: misaligned reg [%x]\n", + where); + return PCIBIOS_SUCCESSFUL; + } + pci_poke_in_progress = 1; pci_poke_faulted = 0; __asm__ __volatile__("membar #Sync\n\t" - "lduwa [%1] %2, %0\n\t" + "lduha [%1] %2, %0\n\t" "membar #Sync" : "=r" (word) : "r" (addr), "i" (ASI_PL)); pci_poke_in_progress = 0; trapped = pci_poke_faulted; pci_poke_faulted = 0; - if(!trapped) { - switch(where & 3) { - case 0: - *value = word & 0xffff; - break; - case 2: - *value = (word >> 16) & 0xffff; - break; - default: - printk("pcibios_read_config_word: misaligned " - "reg [%x]\n", where); - break; - }; - } + if(!trapped) + *value = word; return PCIBIOS_SUCCESSFUL; } -int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned int *value) +static int +pbm_read_config_dword(struct linux_pbm_info *pbm, + unsigned char bus, unsigned char devfn, + unsigned char where, unsigned int *value) { - unsigned int *addr = (unsigned int *)pci_mkaddr(bus, device_fn, where); + unsigned int *addr = pci_mkaddr(pbm, bus, devfn, where); unsigned int word, trapped; *value = 0xffffffff; - if(out_of_range(bus, device_fn)) + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (out_of_range(pbm, bus, devfn)) + return PCIBIOS_SUCCESSFUL; + + if (where & 0x03) { + printk("pcibios_read_config_dword: misaligned reg [%x]\n", + where); return PCIBIOS_SUCCESSFUL; + } pci_poke_in_progress = 1; pci_poke_faulted = 0; @@ -1276,12 +1485,17 @@ int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn, return PCIBIOS_SUCCESSFUL; } -int pcibios_write_config_byte (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned char value) +static int +pbm_write_config_byte(struct linux_pbm_info *pbm, + unsigned char bus, unsigned char devfn, + unsigned char where, unsigned char value) { - unsigned char *addr = pci_mkaddr(bus, device_fn, where); + unsigned char *addr = pci_mkaddr(pbm, bus, devfn, where); - if(out_of_range(bus, device_fn)) + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (out_of_range(pbm, bus, devfn)) return PCIBIOS_SUCCESSFUL; pci_poke_in_progress = 1; @@ -1299,14 +1513,25 @@ int pcibios_write_config_byte (unsigned char bus, unsigned char device_fn, return PCIBIOS_SUCCESSFUL; } -int pcibios_write_config_word (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned short value) +static int +pbm_write_config_word(struct linux_pbm_info *pbm, + unsigned char bus, unsigned char devfn, + unsigned char where, unsigned short value) { - unsigned short *addr = (unsigned short *)pci_mkaddr(bus, device_fn, where); + unsigned short *addr = pci_mkaddr(pbm, bus, devfn, where); - if(out_of_range(bus, device_fn)) + if (!addr) return PCIBIOS_SUCCESSFUL; + if (out_of_range(pbm, bus, devfn)) + return PCIBIOS_SUCCESSFUL; + + if (where & 0x01) { + printk("pcibios_write_config_word: misaligned reg [%x]\n", + where); + return PCIBIOS_SUCCESSFUL; + } + pci_poke_in_progress = 1; __asm__ __volatile__("membar #Sync\n\t" "stha %0, [%1] %2\n\t" @@ -1317,14 +1542,25 @@ int pcibios_write_config_word (unsigned char bus, unsigned char device_fn, return PCIBIOS_SUCCESSFUL; } -int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned int value) +static int +pbm_write_config_dword(struct linux_pbm_info *pbm, + unsigned char bus, unsigned char devfn, + unsigned char where, unsigned int value) { - unsigned int *addr = (unsigned int *)pci_mkaddr(bus, device_fn, where); + unsigned int *addr = pci_mkaddr(pbm, bus, devfn, where); - if(out_of_range(bus, device_fn)) + if (!addr) return PCIBIOS_SUCCESSFUL; + if (out_of_range(pbm, bus, devfn)) + return PCIBIOS_SUCCESSFUL; + + if (where & 0x03) { + printk("pcibios_write_config_dword: misaligned reg [%x]\n", + where); + return PCIBIOS_SUCCESSFUL; + } + pci_poke_in_progress = 1; __asm__ __volatile__("membar #Sync\n\t" "stwa %0, [%1] %2\n\t" @@ -1335,6 +1571,42 @@ int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn, return PCIBIOS_SUCCESSFUL; } +int pcibios_read_config_byte (unsigned char bus, unsigned char devfn, + unsigned char where, unsigned char *value) +{ + return pbm_read_config_byte(bus2pbm[bus], bus, devfn, where, value); +} + +int pcibios_read_config_word (unsigned char bus, unsigned char devfn, + unsigned char where, unsigned short *value) +{ + return pbm_read_config_word(bus2pbm[bus], bus, devfn, where, value); +} + +int pcibios_read_config_dword (unsigned char bus, unsigned char devfn, + unsigned char where, unsigned int *value) +{ + return pbm_read_config_dword(bus2pbm[bus], bus, devfn, where, value); +} + +int pcibios_write_config_byte (unsigned char bus, unsigned char devfn, + unsigned char where, unsigned char value) +{ + return pbm_write_config_byte(bus2pbm[bus], bus, devfn, where, value); +} + +int pcibios_write_config_word (unsigned char bus, unsigned char devfn, + unsigned char where, unsigned short value) +{ + return pbm_write_config_word(bus2pbm[bus], bus, devfn, where, value); +} + +int pcibios_write_config_dword (unsigned char bus, unsigned char devfn, + unsigned char where, unsigned int value) +{ + return pbm_write_config_dword(bus2pbm[bus], bus, devfn, where, value); +} + asmlinkage int sys_pciconfig_read(unsigned long bus, unsigned long dfn, unsigned long off, @@ -1346,19 +1618,22 @@ asmlinkage int sys_pciconfig_read(unsigned long bus, unsigned int uint; int err = 0; + if(!suser()) + return -EPERM; + lock_kernel(); switch(len) { case 1: pcibios_read_config_byte(bus, dfn, off, &ubyte); - put_user(ubyte, buf); + put_user(ubyte, (unsigned char *)buf); break; case 2: pcibios_read_config_word(bus, dfn, off, &ushort); - put_user(ushort, buf); + put_user(ushort, (unsigned short *)buf); break; case 4: pcibios_read_config_dword(bus, dfn, off, &uint); - put_user(uint, buf); + put_user(uint, (unsigned int *)buf); break; default: @@ -1381,6 +1656,9 @@ asmlinkage int sys_pciconfig_write(unsigned long bus, unsigned int uint; int err = 0; + if(!suser()) + return -EPERM; + lock_kernel(); switch(len) { case 1: diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index 3df35ef14..9174e7e45 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c @@ -309,12 +309,14 @@ static inline void read_sunos_user(struct pt_regs *regs, unsigned long offset, } if(offset >= 16 && offset < 784) { offset -= 16; offset >>= 2; - pt_os_succ_return(regs, *(((unsigned long *)(&t->reg_window[0]))+offset), addr); + if (t->w_saved) + pt_os_succ_return(regs, *(((unsigned long *)(&t->reg_window[0]))+offset), addr); return; } if(offset >= 784 && offset < 832) { offset -= 784; offset >>= 2; - pt_os_succ_return(regs, *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset), addr); + if (t->w_saved) + pt_os_succ_return(regs, *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset), addr); return; } switch(offset) { @@ -399,12 +401,14 @@ static inline void write_sunos_user(struct pt_regs *regs, unsigned long offset, goto failure; if(offset >= 16 && offset < 784) { offset -= 16; offset >>= 2; - *(((unsigned long *)(&t->reg_window[0]))+offset) = value; + if (t->w_saved) + *(((unsigned long *)(&t->reg_window[0]))+offset) = value; goto success; } if(offset >= 784 && offset < 832) { offset -= 784; offset >>= 2; - *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset) = value; + if (t->w_saved) + *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset) = value; goto success; } switch(offset) { @@ -964,7 +968,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) addr = 1; case PTRACE_CONT: { /* restart after signal. */ - if (data > NSIG) { + if (data > _NSIG) { pt_error_return(regs, EIO); goto out; } @@ -1016,7 +1020,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) } case PTRACE_SUNDETACH: { /* detach a process that was attached. */ - if ((unsigned long) data > NSIG) { + if ((unsigned long) data > _NSIG) { pt_error_return(regs, EIO); goto out; } @@ -1063,10 +1067,7 @@ asmlinkage void syscall_trace(void) current->pid, current->exit_code); #endif if (current->exit_code) { - spin_lock_irq(¤t->sigmask_lock); - current->signal |= (1 << (current->exit_code - 1)); - spin_unlock_irq(¤t->sigmask_lock); + send_sig (current->exit_code, current, 1); + current->exit_code = 0; } - - current->exit_code = 0; } diff --git a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S index a3ac093f3..685182473 100644 --- a/arch/sparc64/kernel/rtrap.S +++ b/arch/sparc64/kernel/rtrap.S @@ -1,4 +1,4 @@ -/* $Id: rtrap.S,v 1.33 1997/08/21 09:13:22 davem Exp $ +/* $Id: rtrap.S,v 1.37 1997/12/11 15:14:54 jj Exp $ * rtrap.S: Preparing for return from trap on Sparc V9. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -55,11 +55,11 @@ rtrap: sethi %hi(bh_active), %l2 ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x0c0] %asi, %f48 1: membar #Sync ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x100], %fsr -rt_continue: ld [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0 +rt_continue: lduh [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0 ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1 ldx [%sp + PTREGS_OFF + PT_V9_G2], %g2 ldx [%sp + PTREGS_OFF + PT_V9_G3], %g3 - mov %g6, %l6 + mov %g6, %o5 ldx [%sp + PTREGS_OFF + PT_V9_G4], %g4 ldx [%sp + PTREGS_OFF + PT_V9_G5], %g5 ldx [%sp + PTREGS_OFF + PT_V9_G6], %g6 @@ -88,10 +88,10 @@ rt_continue: ld [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0 wrpr %o2, %g0, %tnpc mov PRIMARY_CONTEXT, %l7 brnz,pn %l3, kern_rtt - mov SECONDARY_CONTEXT, %l5 + mov SECONDARY_CONTEXT, %o4 stxa %l0, [%l7] ASI_DMMU - stxa %l0, [%l5] ASI_DMMU - flush %l6 + stxa %l0, [%o4] ASI_DMMU + flush %o5 rdpr %wstate, %l1 rdpr %otherwin, %l2 @@ -106,30 +106,25 @@ rt_continue: ld [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0 retry kern_rtt: restore retry -to_user: lduw [%g6 + AOFF_task_processor], %o0 - mov 1, %o1 - sethi %hi(need_resched), %l0 +to_user: sethi %hi(need_resched), %l0 ldx [%l0 + %lo(need_resched)], %l0 - sllx %o1, %o0, %o1 wrpr %l7, PSTATE_IE, %pstate - andcc %o1, %l0, %g0 - be,pt %xcc, check_signal - ldx [%g6 + AOFF_task_signal], %l0 + orcc %g0, %l0, %g0 + be,a,pt %xcc, check_signal + lduw [%g6 + AOFF_task_sigpending], %l0 call schedule nop - ldx [%g6 + AOFF_task_signal], %l0 - nop -check_signal: ldx [%g6 + AOFF_task_blocked], %o0 - ld [%sp + PTREGS_OFF + PT_V9_FPRS], %l2 - andncc %l0, %o0, %g0 - be,pt %xcc, check_user_wins - ldx [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2 + lduw [%g6 + AOFF_task_sigpending], %l0 +check_signal: ld [%sp + PTREGS_OFF + PT_V9_FPRS], %l2 + brz,a,pt %l0, check_user_wins + lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2 + clr %o0 mov %l5, %o2 mov %l6, %o3 call do_signal add %sp, STACK_BIAS + REGWIN_SZ, %o1 - ldx [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2 + lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2 clr %l6 check_user_wins:brz,pt %o2, 1f sethi %hi(TSTATE_PEF), %o3 @@ -142,7 +137,7 @@ check_user_wins:brz,pt %o2, 1f be,a,pt %icc, rt_continue andn %l1, %o3, %l1 ! If fprs.FEF is not set, disable tstate.PEF ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x108], %o3 - ld [%g6 + AOFF_task_tss + AOFF_thread_flags], %l2 + lduh [%g6 + AOFF_task_tss + AOFF_thread_flags], %l2 wr %g0, FPRS_FEF, %fprs wr %o3, 0, %gsr andcc %l2, SPARC_FLAG_USEDFPUL, %g0 diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c index 147c6e55d..932addbb4 100644 --- a/arch/sparc64/kernel/setup.c +++ b/arch/sparc64/kernel/setup.c @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.12 1997/08/28 02:23:19 ecd Exp $ +/* $Id: setup.c,v 1.18 1997/12/18 02:43:00 ecd Exp $ * linux/arch/sparc64/kernel/setup.c * * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) @@ -37,6 +37,10 @@ #include <asm/idprom.h> #include <asm/head.h> +#ifdef CONFIG_IP_PNP +#include <net/ipconfig.h> +#endif + struct screen_info screen_info = { 0, 0, /* orig-x, orig-y */ { 0, 0, }, /* unused */ @@ -236,20 +240,35 @@ extern int root_mountflags; char saved_command_line[256]; char reboot_command[256]; -#ifdef CONFIG_ROOT_NFS -extern char nfs_root_addrs[]; -#endif - unsigned long phys_base; static struct pt_regs fake_swapper_regs = { { 0, }, 0, 0, 0, 0 }; +#if 0 +#include <linux/console.h> + +static void prom_cons_write(struct console *con, const char *str, unsigned count) +{ + while (count--) + prom_printf("%c", *str++); +} + +static struct console prom_console = { + "PROM", prom_cons_write, 0, 0, 0, 0, 0, CON_PRINTBUFFER, 0, 0, 0 +}; +#endif + __initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p)) { + extern int serial_console; /* in console.c, of course */ unsigned long lowest_paddr; int total, i; +#if 0 + register_console(&prom_console); +#endif + /* Initialize PROM console and command line. */ *cmdline_p = prom_getbootargs(); strcpy(saved_command_line, *cmdline_p); @@ -330,62 +349,58 @@ __initfunc(void setup_arch(char **cmdline_p, init_task.mm->context = (unsigned long) NO_CONTEXT; init_task.tss.kregs = &fake_swapper_regs; -#ifdef CONFIG_ROOT_NFS - if (!*nfs_root_addrs) { +#ifdef CONFIG_IP_PNP + if (!ic_set_manually) { int chosen = prom_finddevice ("/chosen"); u32 cl, sv, gw; - char *p = nfs_root_addrs; cl = prom_getintdefault (chosen, "client-ip", 0); sv = prom_getintdefault (chosen, "server-ip", 0); gw = prom_getintdefault (chosen, "gateway-ip", 0); if (cl && sv) { - strcpy (p, in_ntoa (cl)); - p += strlen (p); - *p++ = ':'; - strcpy (p, in_ntoa (sv)); - p += strlen (p); - *p++ = ':'; - if (gw) { - strcpy (p, in_ntoa (gw)); - p += strlen (p); - } - strcpy (p, "::::none"); + ic_myaddr = cl; + ic_servaddr = sv; + if (gw) + ic_gateway = gw; + ic_bootp_flag = ic_rarp_flag = 0; } } #endif #ifdef CONFIG_SUN_SERIAL - *memory_start_p = sun_serial_setup(*memory_start_p); /* set this up ASAP */ -#endif - { - extern int serial_console; /* in console.c, of course */ -#if !CONFIG_SUN_SERIAL - serial_console = 0; -#else - switch (console_fb) { - case 0: /* Let's get our io devices from prom */ - { - int idev = prom_query_input_device(); - int odev = prom_query_output_device(); - if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) { - serial_console = 0; - } else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) { - serial_console = 1; - } else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) { - serial_console = 2; - } else { - prom_printf("Inconsistent console\n"); - prom_halt(); - } + switch (console_fb) { + case 0: /* Let's get our io devices from prom */ + { + int idev = prom_query_input_device(); + int odev = prom_query_output_device(); + if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) { + serial_console = 0; + } else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) { + serial_console = 1; + } else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) { + serial_console = 2; + } else { + prom_printf("Inconsistent console: " + "input %d, output %d\n", + idev, odev); + prom_halt(); } - break; - case 1: serial_console = 0; break; /* Force one of the framebuffers as console */ - case 2: serial_console = 1; break; /* Force ttya as console */ - case 3: serial_console = 2; break; /* Force ttyb as console */ } -#endif + break; + case 1: /* Force one of the framebuffers as console */ + serial_console = 0; + break; + case 2: /* Force ttya as console */ + serial_console = 1; + break; + case 3: /* Force ttyb as console */ + serial_console = 2; + break; } + *memory_start_p = sun_serial_setup(*memory_start_p); /* set this up ASAP */ +#else + serial_console = 0; +#endif } asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on) diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c index 87241f8e3..94bf90398 100644 --- a/arch/sparc64/kernel/signal.c +++ b/arch/sparc64/kernel/signal.c @@ -1,4 +1,4 @@ -/* $Id: signal.c,v 1.24 1997/09/02 20:53:03 davem Exp $ +/* $Id: signal.c,v 1.27 1997/12/15 15:04:44 jj Exp $ * arch/sparc64/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -26,15 +26,14 @@ #include <asm/fpumacro.h> #include <asm/uctx.h> #include <asm/smp_lock.h> +#include <asm/siginfo.h> -#define _S(nr) (1<<((nr)-1)) - -#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(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, +asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, unsigned long orig_o0, int ret_from_syscall); /* This turned off for production... */ @@ -61,8 +60,20 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs) if((pc | npc) & 3) goto do_sigsegv; if(regs->u_regs[UREG_I1]) { - __get_user(current->blocked, &ucp->uc_sigmask); - current->blocked &= _BLOCKABLE; + sigset_t set; + + if (_NSIG_WORDS == 1) { + if (__get_user(set.sig[0], &ucp->uc_sigmask.sig[0])) + goto do_sigsegv; + } else { + if (__copy_from_user(&set, &ucp->uc_sigmask, sizeof(sigset_t))) + goto do_sigsegv; + } + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); } regs->tpc = pc; regs->tnpc = npc; @@ -132,7 +143,11 @@ asmlinkage void sparc64_get_context(struct pt_regs *regs) regs->tpc = regs->tnpc; regs->tnpc += 4; - __put_user(current->blocked, &ucp->uc_sigmask); + if (_NSIG_WORDS == 1) + __put_user(current->blocked.sig[0], (unsigned long *)&ucp->uc_sigmask); + else + __copy_to_user(&ucp->uc_sigmask, ¤t->blocked, sizeof(sigset_t)); + __put_user(regs->tstate, &((*grp)[MC_TSTATE])); __put_user(regs->tpc, &((*grp)[MC_PC])); __put_user(regs->tnpc, &((*grp)[MC_NPC])); @@ -198,31 +213,45 @@ struct new_signal_frame { __siginfo_t info; __siginfo_fpu_t * fpu_save; unsigned int insns [2]; + unsigned long extramask[_NSIG_WORDS-1]; + __siginfo_fpu_t fpu_state; +}; + +struct rt_signal_frame { + struct sparc_stackf ss; + siginfo_t info; + struct pt_regs regs; + sigset_t mask; + __siginfo_fpu_t * fpu_save; + unsigned int insns [2]; __siginfo_fpu_t fpu_state; }; /* Align macros */ #define NF_ALIGNEDSZ (((sizeof(struct new_signal_frame) + 7) & (~7))) +#define RT_ALIGNEDSZ (((sizeof(struct rt_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) +asmlinkage void _sigpause_common(old_sigset_t set, struct pt_regs *regs) { - unsigned long mask; + sigset_t saveset; #ifdef CONFIG_SPARC32_COMPAT if (current->tss.flags & SPARC_FLAG_32BIT) { - extern asmlinkage void _sigpause32_common(unsigned int, + extern asmlinkage void _sigpause32_common(old_sigset_t32, struct pt_regs *); _sigpause32_common(set, regs); return; } #endif + set &= _BLOCKABLE; spin_lock_irq(¤t->sigmask_lock); - mask = current->blocked; - current->blocked = set & _BLOCKABLE; + saveset = current->blocked; + siginitset(¤t->blocked, set); + recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); regs->tpc = regs->tnpc; @@ -242,7 +271,7 @@ asmlinkage void _sigpause_common(unsigned int set, struct pt_regs *regs) */ regs->tstate |= (TSTATE_ICARRY|TSTATE_XCARRY); regs->u_regs[UREG_I0] = EINTR; - if (do_signal(mask, regs, 0, 0)) + if (do_signal(&saveset, regs, 0, 0)) return; } } @@ -257,6 +286,50 @@ asmlinkage void do_sigsuspend(struct pt_regs *regs) _sigpause_common(regs->u_regs[UREG_I0], regs); } +asmlinkage void do_rt_sigsuspend(sigset_t *uset, size_t sigsetsize, struct pt_regs *regs) +{ + sigset_t oldset, set; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) { + regs->tstate |= (TSTATE_ICARRY|TSTATE_XCARRY); + regs->u_regs[UREG_I0] = EINVAL; + return; + } + if (copy_from_user(&set, uset, sizeof(set))) { + regs->tstate |= (TSTATE_ICARRY|TSTATE_XCARRY); + regs->u_regs[UREG_I0] = EFAULT; + return; + } + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + oldset = current->blocked; + current->blocked = set; + recalc_sigpending(current); + 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(&oldset, regs, 0, 0)) + return; + } +} static inline void restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu) @@ -282,47 +355,100 @@ void do_sigreturn(struct pt_regs *regs) struct new_signal_frame *sf; unsigned long tpc, tnpc, tstate; __siginfo_fpu_t *fpu_save; - unsigned long mask; + sigset_t set; -#ifdef CONFIG_SPARC32_COMPAT - if (current->tss.flags & SPARC_FLAG_32BIT) { - extern asmlinkage void do_sigreturn32(struct pt_regs *); - return do_sigreturn32(regs); - } -#endif synchronize_user_stack (); sf = (struct new_signal_frame *) (regs->u_regs [UREG_FP] + STACK_BIAS); /* 1. Make sure we are not getting garbage from the user */ - if (verify_area (VERIFY_READ, sf, sizeof (*sf))) + if (((unsigned long) sf) & 3) goto segv; + if (get_user(tpc, &sf->info.si_regs.tpc) || + __get_user(tnpc, &sf->info.si_regs.tnpc) || + ((tpc | tnpc) & 3)) + goto segv; + + regs->tpc = tpc; + regs->tnpc = tnpc; + + /* 2. Restore the state */ + if (__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))) + goto segv; + + /* User can only change condition codes in %tstate. */ + regs->tstate &= ~(TSTATE_ICC); + regs->tstate |= (tstate & TSTATE_ICC); + + if (__get_user(fpu_save, &sf->fpu_save)) + goto segv; + if (fpu_save) + restore_fpu_state(regs, &sf->fpu_state); + if (__get_user(set.sig[0], &sf->info.si_mask) || + (_NSIG_WORDS > 1 && + __copy_from_user(&set.sig[1], &sf->extramask, + sizeof(sf->extramask)))) + goto segv; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + return; +segv: + lock_kernel(); + do_exit(SIGSEGV); +} + +void do_rt_sigreturn(struct pt_regs *regs) +{ + struct rt_signal_frame *sf; + unsigned long tpc, tnpc, tstate; + __siginfo_fpu_t *fpu_save; + sigset_t set; + + synchronize_user_stack (); + sf = (struct rt_signal_frame *) + (regs->u_regs [UREG_FP] + STACK_BIAS); + + /* 1. Make sure we are not getting garbage from the user */ 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) + if (get_user(tpc, &sf->regs.tpc) || + __get_user(tnpc, &sf->regs.tnpc) || + ((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)); + if (__get_user(regs->y, &sf->regs.y) || + __get_user(tstate, &sf->regs.tstate) || + copy_from_user(regs->u_regs, sf->regs.u_regs, sizeof(regs->u_regs))) + goto segv; /* User can only change condition codes in %tstate. */ regs->tstate &= ~(TSTATE_ICC); regs->tstate |= (tstate & TSTATE_ICC); - __get_user(fpu_save, &sf->fpu_save); + if (__get_user(fpu_save, &sf->fpu_save)) + goto segv; if (fpu_save) restore_fpu_state(regs, &sf->fpu_state); - __get_user(mask, &sf->info.si_mask); - current->blocked = mask & _BLOCKABLE; + + if (__copy_from_user(&set, &sf->mask, sizeof(sigset_t))) + goto segv; + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); return; segv: lock_kernel(); @@ -364,8 +490,8 @@ save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu) } static inline void -new_setup_frame(struct sigaction *sa, struct pt_regs *regs, - int signo, unsigned long oldmask) +new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs, + int signo, sigset_t *oldset) { struct new_signal_frame *sf; int sigframe_size; @@ -398,33 +524,122 @@ new_setup_frame(struct sigaction *sa, struct pt_regs *regs, __put_user(0, &sf->fpu_save); } - __put_user(oldmask, &sf->info.si_mask); + __put_user(oldset->sig[0], &sf->info.si_mask); + if (_NSIG_WORDS > 1) + __copy_to_user(sf->extramask, &oldset->sig[1], sizeof(sf->extramask)); copy_in_user((u64 *)sf, (u64 *)(regs->u_regs[UREG_FP]+STACK_BIAS), sizeof(struct reg_window)); - /* 3. return to kernel instructions */ - __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */ - __put_user(0x91d02011, &sf->insns[1]); /* t 0x11 */ + /* 3. signal handler back-trampoline and parameters */ + regs->u_regs[UREG_FP] = ((unsigned long) sf) - STACK_BIAS; + regs->u_regs[UREG_I0] = signo; + regs->u_regs[UREG_I1] = (unsigned long) &sf->info; + + /* 5. signal handler */ + regs->tpc = (unsigned long) ka->sa.sa_handler; + regs->tnpc = (regs->tpc + 4); + + /* 4. return to kernel instructions */ + if (ka->ka_restorer) + regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer; + else { + /* Flush instruction space. */ + unsigned long address = ((unsigned long)&(sf->insns[0])); + pgd_t *pgdp = pgd_offset(current->mm, address); + pmd_t *pmdp = pmd_offset(pgdp, address); + pte_t *ptep = pte_offset(pmdp, address); + + regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2); + + __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */ + __put_user(0x91d0206d, &sf->insns[1]); /* t 0x6d */ + + if(pte_present(*ptep)) { + unsigned long page = pte_page(*ptep); + + __asm__ __volatile__(" + membar #StoreStore + flush %0 + %1" + : : "r" (page), "r" (address & (PAGE_SIZE - 1)) + : "memory"); + } + } + return; + +sigill: + lock_kernel(); + do_exit(SIGILL); +} + +static inline void +setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, + int signo, sigset_t *oldset, siginfo_t *info) +{ + struct rt_signal_frame *sf; + int sigframe_size; + + /* 1. Make sure everything is clean */ + synchronize_user_stack(); + sigframe_size = RT_ALIGNEDSZ; + if (!(current->tss.flags & SPARC_FLAG_USEDFPU)) + sigframe_size -= sizeof(__siginfo_fpu_t); - /* 4. signal handler back-trampoline and parameters */ + sf = (struct rt_signal_frame *) + (regs->u_regs[UREG_FP] + STACK_BIAS - sigframe_size); + + if (invalid_frame_pointer (sf, sigframe_size)) + goto sigill; + + if (current->tss.w_saved != 0) { + printk ("%s[%d]: Invalid user stack frame for " + "signal delivery.\n", current->comm, current->pid); + goto sigill; + } + + /* 2. Save the current process state */ + copy_to_user(&sf->regs, regs, sizeof (*regs)); + + if (current->tss.flags & SPARC_FLAG_USEDFPU) { + save_fpu_state(regs, &sf->fpu_state); + __put_user((u64)&sf->fpu_state, &sf->fpu_save); + } else { + __put_user(0, &sf->fpu_save); + } + + copy_to_user(&sf->mask, oldset, sizeof(sigset_t)); + + copy_in_user((u64 *)sf, + (u64 *)(regs->u_regs[UREG_FP]+STACK_BIAS), + sizeof(struct reg_window)); + + copy_to_user(&sf->info, info, sizeof(siginfo_t)); + + /* 3. signal handler back-trampoline and parameters */ regs->u_regs[UREG_FP] = ((unsigned long) sf) - STACK_BIAS; 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->tpc = (unsigned long) ka->sa.sa_handler; regs->tnpc = (regs->tpc + 4); - /* Flush instruction space. */ - { + /* 4. return to kernel instructions */ + if (ka->ka_restorer) + regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer; + else { + /* Flush instruction space. */ unsigned long address = ((unsigned long)&(sf->insns[0])); pgd_t *pgdp = pgd_offset(current->mm, address); pmd_t *pmdp = pmd_offset(pgdp, address); pte_t *ptep = pte_offset(pmdp, address); + regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2); + + __put_user(0x82102065, &sf->insns[0]); /* mov __NR_rt_sigreturn, %g1 */ + __put_user(0x91d0206d, &sf->insns[1]); /* t 0x6d */ + if(pte_present(*ptep)) { unsigned long page = pte_page(*ptep); @@ -442,15 +657,21 @@ sigill: do_exit(SIGILL); } -static inline void handle_signal(unsigned long signr, struct sigaction *sa, - unsigned long oldmask, struct pt_regs *regs) +static inline void handle_signal(unsigned long signr, struct k_sigaction *ka, + siginfo_t *info, + sigset_t *oldset, 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)) { + if(ka->sa.sa_flags & SA_SIGINFO) + setup_rt_frame(ka, regs, signr, oldset, info); + else + new_setup_frame(ka, regs, signr, oldset); + if(ka->sa.sa_flags & SA_ONESHOT) + ka->sa.sa_handler = SIG_DFL; + if(!(ka->sa.sa_flags & SA_NOMASK)) { spin_lock_irq(¤t->sigmask_lock); - current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE; + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + sigaddset(¤t->blocked,signr); + recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); } } @@ -479,28 +700,30 @@ static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs, * 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) +asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, + unsigned long orig_i0, int restart_syscall) { - unsigned long signr, mask = ~current->blocked; - struct sigaction *sa; + unsigned long signr; + siginfo_t info; + struct k_sigaction *ka; + + if (!oldset) + oldset = ¤t->blocked; #ifdef CONFIG_SPARC32_COMPAT if (current->tss.flags & SPARC_FLAG_32BIT) { - extern asmlinkage int do_signal32(unsigned long, struct pt_regs *, + extern asmlinkage int do_signal32(sigset_t *, struct pt_regs *, unsigned long, int); - return do_signal32(oldmask, regs, orig_i0, restart_syscall); + return do_signal32(oldset, regs, orig_i0, restart_syscall); } #endif - while ((signr = current->signal & mask) != 0) { - signr = ffz(~signr); - + for (;;) { spin_lock_irq(¤t->sigmask_lock); - current->signal &= ~(1 << signr); + signr = dequeue_signal(¤t->blocked, &info); spin_unlock_irq(¤t->sigmask_lock); + + if (!signr) break; - sa = current->sig->action + signr; - signr++; if ((current->flags & PF_PTRACED) && signr != SIGKILL) { current->exit_code = signr; current->state = TASK_STOPPED; @@ -511,15 +734,26 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs, current->exit_code = 0; if (signr == SIGSTOP) continue; - if (_S(signr) & current->blocked) { - spin_lock_irq(¤t->sigmask_lock); - current->signal |= _S(signr); - spin_unlock_irq(¤t->sigmask_lock); + + /* Update the siginfo structure. Is this good? */ + if (signr != info.si_signo) { + info.si_signo = signr; + info.si_errno = 0; + info.si_code = SI_USER; + info.si_pid = current->p_pptr->pid; + info.si_uid = current->p_pptr->uid; + } + + /* If the (new) signal is now blocked, requeue it. */ + if (sigismember(¤t->blocked, signr)) { + send_sig_info(signr, &info, current); continue; } - sa = current->sig->action + signr - 1; } - if(sa->sa_handler == SIG_IGN) { + + ka = ¤t->sig->action[signr-1]; + + if(ka->sa.sa_handler == SIG_IGN) { if(signr != SIGCHLD) continue; @@ -532,7 +766,9 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs, ; continue; } - if(sa->sa_handler == SIG_DFL) { + if(ka->sa.sa_handler == SIG_DFL) { + unsigned long exit_code = signr; + if(current->pid == 1) continue; switch(signr) { @@ -548,7 +784,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs, continue; current->state = TASK_STOPPED; current->exit_code = signr; - if(!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags & + if(!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP)) notify_parent(current, SIGCHLD); schedule(); @@ -559,7 +795,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs, if(current->binfmt && current->binfmt->core_dump) { lock_kernel(); if(current->binfmt->core_dump(signr, regs)) - signr |= 0x80; + exit_code |= 0x80; unlock_kernel(); } #ifdef DEBUG_SIGNALS @@ -569,20 +805,16 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs, #endif /* fall through */ default: - spin_lock_irq(¤t->sigmask_lock); - current->signal |= _S(signr & 0x7f); - spin_unlock_irq(¤t->sigmask_lock); - - current->flags |= PF_SIGNALED; - lock_kernel(); - do_exit(signr); - unlock_kernel(); + sigaddset(¤t->signal, signr); + current->flags |= PF_SIGNALED; + do_exit(exit_code); + /* NOT REACHED */ } } if(restart_syscall) - syscall_restart(orig_i0, regs, sa); - handle_signal(signr, sa, oldmask, regs); + syscall_restart(orig_i0, regs, &ka->sa); + handle_signal(signr, ka, &info, oldset, regs); return 1; } if(restart_syscall && diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c index 16cec2a72..8ca15c80b 100644 --- a/arch/sparc64/kernel/signal32.c +++ b/arch/sparc64/kernel/signal32.c @@ -1,4 +1,4 @@ -/* $Id: signal32.c,v 1.30 1997/08/29 15:51:33 jj Exp $ +/* $Id: signal32.c,v 1.34 1997/12/15 15:04:49 jj Exp $ * arch/sparc64/kernel/signal32.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -26,14 +26,12 @@ #include <asm/fpumacro.h> #include <asm/smp_lock.h> -#define _S(nr) (1<<((nr)-1)) - -#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr, int options, unsigned long *ru); -asmlinkage int do_signal32(unsigned long oldmask, struct pt_regs * regs, +asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs *regs, unsigned long orig_o0, int ret_from_syscall); /* This turned off for production... */ @@ -60,6 +58,7 @@ struct signal_sframe32 { /* struct sigcontext32 * */ u32 sig_scptr; int sig_address; struct sigcontext32 sig_context; + unsigned extramask[_NSIG_WORDS32 - 1]; }; /* @@ -72,24 +71,89 @@ struct new_signal_frame32 { __siginfo32_t info; /* __siginfo_fpu32_t * */ u32 fpu_save; unsigned int insns [2]; + unsigned extramask[_NSIG_WORDS32 - 1]; + __siginfo_fpu_t fpu_state; +}; + +struct rt_signal_frame32 { + struct sparc_stackf32 ss; + siginfo_t32 info; + struct pt_regs32 regs; + sigset_t32 mask; + /* __siginfo_fpu32_t * */ u32 fpu_save; + unsigned int insns [2]; __siginfo_fpu_t fpu_state; }; /* Align macros */ #define SF_ALIGNEDSZ (((sizeof(struct signal_sframe32) + 7) & (~7))) #define NF_ALIGNEDSZ (((sizeof(struct new_signal_frame32) + 7) & (~7))) +#define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame32) + 7) & (~7))) /* * atomically swap in the new signal mask, and wait for a signal. * This is really tricky on the Sparc, watch out... */ -asmlinkage void _sigpause32_common(unsigned int set, struct pt_regs *regs) +asmlinkage void _sigpause32_common(old_sigset_t32 set, struct pt_regs *regs) { - unsigned int mask; + sigset_t saveset; + + set &= _BLOCKABLE; + spin_lock_irq(¤t->sigmask_lock); + saveset = current->blocked; + siginitset(¤t->blocked, set); + recalc_sigpending(current); + 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; + regs->u_regs[UREG_I0] = EINTR; + if (do_signal32(&saveset, regs, 0, 0)) + return; + } +} +asmlinkage void do_rt_sigsuspend32(u32 uset, size_t sigsetsize, struct pt_regs *regs) +{ + sigset_t oldset, set; + sigset_t32 set32; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (((__kernel_size_t32)sigsetsize) != sizeof(sigset_t)) { + regs->tstate |= TSTATE_ICARRY; + regs->u_regs[UREG_I0] = EINVAL; + return; + } + if (copy_from_user(&set32, (void *)(long)uset, sizeof(set32))) { + regs->tstate |= TSTATE_ICARRY; + regs->u_regs[UREG_I0] = EFAULT; + return; + } + switch (_NSIG_WORDS) { + case 4: set.sig[3] = set32.sig[6] + (((long)set32.sig[7]) << 32); + case 3: set.sig[2] = set32.sig[4] + (((long)set32.sig[5]) << 32); + case 2: set.sig[1] = set32.sig[2] + (((long)set32.sig[3]) << 32); + case 1: set.sig[0] = set32.sig[0] + (((long)set32.sig[1]) << 32); + } + sigdelsetmask(&set, ~_BLOCKABLE); spin_lock_irq(¤t->sigmask_lock); - mask = current->blocked; - current->blocked = set & _BLOCKABLE; + oldset = current->blocked; + current->blocked = set; + recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); regs->tpc = regs->tnpc; @@ -109,7 +173,7 @@ asmlinkage void _sigpause32_common(unsigned int set, struct pt_regs *regs) */ regs->tstate |= TSTATE_ICARRY; regs->u_regs[UREG_I0] = EINTR; - if (do_signal32(mask, regs, 0, 0)) + if (do_signal32(&oldset, regs, 0, 0)) return; } } @@ -134,7 +198,9 @@ void do_new_sigreturn32(struct pt_regs *regs) { struct new_signal_frame32 *sf; unsigned int psr; - unsigned pc, npc, fpu_save, mask; + unsigned pc, npc, fpu_save; + sigset_t set; + unsigned seta[_NSIG_WORDS32]; regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL; sf = (struct new_signal_frame32 *) regs->u_regs [UREG_FP]; @@ -177,16 +243,23 @@ void do_new_sigreturn32(struct pt_regs *regs) regs->tstate &= ~(TSTATE_ICC); regs->tstate |= psr_to_tstate_icc(psr); -#if 0 - if (psr & PSR_EF) - regs->tstate |= TSTATE_PEF; -#endif - __get_user(fpu_save, &sf->fpu_save); if (fpu_save) restore_fpu_state32(regs, &sf->fpu_state); - __get_user(mask, &sf->info.si_mask); - current->blocked = mask & _BLOCKABLE; + if (__get_user(seta[0], &sf->info.si_mask) || + copy_from_user(seta+1, &sf->extramask, (_NSIG_WORDS32 - 1) * sizeof(unsigned))) + goto segv; + switch (_NSIG_WORDS) { + case 4: set.sig[3] = seta[6] + (((long)seta[7]) << 32); + case 3: set.sig[2] = seta[4] + (((long)seta[5]) << 32); + case 2: set.sig[1] = seta[2] + (((long)seta[3]) << 32); + case 1: set.sig[0] = seta[0] + (((long)seta[1]) << 32); + } + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); return; segv: lock_kernel(); @@ -197,7 +270,8 @@ asmlinkage void do_sigreturn32(struct pt_regs *regs) { struct sigcontext32 *scptr; unsigned pc, npc, psr; - unsigned long mask; + sigset_t set; + unsigned seta[_NSIG_WORDS32]; synchronize_user_stack(); if (current->tss.new_signal) @@ -216,8 +290,22 @@ asmlinkage void do_sigreturn32(struct pt_regs *regs) if((pc | npc) & 3) goto segv; /* Nice try. */ - __get_user(mask, &scptr->sigc_mask); - current->blocked = (mask & _BLOCKABLE); + if (__get_user(seta[0], &scptr->sigc_mask) || + /* Note that scptr + 1 points to extramask */ + copy_from_user(seta+1, scptr + 1, (_NSIG_WORDS32 - 1) * sizeof(unsigned))) + goto segv; + switch (_NSIG_WORDS) { + case 4: set.sig[3] = seta[6] + (((long)seta[7]) << 32); + case 3: set.sig[2] = seta[4] + (((long)seta[5]) << 32); + case 2: set.sig[1] = seta[2] + (((long)seta[3]) << 32); + case 1: set.sig[0] = seta[0] + (((long)seta[1]) << 32); + } + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + __get_user(current->tss.sstk_info.cur_status, &scptr->sigc_onstack); current->tss.sstk_info.cur_status &= 1; regs->tpc = pc; @@ -236,6 +324,78 @@ segv: do_exit (SIGSEGV); } +asmlinkage void do_rt_sigreturn32(struct pt_regs *regs) +{ + struct rt_signal_frame32 *sf; + unsigned int psr; + unsigned pc, npc, fpu_save; + sigset_t set; + sigset_t32 seta; + + synchronize_user_stack(); + regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL; + sf = (struct rt_signal_frame32 *) regs->u_regs [UREG_FP]; + + /* 1. Make sure we are not getting garbage from the user */ + if (verify_area (VERIFY_READ, sf, sizeof (*sf)) || + (((unsigned long) sf) & 3)) + goto segv; + + get_user(pc, &sf->regs.pc); + __get_user(npc, &sf->regs.npc); + + if ((pc | npc) & 3) + goto segv; + + regs->tpc = pc; + regs->tnpc = npc; + + /* 2. Restore the state */ + __get_user(regs->y, &sf->regs.y); + __get_user(psr, &sf->regs.psr); + + __get_user(regs->u_regs[UREG_G1], &sf->regs.u_regs[UREG_G1]); + __get_user(regs->u_regs[UREG_G2], &sf->regs.u_regs[UREG_G2]); + __get_user(regs->u_regs[UREG_G3], &sf->regs.u_regs[UREG_G3]); + __get_user(regs->u_regs[UREG_G4], &sf->regs.u_regs[UREG_G4]); + __get_user(regs->u_regs[UREG_G5], &sf->regs.u_regs[UREG_G5]); + __get_user(regs->u_regs[UREG_G6], &sf->regs.u_regs[UREG_G6]); + __get_user(regs->u_regs[UREG_G7], &sf->regs.u_regs[UREG_G7]); + __get_user(regs->u_regs[UREG_I0], &sf->regs.u_regs[UREG_I0]); + __get_user(regs->u_regs[UREG_I1], &sf->regs.u_regs[UREG_I1]); + __get_user(regs->u_regs[UREG_I2], &sf->regs.u_regs[UREG_I2]); + __get_user(regs->u_regs[UREG_I3], &sf->regs.u_regs[UREG_I3]); + __get_user(regs->u_regs[UREG_I4], &sf->regs.u_regs[UREG_I4]); + __get_user(regs->u_regs[UREG_I5], &sf->regs.u_regs[UREG_I5]); + __get_user(regs->u_regs[UREG_I6], &sf->regs.u_regs[UREG_I6]); + __get_user(regs->u_regs[UREG_I7], &sf->regs.u_regs[UREG_I7]); + + /* User can only change condition codes in %tstate. */ + regs->tstate &= ~(TSTATE_ICC); + regs->tstate |= psr_to_tstate_icc(psr); + + __get_user(fpu_save, &sf->fpu_save); + if (fpu_save) + restore_fpu_state32(regs, &sf->fpu_state); + if (copy_from_user(&seta, &sf->mask, sizeof(sigset_t32))) + goto segv; + switch (_NSIG_WORDS) { + case 4: set.sig[3] = seta.sig[6] + (((long)seta.sig[7]) << 32); + case 3: set.sig[2] = seta.sig[4] + (((long)seta.sig[5]) << 32); + case 2: set.sig[1] = seta.sig[2] + (((long)seta.sig[3]) << 32); + case 1: set.sig[0] = seta.sig[0] + (((long)seta.sig[1]) << 32); + } + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + return; +segv: + lock_kernel(); + do_exit(SIGSEGV); +} + /* Checks if the fp is valid */ static int invalid_frame_pointer(void *fp, int fplen) { @@ -246,10 +406,12 @@ static int invalid_frame_pointer(void *fp, int fplen) static void setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, - struct pt_regs *regs, int signr, unsigned long oldmask) + struct pt_regs *regs, int signr, sigset_t *oldset) { struct signal_sframe32 *sframep; struct sigcontext32 *sc; + unsigned seta[_NSIG_WORDS32]; + #if 0 int window = 0; #endif @@ -278,7 +440,19 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, /* We've already made sure frame pointer isn't in kernel space... */ __put_user(old_status, &sc->sigc_onstack); - __put_user(oldmask, &sc->sigc_mask); + + switch (_NSIG_WORDS) { + case 4: seta[7] = (oldset->sig[3] >> 32); + seta[6] = oldset->sig[3]; + case 3: seta[5] = (oldset->sig[2] >> 32); + seta[4] = oldset->sig[2]; + case 2: seta[3] = (oldset->sig[1] >> 32); + seta[2] = oldset->sig[1]; + case 1: seta[1] = (oldset->sig[0] >> 32); + seta[0] = oldset->sig[0]; + } + __put_user(seta[0], &sc->sigc_mask); + __copy_to_user(sframep->extramask, seta + 1, (_NSIG_WORDS32 - 1) * sizeof(unsigned)); __put_user(regs->u_regs[UREG_FP], &sc->sigc_sp); __put_user(pc, &sc->sigc_pc); __put_user(npc, &sc->sigc_npc); @@ -346,13 +520,14 @@ static inline void save_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t *fpu) regs->tstate &= ~TSTATE_PEF; } -static inline void new_setup_frame32(struct sigaction *sa, struct pt_regs *regs, - int signo, unsigned long oldmask) +static inline void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *regs, + int signo, sigset_t *oldset) { struct new_signal_frame32 *sf; int sigframe_size; u32 psr; int i; + unsigned seta[_NSIG_WORDS32]; /* 1. Make sure everything is clean */ synchronize_user_stack(); @@ -397,33 +572,47 @@ static inline void new_setup_frame32(struct sigaction *sa, struct pt_regs *regs, __put_user(0, &sf->fpu_save); } - __put_user(oldmask, &sf->info.si_mask); + switch (_NSIG_WORDS) { + case 4: seta[7] = (oldset->sig[3] >> 32); + seta[6] = oldset->sig[3]; + case 3: seta[5] = (oldset->sig[2] >> 32); + seta[4] = oldset->sig[2]; + case 2: seta[3] = (oldset->sig[1] >> 32); + seta[2] = oldset->sig[1]; + case 1: seta[1] = (oldset->sig[0] >> 32); + seta[0] = oldset->sig[0]; + } + __put_user(seta[0], &sf->info.si_mask); + __copy_to_user(sf->extramask, seta + 1, (_NSIG_WORDS32 - 1) * sizeof(unsigned)); copy_in_user((u32 *)sf, (u32 *)(regs->u_regs[UREG_FP]), sizeof(struct reg_window32)); - /* 3. return to kernel instructions */ - __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */ - __put_user(0x91d02010, &sf->insns[1]); /* t 0x10 */ - - /* 4. signal handler back-trampoline and parameters */ + /* 3. signal handler back-trampoline and parameters */ regs->u_regs[UREG_FP] = (unsigned long) sf; regs->u_regs[UREG_I0] = signo; regs->u_regs[UREG_I1] = (unsigned long) &sf->info; - regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2); - /* 5. signal handler */ - regs->tpc = (unsigned long) sa->sa_handler; + /* 4. signal handler */ + regs->tpc = (unsigned long) ka->sa.sa_handler; regs->tnpc = (regs->tpc + 4); - /* Flush instruction space. */ - { + /* 5. return to kernel instructions */ + if (ka->ka_restorer) + regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer; + else { + /* Flush instruction space. */ unsigned long address = ((unsigned long)&(sf->insns[0])); pgd_t *pgdp = pgd_offset(current->mm, address); pmd_t *pmdp = pmd_offset(pgdp, address); pte_t *ptep = pte_offset(pmdp, address); + regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2); + + __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */ + __put_user(0x91d02010, &sf->insns[1]); /* t 0x10 */ + if(pte_present(*ptep)) { unsigned long page = pte_page(*ptep); @@ -444,7 +633,7 @@ sigill: /* Setup a Solaris stack frame */ static inline void setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, - struct pt_regs *regs, int signr, unsigned long oldmask) + struct pt_regs *regs, int signr, sigset_t *oldset) { svr4_signal_frame_t *sfp; svr4_gregset_t *gr; @@ -452,6 +641,7 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, svr4_mcontext_t *mc; svr4_gwindows_t *gw; svr4_ucontext_t *uc; + svr4_sigset_t setv; #if 0 int window = 0; #endif @@ -485,8 +675,15 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, * sc->sigc_onstack = old_status; * anyways, it does not look like it is used for anything at all. */ - __put_user(oldmask, &uc->sigmask.sigbits [0]); - + setv.sigbits[0] = oldset->sig[0]; + setv.sigbits[1] = (oldset->sig[0] >> 32); + if (_NSIG_WORDS >= 2) { + setv.sigbits[2] = oldset->sig[1]; + setv.sigbits[3] = (oldset->sig[1] >> 32); + __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t)); + } else + __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned)); + /* Store registers */ __put_user(regs->tpc, &((*gr) [SVR4_PC])); __put_user(regs->tnpc, &((*gr) [SVR4_NPC])); @@ -572,11 +769,12 @@ svr4_getcontext(svr4_ucontext_t *uc, struct pt_regs *regs) { svr4_gregset_t *gr; svr4_mcontext_t *mc; + svr4_sigset_t setv; int i; synchronize_user_stack(); if (current->tss.w_saved){ - printk ("Uh oh, w_saved is not zero (%ld)\n", current->tss.w_saved); + printk ("Uh oh, w_saved is not zero (%d)\n", (int) current->tss.w_saved); lock_kernel(); do_exit (SIGSEGV); } @@ -586,9 +784,15 @@ svr4_getcontext(svr4_ucontext_t *uc, struct pt_regs *regs) /* Setup convenience variables */ mc = &uc->mcontext; gr = &mc->greg; - - /* We only have < 32 signals, fill the first slot only */ - __put_user(current->blocked, &uc->sigmask.sigbits [0]); + + setv.sigbits[0] = current->blocked.sig[0]; + setv.sigbits[1] = (current->blocked.sig[0] >> 32); + if (_NSIG_WORDS >= 2) { + setv.sigbits[2] = current->blocked.sig[1]; + setv.sigbits[3] = (current->blocked.sig[1] >> 32); + __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t)); + } else + __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned)); /* Store registers */ __put_user(regs->tpc, &uc->mcontext.greg [SVR4_PC]); @@ -622,6 +826,8 @@ asmlinkage int svr4_setcontext(svr4_ucontext_t *c, struct pt_regs *regs) struct thread_struct *tp = ¤t->tss; svr4_gregset_t *gr; u32 pc, npc, psr; + sigset_t set; + svr4_sigset_t setv; int i; /* Fixme: restore windows, or is this already taken care of in @@ -630,7 +836,7 @@ asmlinkage int svr4_setcontext(svr4_ucontext_t *c, struct pt_regs *regs) flush_user_windows(); if (tp->w_saved){ - printk ("Uh oh, w_saved is: 0x%lx\n", tp->w_saved); + printk ("Uh oh, w_saved is: 0x%x\n", tp->w_saved); goto sigsegv; } if (((unsigned long) c) & 3){ @@ -654,8 +860,16 @@ asmlinkage int svr4_setcontext(svr4_ucontext_t *c, struct pt_regs *regs) /* Retrieve information from passed ucontext */ /* note that nPC is ored a 1, this is used to inform entry.S */ /* that we don't want it to mess with our PC and nPC */ - __get_user(current->blocked, &c->sigmask.sigbits [0]); - current->blocked &= _BLOCKABLE; + if (copy_from_user (&setv, &c->sigmask, sizeof(svr4_sigset_t))) + goto sigsegv; + set.sig[0] = setv.sigbits[0] | (((long)setv.sigbits[1]) << 32); + if (_NSIG_WORDS >= 2) + set.sig[1] = setv.sigbits[2] | (((long)setv.sigbits[3]) << 32); + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); regs->tpc = pc; regs->tnpc = npc | 1; __get_user(regs->y, &((*gr) [SVR4_Y])); @@ -678,23 +892,137 @@ sigsegv: do_exit(SIGSEGV); } -static inline void handle_signal32(unsigned long signr, struct sigaction *sa, - unsigned long oldmask, struct pt_regs *regs, +static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs, + unsigned long signr, sigset_t *oldset, + siginfo_t *info) +{ + struct rt_signal_frame32 *sf; + int sigframe_size; + u32 psr; + int i; + sigset_t32 seta; + + /* 1. Make sure everything is clean */ + synchronize_user_stack(); + sigframe_size = RT_ALIGNEDSZ; + if (!(current->tss.flags & SPARC_FLAG_USEDFPU)) + sigframe_size -= sizeof(__siginfo_fpu_t); + + regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL; + sf = (struct rt_signal_frame32 *)(regs->u_regs[UREG_FP] - sigframe_size); + + if (invalid_frame_pointer (sf, sigframe_size)) { +#ifdef DEBUG_SIGNALS + printk("rt_setup_frame32(%s:%d): invalid_frame_pointer(%p, %d)\n", + current->comm, current->pid, sf, sigframe_size); +#endif + goto sigill; + } + + if (current->tss.w_saved != 0) { +#ifdef DEBUG_SIGNALS + printk ("%s[%d]: Invalid user stack frame for " + "signal delivery.\n", current->comm, current->pid); +#endif + goto sigill; + } + + /* 2. Save the current process state */ + put_user(regs->tpc, &sf->regs.pc); + __put_user(regs->tnpc, &sf->regs.npc); + __put_user(regs->y, &sf->regs.y); + psr = tstate_to_psr (regs->tstate); + if(current->tss.flags & SPARC_FLAG_USEDFPU) + psr |= PSR_EF; + __put_user(psr, &sf->regs.psr); + for (i = 0; i < 16; i++) + __put_user(regs->u_regs[i], &sf->regs.u_regs[i]); + + if (psr & PSR_EF) { + save_fpu_state32(regs, &sf->fpu_state); + __put_user((u64)&sf->fpu_state, &sf->fpu_save); + } else { + __put_user(0, &sf->fpu_save); + } + + switch (_NSIG_WORDS) { + case 4: seta.sig[7] = (oldset->sig[3] >> 32); + seta.sig[6] = oldset->sig[3]; + case 3: seta.sig[5] = (oldset->sig[2] >> 32); + seta.sig[4] = oldset->sig[2]; + case 2: seta.sig[3] = (oldset->sig[1] >> 32); + seta.sig[2] = oldset->sig[1]; + case 1: seta.sig[1] = (oldset->sig[0] >> 32); + seta.sig[0] = oldset->sig[0]; + } + __copy_to_user(&sf->mask, &seta, sizeof(sigset_t)); + + copy_in_user((u32 *)sf, + (u32 *)(regs->u_regs[UREG_FP]), + sizeof(struct reg_window32)); + + /* 3. signal handler back-trampoline and parameters */ + regs->u_regs[UREG_FP] = (unsigned long) sf; + regs->u_regs[UREG_I0] = signr; + regs->u_regs[UREG_I1] = (unsigned long) &sf->info; + + /* 4. signal handler */ + regs->tpc = (unsigned long) ka->sa.sa_handler; + regs->tnpc = (regs->tpc + 4); + + /* 5. return to kernel instructions */ + if (ka->ka_restorer) + regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer; + else { + /* Flush instruction space. */ + unsigned long address = ((unsigned long)&(sf->insns[0])); + pgd_t *pgdp = pgd_offset(current->mm, address); + pmd_t *pmdp = pmd_offset(pgdp, address); + pte_t *ptep = pte_offset(pmdp, address); + + regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2); + + __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */ + __put_user(0x91d02010, &sf->insns[1]); /* t 0x10 */ + + if(pte_present(*ptep)) { + unsigned long page = pte_page(*ptep); + + __asm__ __volatile__(" + membar #StoreStore + flush %0 + %1" + : : "r" (page), "r" (address & (PAGE_SIZE - 1)) + : "memory"); + } + } + return; + +sigill: + lock_kernel(); + do_exit(SIGILL); +} + +static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka, + siginfo_t *info, + sigset_t *oldset, struct pt_regs *regs, int svr4_signal) { if(svr4_signal) - setup_svr4_frame32(sa, regs->tpc, regs->tnpc, regs, signr, oldmask); + setup_svr4_frame32(&ka->sa, regs->tpc, regs->tnpc, regs, signr, oldset); else { - if (current->tss.new_signal) - new_setup_frame32(sa, regs, signr, oldmask); + if (ka->sa.sa_flags & SA_SIGINFO) + setup_rt_frame32(ka, regs, signr, oldset, info); + else if (current->tss.new_signal) + new_setup_frame32(ka, regs, signr, oldset); else - setup_frame32(sa, regs->tpc, regs->tnpc, regs, signr, oldmask); + setup_frame32(&ka->sa, regs->tpc, regs->tnpc, regs, signr, oldset); } - if(sa->sa_flags & SA_ONESHOT) - sa->sa_handler = NULL; - if(!(sa->sa_flags & SA_NOMASK)) { + if(ka->sa.sa_flags & SA_ONESHOT) + ka->sa.sa_handler = SIG_DFL; + if(!(ka->sa.sa_flags & SA_NOMASK)) { spin_lock_irq(¤t->sigmask_lock); - current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE; + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + sigaddset(¤t->blocked,signr); spin_unlock_irq(¤t->sigmask_lock); } } @@ -723,22 +1051,22 @@ static inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. */ -asmlinkage int do_signal32(unsigned long oldmask, struct pt_regs * regs, +asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs * regs, unsigned long orig_i0, int restart_syscall) { - unsigned long signr, mask = ~current->blocked; - struct sigaction *sa; + unsigned long signr; + struct k_sigaction *ka; + siginfo_t info; + int svr4_signal = current->personality == PER_SVR4; - while ((signr = current->signal & mask) != 0) { - signr = ffz(~signr); - + for (;;) { spin_lock_irq(¤t->sigmask_lock); - current->signal &= ~(1 << signr); + signr = dequeue_signal(¤t->blocked, &info); spin_unlock_irq(¤t->sigmask_lock); + + if (!signr) break; - sa = current->sig->action + signr; - signr++; if ((current->flags & PF_PTRACED) && signr != SIGKILL) { current->exit_code = signr; current->state = TASK_STOPPED; @@ -749,15 +1077,26 @@ asmlinkage int do_signal32(unsigned long oldmask, struct pt_regs * regs, current->exit_code = 0; if (signr == SIGSTOP) continue; - if (_S(signr) & current->blocked) { - spin_lock_irq(¤t->sigmask_lock); - current->signal |= _S(signr); - spin_unlock_irq(¤t->sigmask_lock); + + /* Update the siginfo structure. Is this good? */ + if (signr != info.si_signo) { + info.si_signo = signr; + info.si_errno = 0; + info.si_code = SI_USER; + info.si_pid = current->p_pptr->pid; + info.si_uid = current->p_pptr->uid; + } + + /* If the (new) signal is now blocked, requeue it. */ + if (sigismember(¤t->blocked, signr)) { + send_sig_info(signr, &info, current); continue; } - sa = current->sig->action + signr - 1; } - if(sa->sa_handler == SIG_IGN) { + + ka = ¤t->sig->action[signr-1]; + + if(ka->sa.sa_handler == SIG_IGN) { if(signr != SIGCHLD) continue; @@ -770,7 +1109,9 @@ asmlinkage int do_signal32(unsigned long oldmask, struct pt_regs * regs, ; continue; } - if(sa->sa_handler == SIG_DFL) { + if(ka->sa.sa_handler == SIG_DFL) { + unsigned long exit_code = signr; + if(current->pid == 1) continue; switch(signr) { @@ -786,7 +1127,7 @@ asmlinkage int do_signal32(unsigned long oldmask, struct pt_regs * regs, continue; current->state = TASK_STOPPED; current->exit_code = signr; - if(!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags & + if(!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP)) notify_parent(current, SIGCHLD); schedule(); @@ -797,7 +1138,7 @@ asmlinkage int do_signal32(unsigned long oldmask, struct pt_regs * regs, if(current->binfmt && current->binfmt->core_dump) { lock_kernel(); if(current->binfmt->core_dump(signr, regs)) - signr |= 0x80; + exit_code |= 0x80; unlock_kernel(); } #ifdef DEBUG_SIGNALS @@ -807,20 +1148,16 @@ asmlinkage int do_signal32(unsigned long oldmask, struct pt_regs * regs, #endif /* fall through */ default: - spin_lock_irq(¤t->sigmask_lock); - current->signal |= _S(signr & 0x7f); - spin_unlock_irq(¤t->sigmask_lock); - - current->flags |= PF_SIGNALED; - lock_kernel(); - do_exit(signr); - unlock_kernel(); + sigaddset(¤t->signal, signr); + current->flags |= PF_SIGNALED; + do_exit(exit_code); + /* NOT REACHED */ } } if(restart_syscall) - syscall_restart32(orig_i0, regs, sa); - handle_signal32(signr, sa, oldmask, regs, svr4_signal); + syscall_restart32(orig_i0, regs, &ka->sa); + handle_signal32(signr, ka, &info, oldset, regs, svr4_signal); return 1; } if(restart_syscall && diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index 8dd471be6..932534c05 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -3,6 +3,7 @@ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) */ +#include <linux/config.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/tasks.h> @@ -23,6 +24,7 @@ #include <asm/spinlock.h> #include <asm/hardirq.h> #include <asm/softirq.h> +#include <asm/uaccess.h> #define __KERNEL_SYSCALLS__ #include <linux/unistd.h> @@ -346,7 +348,7 @@ static void smp_cross_call_avoidance(struct mm_struct *mm) spin_lock(&scheduler_lock); get_new_mmu_context(mm, &tlb_context_cache); mm->cpu_vm_mask = (1UL << smp_processor_id()); - if(current->tss.current_ds) { + if(segment_eq(current->tss.current_ds,USER_DS)) { u32 ctx = mm->context & 0x1fff; current->tss.ctx = ctx; @@ -473,6 +475,7 @@ void smp_penguin_jailcell(void) static inline void sparc64_do_profile(unsigned long pc) { +#ifdef CONFIG_PROFILE if(prof_buffer && current->pid) { extern int _stext; @@ -483,6 +486,7 @@ static inline void sparc64_do_profile(unsigned long pc) pc = prof_len - 1; atomic_inc((atomic_t *)&prof_buffer[pc]); } +#endif } static unsigned long real_tick_offset, current_tick_offset; @@ -510,7 +514,7 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs) update_one_process(current, 1, user, !user); if(--current->counter < 0) { current->counter = 0; - resched_force(); + need_resched = 1; } if(user) { diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index c1ceacc3f..b776ea06e 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c @@ -1,10 +1,12 @@ -/* $Id: sparc64_ksyms.c,v 1.21 1997/09/03 12:29:07 jj Exp $ +/* $Id: sparc64_ksyms.c,v 1.27 1997/11/19 07:57:46 jj Exp $ * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) */ +/* Tell string.h we don't want memcpy etc. as cpp defines */ +#define EXPORT_SYMTAB_STROPS #define PROMLIB_INTERNAL #include <linux/config.h> @@ -12,6 +14,7 @@ #include <linux/types.h> #include <linux/string.h> #include <linux/in6.h> +#include <linux/pci.h> #include <asm/oplib.h> #include <asm/delay.h> @@ -30,10 +33,14 @@ #include <asm/user.h> #include <asm/uaccess.h> #include <asm/checksum.h> +#include <asm/fpumacro.h> #ifdef CONFIG_SBUS #include <asm/sbus.h> #include <asm/dma.h> #endif +#ifdef CONFIG_PCI +#include <asm/ebus.h> +#endif #include <asm/a.out.h> #include <asm/svr4.h> @@ -43,6 +50,7 @@ struct poll { short revents; }; +extern void die_if_kernel(char *str, struct pt_regs *regs); extern unsigned long sunos_mmap(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long); void _sigpause_common (unsigned int set, struct pt_regs *); @@ -68,6 +76,7 @@ extern int svr4_getcontext(svr4_ucontext_t *uc, struct pt_regs *regs); extern int svr4_setcontext(svr4_ucontext_t *uc, struct pt_regs *regs); extern int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); extern int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg); +extern int (*handle_mathemu)(struct pt_regs *, struct fpustate *); extern void bcopy (const char *, char *, int); extern int __ashrdi3(int, int); @@ -123,6 +132,10 @@ EXPORT_SYMBOL(mmu_release_scsi_sgl); EXPORT_SYMBOL(SBus_chain); EXPORT_SYMBOL(dma_chain); #endif +#if CONFIG_PCI +EXPORT_SYMBOL(ebus_chain); +EXPORT_SYMBOL(pci_devices); +#endif /* Solaris/SunOS binary compatibility */ EXPORT_SYMBOL(_sigpause_common); @@ -131,6 +144,9 @@ EXPORT_SYMBOL(sunos_mmap); /* Should really be in linux/kernel/ksyms.c */ EXPORT_SYMBOL(dump_thread); +/* math-emu wants this */ +EXPORT_SYMBOL(die_if_kernel); + /* prom symbols */ EXPORT_SYMBOL(idprom); EXPORT_SYMBOL(prom_root_node); @@ -190,6 +206,10 @@ EXPORT_SYMBOL(sys_ioctl); EXPORT_SYMBOL(sys32_ioctl); #endif +#ifdef CONFIG_MATHEMU_MODULE +EXPORT_SYMBOL(handle_mathemu); +#endif + /* Special internal versions of library functions. */ EXPORT_SYMBOL(__memcpy); EXPORT_SYMBOL(__memset); diff --git a/arch/sparc64/kernel/sunos_ioctl32.c b/arch/sparc64/kernel/sunos_ioctl32.c index bb991dee6..d94a7c6d6 100644 --- a/arch/sparc64/kernel/sunos_ioctl32.c +++ b/arch/sparc64/kernel/sunos_ioctl32.c @@ -1,4 +1,4 @@ -/* $Id: sunos_ioctl32.c,v 1.4 1997/07/17 02:20:43 davem Exp $ +/* $Id: sunos_ioctl32.c,v 1.5 1997/09/18 10:37:57 rth Exp $ * sunos_ioctl32.c: SunOS ioctl compatability on sparc64. * * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) @@ -100,7 +100,7 @@ asmlinkage int sunos_ioctl (int fd, u32 cmd, u32 arg) goto out; if(cmd == TIOCSETD) { - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); int *p, ntty = N_TTY; int tmp; diff --git a/arch/sparc64/kernel/sys32.S b/arch/sparc64/kernel/sys32.S index 37c541755..6fb6f739b 100644 --- a/arch/sparc64/kernel/sys32.S +++ b/arch/sparc64/kernel/sys32.S @@ -1,4 +1,4 @@ -/* $Id: sys32.S,v 1.3 1997/08/22 20:11:47 davem Exp $ +/* $Id: sys32.S,v 1.4 1997/09/09 17:13:29 jj Exp $ * sys32.S: I-cache tricks for 32-bit compatability layer simple * conversions. * @@ -8,8 +8,7 @@ .text .align 32 - .globl sys32_mmap, sys32_mprotect, sys32_munmap, sys32_msync - .globl sys32_mlock, sys32_munlock, sys32_mremap, sparc32_brk + .globl sys32_mmap sys32_mmap: srl %o0, 0, %o0 ! IEU0 Group sethi %hi(0xffffffff), %g2 ! IEU1 @@ -22,153 +21,15 @@ sys32_mmap: and %o5, %g2, %o5 ! IEU0 Group call sys_mmap ! CTI Group brk forced mov %g1, %o7 ! IEU0 Group (regdep) -sys32_mprotect: - srl %o0, 0, %o0 - mov %o7, %g1 - srl %o1, 0, %o1 - srl %o2, 0, %o2 - call sys_mprotect - mov %g1, %o7 -sys32_munmap: - srl %o0, 0, %o0 - mov %o7, %g1 - srl %o1, 0, %o1 - call sys_munmap - mov %g1, %o7 -sparc32_brk: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_brk - mov %g1, %o7 -sys32_msync: - srl %o0, 0, %o0 - mov %o7, %g1 - srl %o1, 0, %o1 - call sys_msync - mov %g1, %o7 -sys32_mlock: - srl %o0, 0, %o0 - mov %o7, %g1 - srl %o1, 0, %o1 - call sys_mlock - mov %g1, %o7 -sys32_munlock: - srl %o0, 0, %o0 - mov %o7, %g1 - srl %o1, 0, %o1 - call sys_munlock - mov %g1, %o7 -sys32_mremap: - srl %o0, 0, %o0 - mov %o7, %g1 - srl %o1, 0, %o1 - srl %o2, 0, %o2 - srl %o3, 0, %o3 - call sys_mremap - mov %g1, %o7 .align 32 - .globl sys32_read, sys32_write, sys32_open, sys32_access - .globl sys32_chdir, sys32_lseek, sys32_llseek, sys32_poll - .globl sys32_readlink, sys32_unlink, sys32_rmdir, sys32_symlink - .globl sys32_link, sys32_rename, sys32_truncate, sys32_ftruncate - .globl sys32_chroot, sys32_chmod, sys32_chown, sys32_creat - .globl sys32_mkdir, sys32_mknod, sys32_ustat -sys32_read: - srl %o1, 0, %o1 - mov %o7, %g1 - srl %o2, 0, %o2 - call sys_read - mov %g1, %o7 -sys32_write: - srl %o1, 0, %o1 - mov %o7, %g1 - srl %o2, 0, %o2 - call sys_write - mov %g1, %o7 -sys32_open: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_open - mov %g1, %o7 -sys32_access: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_access - mov %g1, %o7 -sys32_chdir: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_chdir - mov %g1, %o7 + .globl sys32_lseek + .globl sys32_chmod, sys32_chown, sys32_mknod sys32_lseek: sra %o1, 0, %o1 mov %o7, %g1 call sys_lseek mov %g1, %o7 -sys32_llseek: - srl %o1, 0, %o1 - mov %o7, %g1 - srl %o2, 0, %o2 - srl %o3, 0, %o3 - call sys_llseek - mov %g1, %o7 -sys32_poll: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_poll - mov %g1, %o7 -sys32_readlink: - srl %o0, 0, %o0 - mov %o7, %g1 - srl %o1, 0, %o1 - call sys_readlink - mov %g1, %o7 -sys32_unlink: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_unlink - mov %g1, %o7 -sys32_rmdir: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_rmdir - mov %g1, %o7 -sys32_symlink: - srl %o0, 0, %o0 - mov %o7, %g1 - srl %o1, 0, %o1 - call sys_symlink - mov %g1, %o7 -sys32_link: - srl %o0, 0, %o0 - mov %o7, %g1 - srl %o1, 0, %o1 - call sys_link - mov %g1, %o7 -sys32_rename: - srl %o0, 0, %o0 - mov %o7, %g1 - srl %o1, 0, %o1 - call sys_rename - mov %g1, %o7 - nop -sys32_truncate: - srl %o0, 0, %o0 - mov %o7, %g1 - srl %o1, 0, %o1 - call sys_truncate - mov %g1, %o7 -sys32_ftruncate: - srl %o1, 0, %o1 - mov %o7, %g1 - call sys_ftruncate - mov %g1, %o7 -sys32_chroot: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_chroot - mov %g1, %o7 sys32_chmod: sll %o1, 16, %o1 mov %o7, %g1 @@ -185,16 +46,6 @@ sys32_chown: srl %o2, 16, %o2 call sys_chown mov %g1, %o7 -sys32_creat: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_creat - mov %g1, %o7 -sys32_mkdir: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_mkdir - mov %g1, %o7 sys32_mknod: sll %o2, 16, %o2 mov %o7, %g1 @@ -202,50 +53,9 @@ sys32_mknod: srl %o2, 16, %o2 call sys_mknod mov %g1, %o7 -sys32_ustat: - srl %o1, 0, %o1 - mov %o7, %g1 - call sys_ustat - mov %g1, %o7 .align 32 - .globl sys32_bind, sys32_accept, sys32_connect, sys32_getsockname - .globl sys32_getpeername, sys32_send, sys32_sendto, sys32_recv - .globl sys32_recvfrom, sys32_setsockopt, sys32_getsockopt -sys32_bind: - srl %o1, 0, %o1 - mov %o7, %g1 - call sys_bind - mov %g1, %o7 -sys32_accept: - srl %o1, 0, %o1 - mov %o7, %g1 - srl %o2, 0, %o2 - call sys_accept - mov %g1, %o7 -sys32_connect: - srl %o1, 0, %o1 - mov %o7, %g1 - call sys_connect - mov %g1, %o7 -sys32_getsockname: - srl %o1, 0, %o1 - mov %o7, %g1 - srl %o2, 0, %o2 - call sys_getsockname - mov %g1, %o7 -sys32_getpeername: - srl %o1, 0, %o1 - mov %o7, %g1 - srl %o2, 0, %o2 - call sys_getpeername - mov %g1, %o7 -sys32_send: - srl %o1, 0, %o1 - mov %o7, %g1 - srl %o2, 0, %o2 - call sys_send - mov %g1, %o7 + .globl sys32_sendto, sys32_recvfrom, sys32_getsockopt sys32_sendto: srl %o1, 0, %o1 mov %o7, %g1 @@ -253,12 +63,6 @@ sys32_sendto: srl %o4, 0, %o4 call sys_sendto mov %g1, %o7 -sys32_recv: - srl %o1, 0, %o1 - mov %o7, %g1 - srl %o2, 0, %o2 - call sys_recv - mov %g1, %o7 sys32_recvfrom: srl %o1, 0, %o1 mov %o7, %g1 @@ -267,11 +71,6 @@ sys32_recvfrom: srl %o5, 0, %o5 call sys_recvfrom mov %g1, %o7 -sys32_setsockopt: - srl %o3, 0, %o3 - mov %o7, %g1 - call sys_setsockopt - mov %g1, %o7 sys32_getsockopt: srl %o3, 0, %o3 mov %o7, %g1 @@ -279,111 +78,9 @@ sys32_getsockopt: call sys_setsockopt mov %g1, %o7 - .globl sys32_bdflush, sys32_uselib, sys32_umount, sys32_syslog - .globl sys32_personality, sys32_waitpid - .globl sys32_sched_setscheduler - .globl sys32_sched_setparam, sys32_sched_getparam, sys32_signal - .globl sys32_reboot, sys32_acct, sys32_newuname, sys32_olduname - .globl sys32_sethostname, sys32_gethostname, sys32_setdomainname - .globl sys32_time, sys32_swapoff, sys32_swapon - .globl sys32_create_module, sys32_init_module, sys32_delete_module + .globl sys32_bdflush sys32_bdflush: sra %o1, 0, %o1 mov %o7, %g1 call sys_bdflush mov %g1, %o7 -sys32_uselib: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_uselib - mov %g1, %o7 -sys32_umount: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_umount - mov %g1, %o7 -sys32_syslog: - srl %o1, 0, %o1 - mov %o7, %g1 - call sys_syslog - mov %g1, %o7 -sys32_personality: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_personality - mov %g1, %o7 -sys32_waitpid: - srl %o1, 0, %o1 - mov %o7, %g1 - call sys_waitpid - mov %g1, %o7 -sys32_sched_setscheduler: - srl %o2, 0, %o2 - mov %o7, %g1 - call sys_sched_setscheduler - mov %g1, %o7 -sys32_sched_setparam: - srl %o1, 0, %o1 - mov %o7, %g1 - call sys_sched_setparam - mov %g1, %o7 -sys32_sched_getparam: - srl %o1, 0, %o1 - mov %o7, %g1 - call sys_sched_getparam - mov %g1, %o7 -sys32_signal: - srl %o1, 0, %o1 - mov %o7, %g1 - call sys_signal - mov %g1, %o7 -sys32_reboot: - srl %o3, 0, %o3 - mov %o7, %g1 - call sys_reboot - mov %g1, %o7 -sys32_acct: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_acct - mov %g1, %o7 -sys32_newuname: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_newuname - mov %g1, %o7 -sys32_olduname: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_olduname - mov %g1, %o7 -sys32_sethostname: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_sethostname - mov %g1, %o7 -sys32_gethostname: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_gethostname - mov %g1, %o7 -sys32_setdomainname: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_setdomainname - mov %g1, %o7 -sys32_time: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_time - mov %g1, %o7 -sys32_swapoff: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_swapoff - mov %g1, %o7 -sys32_swapon: - srl %o0, 0, %o0 - mov %o7, %g1 - call sys_swapon - mov %g1, %o7 diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c index 0ec6de167..e0e69abd9 100644 --- a/arch/sparc64/kernel/sys_sparc.c +++ b/arch/sparc64/kernel/sys_sparc.c @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.5 1997/09/03 12:29:05 jj Exp $ +/* $Id: sys_sparc.c,v 1.9 1997/12/11 15:15:44 jj Exp $ * linux/arch/sparc64/kernel/sys_sparc.c * * This file contains various random system calls that @@ -16,11 +16,14 @@ #include <linux/shm.h> #include <linux/stat.h> #include <linux/mman.h> +#include <linux/utsname.h> #include <linux/smp.h> #include <linux/smp_lock.h> +#include <linux/malloc.h> #include <asm/uaccess.h> #include <asm/ipc.h> +#include <asm/utrap.h> /* XXX Make this per-binary type, this way we can detect the type of * XXX a binary. Every Sparc executable calls this very early on. @@ -219,39 +222,16 @@ sparc_breakpoint (struct pt_regs *regs) extern void check_pending(int signum); -asmlinkage int -sparc_sigaction (int signum, const struct sigaction *action, struct sigaction *oldaction) +asmlinkage int sys_getdomainname(char *name, int len) { - struct sigaction new_sa, *p; + int nlen = strlen(system_utsname.domainname); - if(signum < 0) { - current->tss.new_signal = 1; - signum = -signum; - } - if (signum<1 || signum>32) - return -EINVAL; - p = signum - 1 + current->sig->action; - if (action) { - if (signum==SIGKILL || signum==SIGSTOP) - return -EINVAL; - if(copy_from_user(&new_sa, action, sizeof(struct sigaction))) - return -EFAULT; - if (new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) { - int err = verify_area(VERIFY_READ, new_sa.sa_handler, 1); - if (err) - return err; - } - } - if (oldaction) { - if (copy_to_user(oldaction, p, sizeof(struct sigaction))) - return -EFAULT; - } - if (action) { - spin_lock_irq(¤t->sig->siglock); - *p = new_sa; - check_pending(signum); - spin_unlock_irq(¤t->sig->siglock); - } + if (nlen < len) + len = nlen; + if(len > __NEW_UTS_LEN) + return -EFAULT; + if(copy_to_user(name, system_utsname.domainname, len)) + return -EFAULT; return 0; } @@ -272,3 +252,116 @@ asmlinkage int solaris_syscall(struct pt_regs *regs) unlock_kernel(); return 0; } + +asmlinkage int sys_utrap_install(utrap_entry_t type, utrap_handler_t new_p, utrap_handler_t new_d, + utrap_handler_t *old_p, utrap_handler_t *old_d) +{ + if (type < UT_INSTRUCTION_EXCEPTION || type > UT_TRAP_INSTRUCTION_31) + return -EINVAL; + if (new_p == (utrap_handler_t)(long)UTH_NOCHANGE) { + if (old_p) { + if (!current->tss.utraps) + put_user_ret(NULL, old_p, -EFAULT); + else + put_user_ret((utrap_handler_t)(current->tss.utraps[type]), old_p, -EFAULT); + } + if (old_d) + put_user_ret(NULL, old_d, -EFAULT); + return 0; + } + lock_kernel(); + if (!current->tss.utraps) { + current->tss.utraps = kmalloc((UT_TRAP_INSTRUCTION_31+1)*sizeof(long), GFP_KERNEL); + if (!current->tss.utraps) return -ENOMEM; + current->tss.utraps[0] = 1; + memset(current->tss.utraps+1, 0, UT_TRAP_INSTRUCTION_31*sizeof(long)); + } else { + if ((utrap_handler_t)current->tss.utraps[type] != new_p && current->tss.utraps[0] > 1) { + long *p = current->tss.utraps; + + current->tss.utraps = kmalloc((UT_TRAP_INSTRUCTION_31+1)*sizeof(long), GFP_KERNEL); + if (!current->tss.utraps) { + current->tss.utraps = p; + return -ENOMEM; + } + p[0]--; + current->tss.utraps[0] = 1; + memcpy(current->tss.utraps+1, p+1, UT_TRAP_INSTRUCTION_31*sizeof(long)); + } + } + if (old_p) + put_user_ret((utrap_handler_t)(current->tss.utraps[type]), old_p, -EFAULT); + if (old_d) + put_user_ret(NULL, old_d, -EFAULT); + current->tss.utraps[type] = (long)new_p; + unlock_kernel(); + return 0; +} + +long sparc_memory_ordering(unsigned long model, struct pt_regs *regs) +{ + if (model >= 3) + return -EINVAL; + regs->tstate = (regs->tstate & ~TSTATE_MM) | (model << 14); + return 0; +} + +asmlinkage int +sys_sigaction(int sig, const struct old_sigaction *act, + struct old_sigaction *oact) +{ + struct k_sigaction new_ka, old_ka; + int ret; + + if (act) { + old_sigset_t mask; + if (verify_area(VERIFY_READ, act, sizeof(*act)) || + __get_user(new_ka.sa.sa_handler, &act->sa_handler) || + __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) + return -EFAULT; + __get_user(new_ka.sa.sa_flags, &act->sa_flags); + __get_user(mask, &act->sa_mask); + siginitset(&new_ka.sa.sa_mask, mask); + new_ka.ka_restorer = NULL; + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || + __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || + __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) + return -EFAULT; + __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); + } + + return ret; +} + +asmlinkage int +sys_rt_sigaction(int sig, const struct sigaction *act, struct sigaction *oact, + void *restorer, size_t sigsetsize) +{ + struct k_sigaction new_ka, old_ka; + int ret; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + if (act) { + new_ka.ka_restorer = restorer; + if (copy_from_user(&new_ka.sa, act, sizeof(*act))) + return -EFAULT; + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + if (copy_to_user(oact, &old_ka.sa, sizeof(*oact))) + return -EFAULT; + } + + return ret; +} diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index 81640c8e6..66993ebcb 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.55 1997/09/04 01:54:51 davem Exp $ +/* $Id: sys_sparc32.c,v 1.71 1997/12/11 15:15:11 jj Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -28,6 +28,7 @@ #include <linux/uio.h> #include <linux/nfs_fs.h> #include <linux/smb_fs.h> +#include <linux/smb_mount.h> #include <linux/ncp_fs.h> #include <linux/quota.h> #include <linux/file.h> @@ -39,6 +40,7 @@ #include <linux/nfsd/syscall.h> #include <linux/module.h> #include <linux/poll.h> +#include <linux/personality.h> #include <asm/types.h> #include <asm/ipc.h> @@ -253,7 +255,7 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u case SEMCTL: { union semun fourth; void *pad; - unsigned long old_fs; + mm_segment_t old_fs; struct semid_ds s; err = -EINVAL; @@ -336,7 +338,7 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u err = -EFAULT; } if (!err) { - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); set_fs (KERNEL_DS); err = sys_msgsnd (first, p, second, third); set_fs (old_fs); @@ -348,7 +350,7 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u case MSGRCV: { struct msgbuf *p; - unsigned long old_fs; + mm_segment_t old_fs; long msgtyp = fifth; if (!version) { @@ -398,7 +400,7 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u case MSGCTL: { struct msqid_ds m; - unsigned long old_fs; + mm_segment_t old_fs; switch (second) { case IPC_INFO: @@ -482,7 +484,7 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u case SHMCTL: { struct shmid_ds s; - unsigned long old_fs; + mm_segment_t old_fs; switch (second) { case IPC_INFO: @@ -590,7 +592,7 @@ asmlinkage long sys32_fcntl(unsigned int fd, unsigned int cmd, u32 arg) case F_SETLKW: { struct flock f; - unsigned long old_fs; + mm_segment_t old_fs; long ret; if(get_flock(&f, (struct flock32 *)A(arg))) @@ -625,7 +627,7 @@ asmlinkage int sys32_quotactl(int cmd, u32 special, int id, u32 addr) int cmds = cmd >> SUBCMDSHIFT; int err; struct dqblk d; - unsigned long old_fs; + mm_segment_t old_fs; char *spec; switch (cmds) { @@ -685,7 +687,7 @@ asmlinkage int sys32_statfs(u32 path, u32 buf) { int ret; struct statfs s; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); char *pth; pth = getname32 (path); @@ -707,7 +709,7 @@ asmlinkage int sys32_fstatfs(unsigned int fd, u32 buf) { int ret; struct statfs s; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); set_fs (KERNEL_DS); ret = sys_fstatfs(fd, &s); @@ -723,7 +725,7 @@ asmlinkage int sys32_utime(u32 filename, u32 times) { struct utimbuf32 { __kernel_time_t32 actime, modtime; }; struct utimbuf t; - unsigned long old_fs; + mm_segment_t old_fs; int ret; char *filenam; @@ -746,14 +748,15 @@ asmlinkage int sys32_utime(u32 filename, u32 times) struct iovec32 { u32 iov_base; __kernel_size_t32 iov_len; }; -typedef long (*IO_fn_t)(struct inode *, struct file *, char *, unsigned long); +typedef ssize_t (*IO_fn_t)(struct file *, char *, size_t, loff_t *); -static long do_readv_writev32(int type, struct inode *inode, struct file *file, +static long do_readv_writev32(int type, struct file *file, const struct iovec32 *vector, u32 count) { unsigned long tot_len; struct iovec iovstack[UIO_FASTIOV]; struct iovec *iov=iovstack, *ivp; + struct inode *inode; long retval, i; IO_fn_t fn; @@ -789,6 +792,7 @@ static long do_readv_writev32(int type, struct inode *inode, struct file *file, i--; } + inode = file->f_dentry->d_inode; retval = locks_verify_area((type == VERIFY_READ) ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE, inode, file, file->f_pos, tot_len); @@ -828,7 +832,7 @@ static long do_readv_writev32(int type, struct inode *inode, struct file *file, len = ivp->iov_len; ivp++; count--; - nr = fn(inode, file, base, len); + nr = fn(file, base, len, &file->f_pos); if (nr < 0) { if (retval) break; @@ -847,69 +851,53 @@ static long do_readv_writev32(int type, struct inode *inode, struct file *file, asmlinkage long sys32_readv(int fd, u32 vector, u32 count) { struct file *file; - struct dentry *dentry; - struct inode *inode; - long err = -EBADF; + long ret = -EBADF; lock_kernel(); - if(fd >= NR_OPEN) - goto out; - - file = current->files->fd[fd]; + file = fget(fd); if(!file) - goto out; + goto bad_file; if(!(file->f_mode & 1)) goto out; - dentry = file->f_dentry; - if(!dentry) - goto out; - - inode = dentry->d_inode; - if(!inode) - goto out; - - err = do_readv_writev32(VERIFY_WRITE, inode, file, + ret = do_readv_writev32(VERIFY_WRITE, file, (struct iovec32 *)A(vector), count); + if (ret > 0) + current->io_usage += ret; + out: + fput(file); +bad_file: unlock_kernel(); - return err; + return ret; } asmlinkage long sys32_writev(int fd, u32 vector, u32 count) { - int error = -EBADF; struct file *file; - struct dentry *dentry; - struct inode *inode; + int ret = -EBADF; lock_kernel(); - if(fd >= NR_OPEN) - goto out; - - file = current->files->fd[fd]; + file = fget(fd); if(!file) - goto out; + goto bad_file; if(!(file->f_mode & 2)) goto out; - dentry = file->f_dentry; - if(!dentry) - goto out; - - inode = dentry->d_inode; - if(!inode) - goto out; - - down(&inode->i_sem); - error = do_readv_writev32(VERIFY_READ, inode, file, + down(&file->f_dentry->d_inode->i_sem); + ret = do_readv_writev32(VERIFY_READ, file, (struct iovec32 *)A(vector), count); - up(&inode->i_sem); + up(&file->f_dentry->d_inode->i_sem); + if (ret > 0) + current->io_usage += ret; + out: + fput(file); +bad_file: unlock_kernel(); - return error; + return ret; } /* readdir & getdents */ @@ -951,8 +939,6 @@ asmlinkage int old32_readdir(unsigned int fd, u32 dirent, unsigned int count) { int error = -EBADF; struct file * file; - struct dentry * dentry; - struct inode * inode; struct readdir_callback32 buf; lock_kernel(); @@ -963,14 +949,6 @@ asmlinkage int old32_readdir(unsigned int fd, u32 dirent, unsigned int count) if(!file) goto out; - dentry = file->f_dentry; - if(!dentry) - goto out; - - inode = dentry->d_inode; - if(!inode) - goto out; - buf.count = 0; buf.dirent = (struct old_linux_dirent32 *)A(dirent); @@ -978,7 +956,7 @@ asmlinkage int old32_readdir(unsigned int fd, u32 dirent, unsigned int count) if (!file->f_op || !file->f_op->readdir) goto out; - error = file->f_op->readdir(inode, file, &buf, fillonedir); + error = file->f_op->readdir(file, &buf, fillonedir); if (error < 0) goto out; error = buf.count; @@ -1028,8 +1006,6 @@ static int filldir(void * __buf, const char * name, int namlen, off_t offset, in asmlinkage int sys32_getdents(unsigned int fd, u32 dirent, unsigned int count) { struct file * file; - struct dentry * dentry; - struct inode *inode; struct linux_dirent32 * lastdirent; struct getdents_callback32 buf; int error = -EBADF; @@ -1042,14 +1018,6 @@ asmlinkage int sys32_getdents(unsigned int fd, u32 dirent, unsigned int count) if(!file) goto out; - dentry = file->f_dentry; - if(!dentry) - goto out; - - inode = dentry->d_inode; - if(!inode) - goto out; - buf.current_dir = (struct linux_dirent32 *) A(dirent); buf.previous = NULL; buf.count = count; @@ -1059,7 +1027,7 @@ asmlinkage int sys32_getdents(unsigned int fd, u32 dirent, unsigned int count) if (!file->f_op || !file->f_op->readdir) goto out; - error = file->f_op->readdir(inode, file, &buf, filldir); + error = file->f_op->readdir(file, &buf, filldir); if (error < 0) goto out; lastdirent = buf.previous; @@ -1088,7 +1056,7 @@ get_fd_set32(unsigned long n, unsigned long *fdset, u32 ufdset_x) if (ufdset) { unsigned long odd; - if (verify_area(VERIFY_WRITE, ufdset, nn*sizeof(u32))) + if (verify_area(VERIFY_WRITE, ufdset, n*sizeof(u32))) return -EFAULT; odd = n & 1UL; @@ -1104,12 +1072,12 @@ get_fd_set32(unsigned long n, unsigned long *fdset, u32 ufdset_x) if (odd) __get_user(*fdset, ufdset); } else { - /* Tricky, must clear full unsigned long in the kernel - fdset at the end, this makes sure that actually - happens. */ + /* Tricky, must clear full unsigned long in the + * kernel fdset at the end, this makes sure that + * actually happens. + */ memset(fdset, 0, ((n + 1) & ~1)*sizeof(u32)); } - return 0; } @@ -1168,7 +1136,7 @@ asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp_x) goto out; if (n > KFDS_NR) n = KFDS_NR; - + nn = (n + 8*sizeof(u32) - 1) / (8*sizeof(u32)); if ((ret = get_fd_set32(nn, fds->in, inp)) || (ret = get_fd_set32(nn, fds->out, outp)) || @@ -1196,7 +1164,7 @@ asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp_x) goto out; if (!ret) { ret = -ERESTARTNOHAND; - if (current->signal & ~current->blocked) + if (signal_pending(current)) goto out; ret = 0; } @@ -1237,7 +1205,7 @@ asmlinkage int sys32_newstat(u32 filename, u32 statbuf) int ret; struct stat s; char *filenam; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); filenam = getname32 (filename); ret = PTR_ERR(filenam); @@ -1259,7 +1227,7 @@ asmlinkage int sys32_newlstat(u32 filename, u32 statbuf) int ret; struct stat s; char *filenam; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); filenam = getname32 (filename); ret = PTR_ERR(filenam); @@ -1280,7 +1248,7 @@ asmlinkage int sys32_newfstat(unsigned int fd, u32 statbuf) { int ret; struct stat s; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); set_fs (KERNEL_DS); ret = sys_newfstat(fd, &s); @@ -1290,29 +1258,11 @@ asmlinkage int sys32_newfstat(unsigned int fd, u32 statbuf) return ret; } -extern asmlinkage int sys_sysfs(int option, ...); +extern asmlinkage int sys_sysfs(int option, unsigned long arg1, unsigned long arg2); -asmlinkage int sys32_sysfs(int option, ...) +asmlinkage int sys32_sysfs(int option, u32 arg1, u32 arg2) { - va_list args; - unsigned int x; - int ret = -EINVAL; - - va_start(args, option); - switch (option) { - case 1: - ret = sys_sysfs(option, (const char *)A(va_arg(args, u32))); - break; - case 2: - x = va_arg(args, unsigned int); - ret = sys_sysfs(option, x, (char *)A(va_arg(args, u32))); - break; - case 3: - ret = sys_sysfs(option); - break; - } - va_end(args); - return ret; + return sys_sysfs(option, arg1, arg2); } struct ncp_mount_data32 { @@ -1347,17 +1297,7 @@ static void *do_ncp_super_data_conv(void *raw_data) struct smb_mount_data32 { int version; - unsigned int fd; __kernel_uid_t32 mounted_uid; - struct sockaddr_in addr; - char server_name[17]; - char client_name[17]; - char service[64]; - char root_path[64]; - char username[64]; - char password[64]; - char domain[64]; - unsigned short max_xmit; __kernel_uid_t32 uid; __kernel_gid_t32 gid; __kernel_mode_t32 file_mode; @@ -1434,7 +1374,7 @@ asmlinkage int sys32_mount(u32 dev_name, u32 dir_name, u32 type, u32 new_flags, (void *)A(data)); } else { unsigned long dev_page, dir_page, data_page; - int old_fs; + mm_segment_t old_fs; err = copy_mount_stuff_to_kernel((const void *)A(dev_name), &dev_page); if(err) @@ -1527,7 +1467,7 @@ asmlinkage int sys32_wait4(__kernel_pid_t32 pid, u32 stat_addr, int options, u32 struct rusage r; int ret; unsigned int status; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); set_fs (KERNEL_DS); ret = sys_wait4(pid, stat_addr ? &status : NULL, options, &r); @@ -1558,7 +1498,7 @@ asmlinkage int sys32_sysinfo(u32 info) { struct sysinfo s; int ret; - unsigned long old_fs = get_fs (); + mm_segment_t old_fs = get_fs (); set_fs (KERNEL_DS); ret = sys_sysinfo(&s); @@ -1589,7 +1529,7 @@ asmlinkage int sys32_sched_rr_get_interval(__kernel_pid_t32 pid, u32 interval) { struct timespec t; int ret; - unsigned long old_fs = get_fs (); + mm_segment_t old_fs = get_fs (); set_fs (KERNEL_DS); ret = sys_sched_rr_get_interval(pid, &t); @@ -1606,7 +1546,7 @@ asmlinkage int sys32_nanosleep(u32 rqtp, u32 rmtp) { struct timespec t; int ret; - unsigned long old_fs = get_fs (); + mm_segment_t old_fs = get_fs (); if (get_user (t.tv_sec, &(((struct timespec32 *)A(rqtp))->tv_sec)) || __get_user (t.tv_nsec, &(((struct timespec32 *)A(rqtp))->tv_nsec))) @@ -1622,34 +1562,235 @@ asmlinkage int sys32_nanosleep(u32 rqtp, u32 rmtp) return ret; } -extern asmlinkage int sys_sigprocmask(int how, sigset_t *set, sigset_t *oset); +extern asmlinkage int sys_sigprocmask(int how, old_sigset_t *set, old_sigset_t *oset); asmlinkage int sys32_sigprocmask(int how, u32 set, u32 oset) { - sigset_t s; + old_sigset_t s; int ret; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); - if (set && get_user (s, (sigset_t32 *)A(set))) return -EFAULT; + if (set && get_user (s, (old_sigset_t32 *)A(set))) return -EFAULT; set_fs (KERNEL_DS); ret = sys_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL); set_fs (old_fs); - if (oset && put_user (s, (sigset_t32 *)A(oset))) return -EFAULT; - return ret; + if (ret) return ret; + if (oset && put_user (s, (old_sigset_t32 *)A(oset))) return -EFAULT; + return 0; } -extern asmlinkage int sys_sigpending(sigset_t *set); +extern asmlinkage int sys_rt_sigprocmask(int how, sigset_t *set, sigset_t *oset, size_t sigsetsize); -asmlinkage int sys32_sigpending(u32 set) +asmlinkage int sys32_rt_sigprocmask(int how, u32 set, u32 oset, __kernel_size_t32 sigsetsize) { sigset_t s; + sigset_t32 s32; int ret; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); + + if (set) { + if (copy_from_user (&s32, (sigset_t32 *)A(set), sizeof(sigset_t32))) + return -EFAULT; + switch (_NSIG_WORDS) { + case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32); + case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32); + case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32); + case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32); + } + } + set_fs (KERNEL_DS); + ret = sys_rt_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL, sigsetsize); + set_fs (old_fs); + if (ret) return ret; + if (oset) { + switch (_NSIG_WORDS) { + case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3]; + case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2]; + case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1]; + case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0]; + } + if (copy_to_user ((sigset_t32 *)A(set), &s32, sizeof(sigset_t32))) + return -EFAULT; + } + return 0; +} + +extern asmlinkage int sys_sigpending(old_sigset_t *set); + +asmlinkage int sys32_sigpending(u32 set) +{ + old_sigset_t s; + int ret; + mm_segment_t old_fs = get_fs(); set_fs (KERNEL_DS); ret = sys_sigpending(&s); set_fs (old_fs); - if (put_user (s, (sigset_t32 *)A(set))) return -EFAULT; + if (put_user (s, (old_sigset_t32 *)A(set))) return -EFAULT; + return ret; +} + +extern asmlinkage int sys_rt_sigpending(sigset_t *set, size_t sigsetsize); + +asmlinkage int sys32_rt_sigpending(u32 set, __kernel_size_t32 sigsetsize) +{ + sigset_t s; + sigset_t32 s32; + int ret; + mm_segment_t old_fs = get_fs(); + + set_fs (KERNEL_DS); + ret = sys_rt_sigpending(&s, sigsetsize); + set_fs (old_fs); + if (!ret) { + switch (_NSIG_WORDS) { + case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3]; + case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2]; + case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1]; + case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0]; + } + if (copy_to_user ((sigset_t32 *)A(set), &s32, sizeof(sigset_t32))) + return -EFAULT; + } + return ret; +} + +siginfo_t32 * +siginfo64to32(siginfo_t32 *d, siginfo_t *s) +{ + memset (&d, 0, sizeof(siginfo_t32)); + d->si_signo = s->si_signo; + d->si_errno = s->si_errno; + d->si_code = s->si_code; + if (s->si_signo >= SIGRTMIN) { + d->si_pid = s->si_pid; + d->si_uid = s->si_uid; + /* XXX: Ouch, how to find this out??? */ + d->si_int = s->si_int; + } else switch (s->si_signo) { + /* XXX: What about POSIX1.b timers */ + case SIGCHLD: + d->si_pid = s->si_pid; + d->si_status = s->si_status; + d->si_utime = s->si_utime; + d->si_stime = s->si_stime; + break; + case SIGSEGV: + case SIGBUS: + case SIGFPE: + case SIGILL: + d->si_addr = (long)(s->si_addr); + /* XXX: Do we need to translate this from sparc64 to sparc32 traps? */ + d->si_trapno = s->si_trapno; + break; + case SIGPOLL: + d->si_band = s->si_band; + d->si_fd = s->si_fd; + break; + default: + d->si_pid = s->si_pid; + d->si_uid = s->si_uid; + break; + } + return d; +} + +siginfo_t * +siginfo32to64(siginfo_t *d, siginfo_t32 *s) +{ + d->si_signo = s->si_signo; + d->si_errno = s->si_errno; + d->si_code = s->si_code; + if (s->si_signo >= SIGRTMIN) { + d->si_pid = s->si_pid; + d->si_uid = s->si_uid; + /* XXX: Ouch, how to find this out??? */ + d->si_int = s->si_int; + } else switch (s->si_signo) { + /* XXX: What about POSIX1.b timers */ + case SIGCHLD: + d->si_pid = s->si_pid; + d->si_status = s->si_status; + d->si_utime = s->si_utime; + d->si_stime = s->si_stime; + break; + case SIGSEGV: + case SIGBUS: + case SIGFPE: + case SIGILL: + d->si_addr = (void *)A(s->si_addr); + /* XXX: Do we need to translate this from sparc32 to sparc64 traps? */ + d->si_trapno = s->si_trapno; + break; + case SIGPOLL: + d->si_band = s->si_band; + d->si_fd = s->si_fd; + break; + default: + d->si_pid = s->si_pid; + d->si_uid = s->si_uid; + break; + } + return d; +} + +extern asmlinkage int +sys_rt_sigtimedwait(const sigset_t *uthese, siginfo_t *uinfo, + const struct timespec *uts, size_t sigsetsize); + +asmlinkage int +sys32_rt_sigtimedwait(u32 uthese, u32 uinfo, + u32 uts, __kernel_size_t32 sigsetsize) +{ + sigset_t s; + sigset_t32 s32; + struct timespec t; + int ret; + mm_segment_t old_fs = get_fs(); + siginfo_t info; + siginfo_t32 info32; + + if (copy_from_user (&s32, (sigset_t32 *)A(uthese), sizeof(sigset_t32))) + return -EFAULT; + switch (_NSIG_WORDS) { + case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32); + case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32); + case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32); + case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32); + } + if (uts) { + if (get_user (t.tv_sec, &(((struct timespec32 *)A(uts))->tv_sec)) || + __get_user (t.tv_nsec, &(((struct timespec32 *)A(uts))->tv_nsec))) + return -EFAULT; + } + set_fs (KERNEL_DS); + ret = sys_rt_sigtimedwait(&s, &info, &t, sigsetsize); + set_fs (old_fs); + if (ret >= 0 && uinfo) { + if (copy_to_user ((siginfo_t32 *)A(uinfo), siginfo64to32(&info32, &info), sizeof(siginfo_t32))) + return -EFAULT; + } + return ret; +} + +extern asmlinkage int +sys_rt_sigqueueinfo(int pid, int sig, siginfo_t *uinfo); + +asmlinkage int +sys32_rt_sigqueueinfo(int pid, int sig, u32 uinfo) +{ + siginfo_t info; + siginfo_t32 info32; + int ret; + mm_segment_t old_fs = get_fs(); + + if (copy_from_user (&info32, (siginfo_t32 *)A(uinfo), sizeof(siginfo_t32))) + return -EFAULT; + /* XXX: Is this correct? */ + siginfo32to64(&info, &info32); + set_fs (KERNEL_DS); + ret = sys_rt_sigqueueinfo(pid, sig, &info); + set_fs (old_fs); return ret; } @@ -1684,7 +1825,7 @@ asmlinkage int sys32_getresuid(u32 ruid, u32 euid, u32 suid) { uid_t a, b, c; int ret; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); set_fs (KERNEL_DS); ret = sys_getresuid(&a, &b, &c); @@ -1696,6 +1837,49 @@ asmlinkage int sys32_getresuid(u32 ruid, u32 euid, u32 suid) return ret; } +extern asmlinkage int sys_setregid(gid_t rgid, gid_t egid); + +asmlinkage int sys32_setregid(__kernel_gid_t32 rgid, __kernel_gid_t32 egid) +{ + gid_t srgid, segid; + + srgid = (rgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)rgid); + segid = (egid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)egid); + return sys_setregid(srgid, segid); +} + +extern asmlinkage int sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid); + +asmlinkage int sys32_setresgid(__kernel_gid_t32 rgid, + __kernel_gid_t32 egid, + __kernel_gid_t32 sgid) +{ + gid_t srgid, segid, ssgid; + + srgid = (rgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)rgid); + segid = (egid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)egid); + ssgid = (sgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)sgid); + return sys_setresgid(srgid, segid, ssgid); +} + +extern asmlinkage int sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); + +asmlinkage int sys32_getresgid(u32 rgid, u32 egid, u32 sgid) +{ + gid_t a, b, c; + int ret; + mm_segment_t old_fs = get_fs(); + + set_fs (KERNEL_DS); + ret = sys_getresgid(&a, &b, &c); + set_fs (old_fs); + if (put_user (a, (__kernel_gid_t32 *)A(rgid)) || + put_user (b, (__kernel_gid_t32 *)A(egid)) || + put_user (c, (__kernel_gid_t32 *)A(sgid))) + return -EFAULT; + return ret; +} + struct tms32 { __kernel_clock_t32 tms_utime; __kernel_clock_t32 tms_stime; @@ -1709,7 +1893,7 @@ asmlinkage long sys32_times(u32 tbuf) { struct tms t; long ret; - unsigned long old_fs = get_fs (); + mm_segment_t old_fs = get_fs (); set_fs (KERNEL_DS); ret = sys_times(tbuf ? &t : NULL); @@ -1729,7 +1913,7 @@ asmlinkage int sys32_getgroups(int gidsetsize, u32 grouplist) { gid_t gl[NGROUPS]; int ret, i; - unsigned long old_fs = get_fs (); + mm_segment_t old_fs = get_fs (); set_fs (KERNEL_DS); ret = sys_getgroups(gidsetsize, gl); @@ -1747,7 +1931,7 @@ asmlinkage int sys32_setgroups(int gidsetsize, u32 grouplist) { gid_t gl[NGROUPS]; int ret, i; - unsigned long old_fs = get_fs (); + mm_segment_t old_fs = get_fs (); if ((unsigned) gidsetsize > NGROUPS) return -EINVAL; @@ -1774,7 +1958,7 @@ asmlinkage int sys32_getrlimit(unsigned int resource, u32 rlim) { struct rlimit r; int ret; - unsigned long old_fs = get_fs (); + mm_segment_t old_fs = get_fs (); set_fs (KERNEL_DS); ret = sys_getrlimit(resource, &r); @@ -1792,7 +1976,7 @@ asmlinkage int sys32_setrlimit(unsigned int resource, u32 rlim) { struct rlimit r; int ret; - unsigned long old_fs = get_fs (); + mm_segment_t old_fs = get_fs (); if (resource >= RLIM_NLIMITS) return -EINVAL; if (get_user (r.rlim_cur, &(((struct rlimit32 *)A(rlim))->rlim_cur)) || @@ -1814,7 +1998,7 @@ asmlinkage int sys32_getrusage(int who, u32 ru) { struct rusage r; int ret; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); set_fs (KERNEL_DS); ret = sys_getrusage(who, &r); @@ -1854,7 +2038,7 @@ asmlinkage int sys32_adjtimex(u32 txc_p) { struct timex t; int ret; - unsigned long old_fs = get_fs (); + mm_segment_t old_fs = get_fs (); if (get_user (t.modes, &(((struct timex32 *)A(txc_p))->modes)) || __get_user (t.offset, &(((struct timex32 *)A(txc_p))->offset)) || @@ -2158,21 +2342,19 @@ static unsigned char nargs[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)}; #undef AL -extern asmlinkage int sys32_bind(int fd, u32 umyaddr, int addrlen); -extern asmlinkage int sys32_connect(int fd, u32 uservaddr, int addrlen); -extern asmlinkage int sys32_accept(int fd, u32 upeer_sockaddr, u32 upeer_addrlen); -extern asmlinkage int sys32_getsockname(int fd, u32 usockaddr, u32 usockaddr_len); -extern asmlinkage int sys32_getpeername(int fd, u32 usockaddr, u32 usockaddr_len); -extern asmlinkage int sys32_send(int fd, u32 buff, __kernel_size_t32 len, - unsigned flags); +extern asmlinkage int sys_bind(int fd, struct sockaddr *umyaddr, int addrlen); +extern asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen); +extern asmlinkage int sys_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrlen); +extern asmlinkage int sys_getsockname(int fd, struct sockaddr *usockaddr, int *usockaddr_len); +extern asmlinkage int sys_getpeername(int fd, struct sockaddr *usockaddr, int *usockaddr_len); +extern asmlinkage int sys_send(int fd, void *buff, size_t len, unsigned flags); extern asmlinkage int sys32_sendto(int fd, u32 buff, __kernel_size_t32 len, unsigned flags, u32 addr, int addr_len); -extern asmlinkage int sys32_recv(int fd, u32 ubuf, __kernel_size_t32 size, - unsigned flags); +extern asmlinkage int sys_recv(int fd, void *ubuf, size_t size, unsigned flags); extern asmlinkage int sys32_recvfrom(int fd, u32 ubuf, __kernel_size_t32 size, unsigned flags, u32 addr, u32 addr_len); -extern asmlinkage int sys32_setsockopt(int fd, int level, int optname, - u32 optval, int optlen); +extern asmlinkage int sys_setsockopt(int fd, int level, int optname, + char *optval, int optlen); extern asmlinkage int sys32_getsockopt(int fd, int level, int optname, u32 optval, u32 optlen); @@ -2199,31 +2381,31 @@ asmlinkage int sys32_socketcall(int call, u32 args) case SYS_SOCKET: return sys_socket(a0, a1, a[2]); case SYS_BIND: - return sys32_bind(a0, a1, a[2]); + return sys_bind(a0, (struct sockaddr *)A(a1), a[2]); case SYS_CONNECT: - return sys32_connect(a0, a1, a[2]); + return sys_connect(a0, (struct sockaddr *)A(a1), a[2]); case SYS_LISTEN: return sys_listen(a0, a1); case SYS_ACCEPT: - return sys32_accept(a0, a1, a[2]); + return sys_accept(a0, (struct sockaddr *)A(a1), (int *)A(a[2])); case SYS_GETSOCKNAME: - return sys32_getsockname(a0, a1, a[2]); + return sys_getsockname(a0, (struct sockaddr *)A(a1), (int *)A(a[2])); case SYS_GETPEERNAME: - return sys32_getpeername(a0, a1, a[2]); + return sys_getpeername(a0, (struct sockaddr *)A(a1), (int *)A(a[2])); case SYS_SOCKETPAIR: return sys_socketpair(a0, a1, a[2], (int *)A(a[3])); case SYS_SEND: - return sys32_send(a0, a1, a[2], a[3]); + return sys_send(a0, (void *)A(a1), a[2], a[3]); case SYS_SENDTO: return sys32_sendto(a0, a1, a[2], a[3], a[4], a[5]); case SYS_RECV: - return sys32_recv(a0, a1, a[2], a[3]); + return sys_recv(a0, (void *)A(a1), a[2], a[3]); case SYS_RECVFROM: return sys32_recvfrom(a0, a1, a[2], a[3], a[4], a[5]); case SYS_SHUTDOWN: return sys_shutdown(a0,a1); case SYS_SETSOCKOPT: - return sys32_setsockopt(a0, a1, a[2], a[3], a[4]); + return sys_setsockopt(a0, a1, a[2], (char *)A(a[3]), a[4]); case SYS_GETSOCKOPT: return sys32_getsockopt(a0, a1, a[2], a[3], a[4]); case SYS_SENDMSG: @@ -2236,51 +2418,88 @@ asmlinkage int sys32_socketcall(int call, u32 args) extern void check_pending(int signum); -asmlinkage int sparc32_sigaction (int signum, u32 action, u32 oldaction) +asmlinkage int sys32_sigaction (int sig, u32 act, u32 oact) { - struct sigaction32 new_sa, old_sa; - struct sigaction *p; + struct k_sigaction new_ka, old_ka; + int ret; - if(signum < 0) { + if(sig < 0) { current->tss.new_signal = 1; - signum = -signum; + sig = -sig; } - if (signum<1 || signum>32) - return -EINVAL; - p = signum - 1 + current->sig->action; - if (action) { - if (signum==SIGKILL || signum==SIGSTOP) - return -EINVAL; - if(copy_from_user(&new_sa, A(action), sizeof(struct sigaction32))) + + if (act) { + old_sigset_t32 mask; + + if (get_user((long)new_ka.sa.sa_handler, &((struct old_sigaction32 *)A(act))->sa_handler) || + __get_user((long)new_ka.sa.sa_restorer, &((struct old_sigaction32 *)A(act))->sa_restorer)) return -EFAULT; - if (((__sighandler_t)A(new_sa.sa_handler)) != SIG_DFL && - ((__sighandler_t)A(new_sa.sa_handler)) != SIG_IGN) { - int err = verify_area(VERIFY_READ, - (__sighandler_t)A(new_sa.sa_handler), 1); - if (err) - return err; + __get_user(new_ka.sa.sa_flags, &((struct old_sigaction32 *)A(act))->sa_flags); + __get_user(mask, &((struct old_sigaction32 *)A(act))->sa_mask); + new_ka.ka_restorer = NULL; + siginitset(&new_ka.sa.sa_mask, mask); + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + if (put_user((long)old_ka.sa.sa_handler, &((struct old_sigaction32 *)A(oact))->sa_handler) || + __put_user((long)old_ka.sa.sa_restorer, &((struct old_sigaction32 *)A(oact))->sa_restorer)) + return -EFAULT; + __put_user(old_ka.sa.sa_flags, &((struct old_sigaction32 *)A(oact))->sa_flags); + __put_user(old_ka.sa.sa_mask.sig[0], &((struct old_sigaction32 *)A(oact))->sa_mask); + } + + return ret; +} + +asmlinkage int +sys32_rt_sigaction(int sig, u32 act, u32 oact, + u32 restorer, __kernel_size_t32 sigsetsize) +{ + struct k_sigaction new_ka, old_ka; + int ret; + sigset_t32 set32; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t32)) + return -EINVAL; + + if (act) { + if (get_user((long)new_ka.sa.sa_handler, &((struct sigaction32 *)A(act))->sa_handler) || + __copy_from_user(&set32, &((struct sigaction32 *)A(act))->sa_mask, sizeof(sigset_t32))) + return -EFAULT; + switch (_NSIG_WORDS) { + case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6] | (((long)set32.sig[7]) << 32); + case 3: new_ka.sa.sa_mask.sig[2] = set32.sig[4] | (((long)set32.sig[5]) << 32); + case 2: new_ka.sa.sa_mask.sig[1] = set32.sig[2] | (((long)set32.sig[3]) << 32); + case 1: new_ka.sa.sa_mask.sig[0] = set32.sig[0] | (((long)set32.sig[1]) << 32); } - } - if (oldaction) { - old_sa.sa_handler = (unsigned)(u64)(p->sa_handler); - old_sa.sa_mask = (sigset_t32)(p->sa_mask); - old_sa.sa_flags = (unsigned)(p->sa_flags); - old_sa.sa_restorer = (unsigned)(u64)(p->sa_restorer); - if (copy_to_user(A(oldaction), &old_sa, sizeof(struct sigaction32))) - return -EFAULT; - } - if (action) { - spin_lock_irq(¤t->sig->siglock); - p->sa_handler = (__sighandler_t)A(new_sa.sa_handler); - p->sa_mask = (sigset_t)(new_sa.sa_mask); - p->sa_flags = new_sa.sa_flags; - p->sa_restorer = (void (*)(void))A(new_sa.sa_restorer); - check_pending(signum); - spin_unlock_irq(¤t->sig->siglock); - } - return 0; + __get_user(new_ka.sa.sa_flags, &((struct sigaction32 *)A(act))->sa_flags); + __get_user((long)new_ka.sa.sa_restorer, &((struct sigaction32 *)A(act))->sa_restorer); + new_ka.ka_restorer = (void *)(long)restorer; + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + switch (_NSIG_WORDS) { + case 4: set32.sig[7] = (old_ka.sa.sa_mask.sig[3] >> 32); set32.sig[6] = old_ka.sa.sa_mask.sig[3]; + case 3: set32.sig[5] = (old_ka.sa.sa_mask.sig[2] >> 32); set32.sig[4] = old_ka.sa.sa_mask.sig[2]; + case 2: set32.sig[3] = (old_ka.sa.sa_mask.sig[1] >> 32); set32.sig[2] = old_ka.sa.sa_mask.sig[1]; + case 1: set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32); set32.sig[0] = old_ka.sa.sa_mask.sig[0]; + } + if (put_user((long)old_ka.sa.sa_handler, &((struct sigaction32 *)A(oact))->sa_handler) || + __copy_to_user(&((struct sigaction32 *)A(oact))->sa_mask, &set32, sizeof(sigset_t32))) + return -EFAULT; + __put_user(old_ka.sa.sa_flags, &((struct sigaction32 *)A(oact))->sa_flags); + __put_user((long)old_ka.sa.sa_restorer, &((struct sigaction32 *)A(oact))->sa_restorer); + } + + return ret; } + /* * count32() counts the number of arguments/envelopes */ @@ -2476,7 +2695,7 @@ extern asmlinkage int sys_query_module(const char *name_user, int which, char *b asmlinkage int sys32_query_module(u32 name_user, int which, u32 buf, __kernel_size_t32 bufsize, u32 retv) { char *buff; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); size_t val; int ret, i, j; unsigned long *p; @@ -2544,7 +2763,7 @@ qmsym_toshort: if (!ret && val) { char *strings = buff + ((unsigned long *)buff)[1]; j = *(p - 1) - ((unsigned long *)buff)[1]; - j = j + strlen (buff + j) + 1; + j = j + strlen (strings + j) + 1; if (bufsize < j) { bufsiz = 0; goto qmsym_toshort; @@ -2597,7 +2816,7 @@ asmlinkage int sys32_get_kernel_syms(u32 table) { int len, i; struct kernel_sym *tbl; - unsigned long old_fs; + mm_segment_t old_fs; len = sys_get_kernel_syms(NULL); if (!table) return len; @@ -2858,7 +3077,7 @@ int asmlinkage sys32_nfsservctl(int cmd, u32 u_argp, u32 u_resp) union nfsctl_res32 *res32 = (union nfsctl_res32 *)A(u_resp); struct nfsctl_arg *karg = NULL; union nfsctl_res *kres = NULL; - unsigned long oldfs; + mm_segment_t oldfs; int err; karg = kmalloc(sizeof(*karg), GFP_USER); @@ -3003,7 +3222,7 @@ asmlinkage int sys32_utimes(u32 filename, u32 tvs) { char *kfilename; struct timeval ktvs[2]; - unsigned long old_fs; + mm_segment_t old_fs; int ret; kfilename = getname32(filename); @@ -3024,3 +3243,87 @@ asmlinkage int sys32_utimes(u32 filename, u32 tvs) } return ret; } + +/* These are here just in case some old sparc32 binary calls it. */ +asmlinkage int sys32_pause(void) +{ + current->state = TASK_INTERRUPTIBLE; + schedule(); + return -ERESTARTNOHAND; +} + +/* PCI config space poking. */ +extern asmlinkage int sys_pciconfig_read(unsigned long bus, + unsigned long dfn, + unsigned long off, + unsigned long len, + unsigned char *buf); + +extern asmlinkage int sys_pciconfig_write(unsigned long bus, + unsigned long dfn, + unsigned long off, + unsigned long len, + unsigned char *buf); + +asmlinkage int sys32_pciconfig_read(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf) +{ + return sys_pciconfig_read((unsigned long) bus, + (unsigned long) dfn, + (unsigned long) off, + (unsigned long) len, + (unsigned char *)A(ubuf)); +} + +asmlinkage int sys32_pciconfig_write(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf) +{ + return sys_pciconfig_write((unsigned long) bus, + (unsigned long) dfn, + (unsigned long) off, + (unsigned long) len, + (unsigned char *)A(ubuf)); +} + +extern asmlinkage int sys_prctl(int option, unsigned long arg2, unsigned long arg3, + unsigned long arg4, unsigned long arg5); + +asmlinkage int sys32_prctl(int option, u32 arg2, u32 arg3, u32 arg4, u32 arg5) +{ + return sys_prctl(option, + (unsigned long) arg2, + (unsigned long) arg3, + (unsigned long) arg4, + (unsigned long) arg5); +} + + +extern asmlinkage int sys_newuname(struct new_utsname * name); + +asmlinkage int sys32_newuname(struct new_utsname * name) +{ + int ret = sys_newuname(name); + + if (current->personality == PER_LINUX32 && !ret) { + ret = copy_to_user(name->machine, "sparc\0\0", 8); + } + return ret; +} + +extern asmlinkage ssize_t sys_pread(unsigned int fd, char * buf, + size_t count, loff_t pos); + +extern asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf, + size_t count, loff_t pos); + +typedef __kernel_ssize_t32 ssize_t32; + +asmlinkage ssize_t32 sys32_pread(unsigned int fd, u32 ubuf, + __kernel_size_t32 count, u32 pos) +{ + return sys_pread(fd, (char *) A(ubuf), count, pos); +} + +asmlinkage ssize_t32 sys32_pwrite(unsigned int fd, u32 ubuf, + __kernel_size_t32 count, u32 pos) +{ + return sys_pwrite(fd, (char *) A(ubuf), count, pos); +} diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c index dc87c3095..4af388b99 100644 --- a/arch/sparc64/kernel/sys_sunos32.c +++ b/arch/sparc64/kernel/sys_sunos32.c @@ -1,4 +1,4 @@ -/* $Id: sys_sunos32.c,v 1.3 1997/07/17 02:20:48 davem Exp $ +/* $Id: sys_sunos32.c,v 1.7 1997/12/11 15:15:19 jj Exp $ * sys_sunos32.c: SunOS binary compatability layer on sparc64. * * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu) @@ -297,35 +297,28 @@ asmlinkage int sunos_getdtablesize(void) return SUNOS_NR_OPEN; } -#define _S(nr) (1<<((nr)-1)) -#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) asmlinkage u32 sunos_sigblock(u32 blk_mask) { - unsigned long flags; u32 old; - lock_kernel(); - save_and_cli(flags); - old = (u32) current->blocked; - current->blocked |= (blk_mask & _BLOCKABLE); - restore_flags(flags); - unlock_kernel(); + spin_lock_irq(¤t->sigmask_lock); + old = (u32) current->blocked.sig[0]; + current->blocked.sig[0] |= (blk_mask & _BLOCKABLE); + spin_unlock_irq(¤t->sigmask_lock); return old; } asmlinkage u32 sunos_sigsetmask(u32 newmask) { - unsigned long flags; u32 retval; - lock_kernel(); - save_and_cli(flags); - retval = (u32) current->blocked; - current->blocked = (newmask & _BLOCKABLE); - restore_flags(flags); - unlock_kernel(); + spin_lock_irq(¤t->sigmask_lock); + retval = (u32) current->blocked.sig[0]; + current->blocked.sig[0] = (newmask & _BLOCKABLE); + spin_unlock_irq(¤t->sigmask_lock); return retval; } @@ -379,8 +372,6 @@ static int sunos_filldir(void * __buf, const char * name, int namlen, asmlinkage int sunos_getdents(unsigned int fd, u32 u_dirent, int cnt) { struct file * file; - struct dentry * dentry; - struct inode * inode; struct sunos_dirent * lastdirent; struct sunos_dirent_callback buf; int error = -EBADF; @@ -394,14 +385,6 @@ asmlinkage int sunos_getdents(unsigned int fd, u32 u_dirent, int cnt) if(!file) goto out; - dentry = file->f_dentry; - if(!dentry) - goto out; - - inode = dentry->d_inode; - if(!inode) - goto out; - error = -ENOTDIR; if (!file->f_op || !file->f_op->readdir) goto out; @@ -415,7 +398,7 @@ asmlinkage int sunos_getdents(unsigned int fd, u32 u_dirent, int cnt) buf.count = cnt; buf.error = 0; - error = file->f_op->readdir(inode, file, &buf, sunos_filldir); + error = file->f_op->readdir(file, &buf, sunos_filldir); if (error < 0) goto out; lastdirent = buf.previous; @@ -472,8 +455,6 @@ asmlinkage int sunos_getdirentries(unsigned int fd, u32 u_dirent, int cnt, u32 u_basep) { struct file * file; - struct dentry * dentry; - struct inode * inode; struct sunos_direntry * lastdirent; struct sunos_direntry_callback buf; int error = -EBADF; @@ -488,14 +469,6 @@ asmlinkage int sunos_getdirentries(unsigned int fd, u32 u_dirent, if(!file) goto out; - dentry = file->f_dentry; - if(!dentry) - goto out; - - inode = dentry->d_inode; - if(!inode) - goto out; - error = -ENOTDIR; if (!file->f_op || !file->f_op->readdir) goto out; @@ -509,7 +482,7 @@ asmlinkage int sunos_getdirentries(unsigned int fd, u32 u_dirent, buf.count = cnt; buf.error = 0; - error = file->f_op->readdir(inode, file, &buf, sunos_filldirentry); + error = file->f_op->readdir(file, &buf, sunos_filldirentry); if (error < 0) goto out; lastdirent = buf.previous; @@ -1140,7 +1113,7 @@ asmlinkage int sunos_msgsys(int op, u32 arg1, u32 arg2, u32 arg3, u32 arg4) struct sparc_stackf32 *sp; struct msqid_ds kds; struct msgbuf *kmbuf; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); u32 arg5; int rval; @@ -1264,7 +1237,8 @@ extern asmlinkage int sys_shmget (key_t key, int size, int shmflg); asmlinkage int sunos_shmsys(int op, u32 arg1, u32 arg2, u32 arg3) { struct shmid_ds ksds; - unsigned long raddr, old_fs = get_fs(); + unsigned long raddr; + mm_segment_t old_fs = get_fs(); int rval; lock_kernel(); @@ -1328,20 +1302,20 @@ static inline int check_nonblock(int ret, int fd) return ret; } -extern asmlinkage int sys32_read(unsigned int fd, u32 buf, int count); -extern asmlinkage int sys32_write(unsigned int fd, u32 buf,int count); -extern asmlinkage int sys32_recv(int fd, u32 ubuf, int size, unsigned flags); -extern asmlinkage int sys32_send(int fd, u32 buff, int len, unsigned flags); -extern asmlinkage int sys32_accept(int fd, u32 sa, u32 addrlen); +extern asmlinkage int sys_read(unsigned int fd, char *buf, unsigned long count); +extern asmlinkage int sys_write(unsigned int fd, char *buf, unsigned long count); +extern asmlinkage int sys_recv(int fd, void *ubuf, size_t size, unsigned flags); +extern asmlinkage int sys_send(int fd, void *buff, size_t len, unsigned flags); +extern asmlinkage int sys_accept(int fd, struct sockaddr *sa, int *addrlen); extern asmlinkage int sys32_readv(u32 fd, u32 vector, s32 count); extern asmlinkage int sys32_writev(u32 fd, u32 vector, s32 count); -asmlinkage int sunos_read(unsigned int fd, u32 buf, int count) +asmlinkage int sunos_read(unsigned int fd, u32 buf, u32 count) { int ret; lock_kernel(); - ret = check_nonblock(sys32_read(fd, buf, count), fd); + ret = check_nonblock(sys_read(fd, (char *)A(buf), count), fd); unlock_kernel(); return ret; } @@ -1356,12 +1330,12 @@ asmlinkage int sunos_readv(u32 fd, u32 vector, s32 count) return ret; } -asmlinkage int sunos_write(unsigned int fd, u32 buf, int count) +asmlinkage int sunos_write(unsigned int fd, u32 buf, u32 count) { int ret; lock_kernel(); - ret = check_nonblock(sys32_write(fd, buf, count), fd); + ret = check_nonblock(sys_write(fd, (char *)A(buf), count), fd); unlock_kernel(); return ret; } @@ -1381,7 +1355,7 @@ asmlinkage int sunos_recv(int fd, u32 ubuf, int size, unsigned flags) int ret; lock_kernel(); - ret = check_nonblock(sys32_recv(fd, ubuf, size, flags), fd); + ret = check_nonblock(sys_recv(fd, (void *)A(ubuf), size, flags), fd); unlock_kernel(); return ret; } @@ -1391,7 +1365,7 @@ asmlinkage int sunos_send(int fd, u32 buff, int len, unsigned flags) int ret; lock_kernel(); - ret = check_nonblock(sys32_send(fd, buff, len, flags), fd); + ret = check_nonblock(sys_send(fd, (void *)A(buff), len, flags), fd); unlock_kernel(); return ret; } @@ -1401,78 +1375,48 @@ asmlinkage int sunos_accept(int fd, u32 sa, u32 addrlen) int ret; lock_kernel(); - ret = check_nonblock(sys32_accept(fd, sa, addrlen), fd); + ret = check_nonblock(sys_accept(fd, (struct sockaddr *)A(sa), (int *)A(addrlen)), fd); unlock_kernel(); return ret; } #define SUNOS_SV_INTERRUPT 2 -extern void check_pending(int signum); - -asmlinkage int sunos_sigaction(int signum, u32 action, u32 oldaction) +asmlinkage int sunos_sigaction (int sig, u32 act, u32 oact) { - struct sigaction32 new_sa, old_sa; - struct sigaction *p; - const int sigaction_size = sizeof (struct sigaction32) - sizeof (u32); + struct k_sigaction new_ka, old_ka; + int ret; current->personality |= PER_BSD; - if(signum < 1 || signum > 32) - return -EINVAL; - p = signum - 1 + current->sig->action; + if (act) { + old_sigset_t32 mask; - if(action) { - if (signum==SIGKILL || signum==SIGSTOP) - return -EINVAL; - memset(&new_sa, 0, sizeof(struct sigaction32)); - if(copy_from_user(&new_sa, (struct sigaction32 *)A(action), - sigaction_size)) + if (get_user((long)new_ka.sa.sa_handler, &((struct old_sigaction32 *)A(act))->sa_handler) || + __get_user(new_ka.sa.sa_flags, &((struct old_sigaction32 *)A(act))->sa_flags)) return -EFAULT; - if (((__sighandler_t)A(new_sa.sa_handler) != SIG_DFL) && - (__sighandler_t)A(new_sa.sa_handler) != SIG_IGN) { - if(verify_area(VERIFY_READ, - (__sighandler_t)A(new_sa.sa_handler), 1)) - return -EFAULT; - } - new_sa.sa_flags ^= SUNOS_SV_INTERRUPT; + __get_user(mask, &((struct old_sigaction32 *)A(act))->sa_mask); + new_ka.sa.sa_restorer = NULL; + new_ka.ka_restorer = NULL; + siginitset(&new_ka.sa.sa_mask, mask); + new_ka.sa.sa_flags ^= SUNOS_SV_INTERRUPT; } - if (oldaction) { - /* In the clone() case we could copy half consistant - * state to the user, however this could sleep and - * deadlock us if we held the signal lock on SMP. So for - * now I take the easy way out and do no locking. - * But then again we don't support SunOS lwp's anyways ;-) - */ - old_sa.sa_handler = (unsigned)(u64)(p->sa_handler); - old_sa.sa_mask = (sigset_t32)(p->sa_mask); - old_sa.sa_flags = (unsigned)(p->sa_flags); - - if (old_sa.sa_flags & SA_RESTART) - old_sa.sa_flags &= ~SA_RESTART; - else - old_sa.sa_flags |= SUNOS_SV_INTERRUPT; - if (copy_to_user((struct sigaction32 *)A(oldaction), - &old_sa, sigaction_size)) - return -EFAULT; - } + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); - if (action) { - spin_lock_irq(¤t->sig->siglock); - p->sa_handler = (__sighandler_t)A(new_sa.sa_handler); - p->sa_mask = (sigset_t)(new_sa.sa_mask); - p->sa_flags = new_sa.sa_flags; - p->sa_restorer = (void (*)(void))0; - check_pending(signum); - spin_unlock_irq(¤t->sig->siglock); + if (!ret && oact) { + old_ka.sa.sa_flags ^= SUNOS_SV_INTERRUPT; + if (put_user((long)old_ka.sa.sa_handler, &((struct old_sigaction32 *)A(oact))->sa_handler) || + __put_user(old_ka.sa.sa_flags, &((struct old_sigaction32 *)A(oact))->sa_flags)) + return -EFAULT; + __put_user(old_ka.sa.sa_mask.sig[0], &((struct old_sigaction32 *)A(oact))->sa_mask); } - return 0; -} + return ret; +} -extern asmlinkage int sys32_setsockopt(int fd, int level, int optname, - u32 optval, int optlen); +extern asmlinkage int sys_setsockopt(int fd, int level, int optname, + char *optval, int optlen); extern asmlinkage int sys32_getsockopt(int fd, int level, int optname, u32 optval, u32 optlen); @@ -1488,7 +1432,7 @@ asmlinkage int sunos_setsockopt(int fd, int level, int optname, u32 optval, if (tr_opt >=2 && tr_opt <= 6) tr_opt += 30; } - ret = sys32_setsockopt(fd, level, tr_opt, optval, optlen); + ret = sys_setsockopt(fd, level, tr_opt, (char *)A(optval), optlen); unlock_kernel(); return ret; } diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S index ec2c3c9b6..48ae0ecdf 100644 --- a/arch/sparc64/kernel/systbls.S +++ b/arch/sparc64/kernel/systbls.S @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.24 1997/08/22 20:12:06 davem Exp $ +/* $Id: systbls.S,v 1.37 1997/12/24 17:27:31 ecd Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -17,58 +17,58 @@ .globl sys_call_table32 sys_call_table32: -/*0*/ .word sys_setup, sys_exit, sys_fork, sys32_read, sys32_write -/*5*/ .word sys32_open, sys_close, sys32_wait4, sys32_creat, sys32_link -/*10*/ .word sys32_unlink, sunos_execv, sys32_chdir, sys_nis_syscall, sys32_mknod -/*15*/ .word sys32_chmod, sys32_chown, sparc32_brk, sys_nis_syscall, sys32_lseek +/*0*/ .word sys_setup, sys_exit, sys_fork, sys_read, sys_write +/*5*/ .word sys_open, sys_close, sys32_wait4, sys_creat, sys_link +/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys32_mknod +/*15*/ .word sys32_chmod, sys32_chown, sparc_brk, sys_nis_syscall, sys32_lseek /*20*/ .word sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid -/*25*/ .word sys32_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_pause -/*30*/ .word sys32_utime, sys_stty, sys_gtty, sys32_access, sys_nice - .word sys_ftime, sys_sync, sys_kill, sys32_newstat, sys_nis_syscall -/*40*/ .word sys32_newlstat, sys_dup, sys_pipe, sys32_times, sys_profil - .word sys_nis_syscall, sys_setgid, sys_getgid, sys32_signal, sys_geteuid -/*50*/ .word sys_getegid, sys32_acct, sys_nis_syscall, sys_nis_syscall, sys32_ioctl - .word sys32_reboot, sys_nis_syscall, sys32_symlink, sys32_readlink, sys32_execve -/*60*/ .word sys_umask, sys32_chroot, sys32_newfstat, sys_nis_syscall, sys_getpagesize - .word sys32_msync, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall -/*70*/ .word sys_nis_syscall, sys32_mmap, sys_nis_syscall, sys32_munmap, sys32_mprotect +/*25*/ .word sys_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys32_pause +/*30*/ .word sys32_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice + .word sys_nis_syscall, sys_sync, sys_kill, sys32_newstat, sys_nis_syscall +/*40*/ .word sys32_newlstat, sys_dup, sys_pipe, sys32_times, sys_nis_syscall + .word sys_nis_syscall, sys_setgid, sys_getgid, sys_signal, sys_geteuid +/*50*/ .word sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys32_ioctl + .word sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys32_execve +/*60*/ .word sys_umask, sys_chroot, sys32_newfstat, sys_nis_syscall, sys_getpagesize + .word sys_msync, sys_vfork, sys32_pread, sys32_pwrite, sys_nis_syscall +/*70*/ .word sys_nis_syscall, sys32_mmap, sys_nis_syscall, sys_munmap, sys_mprotect .word sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys32_getgroups /*80*/ .word sys32_setgroups, sys_getpgrp, sys_nis_syscall, sys32_setitimer, sys_nis_syscall - .word sys32_swapon, sys32_getitimer, sys_nis_syscall, sys32_sethostname, sys_nis_syscall + .word sys_swapon, sys32_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall /*90*/ .word sys_dup2, sys_nis_syscall, sys32_fcntl, sys32_select, sys_nis_syscall .word sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall -/*100*/ .word sys_getpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall - .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall +/*100*/ .word sys_getpriority, sys32_rt_sigreturn, sys32_rt_sigaction, sys32_rt_sigprocmask, sys32_rt_sigpending + .word sys32_rt_sigtimedwait, sys32_rt_sigqueueinfo, sys32_rt_sigsuspend, sys_nis_syscall, sys_nis_syscall /*110*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall .word sys_nis_syscall, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_nis_syscall /*120*/ .word sys32_readv, sys32_writev, sys32_settimeofday, sys_fchown, sys_fchmod - .word sys_nis_syscall, sys32_setreuid, sys_setregid, sys32_rename, sys32_truncate -/*130*/ .word sys32_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall - .word sys_nis_syscall, sys32_mkdir, sys32_rmdir, sys_nis_syscall, sys_nis_syscall + .word sys_nis_syscall, sys32_setreuid, sys32_setregid, sys_rename, sys_truncate +/*130*/ .word sys_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall + .word sys_nis_syscall, sys_mkdir, sys_rmdir, sys_nis_syscall, sys_nis_syscall /*140*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getrlimit - .word sys32_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall -/*150*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall - .word sys_nis_syscall, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys32_umount -/*160*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_setdomainname, sys_nis_syscall - .word sys32_quotactl, sys_nis_syscall, sys32_mount, sys32_ustat, sys_nis_syscall + .word sys32_setrlimit, sys_nis_syscall, sys32_prctl, sys32_pciconfig_read, sys32_pciconfig_write +/*150*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall + .word sys_nis_syscall, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys_umount +/*160*/ .word sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_nis_syscall + .word sys32_quotactl, sys_nis_syscall, sys32_mount, sys_ustat, sys_nis_syscall /*170*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getdents .word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall /*180*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_sigpending, sys32_query_module .word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_newuname -/*190*/ .word sys32_init_module, sys32_personality, sys_prof, sys_break, sys_lock - .word sys_mpx, sys_ulimit, sys_getppid, sparc32_sigaction, sys_sgetmask -/*200*/ .word sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys32_uselib, old32_readdir - .word sys_nis_syscall, sys32_socketcall, sys32_syslog, sys32_olduname, sys_nis_syscall -/*210*/ .word sys_idle, sys_nis_syscall, sys32_waitpid, sys32_swapoff, sys32_sysinfo - .word sys32_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex +/*190*/ .word sys32_init_module, sys_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall + .word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys32_sigaction, sys_sgetmask +/*200*/ .word sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys_uselib, old32_readdir + .word sys_nis_syscall, sys32_socketcall, sys_syslog, sys_nis_syscall, sys_nis_syscall +/*210*/ .word sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys32_sysinfo + .word sys32_ipc, sys32_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex /*220*/ .word sys32_sigprocmask, sys32_create_module, sys32_delete_module, sys32_get_kernel_syms, sys_getpgid .word sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid -/*230*/ .word sys32_llseek, sys32_time, sys_nis_syscall, sys_stime, sys_nis_syscall - .word sys_nis_syscall, sys32_llseek, sys32_mlock, sys32_munlock, sys_mlockall -/*240*/ .word sys_munlockall, sys32_sched_setparam, sys32_sched_getparam, sys_nis_syscall, sys_nis_syscall +/*230*/ .word sys32_select, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall + .word sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall +/*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_nis_syscall, sys_nis_syscall .word sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys32_nanosleep -/*250*/ .word sys32_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl - .word sys_aplib, sys_prctl +/*250*/ .word sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl + .word sys_aplib /* Now the 64-bit native Linux syscall table. */ @@ -81,23 +81,23 @@ sys_call_table: /*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys_mknod /*15*/ .word sys_chmod, sys_chown, sparc_brk, sys_nis_syscall, sys_lseek /*20*/ .word sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid -/*25*/ .word sys_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_pause -/*30*/ .word sys_utime, sys_stty, sys_gtty, sys_access, sys_nice - .word sys_ftime, sys_sync, sys_kill, sys_newstat, sys_nis_syscall -/*40*/ .word sys_newlstat, sys_dup, sys_pipe, sys_times, sys_profil +/*25*/ .word sys_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_nis_syscall +/*30*/ .word sys_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice + .word sys_nis_syscall, sys_sync, sys_kill, sys_newstat, sys_nis_syscall +/*40*/ .word sys_newlstat, sys_dup, sys_pipe, sys_times, sys_nis_syscall .word sys_nis_syscall, sys_setgid, sys_getgid, sys_signal, sys_geteuid -/*50*/ .word sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys_ioctl +/*50*/ .word sys_getegid, sys_acct, sys_memory_ordering, sys_nis_syscall, sys_ioctl .word sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve /*60*/ .word sys_umask, sys_chroot, sys_newfstat, sys_nis_syscall, sys_getpagesize - .word sys_nis_syscall, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall + .word sys_msync, sys_vfork, sys_pread, sys_pwrite, sys_nis_syscall /*70*/ .word sys_nis_syscall, sys_mmap, sys_nis_syscall, sys_munmap, sys_mprotect .word sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys_getgroups /*80*/ .word sys_setgroups, sys_getpgrp, sys_nis_syscall, sys_setitimer, sys_nis_syscall .word sys_swapon, sys_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall /*90*/ .word sys_dup2, sys_nis_syscall, sys_fcntl, sys_select, sys_nis_syscall .word sys_fsync, sys_setpriority, sys_socket, sys_connect, sys_accept -/*100*/ .word sys_getpriority, sys_send, sys_recv, sys_nis_syscall, sys_bind - .word sys_setsockopt, sys_listen, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall +/*100*/ .word sys_getpriority, sys_rt_sigreturn, sys_rt_sigaction, sys_rt_sigprocmask, sys_rt_sigpending + .word sys_rt_sigtimedwait, sys_rt_sigqueueinfo, sys_rt_sigsuspend, sys_nis_syscall, sys_nis_syscall /*110*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_recvmsg, sys_sendmsg .word sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_getsockopt, sys_nis_syscall /*120*/ .word sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod @@ -105,29 +105,29 @@ sys_call_table: /*130*/ .word sys_ftruncate, sys_flock, sys_nis_syscall, sys_sendto, sys_shutdown .word sys_socketpair, sys_mkdir, sys_rmdir, sys_nis_syscall, sys_nis_syscall /*140*/ .word sys_nis_syscall, sys_getpeername, sys_nis_syscall, sys_nis_syscall, sys_getrlimit - .word sys_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall -/*150*/ .word sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall + .word sys_setrlimit, sys_nis_syscall, sys_prctl, sys_pciconfig_read, sys_pciconfig_write +/*150*/ .word sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall .word sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_umount -/*160*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_setdomainname, sys_nis_syscall +/*160*/ .word sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_utrap_install .word sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall /*170*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents .word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall /*180*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_sigpending, sys_query_module .word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_newuname -/*190*/ .word sys_init_module, sys_personality, sys_prof, sys_break, sys_lock - .word sys_mpx, sys_ulimit, sys_getppid, sparc_sigaction, sys_sgetmask +/*190*/ .word sys_init_module, sys_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall + .word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys_sigaction, sys_sgetmask /*200*/ .word sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, sys_nis_syscall .word sys_nis_syscall, sys_nis_syscall, sys_syslog, sys_nis_syscall, sys_nis_syscall /*210*/ .word sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo .word sys_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys_adjtimex /*220*/ .word sys_sigprocmask, sys_create_module, sys_delete_module, sys_get_kernel_syms, sys_getpgid .word sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid -/*230*/ .word sys_llseek, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall +/*230*/ .word sys_select, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall .word sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall /*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_nis_syscall, sys_nis_syscall .word sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep /*250*/ .word sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl - .word sys_aplib, sys_prctl + .word sys_aplib /* Now the 32-bit SunOS syscall table. */ @@ -136,40 +136,40 @@ sys_call_table: sunos_sys_table: /*0*/ .word sunos_indir, sys_exit, sys_fork .word sunos_read, sunos_write, sunos_open - .word sys_close, sunos_wait4, sys32_creat - .word sys32_link, sys32_unlink, sunos_execv - .word sys32_chdir, sunos_nosys, sys32_mknod + .word sys_close, sunos_wait4, sys_creat + .word sys_link, sys_unlink, sunos_execv + .word sys_chdir, sunos_nosys, sys32_mknod .word sys32_chmod, sys32_chown, sunos_brk .word sunos_nosys, sys32_lseek, sunos_getpid .word sunos_nosys, sunos_nosys, sunos_nosys .word sunos_getuid, sunos_nosys, sys_ptrace .word sunos_nosys, sunos_nosys, sunos_nosys .word sunos_nosys, sunos_nosys, sunos_nosys - .word sys32_access, sunos_nosys, sunos_nosys + .word sys_access, sunos_nosys, sunos_nosys .word sys_sync, sys_kill, sys32_newstat .word sunos_nosys, sys32_newlstat, sys_dup - .word sys_pipe, sunos_nosys, sys_profil + .word sys_pipe, sunos_nosys, sunos_nosys .word sunos_nosys, sunos_nosys, sunos_getgid .word sunos_nosys, sunos_nosys -/*50*/ .word sunos_nosys, sys32_acct, sunos_nosys - .word sunos_mctl, sunos_ioctl, sys32_reboot - .word sunos_nosys, sys32_symlink, sys32_readlink - .word sys32_execve, sys_umask, sys32_chroot +/*50*/ .word sunos_nosys, sys_acct, sunos_nosys + .word sunos_mctl, sunos_ioctl, sys_reboot + .word sunos_nosys, sys_symlink, sys_readlink + .word sys32_execve, sys_umask, sys_chroot .word sys32_newfstat, sunos_nosys, sys_getpagesize - .word sys32_msync, sys_vfork, sunos_nosys + .word sys_msync, sys_vfork, sunos_nosys .word sunos_nosys, sunos_sbrk, sunos_sstk - .word sunos_mmap, sunos_vadvise, sys32_munmap - .word sys32_mprotect, sunos_madvise, sys_vhangup + .word sunos_mmap, sunos_vadvise, sys_munmap + .word sys_mprotect, sunos_madvise, sys_vhangup .word sunos_nosys, sunos_mincore, sys32_getgroups .word sys32_setgroups, sys_getpgrp, sunos_setpgrp - .word sys32_setitimer, sunos_nosys, sys32_swapon - .word sys32_getitimer, sys32_gethostname, sys32_sethostname + .word sys32_setitimer, sunos_nosys, sys_swapon + .word sys32_getitimer, sys_gethostname, sys_sethostname .word sunos_getdtablesize, sys_dup2, sunos_nop .word sys32_fcntl, sunos_select, sunos_nop .word sys_fsync, sys_setpriority, sys_socket - .word sys32_connect, sunos_accept + .word sys_connect, sunos_accept /*100*/ .word sys_getpriority, sunos_send, sunos_recv - .word sunos_nosys, sys32_bind, sunos_setsockopt + .word sunos_nosys, sys_bind, sunos_setsockopt .word sys_listen, sunos_nosys, sunos_sigaction .word sunos_sigblock, sunos_sigsetmask, sys_sigpause .word sys32_sigstack, sys32_recvmsg, sys32_sendmsg @@ -177,21 +177,21 @@ sunos_sys_table: .word sunos_getsockopt, sunos_nosys, sunos_readv .word sunos_writev, sys32_settimeofday, sys_fchown .word sys_fchmod, sys32_recvfrom, sys32_setreuid - .word sys_setregid, sys32_rename, sys32_truncate - .word sys32_ftruncate, sys_flock, sunos_nosys + .word sys_setregid, sys_rename, sys_truncate + .word sys_ftruncate, sys_flock, sunos_nosys .word sys32_sendto, sys_shutdown, sys_socketpair - .word sys32_mkdir, sys32_rmdir, sys32_utimes - .word sys_sigreturn, sunos_nosys, sys32_getpeername + .word sys_mkdir, sys_rmdir, sys32_utimes + .word sys32_sigreturn, sunos_nosys, sys_getpeername .word sunos_gethostid, sunos_nosys, sys32_getrlimit .word sys32_setrlimit, sunos_killpg, sunos_nosys .word sunos_nosys, sunos_nosys -/*150*/ .word sys32_getsockname, sunos_nosys, sunos_nosys - .word sys32_poll, sunos_nosys, sunos_nosys +/*150*/ .word sys_getsockname, sunos_nosys, sunos_nosys + .word sys_poll, sunos_nosys, sunos_nosys .word sunos_getdirentries, sys32_statfs, sys32_fstatfs - .word sys32_umount, sunos_nosys, sunos_nosys - .word sunos_getdomainname, sys32_setdomainname + .word sys_umount, sunos_nosys, sunos_nosys + .word sunos_getdomainname, sys_setdomainname .word sunos_nosys, sys32_quotactl, sunos_nosys - .word sunos_mount, sys32_ustat, sunos_semsys + .word sunos_mount, sys_ustat, sunos_semsys .word sunos_nosys, sunos_shmsys, sunos_audit .word sunos_nosys, sunos_getdents, sys_setsid .word sys_fchdir, sunos_nosys, sunos_nosys @@ -221,4 +221,3 @@ sunos_sys_table: .word sunos_nosys, sunos_nosys /*250*/ .word sunos_nosys, sunos_nosys, sunos_nosys .word sunos_nosys, sunos_nosys, sys_aplib - .word sunos_nosys diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index 1ffd43730..cde799d92 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.31 1997/08/11 14:35:33 davem Exp $ +/* $Id: traps.c,v 1.44 1998/01/09 16:39:35 jj Exp $ * arch/sparc64/kernel/traps.c * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) @@ -26,9 +26,13 @@ #include <asm/uaccess.h> #include <asm/fpumacro.h> #include <asm/lsu.h> +#ifdef CONFIG_KERNELD +#include <linux/kerneld.h> +#endif /* #define SYSCALL_TRACING */ /* #define VERBOSE_SYSCALL_TRACING */ +/* #define DEBUG_FPU */ #ifdef SYSCALL_TRACING #ifdef VERBOSE_SYSCALL_TRACING @@ -125,8 +129,9 @@ void syscall_trace_entry(unsigned long g1, struct pt_regs *regs) int i; #endif - if(strcmp(current->comm, "bash.sunos")) - return; +#if 0 + if (!current->pid) return; +#endif printk("SYS[%s:%d]: PC(%016lx) <%3d> ", current->comm, current->pid, regs->tpc, (int)g1); #ifdef VERBOSE_SYSCALL_TRACING @@ -141,12 +146,20 @@ void syscall_trace_entry(unsigned long g1, struct pt_regs *regs) for(i = 0; i < sdp->num_args; i++) { if(i) printk(","); - if(!sdp->arg_is_string[i]) - printk("%08x", (unsigned int)regs->u_regs[UREG_I0 + i]); - else { - strncpy_from_user(scall_strbuf, - (char *)regs->u_regs[UREG_I0 + i], - 512); + if(!sdp->arg_is_string[i]) { + if (current->tss.flags & SPARC_FLAG_32BIT) + printk("%08x", (unsigned int)regs->u_regs[UREG_I0 + i]); + else + printk("%016lx", regs->u_regs[UREG_I0 + i]); + } else { + if (current->tss.flags & SPARC_FLAG_32BIT) + strncpy_from_user(scall_strbuf, + (char *)(regs->u_regs[UREG_I0 + i] & 0xffffffff), + 512); + else + strncpy_from_user(scall_strbuf, + (char *)regs->u_regs[UREG_I0 + i], + 512); printk("%s", scall_strbuf); } } @@ -157,7 +170,9 @@ void syscall_trace_entry(unsigned long g1, struct pt_regs *regs) unsigned long syscall_trace_exit(unsigned long retval, struct pt_regs *regs) { - if(!strcmp(current->comm, "bash.sunos")) +#if 0 + if (current->pid) +#endif printk("ret[%016lx]\n", retval); return retval; } @@ -192,6 +207,24 @@ void bad_trap_tl1 (struct pt_regs *regs, long lvl) void data_access_exception (struct pt_regs *regs) { + if (regs->tstate & TSTATE_PRIV) { + /* Test if this comes from uaccess places. */ + unsigned long fixup, g2; + + g2 = regs->u_regs[UREG_G2]; + if ((fixup = search_exception_table (regs->tpc, &g2))) { + /* Ouch, somebody is trying ugly VM hole tricks on us... */ +#ifdef DEBUG_EXCEPTIONS + printk("Exception: PC<%016lx> faddr<UNKNOWN>\n", regs->tpc); + printk("EX_TABLE: insn<%016lx> fixup<%016lx> " + "g2<%016lx>\n", regs->tpc, fixup, g2); +#endif + regs->tpc = fixup; + regs->tnpc = regs->tpc + 4; + regs->u_regs[UREG_G2] = g2; + return; + } + } send_sig(SIGSEGV, current, 1); } @@ -271,11 +304,46 @@ void do_fpe_common(struct pt_regs *regs) void do_fpieee(struct pt_regs *regs) { +#ifdef DEBUG_FPU + struct fpustate *f = FPUSTATE; + + printk("fpieee %016lx\n", f->fsr); +#endif do_fpe_common(regs); } +#ifdef CONFIG_MATHEMU_MODULE +volatile int (*handle_mathemu)(struct pt_regs *, struct fpustate *) = NULL; +#else +extern int do_mathemu(struct pt_regs *, struct fpustate *); +#endif + void do_fpother(struct pt_regs *regs) { + struct fpustate *f = FPUSTATE; + int ret = 0; + + switch ((f->fsr & 0x1c000)) { + case (2 << 14): /* unfinished_FPop */ + case (3 << 14): /* unimplemented_FPop */ +#ifdef CONFIG_MATHEMU_MODULE +#ifdef CONFIG_KERNELD + if (!handle_mathemu) + request_module("math-emu"); +#endif + if (handle_mathemu) + ret = handle_mathemu(regs, f); +#else +#ifdef CONFIG_MATHEMU + ret = do_mathemu(regs, f); +#endif +#endif + break; + } + if (ret) return; +#ifdef DEBUG_FPU + printk("fpother %016lx\n", f->fsr); +#endif do_fpe_common(regs); } @@ -298,7 +366,7 @@ void instruction_dump (unsigned int *pc) int i; if((((unsigned long) pc) & 3)) - return; + return; for(i = -3; i < 6; i++) printk("%c%08x%c",i?' ':'<',pc[i],i?' ':'>'); @@ -332,33 +400,51 @@ void die_if_kernel(char *str, struct pt_regs *regs) (rw->ins[6] + STACK_BIAS); } } - printk("Instruction DUMP:"); - instruction_dump ((unsigned int *) regs->tpc); + if(regs->tstate & TSTATE_PRIV) { + printk("Instruction DUMP:"); + instruction_dump ((unsigned int *) regs->tpc); + } lock_kernel(); /* Or else! */ if(regs->tstate & TSTATE_PRIV) do_exit(SIGKILL); do_exit(SIGSEGV); } +extern int handle_popc(u32 insn, struct pt_regs *regs); +extern int handle_ldq_stq(u32 insn, struct pt_regs *regs); + void do_illegal_instruction(struct pt_regs *regs) { unsigned long pc = regs->tpc; unsigned long tstate = regs->tstate; + u32 insn; if(tstate & TSTATE_PRIV) die_if_kernel("Kernel illegal instruction", regs); + if(current->tss.flags & SPARC_FLAG_32BIT) + pc = (u32)pc; + if (get_user(insn, (u32 *)pc) != -EFAULT) { + if ((insn & 0xc1ffc000) == 0x81700000) /* POPC */ { + if (handle_popc(insn, regs)) + return; + } else if ((insn & 0xc1580000) == 0xc1100000) /* LDQ/STQ */ { + if (handle_ldq_stq(insn, regs)) + return; + } + } current->tss.sig_address = pc; current->tss.sig_desc = SUBSIG_ILLINST; send_sig(SIGILL, current, 1); } -void mem_address_unaligned(struct pt_regs *regs) +void mem_address_unaligned(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr) { if(regs->tstate & TSTATE_PRIV) { extern void kernel_unaligned_trap(struct pt_regs *regs, - unsigned int insn); + unsigned int insn, + unsigned long sfar, unsigned long sfsr); - return kernel_unaligned_trap(regs, *((unsigned int *)regs->tpc)); + return kernel_unaligned_trap(regs, *((unsigned int *)regs->tpc), sfar, sfsr); } else { current->tss.sig_address = regs->tpc; current->tss.sig_desc = SUBSIG_PRIVINST; @@ -390,22 +476,6 @@ void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long n send_sig(SIGILL, current, 1); } -/* XXX User may want to be allowed to do this. XXX */ - -void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned long npc, - unsigned long tstate) -{ - if(regs->tstate & TSTATE_PRIV) { - printk("KERNEL MNA at pc %016lx npc %016lx called by %016lx\n", pc, npc, - regs->u_regs[UREG_RETPC]); - die_if_kernel("BOGUS", regs); - /* die_if_kernel("Kernel MNA access", regs); */ - } - current->tss.sig_address = pc; - current->tss.sig_desc = SUBSIG_PRIVINST; - send_sig(SIGBUS, current, 1); -} - void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, unsigned long npc, unsigned long psr) { @@ -463,21 +533,11 @@ void do_irq_tl1(struct pt_regs *regs) die_if_kernel("TL1: IRQ Exception", regs); } -void do_lddfmna(struct pt_regs *regs) -{ - die_if_kernel("TL0: LDDF Exception", regs); -} - void do_lddfmna_tl1(struct pt_regs *regs) { die_if_kernel("TL1: LDDF Exception", regs); } -void do_stdfmna(struct pt_regs *regs) -{ - die_if_kernel("TL0: STDF Exception", regs); -} - void do_stdfmna_tl1(struct pt_regs *regs) { die_if_kernel("TL1: STDF Exception", regs); diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S index bf00cb231..b22cf82f7 100644 --- a/arch/sparc64/kernel/ttable.S +++ b/arch/sparc64/kernel/ttable.S @@ -1,4 +1,4 @@ -/* $Id: ttable.S,v 1.20 1997/08/29 15:51:39 jj Exp $ +/* $Id: ttable.S,v 1.22 1997/10/16 07:07:46 jj Exp $ * ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -33,8 +33,8 @@ tl0_resv031: BTRAP(0x31) tl0_dae: TRAP(do_dae) tl0_resv033: BTRAP(0x33) tl0_mna: TRAP_NOSAVE(do_mna) -tl0_lddfmna: TRAP(do_lddfmna) -tl0_stdfmna: TRAP(do_stdfmna) +tl0_lddfmna: TRAP_NOSAVE(do_lddfmna) +tl0_stdfmna: TRAP_NOSAVE(do_stdfmna) tl0_privact: TRAP(do_privact) tl0_resv038: BTRAP(0x38) BTRAP(0x39) BTRAP(0x3a) BTRAP(0x3b) BTRAP(0x3c) BTRAP(0x3d) tl0_resv03e: BTRAP(0x3e) BTRAP(0x3f) BTRAP(0x40) @@ -106,10 +106,14 @@ tl0_netbsd: NETBSD_SYSCALL_TRAP tl0_resv10a: BTRAP(0x10a) BTRAP(0x10b) BTRAP(0x10c) BTRAP(0x10d) BTRAP(0x10e) tl0_resv10f: BTRAP(0x10f) tl0_linux32: LINUX_32BIT_SYSCALL_TRAP -tl0_linux64: LINUX_64BIT_SYSCALL_TRAP -tl0_resv112: BTRAP(0x112) BTRAP(0x113) BTRAP(0x114) BTRAP(0x115) BTRAP(0x116) -tl0_resv117: BTRAP(0x117) BTRAP(0x118) BTRAP(0x119) BTRAP(0x11a) BTRAP(0x11b) -tl0_resv11c: BTRAP(0x11c) BTRAP(0x11d) BTRAP(0x11e) BTRAP(0x11f) +tl0_oldlinux64: LINUX_64BIT_SYSCALL_TRAP +tl0_resv112: TRAP_UTRAP(UT_TRAP_INSTRUCTION_18,0x112) TRAP_UTRAP(UT_TRAP_INSTRUCTION_19,0x113) +tl0_resv114: TRAP_UTRAP(UT_TRAP_INSTRUCTION_20,0x114) TRAP_UTRAP(UT_TRAP_INSTRUCTION_21,0x115) +tl0_resv116: TRAP_UTRAP(UT_TRAP_INSTRUCTION_22,0x116) TRAP_UTRAP(UT_TRAP_INSTRUCTION_23,0x117) +tl0_resv118: TRAP_UTRAP(UT_TRAP_INSTRUCTION_24,0x118) TRAP_UTRAP(UT_TRAP_INSTRUCTION_25,0x119) +tl0_resv11a: TRAP_UTRAP(UT_TRAP_INSTRUCTION_26,0x11a) TRAP_UTRAP(UT_TRAP_INSTRUCTION_27,0x11b) +tl0_resv11c: TRAP_UTRAP(UT_TRAP_INSTRUCTION_28,0x11c) TRAP_UTRAP(UT_TRAP_INSTRUCTION_29,0x11d) +tl0_resv11e: TRAP_UTRAP(UT_TRAP_INSTRUCTION_30,0x11e) TRAP_UTRAP(UT_TRAP_INSTRUCTION_31,0x11f) tl0_getcc: GETCC_TRAP tl0_setcc: SETCC_TRAP tl0_resv122: BTRAP(0x122) BTRAP(0x123) BTRAP(0x124) BTRAP(0x125) BTRAP(0x126) @@ -127,7 +131,8 @@ tl0_resv155: BTRAP(0x155) BTRAP(0x156) BTRAP(0x157) BTRAP(0x158) BTRAP(0x159) tl0_resv15a: BTRAP(0x15a) BTRAP(0x15b) BTRAP(0x15c) BTRAP(0x15d) BTRAP(0x15e) tl0_resv15f: BTRAP(0x15f) BTRAP(0x160) BTRAP(0x161) BTRAP(0x162) BTRAP(0x163) tl0_resv164: BTRAP(0x164) BTRAP(0x165) BTRAP(0x166) BTRAP(0x167) BTRAP(0x168) -tl0_resv169: BTRAP(0x169) BTRAP(0x16a) BTRAP(0x16b) BTRAP(0x16c) BTRAP(0x16d) +tl0_resv169: BTRAP(0x169) BTRAP(0x16a) BTRAP(0x16b) BTRAP(0x16c) +tl0_linux64: LINUX_64BIT_SYSCALL_TRAP tl0_gsctx: TRAP(sparc64_get_context) TRAP(sparc64_set_context) tl0_resv170: BTRAP(0x170) BTRAP(0x171) #ifdef CONFIG_EC_FLUSH_TRAP diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c index 3aea13953..1c433d793 100644 --- a/arch/sparc64/kernel/unaligned.c +++ b/arch/sparc64/kernel/unaligned.c @@ -1,4 +1,4 @@ -/* $Id: unaligned.c,v 1.4 1997/08/19 15:25:11 jj Exp $ +/* $Id: unaligned.c,v 1.8 1997/10/14 16:21:24 jj Exp $ * unaligned.c: Unaligned load/store trap handling with special * cases for the kernel to do them more quickly. * @@ -17,6 +17,8 @@ #include <asm/uaccess.h> #include <linux/smp.h> #include <linux/smp_lock.h> +#include <asm/fpumacro.h> +#include <asm/bitops.h> /* #define DEBUG_MNA */ @@ -24,8 +26,8 @@ enum direction { load, /* ld, ldd, ldh, ldsh */ store, /* st, std, sth, stsh */ both, /* Swap, ldstub, cas, ... */ - fpload, - fpstore, + fpld, + fpst, invalid, }; @@ -101,34 +103,52 @@ static inline long sign_extend_imm13(long imm) return imm << 51 >> 51; } -static inline unsigned long fetch_reg(unsigned int reg, struct pt_regs *regs) +static unsigned long fetch_reg(unsigned int reg, struct pt_regs *regs) { - struct reg_window *win; - + unsigned long value; + if(reg < 16) return (!reg ? 0 : regs->u_regs[reg]); - - /* Ho hum, the slightly complicated case. */ - win = (struct reg_window *) regs->u_regs[UREG_FP]; - return win->locals[reg - 16]; /* yes, I know what this does... */ + if (regs->tstate & TSTATE_PRIV) { + struct reg_window *win; + win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS); + value = win->locals[reg - 16]; + } else if (current->tss.flags & SPARC_FLAG_32BIT) { + struct reg_window32 *win32; + win32 = (struct reg_window32 *)((unsigned long)((u32)regs->u_regs[UREG_FP])); + get_user(value, &win32->locals[reg - 16]); + } else { + struct reg_window *win; + win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS); + get_user(value, &win->locals[reg - 16]); + } + return value; } -static inline unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *regs) +static unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *regs) { - struct reg_window *win; - if(reg < 16) return ®s->u_regs[reg]; - win = (struct reg_window *) regs->u_regs[UREG_FP]; - return &win->locals[reg - 16]; + if (regs->tstate & TSTATE_PRIV) { + struct reg_window *win; + win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS); + return &win->locals[reg - 16]; + } else if (current->tss.flags & SPARC_FLAG_32BIT) { + struct reg_window32 *win32; + win32 = (struct reg_window32 *)((unsigned long)((u32)regs->u_regs[UREG_FP])); + return (unsigned long *)&win32->locals[reg - 16]; + } else { + struct reg_window *win; + win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS); + return &win->locals[reg - 16]; + } } static inline unsigned long compute_effective_address(struct pt_regs *regs, - unsigned int insn) + unsigned int insn, unsigned int rd) { unsigned int rs1 = (insn >> 14) & 0x1f; unsigned int rs2 = insn & 0x1f; - unsigned int rd = (insn >> 25) & 0x1f; if(insn & 0x2000) { maybe_flush_windows(rs1, 0, rd); @@ -326,7 +346,7 @@ void kernel_mna_trap_fault(struct pt_regs *regs, unsigned int insn) unsigned long fixup = search_exception_table (regs->tpc, &g2); if (!fixup) { - unsigned long address = compute_effective_address(regs, insn); + unsigned long address = compute_effective_address(regs, insn, ((insn >> 25) & 0x1f)); if(address < PAGE_SIZE) { printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference in mna handler"); } else @@ -344,7 +364,7 @@ void kernel_mna_trap_fault(struct pt_regs *regs, unsigned int insn) regs->u_regs [UREG_G2] = g2; } -asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn) +asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, unsigned long sfar, unsigned long sfsr) { enum direction dir = decode_direction(insn); int size = decode_access_size(insn); @@ -365,7 +385,7 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn) : "o0", "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g4", "g5", "g7", "cc"); } else { - unsigned long addr = compute_effective_address(regs, insn); + unsigned long addr = compute_effective_address(regs, insn, ((insn >> 25) & 0x1f)); #ifdef DEBUG_MNA printk("KMNA: pc=%016lx [dir=%s addr=%016lx size=%d] retpc[%016lx]\n", @@ -401,117 +421,243 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn) unlock_kernel(); } -#if 0 /* XXX: Implement user mna some day */ -static inline int ok_for_user(struct pt_regs *regs, unsigned int insn, - enum direction dir) -{ - unsigned int reg; - int retval, check = (dir == load) ? VERIFY_READ : VERIFY_WRITE; - int size = ((insn >> 19) & 3) == 3 ? 8 : 4; - - if((regs->pc | regs->npc) & 3) - return 0; +static char popc_helper[] = { +0, 1, 1, 2, 1, 2, 2, 3, +1, 2, 2, 3, 2, 3, 3, 4, +}; - /* Must verify_area() in all the necessary places. */ -#define WINREG_ADDR(regnum) ((void *)(((unsigned long *)regs->u_regs[UREG_FP])+(regnum))) - retval = 0; - reg = (insn >> 25) & 0x1f; - if(reg >= 16) { - retval = verify_area(check, WINREG_ADDR(reg - 16), size); - if(retval) - return retval; +int handle_popc(u32 insn, struct pt_regs *regs) +{ + u64 value; + int ret, i, rd = ((insn >> 25) & 0x1f); + + if (insn & 0x2000) { + maybe_flush_windows(0, 0, rd); + value = sign_extend_imm13(insn); + } else { + maybe_flush_windows(0, insn & 0x1f, rd); + value = fetch_reg(insn & 0x1f, regs); } - reg = (insn >> 14) & 0x1f; - if(reg >= 16) { - retval = verify_area(check, WINREG_ADDR(reg - 16), size); - if(retval) - return retval; + for (ret = 0, i = 0; i < 16; i++) { + ret += popc_helper[value & 0xf]; + value >>= 4; } - if(!(insn & 0x2000)) { - reg = (insn & 0x1f); - if(reg >= 16) { - retval = verify_area(check, WINREG_ADDR(reg - 16), size); - if(retval) - return retval; + if(rd < 16) { + if (rd) + regs->u_regs[rd] = ret; + } else { + if (current->tss.flags & SPARC_FLAG_32BIT) { + struct reg_window32 *win32; + win32 = (struct reg_window32 *)((unsigned long)((u32)regs->u_regs[UREG_FP])); + put_user(ret, &win32->locals[rd - 16]); + } else { + struct reg_window *win; + win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS); + get_user(ret, &win->locals[rd - 16]); } } - return retval; -#undef WINREG_ADDR + advance(regs); + return 1; } -void user_mna_trap_fault(struct pt_regs *regs, unsigned int insn) __asm__ ("user_mna_trap_fault"); +extern void do_fpother(struct pt_regs *regs); +extern void do_privact(struct pt_regs *regs); +extern void data_access_exception(struct pt_regs *regs); -void user_mna_trap_fault(struct pt_regs *regs, unsigned int insn) +int handle_ldq_stq(u32 insn, struct pt_regs *regs) { - current->tss.sig_address = regs->pc; - current->tss.sig_desc = SUBSIG_PRIVINST; - send_sig(SIGBUS, current, 1); + unsigned long addr = compute_effective_address(regs, insn, 0); + int freg = ((insn >> 25) & 0x1e) | ((insn >> 20) & 0x20); + struct fpustate *f = FPUSTATE; + int asi = decode_asi(insn, regs); + int flag = (freg < 32) ? SPARC_FLAG_USEDFPUL : SPARC_FLAG_USEDFPUU; + + f->fsr &= ~0x1c000; + if (freg & 3) { + f->fsr |= (6 << 14) /* invalid_fp_register */; + do_fpother(regs); + return 0; + } + if (insn & 0x200000) { + /* STQ */ + u64 first = 0, second = 0; + + if (current->tss.flags & flag) { + first = *(u64 *)&f->regs[freg]; + second = *(u64 *)&f->regs[freg+2]; + } + if (asi < 0x80) { + do_privact(regs); + return 1; + } + switch (asi) { + case ASI_P: + case ASI_S: break; + case ASI_PL: + case ASI_SL: + { + /* Need to convert endians */ + u64 tmp = __swab64p(&first); + + first = __swab64p(&second); + second = tmp; + break; + } + default: + data_access_exception(regs); + return 1; + } + if (put_user (first >> 32, (u32 *)addr) || + __put_user ((u32)first, (u32 *)(addr + 4)) || + __put_user (second >> 32, (u32 *)(addr + 8)) || + __put_user ((u32)second, (u32 *)(addr + 12))) { + data_access_exception(regs); + return 1; + } + } else { + /* LDQ */ + u32 first, second, third, fourth; + + if (asi < 0x80) { + do_privact(regs); + return 1; + } else if (asi > ASI_SNFL) { + data_access_exception(regs); + return 1; + } + if (get_user (first, (u32 *)addr) || + __get_user (second, (u32 *)(addr + 4)) || + __get_user (third, (u32 *)(addr + 8)) || + __get_user (fourth, (u32 *)(addr + 12))) { + if (asi & 0x2) /* NF */ { + first = 0; second = 0; third = 0; fourth = 0; + } else { + data_access_exception(regs); + return 1; + } + } + if (asi & 0x8) /* Little */ { + u32 tmp = le32_to_cpup(&first); + + first = le32_to_cpup(&fourth); + fourth = tmp; + tmp = le32_to_cpup(&second); + second = le32_to_cpup(&third); + third = tmp; + } + regs->fprs |= FPRS_FEF; + if (!(current->tss.flags & SPARC_FLAG_USEDFPU)) { + current->tss.flags |= SPARC_FLAG_USEDFPU; + f->fsr = 0; + f->gsr = 0; + } + if (!(current->tss.flags & flag)) { + if (freg < 32) + memset(f->regs, 0, 32*sizeof(u32)); + else + memset(f->regs+32, 0, 32*sizeof(u32)); + } + f->regs[freg] = first; + f->regs[freg+1] = second; + f->regs[freg+2] = third; + f->regs[freg+3] = fourth; + current->tss.flags |= flag; + } + advance(regs); + return 1; } -asmlinkage void user_unaligned_trap(struct pt_regs *regs, unsigned int insn) +void handle_lddfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr) { - enum direction dir; - - lock_kernel(); - if(!(current->tss.flags & SPARC_FLAG_UNALIGNED) || - (((insn >> 30) & 3) != 3)) - goto kill_user; - dir = decode_direction(insn); - if(!ok_for_user(regs, insn, dir)) { - goto kill_user; - } else { - int size = decode_access_size(insn); - unsigned long addr; - - if(floating_point_load_or_store_p(insn)) { - printk("User FPU load/store unaligned unsupported.\n"); - goto kill_user; + unsigned long pc = regs->tpc; + unsigned long tstate = regs->tstate; + u32 insn; + u32 first, second; + u64 value; + u8 asi, freg; + int flag; + struct fpustate *f = FPUSTATE; + + if(tstate & TSTATE_PRIV) + die_if_kernel("lddfmna from kernel", regs); + if(current->tss.flags & SPARC_FLAG_32BIT) + pc = (u32)pc; + if (get_user(insn, (u32 *)pc) != -EFAULT) { + asi = sfsr >> 16; + if (asi > ASI_SNFL) + goto daex; + if (get_user(first, (u32 *)sfar) || + get_user(second, (u32 *)(sfar + 4))) { + if (asi & 0x2) /* NF */ { + first = 0; second = 0; + } else + goto daex; } - - addr = compute_effective_address(regs, insn); - switch(dir) { - case load: - do_integer_load(fetch_reg_addr(((insn>>25)&0x1f), regs), - size, (unsigned long *) addr, - decode_signedness(insn), - user_unaligned_trap_fault); - break; - - case store: - do_integer_store(((insn>>25)&0x1f), size, - (unsigned long *) addr, regs, - user_unaligned_trap_fault); - break; - - case both: - do_atomic(fetch_reg_addr(((insn>>25)&0x1f), regs), - (unsigned long *) addr, - user_unaligned_trap_fault); - break; - - default: - unaligned_panic("Impossible user unaligned trap."); - - __asm__ __volatile__ ("\n" -"user_unaligned_trap_fault:\n\t" - "mov %0, %%o0\n\t" - "call user_mna_trap_fault\n\t" - " mov %1, %%o1\n\t" - : - : "r" (regs), "r" (insn) - : "o0", "o1", "o2", "o3", "o4", "o5", "o7", - "g1", "g2", "g3", "g4", "g5", "g7", "cc"); - goto out; + freg = ((insn >> 25) & 0x1e) | ((insn >> 20) & 0x20); + value = (((u64)first) << 32) | second; + if (asi & 0x8) /* Little */ + value = __swab64p(&value); + flag = (freg < 32) ? SPARC_FLAG_USEDFPUL : SPARC_FLAG_USEDFPUU; + regs->fprs |= FPRS_FEF; + if (!(current->tss.flags & SPARC_FLAG_USEDFPU)) { + current->tss.flags |= SPARC_FLAG_USEDFPU; + f->fsr = 0; + f->gsr = 0; } - advance(regs); - goto out; + if (!(current->tss.flags & flag)) { + if (freg < 32) + memset(f->regs, 0, 32*sizeof(u32)); + else + memset(f->regs+32, 0, 32*sizeof(u32)); + } + *(u64 *)(f->regs + freg) = value; + current->tss.flags |= flag; + } else { +daex: data_access_exception(regs); + return; } + advance(regs); + return; +} -kill_user: - current->tss.sig_address = regs->pc; - current->tss.sig_desc = SUBSIG_PRIVINST; - send_sig(SIGBUS, current, 1); -out: - unlock_kernel(); +void handle_stdfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr) +{ + unsigned long pc = regs->tpc; + unsigned long tstate = regs->tstate; + u32 insn; + u64 value; + u8 asi, freg; + int flag; + struct fpustate *f = FPUSTATE; + + if(tstate & TSTATE_PRIV) + die_if_kernel("stdfmna from kernel", regs); + if(current->tss.flags & SPARC_FLAG_32BIT) + pc = (u32)pc; + if (get_user(insn, (u32 *)pc) != -EFAULT) { + freg = ((insn >> 25) & 0x1e) | ((insn >> 20) & 0x20); + asi = sfsr >> 16; + value = 0; + flag = (freg < 32) ? SPARC_FLAG_USEDFPUL : SPARC_FLAG_USEDFPUU; + if (asi > ASI_SNFL) + goto daex; + if (current->tss.flags & flag) + value = *(u64 *)&f->regs[freg]; + switch (asi) { + case ASI_P: + case ASI_S: break; + case ASI_PL: + case ASI_SL: + value = __swab64p(&value); break; + default: goto daex; + } + if (put_user (value >> 32, (u32 *)sfar) || + __put_user ((u32)value, (u32 *)(sfar + 4))) + goto daex; + } else { +daex: data_access_exception(regs); + return; + } + advance(regs); + return; } -#endif diff --git a/arch/sparc64/kernel/winfixup.S b/arch/sparc64/kernel/winfixup.S index 0ebf92767..6e3f6193a 100644 --- a/arch/sparc64/kernel/winfixup.S +++ b/arch/sparc64/kernel/winfixup.S @@ -1,4 +1,4 @@ -/* $Id: winfixup.S,v 1.19 1997/08/08 08:33:37 jj Exp $ +/* $Id: winfixup.S,v 1.22 1997/10/24 11:57:48 jj Exp $ * * winfixup.S: Handle cases where user stack pointer is found to be bogus. * @@ -48,6 +48,10 @@ fill_fixup: * most things are where they need to be, we also have the address * which triggered the fault handy as well. * + * Also note that we must preserve %l5 and %l6. If the user was + * returning from a system call, we must make it look this way + * after we process the fill fault on the users stack. + * * First, get into the window where the original restore was executed. */ @@ -65,15 +69,23 @@ fill_fixup: rdpr %pstate, %l1 ! Prepare to change globals. mov %g6, %o7 ! Get current. - mov %g5, %l5 ! Fault address - clr %l4 ! It was a load, not a store + andn %l1, PSTATE_MM, %l1 ! We want to be in RMO + srlx %g5, PAGE_SHIFT, %o1 ! Fault address wrpr %g0, 0x0, %tl ! Out of trap levels. wrpr %l1, (PSTATE_IE | PSTATE_AG | PSTATE_RMO), %pstate sethi %uhi(PAGE_OFFSET), %g4 ! Prepare page_offset global reg mov %o7, %g6 - b,pt %xcc, window_scheisse_merge ! And merge. + sllx %g4, 32, %g4 ! and finish it... + clr %o2 - sllx %g4, 32, %g4 ! and finish it... + /* This is the same as below, except we handle this a bit special + * since we must preserve %l5 and %l6, see comment above. + */ + sllx %o1, PAGE_SHIFT, %o1 + call do_sparc64_fault + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + b,pt %xcc, rtrap + nop ! yes, nop is correct /* Be very careful about usage of the alternate globals here. * You cannot touch %g4/%g5 as that has the fault information @@ -84,59 +96,59 @@ fill_fixup: * do not touch %g7 or %g2 so we handle the two cases fine. */ spill_fixup: - ld [%g6 + AOFF_task_tss + AOFF_thread_flags], %g1 + lduh [%g6 + AOFF_task_tss + AOFF_thread_flags], %g1 andcc %g1, SPARC_FLAG_32BIT, %g0 - ldx [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %g1 + lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %g1 + sll %g1, 3, %g3 add %g6, %g3, %g3 stx %sp, [%g3 + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs] sll %g1, 7, %g3 - bne,pt %xcc, 1f add %g6, %g3, %g3 stx %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00] stx %l1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08] + stx %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10] stx %l3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18] stx %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20] stx %l5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28] - stx %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30] stx %l7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38] stx %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x40] stx %i1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x48] + stx %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x50] stx %i3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x58] stx %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x60] stx %i5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x68] - stx %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x70] b,pt %xcc, 2f stx %i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x78] 1: stw %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00] + stw %l1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x04] stw %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08] stw %l3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x0c] stw %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10] - stw %l5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x14] stw %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18] stw %l7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x1c] stw %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20] + stw %i1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x24] stw %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28] stw %i3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x2c] stw %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30] - stw %i5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x34] stw %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38] stw %i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x3c] 2: add %g1, 1, %g1 - stx %g1, [%g6 + AOFF_task_tss + AOFF_thread_w_saved] + + sth %g1, [%g6 + AOFF_task_tss + AOFF_thread_w_saved] rdpr %tstate, %g1 andcc %g1, TSTATE_PRIV, %g0 saved - and %g1, TSTATE_CWP, %g1 be,a,pn %xcc, window_scheisse_from_user_common or %g4, 0x4, %g4 ! we know it was a write @@ -146,7 +158,6 @@ window_scheisse_from_user_common: sethi %hi(109f), %g7 ba,pt %xcc, etrap 109: or %g7, %lo(109b), %g7 -window_scheisse_merge: srlx %l5, PAGE_SHIFT, %o1 and %l4, 0x4, %o2 @@ -173,10 +184,15 @@ fill_fixup_mna: andcc %g1, TSTATE_PRIV, %g0 be,pt %xcc, window_mna_from_user_common and %g1, TSTATE_CWP, %g1 + + /* Please, see fill_fixup commentary about why we must preserve + * %l5 and %l6 to preserve absolute correct semantics. + */ rdpr %wstate, %g2 ! Grab user mode wstate. wrpr %g1, %cwp ! Get into the right window. sll %g2, 3, %g2 ! NORMAL-->OTHER wrpr %g0, 0x0, %canrestore ! Standard etrap stuff. + wrpr %g2, 0x0, %wstate ! This must be consistant. wrpr %g0, 0x0, %otherwin ! We know this. mov PRIMARY_CONTEXT, %g1 ! Change contexts... @@ -185,23 +201,28 @@ fill_fixup_mna: rdpr %pstate, %l1 ! Prepare to change globals. mov %g4, %o5 ! Setup args for mov %g5, %o4 ! final call to do_sparc64_fault. + andn %l1, PSTATE_MM, %l1 ! We want to be in RMO + mov %g6, %o7 ! Stash away current. wrpr %g0, 0x0, %tl ! Out of trap levels. wrpr %l1, (PSTATE_IE | PSTATE_AG | PSTATE_RMO), %pstate sethi %uhi(PAGE_OFFSET), %g4 ! Set page_offset global reg. mov %o7, %g6 ! Get current back. - b,pt %xcc, window_mna_merge ! And merge. - sllx %g4, 32, %g4 ! Finish it. + sllx %g4, 32, %g4 ! Finish it. + call mem_address_unaligned + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + b,pt %xcc, rtrap + nop ! yes, the nop is correct spill_fixup_mna: - ld [%g6 + AOFF_task_tss + AOFF_thread_flags], %g1 + lduh [%g6 + AOFF_task_tss + AOFF_thread_flags], %g1 andcc %g1, SPARC_FLAG_32BIT, %g0 - ldx [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %g1 + lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %g1 sll %g1, 3, %g3 add %g6, %g3, %g3 stx %sp, [%g3 + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs] - sll %g1, 7, %g3 + sll %g1, 7, %g3 bne,pt %xcc, 1f add %g6, %g3, %g3 stx %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00] @@ -209,8 +230,8 @@ spill_fixup_mna: stx %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10] stx %l3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18] stx %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20] - stx %l5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28] + stx %l5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28] stx %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30] stx %l7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38] stx %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x40] @@ -218,8 +239,8 @@ spill_fixup_mna: stx %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x50] stx %i3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x58] stx %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x60] - stx %i5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x68] + stx %i5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x68] stx %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x70] stx %i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x78] b,pt %xcc, 2f @@ -227,16 +248,15 @@ spill_fixup_mna: 1: std %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00] std %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08] std %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10] - std %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18] + std %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18] std %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20] std %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28] std %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30] std %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38] add %g1, 1, %g1 -2: stx %g1, [%g6 + AOFF_task_tss + AOFF_thread_w_saved] +2: sth %g1, [%g6 + AOFF_task_tss + AOFF_thread_w_saved] rdpr %tstate, %g1 - nop andcc %g1, TSTATE_PRIV, %g0 saved @@ -248,7 +268,6 @@ window_mna_from_user_common: sethi %hi(109f), %g7 ba,pt %xcc, etrap 109: or %g7, %lo(109b), %g7 -window_mna_merge: call mem_address_unaligned add %sp, STACK_BIAS + REGWIN_SZ, %o0 ba,pt %xcc, rtrap |