diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-04-29 21:13:14 +0000 |
---|---|---|
committer | <ralf@linux-mips.org> | 1997-04-29 21:13:14 +0000 |
commit | 19c9bba94152148523ba0f7ef7cffe3d45656b11 (patch) | |
tree | 40b1cb534496a7f1ca0f5c314a523c69f1fee464 /arch/mips/kernel | |
parent | 7206675c40394c78a90e74812bbdbf8cf3cca1be (diff) |
Import of Linux/MIPS 2.1.36
Diffstat (limited to 'arch/mips/kernel')
34 files changed, 1592 insertions, 836 deletions
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index e537ac73e..b251d6e1a 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -6,8 +6,6 @@ # unless it's something special (ie not a .c file). # -.S.s: - $(CPP) $(CFLAGS) $< -o $*.s .S.o: $(CC) $(CFLAGS) -c $< -o $*.o @@ -15,9 +13,10 @@ all: kernel.o head.o EXTRA_ASFLAGS = -mips3 -mcpu=r4000 O_TARGET := kernel.o O_OBJS := branch.o process.o signal.o entry.o traps.o ptrace.o vm86.o \ - ioport.o setup.o syscall.o sysmips.o bios32.o ipc.o ksyms.o \ + ioport.o pci.o reset.o setup.o syscall.o sysmips.o ipc.o \ r4k_switch.o r4k_misc.o r4k_scall.o r4k_fpu.o r2300_switch.o \ r2300_misc.o r2300_scall.o r2300_fpu.o r6000_fpu.o unaligned.o +OX_OBJS := mips_ksyms.o # # SGI's have very different interrupt/timer hardware. diff --git a/arch/mips/kernel/bios32.c b/arch/mips/kernel/bios32.c deleted file mode 100644 index 1fe61faa0..000000000 --- a/arch/mips/kernel/bios32.c +++ /dev/null @@ -1,7 +0,0 @@ -/* - * bios 32 replacement - */ -unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end) -{ - return memory_start; -} diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S index 515f9af13..8bb8fb41c 100644 --- a/arch/mips/kernel/entry.S +++ b/arch/mips/kernel/entry.S @@ -18,7 +18,6 @@ #include <asm/asm.h> #include <asm/errno.h> -#include <asm/segment.h> #include <asm/mipsregs.h> #include <asm/mipsconfig.h> #include <asm/page.h> @@ -30,18 +29,6 @@ #include <asm/unistd.h> /* - * These are offsets into the task-struct. - */ -state = 0 -counter = 4 -priority = 8 -signal = 12 -blocked = 16 -flags = 20 -errno = 24 -exec_domain = 60 - -/* * Heia ... The %lo, %hi and %HI stuff is too strong for the ELF assembler * and the ABI to cope with ... */ @@ -49,53 +36,40 @@ exec_domain = 60 .set noreorder .set mips3 .align 4 +/* XXX cli/sti ??? */ handle_bottom_half: - lui s0,%hi(intr_count) - lw s1,%lo(intr_count)(s0) mfc0 s3,CP0_STATUS # Enable IRQs - addiu s2,s1, 1 - sw s2,%lo(intr_count)(s0) ori t0,s3, 0x1f xori t0,0x1e jal do_bottom_half mtc0 t0,CP0_STATUS - mtc0 s3,CP0_STATUS # Restore old IRQ state - b 9f - sw s1,%lo(intr_count)(s0) + mtc0 s3,CP0_STATUS # Restore old IRQ state reschedule: jal schedule nop EXPORT(ret_from_sys_call) - lw t0,intr_count # bottom half - bnez t0,return -9: + lw t0,bh_mask lw t1,bh_active # unused delay slot and t0,t1 bnez t0,handle_bottom_half - lw t0,PT_STATUS(sp) # returning to kernel mode? +9: lw t0,PT_STATUS(sp) # returning to kernel mode? andi t1,t0, 0x10 beqz t1,return # -> yes - mfc0 t0,CP0_STATUS - - lw t1,need_resched - ori t0,0x1f # enable irqs - xori t0,0x1e + lw t1,need_resched bnez t1,reschedule - mtc0 t0,CP0_STATUS - - lw s0,current_set + lw s0,current_set lw t0,task - lw a0,blocked(s0) + lw a0,TASK_BLOCKED(s0) beq s0,t0,return # task[0] cannot have signals - lw t0,signal(s0) # save blocked in a0 for signals + lw t0,TASK_SIGNAL(s0) nor t1,zero,a0 and t1,t0,t1 @@ -159,11 +133,7 @@ NESTED(fast_interrupt, PT_SIZE, sp) * Don't return & unblock the pic */ LEAF(bad_interrupt) - lw t0,%lo(intr_count)(s3) - subu t0,1 - j return - sw t0,%lo(intr_count)(s3) END(bad_interrupt) .text @@ -214,9 +184,8 @@ LEAF(spurious_interrupt) .data; \ EXPORT(exception_count_##exception); \ .word 0; \ - .text; + .previous; #define BUILD_HANDLER(exception,handler,clear,verbose) \ - .text; \ .align 5; \ NESTED(handle_##exception, PT_SIZE, sp); \ .set noat; \ diff --git a/arch/mips/kernel/gdb-low.S b/arch/mips/kernel/gdb-low.S index 9bc35400b..6657bd77c 100644 --- a/arch/mips/kernel/gdb-low.S +++ b/arch/mips/kernel/gdb-low.S @@ -9,7 +9,6 @@ #include <linux/sys.h> #include <asm/asm.h> -#include <asm/segment.h> #include <asm/mipsregs.h> #include <asm/mipsconfig.h> #include <asm/regdef.h> diff --git a/arch/mips/kernel/gdb-stub.c b/arch/mips/kernel/gdb-stub.c index 13bf353ff..255ec2228 100644 --- a/arch/mips/kernel/gdb-stub.c +++ b/arch/mips/kernel/gdb-stub.c @@ -70,7 +70,6 @@ #include <asm/asm.h> #include <asm/mipsregs.h> -#include <asm/segment.h> #include <asm/cachectl.h> #include <asm/system.h> #include <asm/gdb-stub.h> diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S index fa73c95bb..a957e16bd 100644 --- a/arch/mips/kernel/head.S +++ b/arch/mips/kernel/head.S @@ -15,7 +15,6 @@ #include <asm/offset.h> #include <asm/processor.h> #include <asm/regdef.h> -#include <asm/segment.h> #include <asm/cachectl.h> #include <asm/mipsregs.h> #include <asm/mipsconfig.h> diff --git a/arch/mips/kernel/ioport.c b/arch/mips/kernel/ioport.c index ff6c0d518..cc0581038 100644 --- a/arch/mips/kernel/ioport.c +++ b/arch/mips/kernel/ioport.c @@ -15,8 +15,6 @@ asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on) return -ENOSYS; } -unsigned int *stack; - /* * sys_iopl has to be used when you want to access the IO ports * beyond the 0x3ff range: to get the full 65536 ports bitmapped diff --git a/arch/mips/kernel/ipc.c b/arch/mips/kernel/ipc.c index a68a91c21..2e91b6755 100644 --- a/arch/mips/kernel/ipc.c +++ b/arch/mips/kernel/ipc.c @@ -8,6 +8,8 @@ #include <linux/errno.h> #include <linux/sched.h> #include <linux/mm.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> #include <linux/sem.h> #include <linux/msg.h> #include <linux/shm.h> @@ -22,56 +24,68 @@ */ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth) { - int version; + int version, ret; + lock_kernel(); version = call >> 16; /* hack for backward compatibility */ call &= 0xffff; if (call <= SEMCTL) switch (call) { case SEMOP: - return sys_semop (first, (struct sembuf *)ptr, second); + ret = sys_semop (first, (struct sembuf *)ptr, second); + goto out; case SEMGET: - return sys_semget (first, second, third); + ret = sys_semget (first, second, third); + goto out; case SEMCTL: { union semun fourth; - int err; + ret = -EINVAL; if (!ptr) - return -EINVAL; - if ((err = verify_area (VERIFY_READ, ptr, sizeof(long)))) - return err; - get_user(fourth.__pad, (void **) ptr); - return sys_semctl (first, second, third, fourth); + goto out; + ret = -EFAULT; + if (get_user(fourth.__pad, (void **) ptr)) + goto out; + ret = sys_semctl (first, second, third, fourth); + goto out; } default: - return -EINVAL; + ret = -EINVAL; + goto out; } if (call <= MSGCTL) switch (call) { case MSGSND: - return sys_msgsnd (first, (struct msgbuf *) ptr, - second, third); + ret = sys_msgsnd (first, (struct msgbuf *) ptr, + second, third); + goto out; case MSGRCV: switch (version) { case 0: { struct ipc_kludge tmp; - int err; + ret = -EINVAL; if (!ptr) - return -EINVAL; - if ((err = verify_area (VERIFY_READ, ptr, sizeof(tmp)))) - return err; - copy_from_user(&tmp,(struct ipc_kludge *) ptr, sizeof (tmp)); - return sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third); + goto out; + ret = -EFAULT; + if (copy_from_user(&tmp,(struct ipc_kludge *) ptr, + sizeof (tmp))) + goto out; + ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third); + goto out; } case 1: default: - return sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third); + ret = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third); + goto out; } case MSGGET: - return sys_msgget ((key_t) first, second); + ret = sys_msgget ((key_t) first, second); + goto out; case MSGCTL: - return sys_msgctl (first, second, (struct msqid_ds *) ptr); + ret = sys_msgctl (first, second, (struct msqid_ds *) ptr); + goto out; default: - return -EINVAL; + ret = -EINVAL; + goto out; } if (call <= SHMCTL) switch (call) { @@ -79,28 +93,35 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, switch (version) { case 0: default: { ulong raddr; - int err; - if ((err = verify_area(VERIFY_WRITE, (ulong*) third, sizeof(ulong)))) - return err; - err = sys_shmat (first, (char *) ptr, second, &raddr); - if (err) - return err; - put_user (raddr, (ulong *) third); - return 0; - } + ret = sys_shmat (first, (char *) ptr, second, &raddr); + if (ret) + goto out; + ret = put_user (raddr, (ulong *) third); + goto out; + } case 1: /* iBCS2 emulator entry point */ + ret = -EINVAL; if (get_fs() != get_ds()) - return -EINVAL; - return sys_shmat (first, (char *) ptr, second, (ulong *) third); + goto out; + ret = sys_shmat (first, (char *) ptr, second, (ulong *) third); + goto out; } case SHMDT: - return sys_shmdt ((char *)ptr); + ret = sys_shmdt ((char *)ptr); + goto out; case SHMGET: - return sys_shmget (first, second, third); + ret = sys_shmget (first, second, third); + goto out; case SHMCTL: - return sys_shmctl (first, second, (struct shmid_ds *) ptr); + ret = sys_shmctl (first, second, (struct shmid_ds *) ptr); + goto out; default: - return -EINVAL; + ret = -EINVAL; + goto out; } - return -EINVAL; + else + ret = -EINVAL; +out: + unlock_kernel(); + return ret; } diff --git a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c index ec4f5c449..46345b308 100644 --- a/arch/mips/kernel/irixelf.c +++ b/arch/mips/kernel/irixelf.c @@ -27,7 +27,7 @@ #include <linux/personality.h> #include <linux/elfcore.h> -#include <asm/segment.h> +#include <asm/uaccess.h> #include <asm/pgtable.h> #include <linux/config.h> @@ -47,7 +47,7 @@ static struct linux_binfmt irix_format = { #ifndef MODULE NULL, NULL, load_irix_binary, load_irix_library, irix_core_dump #else - NULL, &mod_use_count_, load_irix_binary, load_irix_library, irix_core_dump + NULL, &__this_module.usecount, load_irix_binary, load_irix_library, irix_core_dump #endif }; @@ -138,23 +138,11 @@ static void set_brk(unsigned long start, unsigned long end) static void padzero(unsigned long elf_bss) { unsigned long nbyte; - char * fpnt; - + nbyte = elf_bss & (PAGE_SIZE-1); if (nbyte) { nbyte = PAGE_SIZE - nbyte; - /* FIXME: someone should investigate, why a bad binary - * is allowed to bring a wrong elf_bss until here, - * and how to react. Suffice the plain return? - * rossius@hrz.tu-chemnitz.de - */ - if (verify_area(VERIFY_WRITE, (void *) elf_bss, nbyte)) - return; - - fpnt = (char *) elf_bss; - do { - put_user(0, fpnt++); - } while (--nbyte); + clear_user((void *) elf_bss, nbyte); } } @@ -163,9 +151,9 @@ unsigned long * create_irix_tables(char * p, int argc, int envc, unsigned int interp_load_addr, struct pt_regs *regs, struct elf_phdr *ephdr) { - unsigned long *argv,*envp, *dlinfo; - unsigned long * sp; - unsigned long * csp; + char **argv, **envp; + unsigned long *sp; + unsigned long *csp; #ifdef DEBUG_ELF printk("create_irix_tables: p[%p] argc[%d] envc[%d] " @@ -183,52 +171,51 @@ unsigned long * create_irix_tables(char * p, int argc, int envc, sp--; sp -= exec ? DLINFO_ITEMS*2 : 2; - dlinfo = sp; sp -= envc+1; - envp = sp; + envp = (char **) sp; sp -= argc+1; - argv = sp; + argv = (char **) sp; - put_user((unsigned long)argc, --sp); + __put_user((unsigned long)argc, --sp); -#define NEW_AUX_ENT(id, val) \ - put_user ((id), dlinfo++); \ - put_user ((val), dlinfo++) +#define NEW_AUX_ENT(nr, id, val) \ + __put_user ((id), sp+(nr*2)); \ + __put_user ((val), sp+(nr*2+1)); \ #define INTERP_ALIGN (~((64 * 1024) - 1)) + NEW_AUX_ENT (0, AT_NULL, 0); if(exec) { struct elf_phdr * eppnt; eppnt = (struct elf_phdr *) exec->e_phoff; /* Put this here for an ELF program interpreter */ - NEW_AUX_ENT (AT_PHDR, ephdr->p_vaddr); - NEW_AUX_ENT (AT_PHENT, sizeof (struct elf_phdr)); - NEW_AUX_ENT (AT_PHNUM, exec->e_phnum); - NEW_AUX_ENT (AT_PAGESZ, PAGE_SIZE); - NEW_AUX_ENT (AT_BASE, (interp_load_addr & (INTERP_ALIGN))); - NEW_AUX_ENT (AT_FLAGS, 0); - NEW_AUX_ENT (AT_ENTRY, (unsigned long) exec->e_entry); - NEW_AUX_ENT (AT_UID, (unsigned long) current->uid); - NEW_AUX_ENT (AT_EUID, (unsigned long) current->euid); - NEW_AUX_ENT (AT_GID, (unsigned long) current->gid); - NEW_AUX_ENT (AT_EGID, (unsigned long) current->egid); + NEW_AUX_ENT (0, AT_PHDR, ephdr->p_vaddr); + NEW_AUX_ENT (1, AT_PHENT, sizeof (struct elf_phdr)); + NEW_AUX_ENT (2, AT_PHNUM, exec->e_phnum); + NEW_AUX_ENT (3, AT_PAGESZ, PAGE_SIZE); + NEW_AUX_ENT (4, AT_BASE, (interp_load_addr & (INTERP_ALIGN))); + NEW_AUX_ENT (5, AT_FLAGS, 0); + NEW_AUX_ENT (6, AT_ENTRY, (unsigned long) exec->e_entry); + NEW_AUX_ENT (7, AT_UID, (unsigned long) current->uid); + NEW_AUX_ENT (8, AT_EUID, (unsigned long) current->euid); + NEW_AUX_ENT (9, AT_GID, (unsigned long) current->gid); + NEW_AUX_ENT (10, AT_EGID, (unsigned long) current->egid); } - NEW_AUX_ENT (AT_NULL, 0); #undef NEW_AUX_ENT current->mm->arg_start = (unsigned long) p; while (argc-->0) { - put_user(p,argv++); - while (get_user(p++)) /* nothing */ ; + __put_user(p, argv++); + p += strlen_user(p); } - put_user(0,argv); + __put_user(NULL, argv); current->mm->arg_end = current->mm->env_start = (unsigned long) p; while (envc-->0) { - put_user(p,envp++); - while (get_user(p++)) /* nothing */ ; + __put_user(p, envp++); + p += strlen_user(p); } - put_user(0,envp); + __put_user(NULL, envp); current->mm->env_end = (unsigned long) p; return sp; } @@ -255,7 +242,7 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex, int error; int i; unsigned int k; - + elf_bss = 0; last_bss = 0; error = load_addr = 0; @@ -265,22 +252,22 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex, #endif /* First of all, some simple consistency checks */ - if((interp_elf_ex->e_type != ET_EXEC && - interp_elf_ex->e_type != ET_DYN) || - INCOMPATIBLE_MACHINE(interp_elf_ex->e_machine) || + if((interp_elf_ex->e_type != ET_EXEC && + interp_elf_ex->e_type != ET_DYN) || + !elf_check_arch(interp_elf_ex->e_machine) || (!interpreter_inode->i_op || !interpreter_inode->i_op->default_file_ops->mmap)){ printk("IRIX interp has bad e_type %d\n", interp_elf_ex->e_type); return 0xffffffff; } - + /* Now read in all of the header information */ if(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE) { printk("IRIX interp header bigger than a page (%d)\n", (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum)); return 0xffffffff; } - + elf_phdata = (struct elf_phdr *) kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, GFP_KERNEL); @@ -289,7 +276,7 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex, printk("Cannot kmalloc phdata for IRIX interp.\n"); return 0xffffffff; } - + /* If the size of this structure has changed, then punt, since * we will be doing the wrong thing. */ @@ -303,7 +290,7 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex, retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff, (char *) elf_phdata, sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, 1); - + #ifdef DEBUG_ELF dump_phdrs(elf_phdata, interp_elf_ex->e_phnum); #endif @@ -328,7 +315,7 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex, if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; elf_type |= MAP_FIXED; vaddr = eppnt->p_vaddr; - + #ifdef DEBUG_ELF printk("INTERP do_mmap(%p, %08lx, %08lx, %08lx, %08lx, %08lx) ", file, vaddr, @@ -340,7 +327,7 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex, eppnt->p_filesz + (eppnt->p_vaddr & 0xfff), elf_prot, elf_type, eppnt->p_offset & 0xfffff000); - + if(error < 0 && error > -1024) { printk("Aieee IRIX interp mmap error=%d\n", error); break; /* Real error */ @@ -416,15 +403,15 @@ static int verify_binary(struct elfhdr *ehp, struct linux_binprm *bprm) if (ehp->e_ident[0] != 0x7f || strncmp(&ehp->e_ident[1], "ELF", 3)) { return -ENOEXEC; } - + /* First of all, some simple consistency checks */ if((ehp->e_type != ET_EXEC && ehp->e_type != ET_DYN) || - INCOMPATIBLE_MACHINE(ehp->e_machine) || + !elf_check_arch(ehp->e_machine) || (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops || !bprm->inode->i_op->default_file_ops->mmap)) { return -ENOEXEC; } - + /* Only support MIPS ARCH2 or greater IRIX binaries for now. */ if(!(ehp->e_flags & EF_MIPS_ARCH) && !(ehp->e_flags & 0x04)) { return -ENOEXEC; @@ -824,8 +811,8 @@ static inline int do_load_irix_library(int fd) return -EACCES; /* Seek to the beginning of the file. */ - if (file->f_op->lseek) { - if ((error = file->f_op->lseek(inode, file, 0, 0)) != 0) + if (file->f_op->llseek) { + if ((error = file->f_op->llseek(inode, file, 0, 0)) != 0) return -ENOEXEC; } else file->f_pos = 0; @@ -842,7 +829,7 @@ static inline int do_load_irix_library(int fd) /* First of all, some simple consistency checks. */ if(elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 || - INCOMPATIBLE_MACHINE(elf_ex.e_machine) || + !elf_check_arch(elf_ex.e_machine) || (!inode->i_op || !inode->i_op->default_file_ops->mmap)) return -ENOEXEC; @@ -990,8 +977,8 @@ static int dump_write(struct file *file, const void *addr, int nr) static int dump_seek(struct file *file, off_t off) { - if (file->f_op->lseek) { - if (file->f_op->lseek(file->f_inode, file, off, 0) != off) + if (file->f_op->llseek) { + if (file->f_op->llseek(file->f_inode, file, off, 0) != off) return 0; } else file->f_pos = off; @@ -1134,7 +1121,7 @@ static int irix_core_dump(long signr, struct pt_regs * regs) memset(elf.e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD); elf.e_type = ET_CORE; - elf.e_machine = ELF_EM_CPU; + elf.e_machine = ELF_ARCH; elf.e_version = EV_CURRENT; elf.e_entry = 0; elf.e_phoff = sizeof(elf); @@ -1234,8 +1221,8 @@ static int irix_core_dump(long signr, struct pt_regs * regs) len = current->mm->arg_end - current->mm->arg_start; len = len >= ELF_PRARGSZ ? ELF_PRARGSZ : len; - memcpy_fromfs(&psinfo.pr_psargs, - (const char *)current->mm->arg_start, len); + copy_from_user(&psinfo.pr_psargs, + (const char *)current->mm->arg_start, len); for(i = 0; i < len; i++) if (psinfo.pr_psargs[i] == 0) psinfo.pr_psargs[i] = ' '; diff --git a/arch/mips/kernel/irixioctl.c b/arch/mips/kernel/irixioctl.c index a8498084b..3405904fa 100644 --- a/arch/mips/kernel/irixioctl.c +++ b/arch/mips/kernel/irixioctl.c @@ -52,11 +52,11 @@ static struct tty_struct *get_real_tty(struct tty_struct *tp) asmlinkage int irix_ioctl(int fd, unsigned long cmd, unsigned long arg) { - unsigned long *data; struct tty_struct *tp, *rtp; int error = 0; int old_fs; + lock_kernel(); #ifdef DEBUG_IOCTLS printk("[%s:%d] irix_ioctl(%d, ", current->comm, current->pid, fd); #endif @@ -250,5 +250,6 @@ asmlinkage int irix_ioctl(int fd, unsigned long cmd, unsigned long arg) #ifdef DEBUG_IOCTLS printk("error=%d\n", error); #endif + unlock_kernel(); return error; } diff --git a/arch/mips/kernel/irixsig.c b/arch/mips/kernel/irixsig.c index 94f8004f6..6a5636c76 100644 --- a/arch/mips/kernel/irixsig.c +++ b/arch/mips/kernel/irixsig.c @@ -112,7 +112,8 @@ static void setup_irix_frame(struct sigaction * sa, struct pt_regs *regs, regs->regs[25] = regs->cp0_epc = current->tss.irix_trampoline; } -extern asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options); +asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr, + int options, unsigned long *ru); asmlinkage int do_irix_signal(unsigned long oldmask, struct pt_regs * regs) { @@ -150,7 +151,7 @@ asmlinkage int do_irix_signal(unsigned long oldmask, struct pt_regs * regs) if (signr != SIGCHLD) continue; /* check for SIGCHLD: it's special */ - while (sys_waitpid(-1,NULL,WNOHANG) > 0) + while (sys_wait4(-1,NULL,WNOHANG, NULL) > 0) /* nothing */; continue; } @@ -198,7 +199,7 @@ asmlinkage int do_irix_signal(unsigned long oldmask, struct pt_regs * regs) } } handler_signal |= 1 << (signr-1); - mask &= ~*to_k_sigset_t(&sa->sa_mask); + mask &= ~sa->sa_mask; } /* * Who's code doesn't conform to the restartable syscall convention @@ -224,8 +225,8 @@ asmlinkage int do_irix_signal(unsigned long oldmask, struct pt_regs * regs) setup_irix_frame(sa, regs, signr, oldmask); if (sa->sa_flags & SA_ONESHOT) sa->sa_handler = NULL; - current->blocked |= *to_k_sigset_t(&sa->sa_mask); - oldmask |= *to_k_sigset_t(&sa->sa_mask); + current->blocked |= sa->sa_mask; + oldmask |= sa->sa_mask; } return 1; @@ -282,7 +283,11 @@ asmlinkage unsigned long irix_sigreturn(struct pt_regs *regs) return res; badframe: + lock_kernel(); do_exit(SIGSEGV); + unlock_kernel(); + + return res; } struct sigact_irix5 { @@ -306,22 +311,22 @@ static inline void check_pending(int signum) struct sigaction *p; p = signum - 1 + current->sig->action; + spin_lock(¤t->sigmask_lock); if (p->sa_handler == SIG_IGN) { current->signal &= ~_S(signum); - return; - } - if (p->sa_handler == SIG_DFL) { + } else if if (p->sa_handler == SIG_DFL) { if (signum != SIGCONT && signum != SIGCHLD && signum != SIGWINCH) return; current->signal &= ~_S(signum); - return; } + spin_unlock(¤t->sigmask_lock); } asmlinkage int irix_sigaction(int sig, struct sigact_irix5 *new, struct sigact_irix5 *old, unsigned long trampoline) { struct sigaction new_sa, *p; + int res; #ifdef DEBUG_SIG printk(" (%d,%s,%s,%08lx) ", sig, (!new ? "0" : "NEW"), @@ -330,16 +335,18 @@ asmlinkage int irix_sigaction(int sig, struct sigact_irix5 *new, dump_sigact_irix5(new); printk(" "); } #endif - if(sig < 1 || sig > 32) + if(sig < 1 || sig > 32) { return -EINVAL; + } p = sig - 1 + current->sig->action; if(new) { - int err = verify_area(VERIFY_READ, new, sizeof(*new)); - if(err) - return err; - if(sig == SIGKILL || sig == SIGSTOP) + res = verify_area(VERIFY_READ, new, sizeof(*new)); + if(res) + return res; + if(sig == SIGKILL || sig == SIGSTOP) { return -EINVAL; + } new_sa.sa_flags = new->flags; new_sa.sa_handler = (__sighandler_t) new->handler; new_sa.sa_mask.__sigbits[1] = new_sa.sa_mask.__sigbits[2] = @@ -347,9 +354,9 @@ asmlinkage int irix_sigaction(int sig, struct sigact_irix5 *new, new_sa.sa_mask.__sigbits[0] = new->sigset[0]; if(new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) { - err = verify_area(VERIFY_READ, new_sa.sa_handler, 1); - if(err) - return err; + res = verify_area(VERIFY_READ, new_sa.sa_handler, 1); + if(res) + return res; } } /* Hmmm... methinks IRIX libc always passes a valid trampoline @@ -358,9 +365,9 @@ asmlinkage int irix_sigaction(int sig, struct sigact_irix5 *new, */ current->tss.irix_trampoline = trampoline; if(old) { - int err = verify_area(VERIFY_WRITE, old, sizeof(*old)); - if(err) - return err; + int res = verify_area(VERIFY_WRITE, old, sizeof(*old)); + if(res) + return res; old->flags = p->sa_flags; old->handler = (void *) p->sa_handler; old->sigset[1] = old->sigset[2] = old->sigset[3] = 0; @@ -369,23 +376,30 @@ asmlinkage int irix_sigaction(int sig, struct sigact_irix5 *new, } if(new) { + spin_lock_irq(¤t->sig->siglock); *p = new_sa; check_pending(sig); + spin_unlock_irq(¤t->sig->siglock); } - return 0; } asmlinkage int irix_sigpending(unsigned long *set) { - int err; - - err = verify_area(VERIFY_WRITE, set, (sizeof(unsigned long) * 4)); - if(!err) { - set[1] = set[2] = set[3] = 0; - set[0] = (current->blocked & current->signal); + int res; + + lock_kernel(); + res = verify_area(VERIFY_WRITE, set, (sizeof(unsigned long) * 4)); + if(!res) { + /* fill in "set" with signals pending but blocked. */ + spin_lock_irq(¤t->sigmask_lock); + __put_user(0, &set[1]); + __put_user(0, &set[2]); + __put_user(0, &set[3]); + __put_user((current->blocked & current->signal), &set[0]); + spin_unlock_irq(¤t->sigmask_lock); } - return err; + return res; } asmlinkage int irix_sigprocmask(int how, unsigned long *new, unsigned long *old) @@ -420,9 +434,12 @@ asmlinkage int irix_sigprocmask(int how, unsigned long *new, unsigned long *old) error = verify_area(VERIFY_WRITE, old, (sizeof(unsigned long) * 4)); if(error) return error; - old[1] = old[2] = old[3] = 0; - old[0] = oldbits; + __put_user(0, &old[1]); + __put_user(0, &old[2]); + __put_user(0, &old[3]); + __put_user(oldbits, &old[0]); } + return 0; } @@ -430,15 +447,16 @@ asmlinkage int irix_sigsuspend(struct pt_regs *regs) { unsigned int mask; unsigned long *uset; - int base = 0; + int base = 0, error; if(regs->regs[2] == 1000) base = 1; - mask = current->blocked; uset = (unsigned long *) regs->regs[base + 4]; if(verify_area(VERIFY_READ, uset, (sizeof(unsigned long) * 4))) return -EFAULT; + mask = current->blocked; + current->blocked = uset[0] & _BLOCKABLE; while(1) { current->state = TASK_INTERRUPTIBLE; @@ -446,6 +464,7 @@ asmlinkage int irix_sigsuspend(struct pt_regs *regs) if(do_irix_signal(mask, regs)) return -EINTR; } + return error; } /* hate hate hate... */ @@ -492,6 +511,7 @@ asmlinkage int irix_sigpoll_sys(unsigned long *set, struct irix5_siginfo *info, unsigned long mask, kset, expire = 0; int sig, error, timeo = 0; + lock_kernel(); #ifdef DEBUG_SIG printk("[%s:%d] irix_sigpoll_sys(%p,%p,%p)\n", current->comm, current->pid, set, info, tp); @@ -500,25 +520,24 @@ asmlinkage int irix_sigpoll_sys(unsigned long *set, struct irix5_siginfo *info, /* Must always specify the signal set. */ if(!set) return -EINVAL; - kset = set[0]; - error = verify_area(VERIFY_READ, set, (sizeof(unsigned long) * 4)); + error = get_user(kset, &set[0]); if(error) - return error; + goto out; - if(info) { - error = verify_area(VERIFY_WRITE, info, sizeof(*info)); - if(error) - return error; - memset(info, 0, sizeof(*info)); + if(info && clear_user(info, sizeof(*info))) { + error = -EFAULT; + goto out; } if(tp) { error = verify_area(VERIFY_READ, tp, sizeof(*tp)); if(error) return error; - if(!tp->tv_sec && !tp->tv_nsec) - return -EINVAL; + if(!tp->tv_sec && !tp->tv_nsec) { + error = -EINVAL; + goto out; + } expire = timespectojiffies(tp)+(tp->tv_sec||tp->tv_nsec)+jiffies; current->timeout = expire; } @@ -539,12 +558,17 @@ asmlinkage int irix_sigpoll_sys(unsigned long *set, struct irix5_siginfo *info, if(mask & current->signal) { /* XXX need more than this... */ if(info) info->sig = sig; - return 0; + error = 0; + goto out; } } /* Should not get here, but do something sane if we do. */ - return -EINTR; + error = -EINTR; + +out: + unlock_kernel(); + return error; } /* This is here because of irix5_siginfo definition. */ @@ -570,20 +594,27 @@ asmlinkage int irix_waitsys(int type, int pid, struct irix5_siginfo *info, struct wait_queue wait = { current, NULL }; struct task_struct *p; - if(!info) - return -EINVAL; - flag = verify_area(VERIFY_WRITE, info, sizeof(*info)); - if(flag) - return flag; + lock_kernel(); + if(!info) { + retval = -EINVAL; + goto out; + } + retval = verify_area(VERIFY_WRITE, info, sizeof(*info)); + if(retval) + goto out; if(ru) { - flag = verify_area(VERIFY_WRITE, ru, sizeof(*ru)); - if(flag) - return flag; + retval = verify_area(VERIFY_WRITE, ru, sizeof(*ru)); + if(retval) + goto out; + } + if(options & ~(W_MASK)) { + retval = -EINVAL; + goto out; + } + if(type != P_PID && type != P_PGID && type != P_ALL) { + retval = -EINVAL; + goto out; } - if(options & ~(W_MASK)) - return -EINVAL; - if(type != P_PID && type != P_PGID && type != P_ALL) - return -EINVAL; add_wait_queue(¤t->wait_chldexit, &wait); repeat: flag = 0; @@ -604,15 +635,13 @@ repeat: continue; if (ru != NULL) getrusage(p, RUSAGE_BOTH, ru); - info->sig = SIGCHLD; - info->code = 0; - info->stuff.procinfo.pid = p->pid; - info->stuff.procinfo.procdata.child.status = - (p->exit_code >> 8) & 0xff; - info->stuff.procinfo.procdata.child.utime = - p->utime; - info->stuff.procinfo.procdata.child.stime = - p->stime; + __put_user(SIGCHLD, &info->sig); + __put_user(0, &info->code); + __put_user(p->pid, &info->stuff.procinfo.pid); + __put_user((p->exit_code >> 8) & 0xff, + &info->stuff.procinfo.procdata.child.status); + __put_user(p->utime, &info->stuff.procinfo.procdata.child.utime); + __put_user(p->stime, &info->stuff.procinfo.procdata.child.stime); p->exit_code = 0; retval = 0; goto end_waitsys; @@ -621,15 +650,15 @@ repeat: current->cstime += p->stime + p->cstime; if (ru != NULL) getrusage(p, RUSAGE_BOTH, ru); - info->sig = SIGCHLD; - info->code = 1; /* CLD_EXITED */ - info->stuff.procinfo.pid = p->pid; - info->stuff.procinfo.procdata.child.status = - (p->exit_code >> 8) & 0xff; - info->stuff.procinfo.procdata.child.utime = - p->utime; - info->stuff.procinfo.procdata.child.stime = - p->stime; + __put_user(SIGCHLD, &info->sig); + __put_user(1, &info->code); /* CLD_EXITED */ + __put_user(p->pid, &info->stuff.procinfo.pid); + __put_user((p->exit_code >> 8) & 0xff, + &info->stuff.procinfo.procdata.child.status); + __put_user(p->utime, + &info->stuff.procinfo.procdata.child.utime); + __put_user(p->stime, + &info->stuff.procinfo.procdata.child.stime); retval = 0; if (p->p_opptr != p->p_pptr) { REMOVE_LINKS(p); @@ -657,6 +686,9 @@ repeat: retval = -ECHILD; end_waitsys: remove_wait_queue(¤t->wait_chldexit, &wait); + +out: + unlock_kernel(); return retval; } @@ -678,6 +710,7 @@ asmlinkage int irix_getcontext(struct pt_regs *regs) int error, i, base = 0; struct irix5_context *ctx; + lock_kernel(); if(regs->regs[2] == 1000) base = 1; ctx = (struct irix5_context *) regs->regs[base + 4]; @@ -689,7 +722,7 @@ asmlinkage int irix_getcontext(struct pt_regs *regs) error = verify_area(VERIFY_WRITE, ctx, sizeof(*ctx)); if(error) - return error; + goto out; ctx->flags = 0x0f; ctx->link = current->tss.irix_oldctx; ctx->sigmask[1] = ctx->sigmask[2] = ctx->sigmask[4] = 0; @@ -712,7 +745,11 @@ asmlinkage int irix_getcontext(struct pt_regs *regs) /* XXX wheee... */ printk("Wheee, no code for saving IRIX FPU context yet.\n"); } - return 0; + error = 0; + +out: + unlock_kernel(); + return error; } asmlinkage unsigned long irix_setcontext(struct pt_regs *regs) @@ -720,6 +757,7 @@ asmlinkage unsigned long irix_setcontext(struct pt_regs *regs) int error, base = 0; struct irix5_context *ctx; + lock_kernel(); if(regs->regs[2] == 1000) base = 1; ctx = (struct irix5_context *) regs->regs[base + 4]; @@ -731,7 +769,7 @@ asmlinkage unsigned long irix_setcontext(struct pt_regs *regs) error = verify_area(VERIFY_READ, ctx, sizeof(*ctx)); if(error) - return error; + goto out; if(ctx->flags & 0x02) { /* XXX sigstack garbage, todo... */ @@ -754,7 +792,11 @@ asmlinkage unsigned long irix_setcontext(struct pt_regs *regs) printk("Wheee, cannot restore FPU context yet...\n"); } current->tss.irix_oldctx = ctx->link; - return regs->regs[2]; + error = regs->regs[2]; + +out: + unlock_kernel(); + return error; } struct irix_sigstack { unsigned long sp; int status; }; @@ -763,6 +805,7 @@ asmlinkage int irix_sigstack(struct irix_sigstack *new, struct irix_sigstack *ol { int error; + lock_kernel(); #ifdef DEBUG_SIG printk("[%s:%d] irix_sigstack(%p,%p)\n", current->comm, current->pid, new, old); @@ -770,15 +813,18 @@ asmlinkage int irix_sigstack(struct irix_sigstack *new, struct irix_sigstack *ol if(new) { error = verify_area(VERIFY_READ, new, sizeof(*new)); if(error) - return error; + goto out; } if(old) { error = verify_area(VERIFY_WRITE, old, sizeof(*old)); if(error) - return error; + goto out; } - return 0; + error = 0; +out: + unlock_kernel(); + return error; } struct irix_sigaltstack { unsigned long sp; int size; int status; }; @@ -788,6 +834,7 @@ asmlinkage int irix_sigaltstack(struct irix_sigaltstack *new, { int error; + lock_kernel(); #ifdef DEBUG_SIG printk("[%s:%d] irix_sigaltstack(%p,%p)\n", current->comm, current->pid, new, old); @@ -795,15 +842,19 @@ asmlinkage int irix_sigaltstack(struct irix_sigaltstack *new, if(new) { error = verify_area(VERIFY_READ, new, sizeof(*new)); if(error) - return error; + goto out; } if(old) { error = verify_area(VERIFY_WRITE, old, sizeof(*old)); if(error) - return error; + goto out; } - return 0; + error = 0; + +out: + error = 0; + unlock_kernel(); } struct irix_procset { @@ -814,7 +865,10 @@ asmlinkage int irix_sigsendset(struct irix_procset *pset, int sig) { int error; + lock_kernel(); error = verify_area(VERIFY_READ, pset, sizeof(*pset)); + if(error) + goto out; #ifdef DEBUG_SIG printk("[%s:%d] irix_sigsendset([%d,%d,%d,%d,%d],%d)\n", current->comm, current->pid, @@ -822,5 +876,9 @@ asmlinkage int irix_sigsendset(struct irix_procset *pset, int sig) sig); #endif - return -EINVAL; + error = -EINVAL; + +out: + unlock_kernel(); + return error; } diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c index 2192112e9..a78bc3417 100644 --- a/arch/mips/kernel/irq.c +++ b/arch/mips/kernel/irq.c @@ -38,6 +38,7 @@ unsigned char cache_21 = 0xff; unsigned char cache_A1 = 0xff; +unsigned int local_irq_count[NR_CPUS]; unsigned long spurious_count = 0; /* @@ -99,11 +100,11 @@ extern void interrupt(void); extern void fast_interrupt(void); extern void bad_interrupt(void); -static struct irqaction *irq_action[16] = { - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL +static struct irqaction *irq_action[32] = { + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; int get_irq_list(char *buf) @@ -111,7 +112,7 @@ int get_irq_list(char *buf) int i, len = 0; struct irqaction * action; - for (i = 0 ; i < 16 ; i++) { + for (i = 0 ; i < 32 ; i++) { action = irq_action[i]; if (!action) continue; @@ -129,6 +130,15 @@ int get_irq_list(char *buf) return len; } +atomic_t __mips_bh_counter; + +#ifdef __SMP__ +#error Send superfluous SMP boxes to ralf@uni-koblenz.de +#else +#define irq_enter(cpu, irq) (++local_irq_count[cpu]) +#define irq_exit(cpu, irq) (--local_irq_count[cpu]) +#endif + /* * do_IRQ handles IRQ's that have been installed without the * SA_INTERRUPT flag: it uses the full signal-handling return @@ -139,18 +149,28 @@ int get_irq_list(char *buf) asmlinkage void do_IRQ(int irq, struct pt_regs * regs) { struct irqaction * action = *(irq + irq_action); + int do_random, cpu = smp_processor_id(); + + irq_enter(cpu, irq); kstat.interrupts[irq]++; + #ifdef CONFIG_SGI prom_printf("Got irq %d, press a key.", irq); prom_getchar(); romvec->imode(); #endif + /* slow interrupts run with interrupts enabled */ + sti(); + action = *(irq + irq_action); + do_random = 0; while (action) { - if (action->flags & SA_SAMPLE_RANDOM) - add_interrupt_randomness(irq); + do_random |= action->flags; action->handler(irq, action->dev_id, regs); action = action->next; } + if (do_random & SA_SAMPLE_RANDOM) + add_interrupt_randomness(irq); + irq_exit(cpu, irq); } /* @@ -160,15 +180,21 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs) */ asmlinkage void do_fast_IRQ(int irq) { - struct irqaction * action = *(irq + irq_action); + struct irqaction * action; + int do_random, cpu = smp_processor_id(); + irq_enter(cpu, irq); kstat.interrupts[irq]++; - while (action) { - if (action->flags & SA_SAMPLE_RANDOM) - add_interrupt_randomness(irq); + action = *(irq + irq_action); + do_random = 0; + while (action) { + do_random |= action->flags; action->handler(irq, action->dev_id, NULL); action = action->next; - } + } + if (do_random & SA_SAMPLE_RANDOM) + add_interrupt_randomness(irq); + irq_exit(cpu, irq); } /* @@ -228,7 +254,7 @@ int request_irq(unsigned int irq, int retval; struct irqaction * action; - if (irq > 15) + if (irq > 31) return -EINVAL; if (!handler) return -EINVAL; @@ -256,7 +282,7 @@ void free_irq(unsigned int irq, void *dev_id) struct irqaction * action, **p; unsigned long flags; - if (irq > 15) { + if (irq > 31) { printk("Trying to free IRQ%d\n",irq); return; } @@ -284,7 +310,7 @@ unsigned long probe_irq_on (void) unsigned int i, irqs = 0, irqmask; unsigned long delay; - /* first, enable any unassigned irqs */ + /* first, enable any unassigned (E)ISA irqs */ for (i = 15; i > 0; i--) { if (!irq_action[i]) { enable_irq(i); @@ -322,7 +348,7 @@ void init_IRQ(void) { int i; - for (i = 0; i < 16 ; i++) + for (i = 0; i < 32 ; i++) set_int_vector(i, bad_interrupt); irq_setup(); } diff --git a/arch/mips/kernel/ksyms.c b/arch/mips/kernel/ksyms.c deleted file mode 100644 index 28650741e..000000000 --- a/arch/mips/kernel/ksyms.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Export MIPS-specific functions needed for loadable modules. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1996 by Ralf Baechle - */ -#include <linux/module.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <asm/dma.h> -#include <asm/floppy.h> -#include <asm/io.h> - -static struct symbol_table arch_symbol_table = { -#include <linux/symtab_begin.h> - X(EISA_bus), - /* - * String functions - */ - X(memset), - X(memcpy), - X(memmove), - X(bcopy), - /* - * Functions to control caches. - */ - X(fd_cacheflush), - /* - * Base address of ports for Intel style I/O. - */ - X(port_base), -#include <linux/symtab_end.h> -}; - -void arch_syms_export(void) -{ - register_symtab(&arch_symbol_table); -} diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c new file mode 100644 index 000000000..abcb1946e --- /dev/null +++ b/arch/mips/kernel/mips_ksyms.c @@ -0,0 +1,44 @@ +/* + * Export MIPS-specific functions needed for loadable modules. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996 by Ralf Baechle + */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/interrupt.h> +#include <asm/dma.h> +#include <asm/floppy.h> +#include <asm/io.h> +#include <asm/softirq.h> + +EXPORT_SYMBOL(EISA_bus); + +/* + * String functions + */ +EXPORT_SYMBOL_NOVERS(memset); +EXPORT_SYMBOL_NOVERS(memcpy); +EXPORT_SYMBOL_NOVERS(memmove); +EXPORT_SYMBOL_NOVERS(bcopy); + +EXPORT_SYMBOL(__mips_bh_counter); +EXPORT_SYMBOL(local_irq_count); + +/* Networking helper routines. */ +EXPORT_SYMBOL(csum_partial_copy); + +/* + * Functions to control caches. + */ +EXPORT_SYMBOL(fd_cacheflush); + +/* + * Base address of ports for Intel style I/O. + */ +EXPORT_SYMBOL(port_base); diff --git a/arch/mips/kernel/pci.c b/arch/mips/kernel/pci.c new file mode 100644 index 000000000..e521ecdd9 --- /dev/null +++ b/arch/mips/kernel/pci.c @@ -0,0 +1,177 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * MIPS implementation of PCI BIOS services for PCI support. + */ +#include <linux/bios32.h> +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/types.h> +#include <asm/pci.h> + +#ifndef CONFIG_PCI + +/* + * BIOS32 replacement. + */ +unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end) +{ + return memory_start; +} + +#else /* defined(CONFIG_PCI) */ + +/* + * Following the generic parts of the MIPS BIOS32 code. + */ + +int pcibios_present (void) +{ + return _pcibios_init != NULL; +} + +/* + * Given the vendor and device ids, find the n'th instance of that device + * in the system. + */ +int pcibios_find_device (unsigned short vendor, unsigned short device_id, + unsigned short index, unsigned char *bus, + unsigned char *devfn) +{ + unsigned int curr = 0; + struct pci_dev *dev; + + for (dev = pci_devices; dev; dev = dev->next) { + if (dev->vendor == vendor && dev->device == device_id) { + if (curr == index) { + *devfn = dev->devfn; + *bus = dev->bus->number; + return PCIBIOS_SUCCESSFUL; + } + ++curr; + } + } + return PCIBIOS_DEVICE_NOT_FOUND; +} + +/* + * Given the class, find the n'th instance of that device + * in the system. + */ +int pcibios_find_class (unsigned int class_code, unsigned short index, + unsigned char *bus, unsigned char *devfn) +{ + unsigned int curr = 0; + struct pci_dev *dev; + + for (dev = pci_devices; dev; dev = dev->next) { + if (dev->class == class_code) { + if (curr == index) { + *devfn = dev->devfn; + *bus = dev->bus->number; + return PCIBIOS_SUCCESSFUL; + } + ++curr; + } + } + return PCIBIOS_DEVICE_NOT_FOUND; +} + +const char *pcibios_strerror (int error) +{ + static char buf[80]; + + switch (error) { + case PCIBIOS_SUCCESSFUL: + return "SUCCESSFUL"; + + case PCIBIOS_FUNC_NOT_SUPPORTED: + return "FUNC_NOT_SUPPORTED"; + + case PCIBIOS_BAD_VENDOR_ID: + return "SUCCESSFUL"; + + case PCIBIOS_DEVICE_NOT_FOUND: + return "DEVICE_NOT_FOUND"; + + case PCIBIOS_BAD_REGISTER_NUMBER: + return "BAD_REGISTER_NUMBER"; + + default: + sprintf (buf, "UNKNOWN RETURN 0x%x", error); + return buf; + } +} + +/* + * The functions below are machine specific and must be reimplented for + * each PCI chipset configuration. We just run the hook to the machine + * specific implementation. + */ +unsigned long (*_pcibios_init)(unsigned long memory_start, unsigned long memory_end); +unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end) +{ + return _pcibios_init ? _pcibios_init(memory_start, memory_end) + : memory_start; +} + +unsigned long (*_pcibios_fixup) (unsigned long memory_start, + unsigned long memory_end); +unsigned long pcibios_fixup (unsigned long memory_start, + unsigned long memory_end) +{ + return _pcibios_fixup(memory_start, memory_end); +} + +int (*_pcibios_read_config_byte) (unsigned char bus, unsigned char dev_fn, + unsigned char where, unsigned char *val); +int pcibios_read_config_byte (unsigned char bus, unsigned char dev_fn, + unsigned char where, unsigned char *val) +{ + return _pcibios_read_config_byte(bus, dev_fn, where, val); +} + +int (*_pcibios_read_config_word) (unsigned char bus, unsigned char dev_fn, + unsigned char where, unsigned short *val); +int pcibios_read_config_word (unsigned char bus, unsigned char dev_fn, + unsigned char where, unsigned short *val) +{ + return _pcibios_read_config_word(bus, dev_fn, where, val); +} + +int (*_pcibios_read_config_dword) (unsigned char bus, unsigned char dev_fn, + unsigned char where, unsigned int *val); +int pcibios_read_config_dword (unsigned char bus, unsigned char dev_fn, + unsigned char where, unsigned int *val) +{ + return _pcibios_read_config_dword(bus, dev_fn, where, val); +} + +int (*_pcibios_write_config_byte) (unsigned char bus, unsigned char dev_fn, + unsigned char where, unsigned char val); +int pcibios_write_config_byte (unsigned char bus, unsigned char dev_fn, + unsigned char where, unsigned char val) +{ + return _pcibios_write_config_byte(bus, dev_fn, where, val); +} + +int (*_pcibios_write_config_word) (unsigned char bus, unsigned char dev_fn, + unsigned char where, unsigned short val); +int pcibios_write_config_word (unsigned char bus, unsigned char dev_fn, + unsigned char where, unsigned short val) +{ + return _pcibios_write_config_word(bus, dev_fn, where, val); +} + +int (*_pcibios_write_config_dword) (unsigned char bus, unsigned char dev_fn, + unsigned char where, unsigned int val); +int pcibios_write_config_dword (unsigned char bus, unsigned char dev_fn, + unsigned char where, unsigned int val) +{ + return _pcibios_write_config_dword(bus, dev_fn, where, val); +} + +#endif /* defined(CONFIG_PCI) */ diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 99e3a3075..f8b10bdea 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -24,7 +24,6 @@ #include <linux/a.out.h> #include <asm/bootinfo.h> -#include <asm/segment.h> #include <asm/pgtable.h> #include <asm/system.h> #include <asm/mipsregs.h> @@ -65,7 +64,7 @@ void release_thread(struct task_struct *dead_task) { } -void copy_thread(int nr, unsigned long clone_flags, unsigned long usp, +int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, struct task_struct * p, struct pt_regs * regs) { struct pt_regs * childregs; @@ -106,6 +105,8 @@ void copy_thread(int nr, unsigned long clone_flags, unsigned long usp, ~(ST0_CU3|ST0_CU2|ST0_CU1|ST0_KSU|ST0_ERL|ST0_EXL); childregs->cp0_status &= ~(ST0_CU3|ST0_CU2|ST0_CU1); p->mm->context = 0; + + return 0; } /* Fill in the fpu structure for a core dump.. */ diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 018b68023..41deb8f18 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -9,6 +9,8 @@ #include <linux/mm.h> #include <linux/errno.h> #include <linux/ptrace.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> #include <linux/user.h> #include <asm/uaccess.h> @@ -255,7 +257,9 @@ static int write_long(struct task_struct * tsk, unsigned long addr, asmlinkage int sys_ptrace(long request, long pid, long addr, long data) { struct task_struct *child; + int res; + lock_kernel(); #if 0 printk("ptrace(r=%d,pid=%d,addr=%08lx,data=%08lx)\n", (int) request, (int) pid, (unsigned long) addr, @@ -263,30 +267,43 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) #endif if (request == PTRACE_TRACEME) { /* are we already being traced? */ - if (current->flags & PF_PTRACED) - return -EPERM; + if (current->flags & PF_PTRACED) { + res = -EPERM; + goto out; + } /* set the ptrace bit in the process flags. */ current->flags |= PF_PTRACED; - return 0; + res = 0; + goto out; + } + if (pid == 1) { /* you may not mess with init */ + res = -EPERM; + goto out; + } + if (!(child = get_task(pid))) { + res = -ESRCH; + goto out; } - if (pid == 1) /* you may not mess with init */ - return -EPERM; - if (!(child = get_task(pid))) - return -ESRCH; if (request == PTRACE_ATTACH) { - if (child == current) - return -EPERM; + if (child == current) { + res = -EPERM; + goto out; + } if ((!child->dumpable || (current->uid != child->euid) || (current->uid != child->suid) || (current->uid != child->uid) || (current->gid != child->egid) || (current->gid != child->sgid) || - (current->gid != child->gid)) && !suser()) - return -EPERM; + (current->gid != child->gid)) && !suser()) { + res = -EPERM; + goto out; + } /* the same process cannot be attached many times */ - if (child->flags & PF_PTRACED) - return -EPERM; + if (child->flags & PF_PTRACED) { + res = -EPERM; + goto out; + } child->flags |= PF_PTRACED; if (child->p_pptr != current) { REMOVE_LINKS(child); @@ -294,31 +311,35 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) SET_LINKS(child); } send_sig(SIGSTOP, child, 1); - return 0; + res = 0; + goto out; + } + if (!(child->flags & PF_PTRACED)) { + res = -ESRCH; + goto out; } - if (!(child->flags & PF_PTRACED)) - return -ESRCH; if (child->state != TASK_STOPPED) { - if (request != PTRACE_KILL) - return -ESRCH; + if (request != PTRACE_KILL) { + res = -ESRCH; + goto out; + } + } + if (child->p_pptr != current) { + res = -ESRCH; + goto out; } - if (child->p_pptr != current) - return -ESRCH; switch (request) { /* when I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: { unsigned long tmp; - int res; res = read_long(child, addr, &tmp); if (res < 0) - return res; - res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long)); - if (!res) - put_user(tmp,(unsigned long *) data); - return res; + goto out; + res = put_user(tmp,(unsigned long *) data); + goto out; } /* read the word at location addr in the USER area. */ @@ -326,14 +347,10 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) case PTRACE_PEEKUSR: { struct pt_regs *regs; unsigned long tmp; - int res; regs = (struct pt_regs *) (child->tss.ksp - sizeof(struct pt_regs)); - res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long)); - if(res < 0) - return res; - res = tmp = 0; /* Default return value. */ + tmp = 0; /* Default return value. */ if(addr < 32 && addr >= 0) { tmp = regs->regs[addr]; } else if(addr >= 32 && addr < 64) { @@ -370,18 +387,18 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) default: tmp = 0; res = -EIO; - break; + goto out; }; } - if(!res) - put_user(tmp, (unsigned long *) data); - return res; + res = put_user(tmp, (unsigned long *) data); + goto out; } /* when I and D space are separate, this will have to be fixed. */ case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: - return write_long(child,addr,data); + res = write_long(child,addr,data); + goto out; case PTRACE_POKEUSR: { struct pt_regs *regs; @@ -419,20 +436,23 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) break; }; } - return res; + goto out; } case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: { /* restart after signal. */ - if ((unsigned long) data > NSIG) - return -EIO; + if ((unsigned long) data > NSIG) { + res = -EIO; + goto out; + } if (request == PTRACE_SYSCALL) child->flags |= PF_TRACESYS; else child->flags &= ~PF_TRACESYS; child->exit_code = data; wake_up_process(child); - return data; + res = data; + goto out; } /* @@ -445,24 +465,32 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) wake_up_process(child); child->exit_code = SIGKILL; } - return 0; + res = 0; + goto out; } case PTRACE_DETACH: { /* detach a process that was attached. */ - if ((unsigned long) data > NSIG) - return -EIO; + if ((unsigned long) data > NSIG) { + res = -EIO; + goto out; + } child->flags &= ~(PF_PTRACED|PF_TRACESYS); wake_up_process(child); child->exit_code = data; REMOVE_LINKS(child); child->p_pptr = child->p_opptr; SET_LINKS(child); - return 0; + res = 0; + goto out; } default: - return -EIO; + res = -EIO; + goto out; } +out: + unlock_kernel(); + return res; } asmlinkage void syscall_trace(void) @@ -479,7 +507,10 @@ asmlinkage void syscall_trace(void) * for normal use. strace only continues with a signal if the * stopping signal is not SIGTRAP. -brl */ - if (current->exit_code) + if (current->exit_code) { + spin_lock_irq(¤t->sigmask_lock); current->signal |= (1 << (current->exit_code - 1)); + spin_unlock_irq(¤t->sigmask_lock); + } current->exit_code = 0; } diff --git a/arch/mips/kernel/r2300_fpu.S b/arch/mips/kernel/r2300_fpu.S index 666a9a180..04a66df4e 100644 --- a/arch/mips/kernel/r2300_fpu.S +++ b/arch/mips/kernel/r2300_fpu.S @@ -16,7 +16,6 @@ #include <asm/regdef.h> #include <asm/sigcontext.h> - .text .set mips3 .set noreorder /* Save floating point context */ diff --git a/arch/mips/kernel/r2300_misc.S b/arch/mips/kernel/r2300_misc.S index 0afdab4c9..1a557d456 100644 --- a/arch/mips/kernel/r2300_misc.S +++ b/arch/mips/kernel/r2300_misc.S @@ -18,7 +18,6 @@ #include <asm/pgtable.h> #include <asm/processor.h> #include <asm/regdef.h> -#include <asm/segment.h> #include <asm/stackframe.h> .text diff --git a/arch/mips/kernel/r2300_scall.S b/arch/mips/kernel/r2300_scall.S index 358f46664..690a5c7c4 100644 --- a/arch/mips/kernel/r2300_scall.S +++ b/arch/mips/kernel/r2300_scall.S @@ -16,7 +16,6 @@ #include <asm/pgtable.h> #include <asm/processor.h> #include <asm/regdef.h> -#include <asm/segment.h> #include <asm/stackframe.h> /* @@ -29,7 +28,6 @@ * a2 (int) number of arguments to syscall */ .set noreorder - .text NESTED(r2300_do_syscalls, 32, sp) subu sp,32 sw ra,28(sp) @@ -83,4 +81,4 @@ dst: PTR 0b, 1b, 2b, 3b, 4b, 5b, 6b, 7b PTR 7b,bad_stack PTR 6b,bad_stack PTR 5b,bad_stack - .text + .previous diff --git a/arch/mips/kernel/r2300_switch.S b/arch/mips/kernel/r2300_switch.S index db03636d1..83190514b 100644 --- a/arch/mips/kernel/r2300_switch.S +++ b/arch/mips/kernel/r2300_switch.S @@ -16,7 +16,6 @@ #include <asm/pgtable.h> #include <asm/processor.h> #include <asm/regdef.h> -#include <asm/segment.h> #include <asm/stackframe.h> #include <asm/asmmacro.h> diff --git a/arch/mips/kernel/r4k_misc.S b/arch/mips/kernel/r4k_misc.S index 510f513aa..432c65215 100644 --- a/arch/mips/kernel/r4k_misc.S +++ b/arch/mips/kernel/r4k_misc.S @@ -17,7 +17,6 @@ #include <asm/pgtable.h> #include <asm/processor.h> #include <asm/regdef.h> -#include <asm/segment.h> #include <asm/stackframe.h> #define NOTLB_OPTIMIZE /* If you are paranoid, define this. */ @@ -105,7 +104,6 @@ _PAGE_VALID | _PAGE_DIRTY); \ sw pte, (ptr); - .text .set noreorder .set mips3 diff --git a/arch/mips/kernel/r4k_scall.S b/arch/mips/kernel/r4k_scall.S index d4dd88732..121616a50 100644 --- a/arch/mips/kernel/r4k_scall.S +++ b/arch/mips/kernel/r4k_scall.S @@ -16,10 +16,8 @@ #include <asm/pgtable.h> #include <asm/processor.h> #include <asm/regdef.h> -#include <asm/segment.h> #include <asm/stackframe.h> - .text .set noreorder .set mips3 .align 5 @@ -71,4 +69,4 @@ dst: PTR 0b, 1b, 2b, 3b, 4b, 5b, 6b, 7b PTR 7b,bad_stack PTR 6b,bad_stack PTR 5b,bad_stack - .text + .previous diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S index 22cd96fce..78ced5659 100644 --- a/arch/mips/kernel/r4k_switch.S +++ b/arch/mips/kernel/r4k_switch.S @@ -16,12 +16,10 @@ #include <asm/pgtable.h> #include <asm/processor.h> #include <asm/regdef.h> -#include <asm/segment.h> #include <asm/stackframe.h> #include <asm/asmmacro.h> - .text .set noreorder .set mips3 .align 5 diff --git a/arch/mips/kernel/reset.c b/arch/mips/kernel/reset.c new file mode 100644 index 000000000..143449aac --- /dev/null +++ b/arch/mips/kernel/reset.c @@ -0,0 +1,30 @@ +/* + * linux/arch/mips/sni/process.c + * + * Reset the machine. + */ +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/reboot.h> +#include <asm/reboot.h> + +/* + * Urgs ... Too many MIPS machines to handle this in a generic way. + * So handle all using function pointers to machine specific + * functions. + */ + +void machine_restart(char *command) +{ + _machine_restart(command); +} + +void machine_halt(void) +{ + _machine_halt(); +} + +void machine_power_off(void) +{ + _machine_power_off(); +} diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 48de5d21a..2e2b074f9 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -23,13 +23,16 @@ #ifdef CONFIG_BLK_DEV_RAM #include <linux/blk.h> #endif +#ifdef CONFIG_RTC +#include <linux/ioport.h> +#include <linux/timex.h> +#endif #include <asm/asm.h> #include <asm/bootinfo.h> #include <asm/cachectl.h> #include <asm/io.h> #include <asm/vector.h> -#include <asm/segment.h> #include <asm/stackframe.h> #include <asm/system.h> #ifdef CONFIG_SGI @@ -63,11 +66,6 @@ char wait_available; int EISA_bus = 0; /* - * Do a hardware reset. - */ -void (*hard_reset_now)(void); - -/* * Milo passes some information to the kernel that looks like as if it * had been returned by a Intel PC BIOS. Milo doesn't fill the passed * drive_info and Linux can find out about this anyway, so I'm going to diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index fdbc86558..848f0742b 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -7,6 +7,8 @@ #include <linux/config.h> #include <linux/sched.h> #include <linux/mm.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> #include <linux/kernel.h> #include <linux/signal.h> #include <linux/errno.h> @@ -23,77 +25,37 @@ #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) -asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options); +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); extern asmlinkage void (*save_fp_context)(struct sigcontext *sc); extern asmlinkage void (*restore_fp_context)(struct sigcontext *sc); -asmlinkage int sys_sigprocmask(int how, sigset_t *set, sigset_t *oset) -{ - k_sigset_t new_set, old_set = current->blocked; - int error; - - if (set) { - error = verify_area(VERIFY_READ, set, sizeof(sigset_t)); - if (error) - return error; - new_set = *to_k_sigset_t(set) & _BLOCKABLE; - switch (how) { - case SIG_BLOCK: - current->blocked |= new_set; - break; - case SIG_UNBLOCK: - current->blocked &= ~new_set; - break; - case SIG_SETMASK: - current->blocked = new_set; - break; - /* - * SGI goodie: Just set the low 32 bits of 'blocked' even - * for 128 bit sigset_t. - */ - case SIG_SETMASK32: - current->blocked = new_set; - break; - default: - return -EINVAL; - } - } - if (oset) { - error = verify_area(VERIFY_WRITE, oset, sizeof(sigset_t)); - if (error) - return error; - put_user(old_set, &oset->__sigbits[0]); - put_user(0, &oset->__sigbits[1]); - put_user(0, &oset->__sigbits[2]); - put_user(0, &oset->__sigbits[3]); - } - return 0; -} - /* * Atomically swap in the new signal mask, and wait for a signal. + * Unlike on Intel we pass a sigset_t *, not sigset_t. */ asmlinkage int sys_sigsuspend(struct pt_regs *regs) { - unsigned int mask; - sigset_t *uset; - k_sigset_t kset; + unsigned long mask; + sigset_t *uset, set; - mask = current->blocked; uset = (sigset_t *)(long) regs->regs[4]; - if (verify_area(VERIFY_READ, uset, sizeof(sigset_t))) + if (get_user(set, uset)) return -EFAULT; - kset = *to_k_sigset_t(uset); - current->blocked = kset & _BLOCKABLE; + + spin_lock_irq(¤t->sigmask_lock); + mask = current->blocked; + current->blocked = set & _BLOCKABLE; + spin_unlock_irq(¤t->sigmask_lock); + regs->regs[2] = -EINTR; while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); - if (do_signal(mask,regs)) + if (do_signal(mask, regs)) return -EINTR; } - return -EINTR; } @@ -102,17 +64,12 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs) struct sigcontext *context; int i; - /* - * We don't support fixing ADEL/ADES exceptions for signal stack frames. - * No big loss - who doesn't care about the alignment of this stack - * really deserves to loose. - */ context = (struct sigcontext *)(long) regs->regs[29]; if (!access_ok(VERIFY_READ, context, sizeof(struct sigcontext)) || (regs->regs[29] & (SZREG - 1))) goto badframe; - current->blocked = context->sc_sigset.__sigbits[0] & _BLOCKABLE; + current->blocked = context->sc_sigset & _BLOCKABLE; regs->cp0_epc = context->sc_pc; /* @@ -140,7 +97,7 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs) /* * Don't let your children do this ... */ - asm __volatile__( + __asm__ __volatile__( "move\t$29,%0\n\t" "j\tret_from_sys_call" :/* no outputs */ @@ -148,7 +105,9 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs) /* Unreached */ badframe: + lock_kernel(); do_exit(SIGSEGV); + unlock_kernel(); } /* @@ -201,7 +160,7 @@ static void setup_frame(struct sigaction * sa, struct pt_regs *regs, /* We realign the stack to an adequate boundary for the architecture. */ if (verify_area(VERIFY_WRITE, frame, sizeof (struct sc))) - do_exit(SIGSEGV); + goto segv_and_exit; frame = (struct sc *)((unsigned long)frame & ALMASK); sc = &frame->scc; @@ -235,10 +194,10 @@ static void setup_frame(struct sigaction * sa, struct pt_regs *regs, __put_user(regs->lo, &sc->sc_mdlo); __put_user(regs->cp0_cause, &sc->sc_cause); __put_user((regs->cp0_status & ST0_CU1) != 0, &sc->sc_ownedfp); - __put_user(oldmask, &sc->sc_sigset.__sigbits[0]); - __put_user(0, &sc->sc_sigset.__sigbits[1]); - __put_user(0, &sc->sc_sigset.__sigbits[2]); - __put_user(0, &sc->sc_sigset.__sigbits[3]); + __put_user(oldmask, &sc->sc_sigset); + __put_user(0, &sc->__pad0[0]); + __put_user(0, &sc->__pad0[1]); + __put_user(0, &sc->__pad0[2]); regs->regs[4] = signr; /* Arguments for handler */ regs->regs[5] = 0; /* For now. */ @@ -247,6 +206,11 @@ static void setup_frame(struct sigaction * sa, struct pt_regs *regs, regs->regs[31] = (unsigned long) frame->code; /* Return address */ regs->cp0_epc = (unsigned long) sa->sa_handler; /* "return" to the first handler */ regs->regs[25] = regs->cp0_epc; /* PIC shit... */ + +segv_and_exit: + lock_kernel(); + do_exit(SIGSEGV); + unlock_kernel(); } static inline void handle_signal(unsigned long signr, struct sigaction *sa, @@ -256,9 +220,11 @@ static inline void handle_signal(unsigned long signr, struct sigaction *sa, if (sa->sa_flags & SA_ONESHOT) sa->sa_handler = NULL; - if (!(sa->sa_flags & SA_NOMASK)) - current->blocked |= - ((*to_k_sigset_t(&sa->sa_mask) | _S(signr)) & _BLOCKABLE); + if (!(sa->sa_flags & SA_NOMASK)) { + spin_lock_irq(¤t->sigmask_lock); + current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE; + spin_unlock_irq(¤t->sigmask_lock); + } } static inline void syscall_restart(unsigned long r0, unsigned long or2, @@ -319,7 +285,9 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs) 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); continue; } sa = current->sig->action + signr - 1; @@ -328,7 +296,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs) if (signr != SIGCHLD) continue; /* check for SIGCHLD: it's special */ - while (sys_waitpid(-1,NULL,WNOHANG) > 0) + while (sys_wait4(-1,NULL,WNOHANG, NULL) > 0) /* nothing */; continue; } @@ -350,7 +318,6 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs) schedule(); continue; - case SIGQUIT: case SIGILL: case SIGTRAP: case SIGIOT: case SIGFPE: case SIGSEGV: case SIGBUS: if (current->binfmt && current->binfmt->core_dump) { if (current->binfmt->core_dump(signr, regs)) @@ -358,25 +325,23 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs) } /* 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(); /* 8-( */ do_exit(signr); + unlock_kernel(); } } /* * OK, we're invoking a handler */ -#if 0 - printk("[%s:%d] send sig1: r0[%08lx] r7[%08lx] reg[2]=%08lx\n", - current->comm, current->pid, r0, r7, regs->regs[2]); -#endif if(r0) syscall_restart(r0, regs->orig_reg2, r7, regs, sa); -#if 0 - printk("send sig2: r0[%08lx] r7[%08lx] reg[2]=%08lx\n", - r0, r7, regs->regs[2]); -#endif handle_signal(signr, sa, oldmask, regs); return 1; } @@ -385,10 +350,6 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs) * dies here!!! The li instruction, a single machine instruction, * must directly be followed by the syscall instruction. */ -#if 0 - printk("[%s:%d] send sig3: r0[%08lx] r7[%08lx] reg[2]=%08lx\n", - current->comm, current->pid, r0, r7, regs->regs[2]); -#endif if (r0 && (regs->regs[2] == ERESTARTNOHAND || regs->regs[2] == ERESTARTSYS || diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index 3b595e05d..2faf604c7 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c @@ -17,6 +17,8 @@ #include <linux/config.h> #include <linux/linkage.h> #include <linux/mm.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> #include <linux/mman.h> #include <linux/sched.h> #include <linux/unistd.h> @@ -35,35 +37,49 @@ extern unsigned char sys_narg_table[]; asmlinkage int sys_pipe(struct pt_regs *regs) { int fd[2]; - int error; + int error, res; + lock_kernel(); error = do_pipe(fd); - if (error) - return error; + if (error) { + res = error; + goto out; + } regs->regs[3] = fd[1]; - return fd[0]; + res = fd[0]; +out: + unlock_kernel(); + return res; } asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len, int prot, int flags, int fd, off_t offset) { struct file * file = NULL; + unsigned long res; + lock_kernel(); if (!(flags & MAP_ANONYMOUS)) { if (fd >= NR_OPEN || !(file = current->files->fd[fd])) return -EBADF; } flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - return do_mmap(file, addr, len, prot, flags, offset); + res = do_mmap(file, addr, len, prot, flags, offset); + + unlock_kernel(); + return res; } asmlinkage int sys_idle(void) { - if (current->pid != 0) - return -EPERM; + int ret = -EPERM; + lock_kernel(); + if (current->pid != 0) + goto out; /* endless idle loop with no priority at all */ + current->priority = -100; current->counter = -100; for (;;) { /* @@ -76,25 +92,38 @@ asmlinkage int sys_idle(void) __asm__(".set\tmips3\n\t" "wait\n\t" ".set\tmips0\n\t"); + run_task_queue(&tq_scheduler); schedule(); } +out: + unlock_kernel(); + return ret; } asmlinkage int sys_fork(struct pt_regs *regs) { - return do_fork(SIGCHLD, regs->regs[29], regs); + int res; + + lock_kernel(); + res = do_fork(SIGCHLD, regs->regs[29], regs); + unlock_kernel(); + return res; } asmlinkage int sys_clone(struct pt_regs *regs) { unsigned long clone_flags; unsigned long newsp; + int res; + lock_kernel(); clone_flags = regs->regs[4]; newsp = regs->regs[5]; if (!newsp) newsp = regs->regs[29]; - return do_fork(clone_flags, newsp, regs); + res = do_fork(clone_flags, newsp, regs); + unlock_kernel(); + return res; } /* @@ -102,20 +131,25 @@ asmlinkage int sys_clone(struct pt_regs *regs) */ asmlinkage int sys_execve(struct pt_regs *regs) { - int error; + int res; char * filename; - error = getname((char *) (long)regs->regs[4], &filename); - if (error) - return error; - error = do_execve(filename, (char **) (long)regs->regs[5], - (char **) (long)regs->regs[6], regs); + lock_kernel(); + res = getname((char *) (long)regs->regs[4], &filename); + if (res) + goto out; + res = do_execve(filename, (char **) (long)regs->regs[5], + (char **) (long)regs->regs[6], regs); putname(filename); - return error; + +out: + unlock_kernel(); + return res; } /* * Do the indirect syscall syscall. + * Don't care about kernel locking; the actual syscall will do it. */ asmlinkage int sys_syscall(struct pt_regs *regs) { @@ -184,6 +218,7 @@ asmlinkage int sys_syscall(struct pt_regs *regs) /* * If we ever come here the user sp is bad. Zap the process right away. * Due to the bad stack signaling wouldn't work. + * XXX kernel locking??? */ asmlinkage void bad_stack(void) { @@ -204,6 +239,9 @@ static char *irix_sys_names[] = { }; #endif +/* + * This isn't entirely correct with respect to kernel locking ... + */ void do_sys(struct pt_regs *regs) { unsigned long syscallnr, usp; diff --git a/arch/mips/kernel/syscalls.h b/arch/mips/kernel/syscalls.h index 723cb5e34..4cf778acb 100644 --- a/arch/mips/kernel/syscalls.h +++ b/arch/mips/kernel/syscalls.h @@ -201,3 +201,8 @@ SYS(sys_setsockopt, 5) SYS(sys_shutdown, 2) SYS(sys_socket, 3) SYS(sys_socketpair, 4) +SYS(sys_setresuid, 3) /* 4185 */ +SYS(sys_getresuid, 3) +SYS(sys_query_module, 5) +SYS(sys_poll, 3) +SYS(sys_nfsservctl, 3) diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c index c54f83595..9a4ddca3f 100644 --- a/arch/mips/kernel/sysirix.c +++ b/arch/mips/kernel/sysirix.c @@ -54,12 +54,13 @@ asmlinkage int irix_sysmp(struct pt_regs *regs) int base = 0; int error = 0; + lock_kernel(); if(regs->regs[2] == 1000) base = 1; cmd = regs->regs[base + 4]; switch(cmd) { case MP_PGSIZE: - return PAGE_SIZE; + error = PAGE_SIZE; break; default: @@ -69,6 +70,8 @@ asmlinkage int irix_sysmp(struct pt_regs *regs) break; } +out: + unlock_kernel(); return error; } @@ -95,6 +98,7 @@ asmlinkage int irix_prctl(struct pt_regs *regs) unsigned long cmd; int error = 0, base = 0; + lock_kernel(); if(regs->regs[2] == 1000) base = 1; cmd = regs->regs[base + 4]; @@ -102,7 +106,8 @@ asmlinkage int irix_prctl(struct pt_regs *regs) case PR_MAXPROCS: printk("irix_prctl[%s:%d]: Wants PR_MAXPROCS\n", current->comm, current->pid); - return NR_TASKS; + error = NR_TASKS; + break; case PR_ISBLOCKED: { struct task_struct *task; @@ -110,11 +115,14 @@ asmlinkage int irix_prctl(struct pt_regs *regs) printk("irix_prctl[%s:%d]: Wants PR_ISBLOCKED\n", current->comm, current->pid); task = find_process_by_pid(regs->regs[base + 5]); - if(!task) - return -ESRCH; - return (task->next_run ? 0 : 1); + if(!task) { + error = -ESRCH; + break; + } + error = (task->next_run ? 0 : 1); /* Can _your_ OS find this out that fast? */ - } + break; + } case PR_SETSTACKSIZE: { long value = regs->regs[base + 5]; @@ -126,28 +134,35 @@ asmlinkage int irix_prctl(struct pt_regs *regs) if(suser()) { current->rlim[RLIMIT_STACK].rlim_max = current->rlim[RLIMIT_STACK].rlim_cur = value; - return value; + error = value; + break; + } + if(value > current->rlim[RLIMIT_STACK].rlim_max) { + error = -EINVAL; + break; } - if(value > current->rlim[RLIMIT_STACK].rlim_max) - return -EINVAL; current->rlim[RLIMIT_STACK].rlim_cur = value; - return value; + error = value; + break; } case PR_GETSTACKSIZE: printk("irix_prctl[%s:%d]: Wants PR_GETSTACKSIZE\n", current->comm, current->pid); - return current->rlim[RLIMIT_STACK].rlim_cur; + error = current->rlim[RLIMIT_STACK].rlim_cur; + break; case PR_MAXPPROCS: printk("irix_prctl[%s:%d]: Wants PR_MAXPROCS\n", current->comm, current->pid); - return 1; + error = 1; + break; case PR_UNBLKONEXEC: printk("irix_prctl[%s:%d]: Wants PR_UNBLKONEXEC\n", current->comm, current->pid); - return -EINVAL; + error = -EINVAL; + break; case PR_SETEXITSIG: printk("irix_prctl[%s:%d]: Wants PR_SETEXITSIG\n", @@ -157,45 +172,54 @@ asmlinkage int irix_prctl(struct pt_regs *regs) * exit_code to some non-zero value when this is requested, * and check whether exit_code is already set in do_exit(). */ - return -EINVAL; + error = -EINVAL; + break; case PR_RESIDENT: printk("irix_prctl[%s:%d]: Wants PR_RESIDENT\n", current->comm, current->pid); - return 0; /* Compatability indeed. */ + error = 0; /* Compatability indeed. */ + break; case PR_ATTACHADDR: printk("irix_prctl[%s:%d]: Wants PR_ATTACHADDR\n", current->comm, current->pid); - return -EINVAL; + error = -EINVAL; + break; case PR_DETACHADDR: printk("irix_prctl[%s:%d]: Wants PR_DETACHADDR\n", current->comm, current->pid); - return -EINVAL; + error = -EINVAL; + break; case PR_TERMCHILD: printk("irix_prctl[%s:%d]: Wants PR_TERMCHILD\n", current->comm, current->pid); - return -EINVAL; + error = -EINVAL; + break; case PR_GETSHMASK: printk("irix_prctl[%s:%d]: Wants PR_GETSHMASK\n", current->comm, current->pid); - return -EINVAL; /* Until I have the sproc() stuff in. */ + error = -EINVAL; /* Until I have the sproc() stuff in. */ + break; case PR_GETNSHARE: - return 0; /* Until I have the sproc() stuff in. */ + error = 0; /* Until I have the sproc() stuff in. */ + break; case PR_COREPID: printk("irix_prctl[%s:%d]: Wants PR_COREPID\n", current->comm, current->pid); - return -EINVAL; + error = -EINVAL; + break; case PR_ATTACHADDRPERM: printk("irix_prctl[%s:%d]: Wants PR_ATTACHADDRPERM\n", current->comm, current->pid); - return -EINVAL; + error = -EINVAL; + break; case PR_PTHREADEXIT: printk("irix_prctl[%s:%d]: Wants PR_PTHREADEXIT\n", @@ -209,6 +233,8 @@ asmlinkage int irix_prctl(struct pt_regs *regs) break; } +out: + unlock_kernel(); return error; } @@ -242,6 +268,7 @@ asmlinkage int irix_syssgi(struct pt_regs *regs) unsigned long cmd; int retval, base = 0; + lock_kernel(); if(regs->regs[2] == 1000) base = 1; @@ -251,7 +278,8 @@ asmlinkage int irix_syssgi(struct pt_regs *regs) char *buf = (char *) regs->regs[base + 5]; /* XXX Use ethernet addr.... */ - return clear_user(buf, 64); + retval = clear_user(buf, 64); + break; } case SGI_RDNAME: { @@ -261,77 +289,89 @@ asmlinkage int irix_syssgi(struct pt_regs *regs) retval = verify_area(VERIFY_WRITE, buf, 16); if(retval) - return retval; + break; for_each_task(p) { if(p->pid == pid) goto found0; } - return -ESRCH; + retval = -ESRCH; found0: copy_to_user(buf, p->comm, 16); - return 0; + retval = 0; } case SGI_SETPGID: { - int error; - #ifdef DEBUG_PROCGRPS printk("[%s:%d] setpgid(%d, %d) ", current->comm, current->pid, (int) regs->regs[base + 5], (int)regs->regs[base + 6]); #endif - error = sys_setpgid(regs->regs[base + 5], regs->regs[base + 6]); + retval = sys_setpgid(regs->regs[base + 5], regs->regs[base + 6]); #ifdef DEBUG_PROCGRPS - printk("error=%d\n", error); + printk("retval=%d\n", retval); #endif - return error; } case SGI_SYSCONF: { switch(regs->regs[base + 5]) { case 1: - return (MAX_ARG_PAGES >> 4); /* XXX estimate... */ + retval = (MAX_ARG_PAGES >> 4); /* XXX estimate... */ + goto out; case 2: - return NR_TASKS; + retval = NR_TASKS; + goto out; case 3: - return HZ; + retval = HZ; + goto out; case 4: - return NGROUPS; + retval = NGROUPS; + goto out; case 5: - return NR_OPEN; + retval = NR_OPEN; + goto out; case 6: - return 1; + retval = 1; + goto out; case 7: - return 1; + retval = 1; + goto out; case 8: - return 199009; + retval = 199009; + goto out; case 11: - return PAGE_SIZE; + retval = PAGE_SIZE; + goto out; case 12: - return 4; + retval = 4; + goto out; case 25: case 26: case 27: case 28: case 29: case 30: - return 0; + retval = 0; + goto out; case 31: - return 32; + retval = 32; + goto out; default: - return -EINVAL; + retval = -EINVAL; + goto out; }; } case SGI_SETGROUPS: - return sys_setgroups((int) regs->regs[base + 5], - (gid_t *) regs->regs[base + 6]); + retval = sys_setgroups((int) regs->regs[base + 5], + (gid_t *) regs->regs[base + 6]); + break; case SGI_GETGROUPS: - return sys_getgroups((int) regs->regs[base + 5], - (gid_t *) regs->regs[base + 6]); + retval = sys_getgroups((int) regs->regs[base + 5], + (gid_t *) regs->regs[base + 6]); + break; case SGI_RUSAGE: { struct rusage *ru = (struct rusage *) regs->regs[base + 6]; @@ -339,47 +379,50 @@ asmlinkage int irix_syssgi(struct pt_regs *regs) switch((int) regs->regs[base + 5]) { case 0: /* rusage self */ - return getrusage(current, RUSAGE_SELF, ru); + retval = getrusage(current, RUSAGE_SELF, ru); + goto out; case -1: /* rusage children */ - return getrusage(current, RUSAGE_CHILDREN, ru); + retval = getrusage(current, RUSAGE_CHILDREN, ru); + goto out; default: - return -EINVAL; + retval = -EINVAL; + goto out; }; } case SGI_SSYNC: sys_sync(); - return 0; - - case SGI_GETSID: { - int error; + retval = 0; + break; + case SGI_GETSID: #ifdef DEBUG_PROCGRPS printk("[%s:%d] getsid(%d) ", current->comm, current->pid, (int) regs->regs[base + 5]); #endif - error = sys_getsid(regs->regs[base + 5]); + retval = sys_getsid(regs->regs[base + 5]); #ifdef DEBUG_PROCGRPS - printk("error=%d\n", error); + printk("retval=%d\n", retval); #endif - return error; - } + break; case SGI_ELFMAP: retval = irix_mapelf((int) regs->regs[base + 5], (struct elf_phdr *) regs->regs[base + 6], (int) regs->regs[base + 7]); - return retval; + break; case SGI_TOSSTSAVE: /* XXX We don't need to do anything? */ - return 0; + retval = 0; + break; case SGI_FP_BCOPY: - return 0; + retval = 0; + break; case SGI_PHYSP: { pgd_t *pgdp; @@ -400,13 +443,19 @@ asmlinkage int irix_syssgi(struct pt_regs *regs) return 0; } } - return -EINVAL; + retval = -EINVAL; + break; } default: printk("irix_syssgi: Unsupported command %d\n", (int)cmd); - return -EINVAL; + retval = -EINVAL; + break; }; + +out: + unlock_kernel(); + return retval; } asmlinkage int irix_gtime(struct pt_regs *regs) @@ -425,15 +474,20 @@ asmlinkage int irix_brk(unsigned long brk) unsigned long rlim; unsigned long newbrk, oldbrk; struct mm_struct *mm = current->mm; + int ret; - if (brk < current->mm->end_code) - return -ENOMEM; + lock_kernel(); + if (brk < current->mm->end_code) { + ret = -ENOMEM; + goto out; + } newbrk = PAGE_ALIGN(brk); oldbrk = PAGE_ALIGN(mm->brk); if (oldbrk == newbrk) { mm->brk = brk; - return 0; + ret = 0; + goto out; } /* @@ -442,7 +496,8 @@ asmlinkage int irix_brk(unsigned long brk) if (brk <= current->mm->brk) { mm->brk = brk; do_munmap(newbrk, oldbrk-newbrk); - return 0; + ret = 0; + goto out; } /* * Check against rlimit and stack.. @@ -450,20 +505,26 @@ asmlinkage int irix_brk(unsigned long brk) rlim = current->rlim[RLIMIT_DATA].rlim_cur; if (rlim >= RLIM_INFINITY) rlim = ~0; - if (brk - mm->end_code > rlim) - return -ENOMEM; + if (brk - mm->end_code > rlim) { + ret = -ENOMEM; + goto out; + } /* * Check against existing mmap mappings. */ - if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE)) + if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE)) { return -ENOMEM; + goto out; + } /* * Check if we have enough memory.. */ - if (!vm_enough_memory((newbrk-oldbrk) >> PAGE_SHIFT)) + if (!vm_enough_memory((newbrk-oldbrk) >> PAGE_SHIFT)) { return -ENOMEM; + goto out; + } /* * Ok, looks good - let it rip. @@ -473,7 +534,11 @@ asmlinkage int irix_brk(unsigned long brk) PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, 0); - return 0; + ret = 0; + +out: + unlock_kernel(); + return ret; } asmlinkage int irix_getpid(struct pt_regs *regs) @@ -496,8 +561,13 @@ asmlinkage int irix_getgid(struct pt_regs *regs) asmlinkage int irix_stime(int value) { - if(!suser()) - return -EPERM; + int ret; + + lock_kernel(); + if(!suser()) { + ret = -EPERM; + goto out; + } cli(); xtime.tv_sec = value; xtime.tv_usec = 0; @@ -505,7 +575,11 @@ asmlinkage int irix_stime(int value) time_maxerror = MAXPHASE; time_esterror = MAXPHASE; sti(); - return 0; + ret = 0; + +out: + unlock_kernel(); + return ret; } extern int _setitimer(int which, struct itimerval *value, struct itimerval *ovalue); @@ -541,6 +615,7 @@ asmlinkage unsigned int irix_alarm(unsigned int seconds) struct itimerval it_new, it_old; unsigned int oldalarm; + lock_kernel(); if(!seconds) { getitimer_real(&it_old); del_timer(¤t->real_timer); @@ -555,13 +630,16 @@ asmlinkage unsigned int irix_alarm(unsigned int seconds) /* And we'd better return too much than too little anyway */ if (it_old.it_value.tv_usec) oldalarm++; + unlock_kernel(); return oldalarm; } asmlinkage int irix_pause(void) { + lock_kernel(); current->state = TASK_INTERRUPTIBLE; schedule(); + unlock_kernel(); return -EINTR; } @@ -572,11 +650,17 @@ extern asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type, asmlinkage int irix_mount(char *dev_name, char *dir_name, unsigned long flags, char *type, void *data, int datalen) { + int ret; + + lock_kernel(); printk("[%s:%d] irix_mount(%p,%p,%08lx,%p,%p,%d)\n", current->comm, current->pid, dev_name, dir_name, flags, type, data, datalen); - return sys_mount(dev_name, dir_name, type, flags, data); - /* return -EINVAL; */ + ret = sys_mount(dev_name, dir_name, type, flags, data); + +out: + unlock_kernel(); + return ret; } struct irix_statfs { @@ -593,17 +677,20 @@ asmlinkage int irix_statfs(const char *path, struct irix_statfs *buf, int error, old_fs, i; /* We don't support this feature yet. */ - if(fs_type) - return -EINVAL; + if(fs_type) { + error = -EINVAL; + goto out; + } error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statfs)); if (error) - return error; + goto out; error = namei(path,&inode); if (error) - return error; + goto out; if (!inode->i_sb->s_op->statfs) { iput(inode); - return -ENOSYS; + error = -ENOSYS; + goto out; } old_fs = get_fs(); set_fs(get_ds()); @@ -622,8 +709,11 @@ asmlinkage int irix_statfs(const char *path, struct irix_statfs *buf, __put_user(0, &buf->f_fname[i]); __put_user(0, &buf->f_fpack[i]); } + error = 0; - return 0; +out: + unlock_kernel(); + return error; } asmlinkage int irix_fstatfs(unsigned int fd, struct irix_statfs *buf) @@ -633,15 +723,22 @@ asmlinkage int irix_fstatfs(unsigned int fd, struct irix_statfs *buf) struct file *file; int error, old_fs, i; + lock_kernel(); error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statfs)); if (error) - return error; - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) - return -EBADF; - if (!(inode = file->f_inode)) - return -ENOENT; - if (!inode->i_sb->s_op->statfs) - return -ENOSYS; + goto out; + if (fd >= NR_OPEN || !(file = current->files->fd[fd])) { + error = -EBADF; + goto out; + } + if (!(inode = file->f_inode)) { + error = -ENOENT; + goto out; + } + if (!inode->i_sb->s_op->statfs) { + error = -ENOSYS; + goto out; + } old_fs = get_fs(); set_fs(get_ds()); inode->i_sb->s_op->statfs(inode->i_sb, &kbuf, sizeof(struct statfs)); @@ -658,8 +755,11 @@ asmlinkage int irix_fstatfs(unsigned int fd, struct irix_statfs *buf) __put_user(0, &buf->f_fname[i]); __put_user(0, &buf->f_fpack[i]); } + error = 0; - return 0; +out: + unlock_kernel(); + return error; } extern asmlinkage int sys_setpgid(pid_t pid, pid_t pgid); @@ -669,6 +769,7 @@ asmlinkage int irix_setpgrp(int flags) { int error; + lock_kernel(); #ifdef DEBUG_PROCGRPS printk("[%s:%d] setpgrp(%d) ", current->comm, current->pid, flags); #endif @@ -679,22 +780,29 @@ asmlinkage int irix_setpgrp(int flags) #ifdef DEBUG_PROCGRPS printk("returning %d\n", current->pgrp); #endif + +out: + unlock_kernel(); return error; } asmlinkage int irix_times(struct tms * tbuf) { + lock_kernel(); if (tbuf) { int error = verify_area(VERIFY_WRITE,tbuf,sizeof *tbuf); if (error) - return error; + goto out; __put_user(current->utime,&tbuf->tms_utime); __put_user(current->stime,&tbuf->tms_stime); __put_user(current->cutime,&tbuf->tms_cutime); __put_user(current->cstime,&tbuf->tms_cstime); } + error = 0; - return 0; +out: + unlock_kernel(); + return error; } asmlinkage int irix_exec(struct pt_regs *regs) @@ -702,14 +810,18 @@ asmlinkage int irix_exec(struct pt_regs *regs) int error, base = 0; char * filename; + lock_kernel(); if(regs->regs[2] == 1000) base = 1; error = getname((char *) (long)regs->regs[base + 4], &filename); if (error) - return error; + goto out; error = do_execve(filename, (char **) (long)regs->regs[base + 5], (char **) 0, regs); putname(filename); + +out: + unlock_kernel(); return error; } @@ -718,14 +830,18 @@ asmlinkage int irix_exece(struct pt_regs *regs) int error, base = 0; char * filename; + lock_kernel(); if(regs->regs[2] == 1000) base = 1; error = getname((char *) (long)regs->regs[base + 4], &filename); if (error) - return error; + goto out; error = do_execve(filename, (char **) (long)regs->regs[base + 5], (char **) (long)regs->regs[base + 6], regs); putname(filename); + +out: + unlock_kernel(); return error; } @@ -789,15 +905,20 @@ int irix_poll(struct poll * ufds, size_t nfds, int timeout) select_table wait_table, *wait; struct select_table_entry *entry; + lock_kernel(); if ((error = verify_area(VERIFY_READ, ufds, nfds*sizeof(struct poll)))) - return error; + goto out; - if (nfds > NR_OPEN) - return -EINVAL; + if (nfds > NR_OPEN) { + error = -EINVAL; + goto out; + } if (!(entry = (struct select_table_entry*)__get_free_page(GFP_KERNEL)) - || !(fds = (struct poll *)kmalloc(nfds*sizeof(struct poll), GFP_KERNEL))) - return -ENOMEM; + || !(fds = (struct poll *)kmalloc(nfds*sizeof(struct poll), GFP_KERNEL))) { + error = -ENOMEM; + goto out; + } copy_from_user(fds, ufds, nfds*sizeof(struct poll)); @@ -854,8 +975,10 @@ repeat: } } - if ((current->signal & (~current->blocked))) - return -EINTR; + if ((current->signal & (~current->blocked))) { + error = -EINTR; + goto out; + } wait = NULL; if (!count && current->timeout > jiffies) { @@ -878,20 +1001,28 @@ repeat: kfree(fds1); current->timeout = 0; current->state = TASK_RUNNING; - return fdcount; + error = fdcount; + +out: + unlock_kernel(); + return error; } asmlinkage unsigned long irix_gethostid(void) { + lock_kernel(); printk("[%s:%d]: irix_gethostid() called...\n", current->comm, current->pid); + unlock_kernel(); return -EINVAL; } asmlinkage unsigned long irix_sethostid(unsigned long val) { + lock_kernel(); printk("[%s:%d]: irix_sethostid(%08lx) called...\n", current->comm, current->pid, val); + unlock_kernel(); return -EINVAL; } @@ -935,15 +1066,21 @@ asmlinkage int irix_getdomainname(char *name, int len) { int error; + lock_kernel(); if(len > (__NEW_UTS_LEN - 1)) len = __NEW_UTS_LEN - 1; error = verify_area(VERIFY_WRITE, name, len); if(error) - return -EFAULT; - if(copy_to_user(name, system_utsname.domainname, len)) - return -EFAULT; + goto out; + if(copy_to_user(name, system_utsname.domainname, len)) { + error = -EFAULT; + goto out; + } + error = 0; - return 0; +out: + unlock_kernel(); + return error; } asmlinkage unsigned long irix_getpagesize(void) @@ -1015,22 +1152,28 @@ asmlinkage int irix_lseek64(int fd, int _unused, int offhi, int offlow, int base loff_t junk; int old_fs, error; + lock_kernel(); old_fs = get_fs(); set_fs(get_ds()); error = sys_llseek(fd, offhi, offlow, &junk, base); set_fs(old_fs); if(error) - return error; - return (int) junk; + goto out; + error = (int) junk; +out: + unlock_kernel(); + return error; } asmlinkage int irix_sginap(int ticks) { + lock_kernel(); if(ticks) { current->timeout = ticks + jiffies; current->state = TASK_INTERRUPTIBLE; } schedule(); + unlock_kernel(); return 0; } @@ -1041,7 +1184,12 @@ asmlinkage int irix_sgikopt(char *istring, char *ostring, int len) asmlinkage int irix_gettimeofday(struct timeval *tv) { - return copy_to_user(tv, &xtime, sizeof(*tv)) ? -EFAULT : 0; + int retval; + + lock_kernel(); + retval = copy_to_user(tv, &xtime, sizeof(*tv)) ? -EFAULT : 0; + unlock_kernel(); + return retval; } asmlinkage unsigned long irix_mmap32(unsigned long addr, size_t len, int prot, @@ -1050,34 +1198,46 @@ asmlinkage unsigned long irix_mmap32(unsigned long addr, size_t len, int prot, struct file *file = NULL; unsigned long retval; + lock_kernel(); if(!(flags & MAP_ANONYMOUS)) { - if(fd >= NR_OPEN || !(file = current->files->fd[fd])) - return -EBADF; + if(fd >= NR_OPEN || !(file = current->files->fd[fd])) { + retval = -EBADF; + goto out; + } } flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); retval = do_mmap(file, addr, len, prot, flags, offset); + +out: + unlock_kernel(); return retval; } asmlinkage int irix_madvise(unsigned long addr, int len, int behavior) { + lock_kernel(); printk("[%s:%d] Wheee.. irix_madvise(%08lx,%d,%d)\n", current->comm, current->pid, addr, len, behavior); + unlock_kernel(); return -EINVAL; } asmlinkage int irix_pagelock(char *addr, int len, int op) { + lock_kernel(); printk("[%s:%d] Wheee.. irix_pagelock(%p,%d,%d)\n", current->comm, current->pid, addr, len, op); + unlock_kernel(); return -EINVAL; } asmlinkage int irix_quotactl(struct pt_regs *regs) { + lock_kernel(); printk("[%s:%d] Wheee.. irix_quotactl()\n", current->comm, current->pid); + unlock_kernel(); return -EINVAL; } @@ -1085,6 +1245,7 @@ asmlinkage int irix_BSDsetpgrp(int pid, int pgrp) { int error; + lock_kernel(); #ifdef DEBUG_PROCGRPS printk("[%s:%d] BSDsetpgrp(%d, %d) ", current->comm, current->pid, pid, pgrp); @@ -1101,13 +1262,18 @@ asmlinkage int irix_BSDsetpgrp(int pid, int pgrp) #ifdef DEBUG_PROCGRPS printk("error = %d\n", error); #endif + +out: + unlock_kernel(); return error; } asmlinkage int irix_systeminfo(int cmd, char *buf, int cnt) { + lock_kernel(); printk("[%s:%d] Wheee.. irix_systeminfo(%d,%p,%d)\n", current->comm, current->pid, cmd, buf, cnt); + unlock_kernel(); return -EINVAL; } @@ -1121,18 +1287,22 @@ struct iuname { asmlinkage int irix_uname(struct iuname *buf) { - if(copy_to_user(system_utsname.sysname, buf->sysname, 65)) - return -EFAULT; - if(copy_to_user(system_utsname.nodename, buf->nodename, 65)) - return -EFAULT; - if(copy_to_user(system_utsname.release, buf->release, 65)) - return -EFAULT; - if(copy_to_user(system_utsname.version, buf->version, 65)) - return -EFAULT; - if(copy_to_user(system_utsname.machine, buf->machine, 65)) - return -EFAULT; + int retval; + + lock_kernel(); + if(copy_to_user(system_utsname.sysname, buf->sysname, 65) + || copy_to_user(system_utsname.nodename, buf->nodename, 65) + || copy_to_user(system_utsname.release, buf->release, 65) + || copy_to_user(system_utsname.version, buf->version, 65) + || copy_to_user(system_utsname.machine, buf->machine, 65)) { + retval = -EFAULT; + goto out; + } + retval = 1; - return 1; +out: + unlock_kernel(); + return retval; } #undef DEBUG_XSTAT @@ -1201,6 +1371,9 @@ extern asmlinkage int sys_newstat(char * filename, struct stat * statbuf); asmlinkage int irix_xstat(int version, char *filename, struct stat *statbuf) { + int retval; + + lock_kernel(); #ifdef DEBUG_XSTAT printk("[%s:%d] Wheee.. irix_xstat(%d,%s,%p) ", current->comm, current->pid, version, filename, statbuf); @@ -1208,41 +1381,50 @@ asmlinkage int irix_xstat(int version, char *filename, struct stat *statbuf) switch(version) { case 2: { struct stat kb; - int errno, old_fs; + int old_fs; old_fs = get_fs(); set_fs(get_ds()); - errno = sys_newstat(filename, &kb); + retval = sys_newstat(filename, &kb); set_fs(old_fs); #ifdef DEBUG_XSTAT - printk("errno[%d]\n", errno); + printk("retval[%d]\n", retval); #endif - if(errno) - return errno; - errno = irix_xstat32_xlate(&kb, statbuf); - return errno; + if(retval) + goto out; + retval = irix_xstat32_xlate(&kb, statbuf); + goto out; } case 3: { - int errno = sys_newstat(filename, statbuf); + retval = sys_newstat(filename, statbuf); #ifdef DEBUG_XSTAT - printk("errno[%d]\n", errno); + printk("retval[%d]\n", retval); #endif - if(errno) - return errno; + if(retval) + goto out; irix_xstat64_xlate(statbuf); - return 0; + retval = 0; + break; } default: - return -EINVAL; + retval = -EINVAL; + break; } + +out: + unlock_kernel(); + return retval; } extern asmlinkage int sys_newlstat(char * filename, struct stat * statbuf); asmlinkage int irix_lxstat(int version, char *filename, struct stat *statbuf) { + int error; + + lock_kernel(); #ifdef DEBUG_XSTAT printk("[%s:%d] Wheee.. irix_lxstat(%d,%s,%p) ", current->comm, current->pid, version, filename, statbuf); @@ -1250,41 +1432,50 @@ asmlinkage int irix_lxstat(int version, char *filename, struct stat *statbuf) switch(version) { case 2: { struct stat kb; - int errno, old_fs; + int old_fs; old_fs = get_fs(); set_fs(get_ds()); - errno = sys_newlstat(filename, &kb); + error = sys_newlstat(filename, &kb); set_fs(old_fs); #ifdef DEBUG_XSTAT - printk("errno[%d]\n", errno); + printk("error[%d]\n", error); #endif - if(errno) - return errno; - errno = irix_xstat32_xlate(&kb, statbuf); - return errno; + if(error) + goto out; + error = irix_xstat32_xlate(&kb, statbuf); + goto error; } case 3: { - int errno = sys_newlstat(filename, statbuf); + sys_newlstat(filename, statbuf); #ifdef DEBUG_XSTAT - printk("errno[%d]\n", errno); + printk("error[%d]\n", error); #endif - if(errno) - return errno; + if(error) + goto out; irix_xstat64_xlate(statbuf); - return 0; + error = 0; + goto error; } default: - return -EINVAL; + error = -EINVAL; + goto out; } + +out: + unlock_kernel(); + return errno; } extern asmlinkage int sys_newfstat(unsigned int fd, struct stat * statbuf); asmlinkage int irix_fxstat(int version, int fd, struct stat *statbuf) { + int error; + + lock_kernel(); #ifdef DEBUG_XSTAT printk("[%s:%d] Wheee.. irix_fxstat(%d,%d,%p) ", current->comm, current->pid, version, fd, statbuf); @@ -1292,56 +1483,73 @@ asmlinkage int irix_fxstat(int version, int fd, struct stat *statbuf) switch(version) { case 2: { struct stat kb; - int errno, old_fs; + int old_fs; old_fs = get_fs(); set_fs(get_ds()); - errno = sys_newfstat(fd, &kb); + error = sys_newfstat(fd, &kb); set_fs(old_fs); #ifdef DEBUG_XSTAT - printk("errno[%d]\n", errno); + printk("error[%d]\n", error); #endif - if(errno) - return errno; - errno = irix_xstat32_xlate(&kb, statbuf); - return errno; + if(error) + goto out; + error = irix_xstat32_xlate(&kb, statbuf); + goto out; } case 3: { - int errno = sys_newfstat(fd, statbuf); + error = sys_newfstat(fd, statbuf); #ifdef DEBUG_XSTAT - printk("errno[%d]\n", errno); + printk("error[%d]\n", error); #endif - if(errno) - return errno; + if(error) + goto out; irix_xstat64_xlate(statbuf); - return 0; + error = 0; + goto out; } default: - return -EINVAL; + error = -EINVAL; + goto out; } + +out: + unlock_kernel(); + return error; } extern asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev); asmlinkage int irix_xmknod(int ver, char *filename, int mode, dev_t dev) { + int retval; + + lock_kernel(); printk("[%s:%d] Wheee.. irix_xmknod(%d,%s,%x,%x)\n", current->comm, current->pid, ver, filename, mode, (int) dev); switch(ver) { case 2: - return sys_mknod(filename, mode, dev); + retval = sys_mknod(filename, mode, dev); + goto out; default: - return -EINVAL; + retval = -EINVAL; + goto out; }; + +out: + unlock_kernel(); + return retval; } asmlinkage int irix_swapctl(int cmd, char *arg) { + lock_kernel(); printk("[%s:%d] Wheee.. irix_swapctl(%d,%p)\n", current->comm, current->pid, cmd, arg); + unlock_kernel(); return -EINVAL; } @@ -1359,17 +1567,19 @@ asmlinkage int irix_statvfs(char *fname, struct irix_statvfs *buf) struct statfs kbuf; int error, old_fs, i; + lock_kernel(); printk("[%s:%d] Wheee.. irix_statvfs(%s,%p)\n", current->comm, current->pid, fname, buf); error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statvfs)); if(error) - return error; + goto out; error = namei(fname, &inode); if(error) - return error; + goto out; if(!inode->i_sb->s_op->statfs) { iput(inode); - return -ENOSYS; + error = -ENOSYS; + goto out; } old_fs = get_fs(); set_fs(get_ds()); @@ -1397,7 +1607,11 @@ asmlinkage int irix_statvfs(char *fname, struct irix_statvfs *buf) for(i = 0; i < 32; i++) __put_user(0, &buf->f_fstr[i]); - return 0; + error = 0; + +out: + unlock_kernel(); + return error; } asmlinkage int irix_fstatvfs(int fd, struct irix_statvfs *buf) @@ -1407,18 +1621,25 @@ asmlinkage int irix_fstatvfs(int fd, struct irix_statvfs *buf) struct file *file; int error, old_fs, i; + lock_kernel(); printk("[%s:%d] Wheee.. irix_fstatvfs(%d,%p)\n", current->comm, current->pid, fd, buf); error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statvfs)); if (error) - return error; - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) - return -EBADF; - if (!(inode = file->f_inode)) - return -ENOENT; - if (!inode->i_sb->s_op->statfs) - return -ENOSYS; + goto out; + if (fd >= NR_OPEN || !(file = current->files->fd[fd])) { + error = -EBADF; + goto out; + } + if (!(inode = file->f_inode)) { + error = -ENOENT; + goto out; + } + if (!inode->i_sb->s_op->statfs) { + error = -ENOSYS; + goto out; + } old_fs = get_fs(); set_fs(get_ds()); inode->i_sb->s_op->statfs(inode->i_sb, &kbuf, sizeof(struct statfs)); @@ -1444,7 +1665,11 @@ asmlinkage int irix_fstatvfs(int fd, struct irix_statvfs *buf) for(i = 0; i < 32; i++) __put_user(0, &buf->f_fstr[i]); - return 0; + error = 0; + +out: + unlock_kernel(); + return error; } #define NOFOLLOW_LINKS 0 @@ -1511,27 +1736,41 @@ static inline int chown_common(char *filename, uid_t user, gid_t group, int foll asmlinkage int irix_chown(char *fname, int uid, int gid) { + int retval; + + lock_kernel(); /* Do follow any and all links... */ - return chown_common(fname, uid, gid, FOLLOW_LINKS); + retval = chown_common(fname, uid, gid, FOLLOW_LINKS); + unlock_kernel(); + return retval; } asmlinkage int irix_lchown(char *fname, int uid, int gid) { + int retval; + + lock_kernel(); /* Do _not_ follow any links... */ - return chown_common(fname, uid, gid, NOFOLLOW_LINKS); + retval = chown_common(fname, uid, gid, NOFOLLOW_LINKS); + unlock_kernel(); + return retval; } asmlinkage int irix_priocntl(struct pt_regs *regs) { + lock_kernel(); printk("[%s:%d] Wheee.. irix_priocntl()\n", current->comm, current->pid); + unlock_kernel(); return -EINVAL; } asmlinkage int irix_sigqueue(int pid, int sig, int code, int val) { + lock_kernel(); printk("[%s:%d] Wheee.. irix_sigqueue(%d,%d,%d,%d)\n", current->comm, current->pid, pid, sig, code, val); + unlock_kernel(); return -EINVAL; } @@ -1540,16 +1779,34 @@ extern asmlinkage int sys_ftruncate(unsigned int fd, unsigned long length); asmlinkage int irix_truncate64(char *name, int pad, int size1, int size2) { - if(size1) - return -EINVAL; - return sys_truncate(name, size2); + int retval; + + lock_kernel(); + if(size1) { + retval = -EINVAL; + goto out; + } + retval = sys_truncate(name, size2); + +out: + unlock_kernel(); + return retval; } asmlinkage int irix_ftruncate64(int fd, int pad, int size1, int size2) { - if(size1) - return -EINVAL; - return sys_ftruncate(fd, size2); + int retval; + + lock_kernel(); + if(size1) { + retval = -EINVAL; + goto out; + } + retval = sys_ftruncate(fd, size2); + +out: + unlock_kernel(); + return retval; } extern asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len, int prot, @@ -1561,6 +1818,7 @@ asmlinkage int irix_mmap64(struct pt_regs *regs) int len, prot, flags, fd, off1, off2, base = 0; int error; + lock_kernel(); if(regs->regs[2] == 1000) base = 1; sp = (unsigned long *) (regs->regs[29] + 16); @@ -1571,44 +1829,56 @@ asmlinkage int irix_mmap64(struct pt_regs *regs) flags = regs->regs[base + 7]; error = verify_area(VERIFY_READ, sp, (4 * sizeof(unsigned long))); if(error) - return error; + goto out; fd = sp[0]; __get_user(off1, &sp[1]); __get_user(off2, &sp[2]); } else { error = verify_area(VERIFY_READ, sp, (5 * sizeof(unsigned long))); if(error) - return error; + goto out; __get_user(flags, &sp[0]); __get_user(fd, &sp[1]); __get_user(off1, &sp[2]); __get_user(off2, &sp[3]); } - if(off1) - return -EINVAL; - return sys_mmap(addr, (size_t) len, prot, flags, fd, off2); + if(off1) { + error = -EINVAL; + goto out; + } + error = sys_mmap(addr, (size_t) len, prot, flags, fd, off2); + +out: + unlock_kernel(); + return error; } asmlinkage int irix_dmi(struct pt_regs *regs) { + lock_kernel(); printk("[%s:%d] Wheee.. irix_dmi()\n", current->comm, current->pid); + unlock_kernel(); return -EINVAL; } asmlinkage int irix_pread(int fd, char *buf, int cnt, int off64, int off1, int off2) { + lock_kernel(); printk("[%s:%d] Wheee.. irix_pread(%d,%p,%d,%d,%d,%d)\n", current->comm, current->pid, fd, buf, cnt, off64, off1, off2); + unlock_kernel(); return -EINVAL; } asmlinkage int irix_pwrite(int fd, char *buf, int cnt, int off64, int off1, int off2) { + lock_kernel(); printk("[%s:%d] Wheee.. irix_pwrite(%d,%p,%d,%d,%d,%d)\n", current->comm, current->pid, fd, buf, cnt, off64, off1, off2); + unlock_kernel(); return -EINVAL; } @@ -1616,10 +1886,12 @@ asmlinkage int irix_sgifastpath(int cmd, unsigned long arg0, unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5) { + lock_kernel(); printk("[%s:%d] Wheee.. irix_fastpath(%d,%08lx,%08lx,%08lx,%08lx," "%08lx,%08lx)\n", current->comm, current->pid, cmd, arg0, arg1, arg2, arg3, arg4, arg5); + unlock_kernel(); return -EINVAL; } @@ -1644,13 +1916,14 @@ asmlinkage int irix_statvfs64(char *fname, struct irix_statvfs64 *buf) current->comm, current->pid, fname, buf); error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statvfs)); if(error) - return error; + goto out; error = namei(fname, &inode); if(error) - return error; + goto out; if(!inode->i_sb->s_op->statfs) { iput(inode); - return -ENOSYS; + error = -ENOSYS; + goto out; } old_fs = get_fs(); set_fs(get_ds()); @@ -1678,7 +1951,11 @@ asmlinkage int irix_statvfs64(char *fname, struct irix_statvfs64 *buf) for(i = 0; i < 32; i++) __put_user(0, &buf->f_fstr[i]); - return 0; + error = 0; + +out: + unlock_kernel(); + return error; } asmlinkage int irix_fstatvfs64(int fd, struct irix_statvfs *buf) @@ -1688,18 +1965,25 @@ asmlinkage int irix_fstatvfs64(int fd, struct irix_statvfs *buf) struct file *file; int error, old_fs, i; + lock_kernel(); printk("[%s:%d] Wheee.. irix_fstatvfs(%d,%p)\n", current->comm, current->pid, fd, buf); error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statvfs)); if (error) - return error; - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) - return -EBADF; - if (!(inode = file->f_inode)) - return -ENOENT; - if (!inode->i_sb->s_op->statfs) - return -ENOSYS; + goto out; + if (fd >= NR_OPEN || !(file = current->files->fd[fd])) { + error = -EBADF; + goto out; + } + if (!(inode = file->f_inode)) { + error = -ENOENT; + goto out; + } + if (!inode->i_sb->s_op->statfs) { + error = -ENOSYS; + goto out; + } old_fs = get_fs(); set_fs(get_ds()); inode->i_sb->s_op->statfs(inode->i_sb, &kbuf, sizeof(struct statfs)); @@ -1725,18 +2009,23 @@ asmlinkage int irix_fstatvfs64(int fd, struct irix_statvfs *buf) for(i = 0; i < 32; i++) __put_user(0, &buf->f_fstr[i]); - return 0; + error = 0; + +out: + unlock_kernel(); + return error; } asmlinkage int irix_getmountid(char *fname, unsigned long *midbuf) { int errno; + lock_kernel(); printk("[%s:%d] irix_getmountid(%s, %p)\n", current->comm, current->pid, fname, midbuf); errno = verify_area(VERIFY_WRITE, midbuf, (sizeof(unsigned long) * 4)); if(errno) - return errno; + goto out; /* * The idea with this system call is that when trying to determine @@ -1748,15 +2037,20 @@ asmlinkage int irix_getmountid(char *fname, unsigned long *midbuf) __put_user(0, &midbuf[1]); __put_user(0, &midbuf[2]); __put_user(0, &midbuf[3]); + error = 0; - return 0; +out: + unlock_kernel(); + return error; } asmlinkage int irix_nsproc(unsigned long entry, unsigned long mask, unsigned long arg, unsigned long sp, int slen) { + lock_kernel(); printk("[%s:%d] Wheee.. irix_nsproc(%08lx,%08lx,%08lx,%08lx,%d)\n", current->comm, current->pid, entry, mask, arg, sp, slen); + unlock_kernel(); return -EINVAL; } @@ -1784,14 +2078,18 @@ static int irix_filldir32(void *__buf, const char *name, int namlen, off_t offse struct irix_dirent32 *dirent; struct irix_dirent32_callback *buf = (struct irix_dirent32_callback *)__buf; unsigned short reclen = ROUND_UP32(NAME_OFFSET32(dirent) + namlen + 1); + int retval; + lock_kernel(); #ifdef DEBUG_GETDENTS printk("\nirix_filldir32[reclen<%d>namlen<%d>count<%d>]", reclen, namlen, buf->count); #endif buf->error = -EINVAL; /* only used if we fail.. */ - if (reclen > buf->count) - return -EINVAL; + if (reclen > buf->count) { + retval = -EINVAL; + goto out; + } dirent = buf->previous; if (dirent) __put_user(offset, &dirent->d_off); @@ -1805,7 +2103,11 @@ static int irix_filldir32(void *__buf, const char *name, int namlen, off_t offse buf->current_dir = dirent; buf->count -= reclen; - return 0; + retval = 0; + +out: + unlock_kernel(); + return retval; } asmlinkage int irix_ngetdents(unsigned int fd, void * dirent, unsigned int count, int *eob) @@ -1815,17 +2117,24 @@ asmlinkage int irix_ngetdents(unsigned int fd, void * dirent, unsigned int count struct irix_dirent32_callback buf; int error; + lock_kernel(); #ifdef DEBUG_GETDENTS printk("[%s:%d] ngetdents(%d, %p, %d, %p) ", current->comm, current->pid, fd, dirent, count, eob); #endif - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) - return -EBADF; - if (!file->f_op || !file->f_op->readdir) - return -ENOTDIR; + if (fd >= NR_OPEN || !(file = current->files->fd[fd])) { + error = -EBADF; + goto out; + } + if (!file->f_op || !file->f_op->readdir) { + error = -ENOTDIR; + goto out; + } if(verify_area(VERIFY_WRITE, dirent, count) || - verify_area(VERIFY_WRITE, eob, sizeof(*eob))) - return -EFAULT; + verify_area(VERIFY_WRITE, eob, sizeof(*eob))) { + error = -EFAULT; + goto out; + } __put_user(0, eob); buf.current_dir = (struct irix_dirent32 *) dirent; buf.previous = NULL; @@ -1833,15 +2142,21 @@ asmlinkage int irix_ngetdents(unsigned int fd, void * dirent, unsigned int count buf.error = 0; error = file->f_op->readdir(file->f_inode, file, &buf, irix_filldir32); if (error < 0) - return error; + goto out lastdirent = buf.previous; - if (!lastdirent) - return buf.error; + if (!lastdirent) { + error = buf.error; + goto out; + } lastdirent->d_off = (u32) file->f_pos; #ifdef DEBUG_GETDENTS printk("eob=%d returning %d\n", *eob, count - buf.count); #endif - return count - buf.count; + error = count - buf.count; + +out: + unlock_kernel(); + return error; } struct irix_dirent64 { @@ -1868,10 +2183,14 @@ static int irix_filldir64(void * __buf, const char * name, int namlen, struct irix_dirent64_callback * buf = (struct irix_dirent64_callback *) __buf; unsigned short reclen = ROUND_UP64(NAME_OFFSET64(dirent) + namlen + 1); + int retval; + lock_kernel(); buf->error = -EINVAL; /* only used if we fail.. */ - if (reclen > buf->count) - return -EINVAL; + if (reclen > buf->count) { + retval = -EINVAL; + goto out; + } dirent = buf->previous; if (dirent) __put_user(offset, &dirent->d_off); @@ -1885,7 +2204,10 @@ static int irix_filldir64(void * __buf, const char * name, int namlen, buf->curr = dirent; buf->count -= reclen; - return 0; + retval = 0; +out: + unlock_kernel(); + return retval; } asmlinkage int irix_getdents64(int fd, void *dirent, int cnt) @@ -1895,18 +2217,27 @@ asmlinkage int irix_getdents64(int fd, void *dirent, int cnt) struct irix_dirent64_callback buf; int error; + lock_kernel(); #ifdef DEBUG_GETDENTS printk("[%s:%d] getdents64(%d, %p, %d) ", current->comm, current->pid, fd, dirent, cnt); #endif - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) - return -EBADF; - if (!file->f_op || !file->f_op->readdir) - return -ENOTDIR; - if(verify_area(VERIFY_WRITE, dirent, cnt)) - return -EFAULT; - if(cnt < (sizeof(struct irix_dirent64) + 255)) - return -EINVAL; + if (fd >= NR_OPEN || !(file = current->files->fd[fd])) { + error = -EBADF; + goto out; + } + if (!file->f_op || !file->f_op->readdir) { + error = -ENOTDIR; + goto out; + } + if(verify_area(VERIFY_WRITE, dirent, cnt)) { + error = -EFAULT; + goto out; + } + if(cnt < (sizeof(struct irix_dirent64) + 255)) { + error = -EINVAL; + goto out; + } buf.curr = (struct irix_dirent64 *) dirent; buf.previous = NULL; @@ -1914,15 +2245,21 @@ asmlinkage int irix_getdents64(int fd, void *dirent, int cnt) buf.error = 0; error = file->f_op->readdir(file->f_inode, file, &buf, irix_filldir64); if (error < 0) - return error; + goto out; lastdirent = buf.previous; - if (!lastdirent) - return buf.error; + if (!lastdirent) { + error = buf.error; + goto out; + } lastdirent->d_off = (u64) file->f_pos; #ifdef DEBUG_GETDENTS printk("returning %d\n", cnt - buf.count); #endif - return cnt - buf.count; + error = cnt - buf.count; + +out: + unlock_kernel(); + return error; } asmlinkage int irix_ngetdents64(int fd, void *dirent, int cnt, int *eob) @@ -1932,19 +2269,28 @@ asmlinkage int irix_ngetdents64(int fd, void *dirent, int cnt, int *eob) struct irix_dirent64_callback buf; int error; + lock_kernel(); #ifdef DEBUG_GETDENTS printk("[%s:%d] ngetdents64(%d, %p, %d) ", current->comm, current->pid, fd, dirent, cnt); #endif - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) - return -EBADF; - if (!file->f_op || !file->f_op->readdir) - return -ENOTDIR; + if (fd >= NR_OPEN || !(file = current->files->fd[fd])) { + error = -EBADF; + goto out; + } + if (!file->f_op || !file->f_op->readdir) { + error = -ENOTDIR; + goto out; + } if(verify_area(VERIFY_WRITE, dirent, cnt) || - verify_area(VERIFY_WRITE, eob, sizeof(*eob))) - return -EFAULT; - if(cnt < (sizeof(struct irix_dirent64) + 255)) - return -EINVAL; + verify_area(VERIFY_WRITE, eob, sizeof(*eob))) { + error = -EFAULT; + goto out; + } + if(cnt < (sizeof(struct irix_dirent64) + 255)) { + error = -EINVAL; + goto out; + } *eob = 0; buf.curr = (struct irix_dirent64 *) dirent; @@ -1953,81 +2299,111 @@ asmlinkage int irix_ngetdents64(int fd, void *dirent, int cnt, int *eob) buf.error = 0; error = file->f_op->readdir(file->f_inode, file, &buf, irix_filldir64); if (error < 0) - return error; + goto out; lastdirent = buf.previous; - if (!lastdirent) - return buf.error; + if (!lastdirent) { + error = buf.error; + goto out; + } lastdirent->d_off = (u64) file->f_pos; #ifdef DEBUG_GETDENTS printk("eob=%d returning %d\n", *eob, cnt - buf.count); #endif - return cnt - buf.count; + error = cnt - buf.count; + +out: + unlock_kernel(); + return error; } asmlinkage int irix_uadmin(unsigned long op, unsigned long func, unsigned long arg) { + int retval; + + lock_kernel(); switch(op) { case 1: /* Reboot */ printk("[%s:%d] irix_uadmin: Wants to reboot...\n", current->comm, current->pid); - return -EINVAL; + retval = -EINVAL; + goto out; case 2: /* Shutdown */ printk("[%s:%d] irix_uadmin: Wants to shutdown...\n", current->comm, current->pid); - return -EINVAL; + retval = -EINVAL; + goto out; case 4: /* Remount-root */ printk("[%s:%d] irix_uadmin: Wants to remount root...\n", current->comm, current->pid); - return -EINVAL; + retval = -EINVAL; + goto out; case 8: /* Kill all tasks. */ printk("[%s:%d] irix_uadmin: Wants to kill all tasks...\n", current->comm, current->pid); - return -EINVAL; + retval = -EINVAL; + goto out; case 256: /* Set magic mushrooms... */ printk("[%s:%d] irix_uadmin: Wants to set magic mushroom[%d]...\n", current->comm, current->pid, (int) func); - return -EINVAL; + retval = -EINVAL; + goto out; default: printk("[%s:%d] irix_uadmin: Unknown operation [%d]...\n", current->comm, current->pid, (int) op); - return -EINVAL; + retval = -EINVAL; + goto out; }; + +out: + unlock_kernel(); + return retval; } asmlinkage int irix_utssys(char *inbuf, int arg, int type, char *outbuf) { + int retval; + + lock_kernel(); switch(type) { case 0: /* uname() */ - return irix_uname((struct iuname *)inbuf); + retval = irix_uname((struct iuname *)inbuf); + goto out; case 2: /* ustat() */ printk("[%s:%d] irix_utssys: Wants to do ustat()\n", current->comm, current->pid); - return -EINVAL; + retval = -EINVAL; + goto out; case 3: /* fusers() */ printk("[%s:%d] irix_utssys: Wants to do fusers()\n", current->comm, current->pid); - return -EINVAL; + retval = -EINVAL; + goto out; default: printk("[%s:%d] irix_utssys: Wants to do unknown type[%d]\n", current->comm, current->pid, (int) type); - return -EINVAL; + retval = -EINVAL; + goto out; } + +out: + unlock_kernel(); + return retval; } #undef DEBUG_FCNTL @@ -2039,6 +2415,7 @@ asmlinkage int irix_fcntl(int fd, int cmd, int arg) { int retval; + lock_kernel(); #ifdef DEBUG_FCNTL printk("[%s:%d] irix_fcntl(%d, %d, %d) ", current->comm, current->pid, fd, cmd, arg); @@ -2048,53 +2425,67 @@ asmlinkage int irix_fcntl(int fd, int cmd, int arg) #ifdef DEBUG_FCNTL printk("%d\n", retval); #endif + unlock_kernel(); return retval; } asmlinkage int irix_ulimit(int cmd, int arg) { + lock_kernel(); switch(cmd) { case 1: printk("[%s:%d] irix_ulimit: Wants to get file size limit.\n", current->comm, current->pid); - return -EINVAL; + retval = -EINVAL; + goto out; case 2: printk("[%s:%d] irix_ulimit: Wants to set file size limit.\n", current->comm, current->pid); - return -EINVAL; + retval = -EINVAL; + goto out; case 3: printk("[%s:%d] irix_ulimit: Wants to get brk limit.\n", current->comm, current->pid); - return -EINVAL; + retval = -EINVAL; + goto out; case 4: #if 0 printk("[%s:%d] irix_ulimit: Wants to get fd limit.\n", current->comm, current->pid); - return -EINVAL; + retval = -EINVAL; + goto out; #endif - return current->rlim[RLIMIT_NOFILE].rlim_cur; + retval = current->rlim[RLIMIT_NOFILE].rlim_cur; + goto out; case 5: printk("[%s:%d] irix_ulimit: Wants to get txt offset.\n", current->comm, current->pid); - return -EINVAL; + retval = -EINVAL; + goto out; default: printk("[%s:%d] irix_ulimit: Unknown command [%d].\n", current->comm, current->pid, cmd); - return -EINVAL; + retval = -EINVAL; + goto out; } +out: + unlock_kernel(); + return retval; } asmlinkage int irix_unimp(struct pt_regs *regs) { + lock_kernel(); printk("irix_unimp [%s:%d] v0=%d v1=%d a0=%08lx a1=%08lx a2=%08lx " "a3=%08lx\n", current->comm, current->pid, (int) regs->regs[2], (int) regs->regs[3], regs->regs[4], regs->regs[5], regs->regs[6], regs->regs[7]); + unlock_kernel(); return -ENOSYS; } diff --git a/arch/mips/kernel/sysmips.c b/arch/mips/kernel/sysmips.c index 4aff0bc61..c5e394d56 100644 --- a/arch/mips/kernel/sysmips.c +++ b/arch/mips/kernel/sysmips.c @@ -10,6 +10,8 @@ #include <linux/errno.h> #include <linux/linkage.h> #include <linux/mm.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> #include <linux/sched.h> #include <linux/string.h> #include <linux/utsname.h> @@ -19,12 +21,6 @@ #include <asm/sysmips.h> #include <asm/uaccess.h> -static inline size_t -strnlen_user(const char *s, size_t count) -{ - return strnlen(s, count); -} - /* * How long a hostname can we get from user space? * -EFAULT if invalid area or too long @@ -53,44 +49,65 @@ sys_sysmips(int cmd, int arg1, int arg2, int arg3) { int *p; char *name; - int flags, tmp, len, retval = -EINVAL; + int flags, tmp, len, retval; + lock_kernel(); switch(cmd) { case SETNAME: - if (!suser()) - return -EPERM; + if (!suser()) { + retval = -EPERM; + goto out; + } name = (char *) arg1; - len = get_max_hostname((unsigned long)name); - if (retval < 0) - return len; - len = strnlen_user(name, retval); + len = strlen_user(name); + if (len < 0) + retval = len; + goto out; if (len == 0 || len > __NEW_UTS_LEN) - return -EINVAL; + retval = -EINVAL; + goto out; copy_from_user(system_utsname.nodename, name, len); system_utsname.nodename[len] = '\0'; - return 0; + retval = 0; + goto out; + case MIPS_ATOMIC_SET: + /* This is broken in case of page faults and SMP ... + Risc/OS fauls after maximum 20 tries with EAGAIN. */ p = (int *) arg1; retval = verify_area(VERIFY_WRITE, p, sizeof(*p)); - if(retval) - return -EINVAL; + if (retval) + goto out; save_flags(flags); cli(); retval = *p; *p = arg2; restore_flags(flags); - return retval; + goto out; + case MIPS_FIXADE: tmp = current->tss.mflags & ~3; current->tss.mflags = tmp | (arg1 & 3); retval = 0; - break; + goto out; + case FLUSH_CACHE: flush_cache_all(); - break; + retval = 0; + goto out; + + case MIPS_RDNVRAM: + retval = -EIO; + goto out; + + default: + retval = -EINVAL; + goto out; } +out: + unlock_kernel(); return retval; } @@ -102,36 +119,3 @@ sys_cachectl(char *addr, int nbytes, int op) { return -ENOSYS; } - -/* For emulation of various binary types, and their shared libs, - * we need this. - */ - -extern int do_open_namei(const char *pathname, int flag, int mode, - struct inode **res_inode, struct inode *base); - -/* Only one at this time. */ -#define IRIX32_EMUL "/usr/gnemul/irix" - -int open_namei(const char *pathname, int flag, int mode, - struct inode **res_inode, struct inode *base) -{ - if(!base && (current->personality == PER_IRIX32) && - *pathname == '/') { - struct inode *emul_ino; - const char *p = pathname; - char *emul_path = IRIX32_EMUL; - int v; - - while (*p == '/') - p++; - - if(do_open_namei (emul_path, flag, mode, &emul_ino, NULL) >= 0 && - emul_ino) { - v = do_open_namei (p, flag, mode, res_inode, emul_ino); - if(v >= 0) - return v; - } - } - return do_open_namei (pathname, flag, mode, res_inode, base); -} diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index 2dd1d54ee..aa4547456 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c @@ -22,6 +22,11 @@ #include <linux/mc146818rtc.h> #include <linux/timex.h> +extern volatile unsigned long lost_ticks; + +/* change this if you have some constant time drift */ +#define USECS_PER_JIFFY (1000020/HZ) + /* This function must be called with interrupts disabled * It was inspired by Steve McCanne's microtime-i386 for BSD. -- jrs * @@ -59,22 +64,64 @@ static unsigned long do_slow_gettimeoffset(void) { int count; - unsigned long offset = 0; + + static int count_p = LATCH; /* for the first call after boot */ + static unsigned long jiffies_p = 0; + + /* + * cache volatile jiffies temporarily; we have IRQs turned off. + */ + unsigned long jiffies_t; /* timer count may underflow right here */ outb_p(0x00, 0x43); /* latch the count ASAP */ + count = inb_p(0x40); /* read the latched count */ - count |= inb(0x40) << 8; - /* we know probability of underflow is always MUCH less than 1% */ - if (count > (LATCH - LATCH/100)) { - /* check for pending timer interrupt */ - outb_p(0x0a, 0x20); - if (inb(0x20) & 1) - offset = TICK_SIZE; - } + + /* + * We do this guaranteed double memory access instead of a _p + * postfix in the previous port access. Wheee, hackady hack + */ + jiffies_t = jiffies; + + count |= inb_p(0x40) << 8; + + /* + * avoiding timer inconsistencies (they are rare, but they happen)... + * there are two kinds of problems that must be avoided here: + * 1. the timer counter underflows + * 2. hardware problem with the timer, not giving us continuous time, + * the counter does small "jumps" upwards on some Pentium systems, + * (see c't 95/10 page 335 for Neptun bug.) + */ + + if( jiffies_t == jiffies_p ) { + if( count > count_p ) { + /* the nutcase */ + + outb_p(0x0A, 0x20); + + /* assumption about timer being IRQ1 */ + if( inb(0x20) & 0x01 ) { + /* + * We cannot detect lost timer interrupts ... + * well, thats why we call them lost, dont we? :) + * [hmm, on the Pentium and Alpha we can ... sort of] + */ + count -= LATCH; + } else { + printk("do_slow_gettimeoffset(): hardware timer problem?\n"); + } + } + } else + jiffies_p = jiffies_t; + + count_p = count; + count = ((LATCH-1) - count) * TICK_SIZE; count = (count + LATCH/2) / LATCH; - return offset + count; + + return count; } static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset; @@ -90,11 +137,20 @@ void do_gettimeofday(struct timeval *tv) cli(); *tv = xtime; tv->tv_usec += do_gettimeoffset(); + + /* + * xtime is atomically updated in timer_bh. lost_ticks is + * nonzero if the timer bottom half hasnt executed yet. + */ + if (lost_ticks) + tv->tv_usec += USECS_PER_JIFFY; + + restore_flags(flags); + if (tv->tv_usec >= 1000000) { tv->tv_usec -= 1000000; tv->tv_sec++; } - restore_flags(flags); } void do_settimeofday(struct timeval *tv) @@ -167,7 +223,7 @@ static int set_rtc_mmss(unsigned long nowtime) /* The following flags have to be released exactly in this order, * otherwise the DS12887 (popular MC146818A clone with integrated - * battery and crystal) will not reset the oscillator and will not + * battery and quartz) will not reset the oscillator and will not * update precisely 500 ms later. You won't find this mentioned in * the Dallas Semiconductor data sheets, but who believes data * sheets anyway ... -- Markus Kuhn @@ -205,7 +261,7 @@ static void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) basically because we don't yet share IRQ's around. This message is rigged to be safe on the 386 - basically it's a hack, so don't look closely for now.. */ - smp_message_pass(MSG_ALL_BUT_SELF, MSG_RESCHEDULE, 0L, 0); + /*smp_message_pass(MSG_ALL_BUT_SELF, MSG_RESCHEDULE, 0L, 0); */ } /* Converts Gregorian date to seconds since 1970-01-01 00:00:00. @@ -281,7 +337,7 @@ void time_init(void) if ((year += 1900) < 1970) year += 100; #else - /* true for all MIPS machines? */ + /* Acer PICA clock starts from 1980. True for all MIPS machines? */ year += 1980; #endif xtime.tv_sec = mktime(year, mon, day, hour, min, sec); diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 20cd6fe06..17b1f9a28 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -18,6 +18,8 @@ */ #include <linux/config.h> #include <linux/mm.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> #include <asm/branch.h> #include <asm/cachectl.h> @@ -93,34 +95,15 @@ int kstack_depth_to_print = 24; * This routine abuses get_user()/put_user() to reference pointers * with at least a bit of error checking ... */ -void die_if_kernel(char * str, struct pt_regs * regs, long err) +void show_registers(char * str, struct pt_regs * regs, long err) { int i; int *stack; u32 *sp, *pc, addr, module_start, module_end; extern char start_kernel, _etext; - /* - * Just return if in user mode. - * XXX - */ -#if (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2) - if (!((regs)->cp0_status & 0x4)) - return; -#endif -#if (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) - if (!(regs->cp0_status & 0x18)) - return; -#endif - - /* - * Yes, these double casts are required ... - */ - sp = (u32 *)(unsigned long)regs->regs[29]; - pc = (u32 *)(unsigned long)regs->cp0_epc; - - console_verbose(); - printk("%s: %08lx\n", str, err ); + sp = (u32 *)regs->regs[29]; + pc = (u32 *)regs->cp0_epc; show_regs(regs); @@ -189,6 +172,26 @@ void die_if_kernel(char * str, struct pt_regs * regs, long err) do_exit(SIGSEGV); } +void die_if_kernel(const char * str, struct pt_regs * regs, long err) +{ + /* + * Just return if in user mode. + * XXX + */ +#if (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2) + if (!((regs)->cp0_status & 0x4)) + return; +#endif +#if (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) + if (!(regs->cp0_status & 0x18)) + return; +#endif + console_verbose(); + printk("%s: %04lx\n", str, err & 0xffff); + show_regs(regs); + do_exit(SIGSEGV); +} + static void default_be_board_handler(struct pt_regs *regs) { /* @@ -199,32 +202,44 @@ static void default_be_board_handler(struct pt_regs *regs) void do_ibe(struct pt_regs *regs) { + lock_kernel(); ibe_board_handler(regs); + unlock_kernel(); } void do_dbe(struct pt_regs *regs) { + lock_kernel(); dbe_board_handler(regs); + unlock_kernel(); } void do_ov(struct pt_regs *regs) { + lock_kernel(); #ifdef CONF_DEBUG_EXCEPTIONS show_regs(regs); #endif if (compute_return_epc(regs)) - return; + goto out; force_sig(SIGFPE, current); +out: + unlock_kernel(); } void do_fpe(struct pt_regs *regs, unsigned int fcr31) { + lock_kernel(); #ifdef CONF_DEBUG_EXCEPTIONS show_regs(regs); #endif + printk("Caught floating exception at epc == %08lx, fcr31 == %08x\n", + regs->cp0_epc, fcr31); if (compute_return_epc(regs)) - return; + goto out; force_sig(SIGFPE, current); +out: + unlock_kernel(); } static inline int get_insn_opcode(struct pt_regs *regs, unsigned int *opcode) @@ -262,6 +277,7 @@ void do_bp(struct pt_regs *regs) { unsigned int opcode, bcode; + lock_kernel(); /* * There is the ancient bug in the MIPS assemblers that the break * code starts left to bit 16 instead to bit 6 in the opcode. @@ -271,87 +287,106 @@ void do_bp(struct pt_regs *regs) printk("BREAKPOINT at %08lx\n", regs->cp0_epc); #endif if (get_insn_opcode(regs, &opcode)) - return; + goto out; bcode = ((opcode >> 16) & ((1 << 20) - 1)); do_bp_and_tr(regs, "bp", bcode); if (compute_return_epc(regs)) - return; + goto out; +out: + unlock_kernel(); } void do_tr(struct pt_regs *regs) { unsigned int opcode, bcode; + lock_kernel(); if (get_insn_opcode(regs, &opcode)) - return; + goto out; bcode = ((opcode >> 6) & ((1 << 20) - 1)); do_bp_and_tr(regs, "tr", bcode); +out: + unlock_kernel(); } void do_ri(struct pt_regs *regs) { + lock_kernel(); #ifdef CONF_DEBUG_EXCEPTIONS show_regs(regs); #endif printk("[%s:%d] Illegal instruction at %08lx ra=%08lx\n", current->comm, current->pid, regs->cp0_epc, regs->regs[31]); if (compute_return_epc(regs)) - return; + goto out; force_sig(SIGILL, current); +out: + unlock_kernel(); } void do_cpu(struct pt_regs *regs) { unsigned int cpid; + lock_kernel(); cpid = (regs->cp0_cause >> CAUSEB_CE) & 3; if (cpid == 1) { regs->cp0_status |= ST0_CU1; - return; + goto out; } force_sig(SIGILL, current); +out: + unlock_kernel(); } void do_vcei(struct pt_regs *regs) { + lock_kernel(); /* * Only possible on R4[04]00[SM]C. No handler because I don't have * such a cpu. Theory says this exception doesn't happen. */ panic("Caught VCEI exception - should not happen"); + unlock_kernel(); } void do_vced(struct pt_regs *regs) { + lock_kernel(); /* * Only possible on R4[04]00[SM]C. No handler because I don't have * such a cpu. Theory says this exception doesn't happen. */ panic("Caught VCE exception - should not happen"); + unlock_kernel(); } void do_watch(struct pt_regs *regs) { + lock_kernel(); /* * We use the watch exception where available to detect stack * overflows. */ show_regs(regs); panic("Caught WATCH exception - probably caused by stack overflow."); + unlock_kernel(); } void do_reserved(struct pt_regs *regs) { + lock_kernel(); /* * Game over - no way to handle this if it ever occurs. * Most probably caused by a new unknown cpu type or * after another deadly hard/software error. */ panic("Caught reserved exception - should not happen."); + unlock_kernel(); } static void watch_init(unsigned long cputype) @@ -365,7 +400,7 @@ static void watch_init(unsigned long cputype) case CPU_R4000PC: case CPU_R4400PC: case CPU_R4200: - /* case CPU_R4300: */ + case CPU_R4300: set_except_vector(23, handle_watch); watch_available = 1; break; @@ -454,7 +489,7 @@ void trap_init(void) case CPU_R4000PC: case CPU_R4400PC: case CPU_R4200: - /* case CPU_R4300: */ + case CPU_R4300: /* case CPU_R4640: */ case CPU_R4600: case CPU_R5000: diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c index ba3a612fa..696244b6c 100644 --- a/arch/mips/kernel/unaligned.c +++ b/arch/mips/kernel/unaligned.c @@ -85,6 +85,9 @@ */ #include <linux/mm.h> #include <linux/signal.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> + #include <asm/branch.h> #include <asm/byteorder.h> #include <asm/inst.h> @@ -169,7 +172,7 @@ emulate_load_store_insn(struct pt_regs *regs, unsigned long addr, unsigned long ".section\t__ex_table,\"a\"\n\t" STR(PTR)"\t1b,%2\n\t" STR(PTR)"\t2b,%2\n\t" - ".text" + ".previous" :"=&r" (value) :"r" (addr), "i" (&&fault) :"$1"); @@ -190,7 +193,7 @@ emulate_load_store_insn(struct pt_regs *regs, unsigned long addr, unsigned long ".section\t__ex_table,\"a\"\n\t" STR(PTR)"\t1b,%2\n\t" STR(PTR)"\t2b,%2\n\t" - ".text" + ".previous" :"=&r" (value) :"r" (addr), "i" (&&fault)); regs->regs[insn.i_format.rt] = value; @@ -214,7 +217,7 @@ emulate_load_store_insn(struct pt_regs *regs, unsigned long addr, unsigned long ".section\t__ex_table,\"a\"\n\t" STR(PTR)"\t1b,%2\n\t" STR(PTR)"\t2b,%2\n\t" - ".text" + ".previous" :"=&r" (value) :"r" (addr), "i" (&&fault) :"$1"); @@ -235,7 +238,7 @@ emulate_load_store_insn(struct pt_regs *regs, unsigned long addr, unsigned long ".section\t__ex_table,\"a\"\n\t" STR(PTR)"\t1b,%2\n\t" STR(PTR)"\t2b,%2\n\t" - ".text" + ".previous" :"=&r" (value) :"r" (addr), "i" (&&fault)); value &= 0xffffffff; @@ -258,7 +261,7 @@ emulate_load_store_insn(struct pt_regs *regs, unsigned long addr, unsigned long ".section\t__ex_table,\"a\"\n\t" STR(PTR)"\t1b,%2\n\t" STR(PTR)"\t2b,%2\n\t" - ".text" + ".previous" :"=&r" (value) :"r" (addr), "i" (&&fault)); regs->regs[insn.i_format.rt] = value; @@ -285,7 +288,7 @@ emulate_load_store_insn(struct pt_regs *regs, unsigned long addr, unsigned long ".section\t__ex_table,\"a\"\n\t" STR(PTR)"\t1b,%2\n\t" STR(PTR)"\t2b,%2\n\t" - ".text" + ".previous" : /* no outputs */ :"r" (value), "r" (addr), "i" (&&fault) :"$1"); @@ -306,7 +309,7 @@ emulate_load_store_insn(struct pt_regs *regs, unsigned long addr, unsigned long ".section\t__ex_table,\"a\"\n\t" STR(PTR)"\t1b,%2\n\t" STR(PTR)"\t2b,%2\n\t" - ".text" + ".previous" : /* no outputs */ :"r" (value), "r" (addr), "i" (&&fault)); return; @@ -328,7 +331,7 @@ emulate_load_store_insn(struct pt_regs *regs, unsigned long addr, unsigned long ".section\t__ex_table,\"a\"\n\t" STR(PTR)"\t1b,%2\n\t" STR(PTR)"\t2b,%2\n\t" - ".text" + ".previous" : /* no outputs */ :"r" (value), "r" (addr), "i" (&&fault)); return; @@ -406,6 +409,7 @@ do_ade(struct pt_regs *regs) register_t badvaddr __attribute__ ((unused)) = regs->cp0_badvaddr; char *adels; + lock_kernel(); adels = (((regs->cp0_cause & CAUSEF_EXCCODE) >> CAUSEB_EXCCODE) == 4) ? "adel" : "ades"; @@ -444,11 +448,11 @@ do_ade(struct pt_regs *regs) #endif /* CONF_LOG_UNALIGNED_ACCESSES */ if (compute_return_epc(regs)) - return; + goto out; if(current->tss.mflags & MF_FIXADE) { pc += ((regs->cp0_cause & CAUSEF_BD) ? 4 : 0); fix_ade(regs, pc); - return; + goto out; } #ifdef CONF_DEBUG_EXCEPTIONS @@ -456,4 +460,8 @@ do_ade(struct pt_regs *regs) #endif force_sig(SIGBUS, current); + +out: + unlock_kernel(); + return; } |