diff options
Diffstat (limited to 'arch/sparc64/kernel')
32 files changed, 6272 insertions, 2322 deletions
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile index 199360a5f..9e9013735 100644 --- a/arch/sparc64/kernel/Makefile +++ b/arch/sparc64/kernel/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.22 1997/05/27 19:30:17 jj Exp $ +# $Id: Makefile,v 1.28 1997/07/05 09:52:20 davem Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also @@ -16,20 +16,26 @@ all: kernel.o head.o init_task.o O_TARGET := kernel.o -O_OBJS := etrap.o rtrap.o hack.o process.o setup.o cpu.o idprom.o \ - systbls.o traps.o entry.o devices.o auxio.o ioport.o \ - irq.o ptrace.o time.o sys_sparc.o signal.o winfixup.o +O_OBJS := process.o setup.o cpu.o idprom.o \ + systbls.o traps.o devices.o auxio.o ioport.o \ + irq.o ptrace.o time.o sys_sparc.o signal.o \ + unaligned.o sys_sunos32.o sunos_ioctl32.o OX_OBJS := sparc64_ksyms.o ifdef CONFIG_SPARC32_COMPAT - O_OBJS += sys_sparc32.o signal32.o ioctl32.o + O_OBJS += sys32.o sys_sparc32.o signal32.o ioctl32.o endif ifdef CONFIG_BINFMT_ELF32 O_OBJS += binfmt_elf32.o endif -head.o: head.S ttable.S itlb_miss.S dtlb_miss.S dtlb_prot.S +ifdef CONFIG_BINFMT_AOUT32 + O_OBJS += binfmt_aout32.o +endif + +head.o: head.S ttable.S itlb_miss.S dtlb_miss.S dtlb_prot.S etrap.S rtrap.S \ + winfixup.S entry.S $(CC) -D__ASSEMBLY__ -ansi -c $*.S -o $*.o # diff --git a/arch/sparc64/kernel/binfmt_aout32.c b/arch/sparc64/kernel/binfmt_aout32.c new file mode 100644 index 000000000..215aaf06f --- /dev/null +++ b/arch/sparc64/kernel/binfmt_aout32.c @@ -0,0 +1,482 @@ +/* + * linux/fs/binfmt_aout.c + * + * Copyright (C) 1991, 1992, 1996 Linus Torvalds + * + * Hacked a bit by DaveM to make it work with 32-bit SunOS + * binaries on the sparc64 port. + */ + +#include <linux/module.h> + +#include <linux/fs.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/mman.h> +#include <linux/a.out.h> +#include <linux/errno.h> +#include <linux/signal.h> +#include <linux/string.h> +#include <linux/stat.h> +#include <linux/fcntl.h> +#include <linux/ptrace.h> +#include <linux/user.h> +#include <linux/malloc.h> +#include <linux/binfmts.h> +#include <linux/personality.h> +#include <linux/init.h> + +#include <asm/system.h> +#include <asm/uaccess.h> +#include <asm/pgtable.h> + +static int load_aout32_binary(struct linux_binprm *, struct pt_regs * regs); +static int load_aout32_library(int fd); +static int aout32_core_dump(long signr, struct pt_regs * regs); + +extern void dump_thread(struct pt_regs *, struct user *); + +static struct linux_binfmt aout32_format = { + NULL, NULL, load_aout32_binary, load_aout32_library, aout32_core_dump +}; + +static void set_brk(unsigned long start, unsigned long end) +{ + start = PAGE_ALIGN(start); + end = PAGE_ALIGN(end); + if (end <= start) + return; + do_mmap(NULL, start, end - start, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE, 0); +} + +/* + * These are the only things you should do on a core-file: use only these + * macros to write out all the necessary info. + */ +#define DUMP_WRITE(addr,nr) \ +while (file.f_op->write(inode,&file,(char *)(addr),(nr)) != (nr)) goto close_coredump + +#define DUMP_SEEK(offset) \ +if (file.f_op->llseek) { \ + if (file.f_op->llseek(inode,&file,(offset),0) != (offset)) \ + goto close_coredump; \ +} else file.f_pos = (offset) + +/* + * Routine writes a core dump image in the current directory. + * Currently only a stub-function. + * + * Note that setuid/setgid files won't make a core-dump if the uid/gid + * changed due to the set[u|g]id. It's enforced by the "current->dumpable" + * field, which also makes sure the core-dumps won't be recursive if the + * dumping of the process results in another error.. + */ + +static inline int +do_aout32_core_dump(long signr, struct pt_regs * regs) +{ + struct dentry * dentry = NULL; + struct inode * inode = NULL; + struct file file; + unsigned short fs; + int has_dumped = 0; + char corefile[6+sizeof(current->comm)]; + unsigned long dump_start, dump_size; + struct user dump; +# define START_DATA(u) (u.u_tsize) +# define START_STACK(u) ((regs->u_regs[UREG_FP]) & ~(PAGE_SIZE - 1)) + + if (!current->dumpable || current->mm->count != 1) + return 0; + current->dumpable = 0; + +/* See if we have enough room to write the upage. */ + if (current->rlim[RLIMIT_CORE].rlim_cur < PAGE_SIZE) + return 0; + fs = get_fs(); + set_fs(KERNEL_DS); + memcpy(corefile,"core.",5); +#if 0 + memcpy(corefile+5,current->comm,sizeof(current->comm)); +#else + corefile[4] = '\0'; +#endif + dentry = open_namei(corefile,O_CREAT | 2 | O_TRUNC, 0600); + if (IS_ERR(dentry)) { + dentry = NULL; + goto end_coredump; + } + inode = dentry->d_inode; + if (!S_ISREG(inode->i_mode)) + goto end_coredump; + if (!inode->i_op || !inode->i_op->default_file_ops) + goto end_coredump; + if (get_write_access(inode)) + goto end_coredump; + file.f_mode = 3; + file.f_flags = 0; + file.f_count = 1; + file.f_dentry = dentry; + file.f_pos = 0; + file.f_reada = 0; + file.f_op = inode->i_op->default_file_ops; + if (file.f_op->open) + if (file.f_op->open(inode,&file)) + goto done_coredump; + if (!file.f_op->write) + goto close_coredump; + has_dumped = 1; + current->flags |= PF_DUMPCORE; + strncpy(dump.u_comm, current->comm, sizeof(current->comm)); + dump.signal = signr; + dump_thread(regs, &dump); + +/* If the size of the dump file exceeds the rlimit, then see what would happen + if we wrote the stack, but not the data area. */ + if ((dump.u_dsize+dump.u_ssize) > + current->rlim[RLIMIT_CORE].rlim_cur) + dump.u_dsize = 0; + +/* Make sure we have enough room to write the stack and data areas. */ + if ((dump.u_ssize) > + current->rlim[RLIMIT_CORE].rlim_cur) + dump.u_ssize = 0; + +/* make sure we actually have a data and stack area to dump */ + set_fs(USER_DS); + if (verify_area(VERIFY_READ, (void *) START_DATA(dump), dump.u_dsize)) + dump.u_dsize = 0; + if (verify_area(VERIFY_READ, (void *) START_STACK(dump), dump.u_ssize)) + dump.u_ssize = 0; + + set_fs(KERNEL_DS); +/* struct user */ + DUMP_WRITE(&dump,sizeof(dump)); +/* now we start writing out the user space info */ + set_fs(USER_DS); +/* Dump the data area */ + if (dump.u_dsize != 0) { + dump_start = START_DATA(dump); + dump_size = dump.u_dsize; + DUMP_WRITE(dump_start,dump_size); + } +/* Now prepare to dump the stack area */ + if (dump.u_ssize != 0) { + dump_start = START_STACK(dump); + dump_size = dump.u_ssize; + DUMP_WRITE(dump_start,dump_size); + } +/* Finally dump the task struct. Not be used by gdb, but could be useful */ + set_fs(KERNEL_DS); + DUMP_WRITE(current,sizeof(*current)); +close_coredump: + if (file.f_op->release) + file.f_op->release(inode,&file); +done_coredump: + put_write_access(inode); +end_coredump: + set_fs(fs); + dput(dentry); + return has_dumped; +} + +static int +aout32_core_dump(long signr, struct pt_regs * regs) +{ + int retval; + + MOD_INC_USE_COUNT; + retval = do_aout32_core_dump(signr, regs); + MOD_DEC_USE_COUNT; + return retval; +} + +/* + * create_aout32_tables() parses the env- and arg-strings in new user + * memory and creates the pointer tables from them, and puts their + * addresses on the "stack", returning the new stack pointer value. + */ +#define A(x) ((unsigned long)x) +static u32 *create_aout32_tables(char * p, struct linux_binprm * bprm) +{ + u32 *argv, *envp; + u32 *sp; + int argc = bprm->argc; + int envc = bprm->envc; + + sp = (u32 *) ((-(unsigned long)sizeof(char *)) & (unsigned long) p); + + /* This imposes the proper stack alignment for a new process. */ + sp = (u32 *) (((unsigned long) sp) & ~7); + if ((envc+argc+3)&1) + --sp; + + sp -= envc+1; + envp = (u32 *) sp; + sp -= argc+1; + argv = (u32 *) sp; + put_user(argc,--sp); + current->mm->arg_start = (unsigned long) p; + while (argc-->0) { + char c; + put_user(((u32)A(p)),argv++); + do { + get_user(c,p++); + } while (c); + } + put_user(NULL,argv); + current->mm->arg_end = current->mm->env_start = (unsigned long) p; + while (envc-->0) { + char c; + put_user(((u32)A(p)),envp++); + do { + get_user(c,p++); + } while (c); + } + put_user(NULL,envp); + current->mm->env_end = (unsigned long) p; + return sp; +} + +/* + * These are the functions used to load a.out style executables and shared + * libraries. There is no binary dependent code anywhere else. + */ + +static inline int do_load_aout32_binary(struct linux_binprm * bprm, + struct pt_regs * regs) +{ + struct exec ex; + struct file * file; + int fd; + unsigned long error; + unsigned long p = bprm->p; + unsigned long fd_offset; + unsigned long rlim; + + ex = *((struct exec *) bprm->buf); /* exec-header */ + if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC && + N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) || + N_TRSIZE(ex) || N_DRSIZE(ex) || + bprm->dentry->d_inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) { + return -ENOEXEC; + } + + current->personality = PER_LINUX; + fd_offset = N_TXTOFF(ex); + + /* Check initial limits. This avoids letting people circumvent + * size limits imposed on them by creating programs with large + * arrays in the data or bss. + */ + rlim = current->rlim[RLIMIT_DATA].rlim_cur; + if (rlim >= RLIM_INFINITY) + rlim = ~0; + if (ex.a_data + ex.a_bss > rlim) + return -ENOMEM; + + /* OK, This is the point of no return */ + flush_old_exec(bprm); + memcpy(¤t->tss.core_exec, &ex, sizeof(struct exec)); + + current->mm->end_code = ex.a_text + + (current->mm->start_code = N_TXTADDR(ex)); + current->mm->end_data = ex.a_data + + (current->mm->start_data = N_DATADDR(ex)); + current->mm->brk = ex.a_bss + + (current->mm->start_brk = N_BSSADDR(ex)); + + current->mm->rss = 0; + current->mm->mmap = NULL; + current->suid = current->euid = current->fsuid = bprm->e_uid; + current->sgid = current->egid = current->fsgid = bprm->e_gid; + current->flags &= ~PF_FORKNOEXEC; + if (N_MAGIC(ex) == NMAGIC) { + /* Fuck me plenty... */ + error = do_mmap(NULL, N_TXTADDR(ex), ex.a_text, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_FIXED|MAP_PRIVATE, 0); + read_exec(bprm->dentry, fd_offset, (char *) N_TXTADDR(ex), + ex.a_text, 0); + error = do_mmap(NULL, N_DATADDR(ex), ex.a_data, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_FIXED|MAP_PRIVATE, 0); + read_exec(bprm->dentry, fd_offset + ex.a_text, (char *) N_DATADDR(ex), + ex.a_data, 0); + goto beyond_if; + } + + if (N_MAGIC(ex) == OMAGIC) { + do_mmap(NULL, N_TXTADDR(ex) & PAGE_MASK, + ex.a_text+ex.a_data + PAGE_SIZE - 1, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_FIXED|MAP_PRIVATE, 0); + read_exec(bprm->dentry, fd_offset, (char *) N_TXTADDR(ex), + ex.a_text+ex.a_data, 0); + } else { + if ((ex.a_text & 0xfff || ex.a_data & 0xfff) && + (N_MAGIC(ex) != NMAGIC)) + printk(KERN_NOTICE "executable not page aligned\n"); + + fd = open_dentry(bprm->dentry, O_RDONLY); + + if (fd < 0) + return fd; + file = current->files->fd[fd]; + if (!file->f_op || !file->f_op->mmap) { + sys_close(fd); + do_mmap(NULL, 0, ex.a_text+ex.a_data, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_FIXED|MAP_PRIVATE, 0); + read_exec(bprm->dentry, fd_offset, + (char *) N_TXTADDR(ex), ex.a_text+ex.a_data, 0); + goto beyond_if; + } + + error = do_mmap(file, N_TXTADDR(ex), ex.a_text, + PROT_READ | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, + fd_offset); + + if (error != N_TXTADDR(ex)) { + sys_close(fd); + send_sig(SIGKILL, current, 0); + return error; + } + + error = do_mmap(file, N_DATADDR(ex), ex.a_data, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, + fd_offset + ex.a_text); + sys_close(fd); + if (error != N_DATADDR(ex)) { + send_sig(SIGKILL, current, 0); + return error; + } + } +beyond_if: + if (current->exec_domain && current->exec_domain->module) + __MOD_DEC_USE_COUNT(current->exec_domain->module); + if (current->binfmt && current->binfmt->module) + __MOD_DEC_USE_COUNT(current->binfmt->module); + current->exec_domain = lookup_exec_domain(current->personality); + current->binfmt = &aout32_format; + if (current->exec_domain && current->exec_domain->module) + __MOD_INC_USE_COUNT(current->exec_domain->module); + if (current->binfmt && current->binfmt->module) + __MOD_INC_USE_COUNT(current->binfmt->module); + + set_brk(current->mm->start_brk, current->mm->brk); + + p = setup_arg_pages(p, bprm); + + p = (unsigned long) create_aout32_tables((char *)p, bprm); + current->mm->start_stack = p; + start_thread32(regs, ex.a_entry, p); + if (current->flags & PF_PTRACED) + send_sig(SIGTRAP, current, 0); + return 0; +} + + +static int +load_aout32_binary(struct linux_binprm * bprm, struct pt_regs * regs) +{ + int retval; + + MOD_INC_USE_COUNT; + retval = do_load_aout32_binary(bprm, regs); + MOD_DEC_USE_COUNT; + return retval; +} + +static inline int +do_load_aout32_library(int fd) +{ + struct file * file; + struct exec ex; + struct dentry * dentry; + struct inode * inode; + unsigned int len; + unsigned int bss; + unsigned int start_addr; + unsigned long error; + + file = current->files->fd[fd]; + + if (!file || !file->f_op) + return -EACCES; + + dentry = file->f_dentry; + inode = dentry->d_inode; + + /* Seek into the file */ + if (file->f_op->llseek) { + if ((error = file->f_op->llseek(inode, file, 0, 0)) != 0) + return -ENOEXEC; + } else + file->f_pos = 0; + + set_fs(KERNEL_DS); + error = file->f_op->read(inode, file, (char *) &ex, sizeof(ex)); + set_fs(USER_DS); + if (error != sizeof(ex)) + return -ENOEXEC; + + /* We come in here for the regular a.out style of shared libraries */ + if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC) || N_TRSIZE(ex) || + N_DRSIZE(ex) || ((ex.a_entry & 0xfff) && N_MAGIC(ex) == ZMAGIC) || + inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) { + return -ENOEXEC; + } + if (N_MAGIC(ex) == ZMAGIC && N_TXTOFF(ex) && + (N_TXTOFF(ex) < inode->i_sb->s_blocksize)) { + printk("N_TXTOFF < BLOCK_SIZE. Please convert library\n"); + return -ENOEXEC; + } + + if (N_FLAGS(ex)) return -ENOEXEC; + + /* For QMAGIC, the starting address is 0x20 into the page. We mask + this off to get the starting address for the page */ + + start_addr = ex.a_entry & 0xfffff000; + + /* Now use mmap to map the library into memory. */ + error = do_mmap(file, start_addr, ex.a_text + ex.a_data, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE, + N_TXTOFF(ex)); + if (error != start_addr) + return error; + len = PAGE_ALIGN(ex.a_text + ex.a_data); + bss = ex.a_text + ex.a_data + ex.a_bss; + if (bss > len) { + error = do_mmap(NULL, start_addr + len, bss-len, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_PRIVATE|MAP_FIXED, 0); + if (error != start_addr + len) + return error; + } + return 0; +} + +static int +load_aout32_library(int fd) +{ + int retval; + + MOD_INC_USE_COUNT; + retval = do_load_aout32_library(fd); + MOD_DEC_USE_COUNT; + return retval; +} + + +__initfunc(int init_aout32_binfmt(void)) +{ + return register_binfmt(&aout32_format); +} diff --git a/arch/sparc64/kernel/binfmt_elf32.c b/arch/sparc64/kernel/binfmt_elf32.c index 05d50fe56..9ab2b7aca 100644 --- a/arch/sparc64/kernel/binfmt_elf32.c +++ b/arch/sparc64/kernel/binfmt_elf32.c @@ -6,6 +6,8 @@ #define ELF_CLASS ELFCLASS32 #define ELF_DATA ELFDATA2MSB; +#define elf_check_arch(x) (((x) == EM_SPARC) || ((x) == EM_SPARC32PLUS)) + #include <asm/processor.h> #include <linux/module.h> #include <linux/config.h> diff --git a/arch/sparc64/kernel/cpu.c b/arch/sparc64/kernel/cpu.c index 695ad680e..d6cdf9162 100644 --- a/arch/sparc64/kernel/cpu.c +++ b/arch/sparc64/kernel/cpu.c @@ -6,7 +6,9 @@ #include <linux/kernel.h> #include <linux/init.h> +#include <asm/asi.h> #include <asm/system.h> +#include <asm/fpumacro.h> struct cpu_iu_info { short manuf; @@ -26,6 +28,7 @@ struct cpu_fp_info { */ struct cpu_fp_info linux_sparc_fpu[] = { { 0x17, 0x10, 0, "UltraSparc I integrated FPU"}, + { 0x22, 0x10, 0, "UltraSparc II integrated FPU"}, { 0x17, 0x11, 0, "UltraSparc II integrated FPU"}, { 0x17, 0x12, 0, "UltraSparc III integrated FPU"}, }; @@ -34,6 +37,7 @@ struct cpu_fp_info linux_sparc_fpu[] = { struct cpu_iu_info linux_sparc_chips[] = { { 0x17, 0x10, "TI UltraSparc I (SpitFire)"}, + { 0x22, 0x10, "TI UltraSparc II (BlackBird)"}, { 0x17, 0x11, "TI UltraSparc II (BlackBird)"}, { 0x17, 0x12, "TI UltraSparc III (Cheetah)"}, /* A guess... */ }; @@ -50,11 +54,20 @@ __initfunc(void cpu_probe(void)) int manuf, impl; unsigned i, cpuid; long ver, fpu_vers; - - cpuid = get_cpuid(); + long fprs; +#ifndef __SMP__ + cpuid = 0; +#else +#error SMP not supported on sparc64 yet + /* cpuid = get_cpuid(); */ +#endif + + fprs = fprs_read (); + fprs_write (FPRS_FEF); __asm__ __volatile__ ("rdpr %%ver, %0; stx %%fsr, [%1]" : "=r" (ver) : "r" (&fpu_vers)); - + fprs_write (fprs); + manuf = ((ver >> 48)&0xffff); impl = ((ver >> 32)&0xffff); diff --git a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c index 6aadd14e0..5e6705896 100644 --- a/arch/sparc64/kernel/devices.c +++ b/arch/sparc64/kernel/devices.c @@ -6,7 +6,6 @@ #include <linux/kernel.h> #include <linux/tasks.h> -#include <linux/config.h> #include <linux/init.h> #include <asm/page.h> @@ -15,7 +14,7 @@ #include <asm/smp.h> struct prom_cpuinfo linux_cpus[NCPUS]; -int linux_num_cpus; +int linux_num_cpus = 0; extern void cpu_probe(void); @@ -54,7 +53,7 @@ device_scan(unsigned long mem_start)) }; if(cpu_ctr == 0) { printk("No CPU nodes found, cannot continue.\n"); - halt(); + prom_halt(); } printk("Found %d CPU prom device tree node(s).\n", cpu_ctr); }; diff --git a/arch/sparc64/kernel/dtlb_miss.S b/arch/sparc64/kernel/dtlb_miss.S index 31b87f3de..b034ef407 100644 --- a/arch/sparc64/kernel/dtlb_miss.S +++ b/arch/sparc64/kernel/dtlb_miss.S @@ -1,4 +1,4 @@ -/* $Id: dtlb_miss.S,v 1.11 1997/04/10 01:59:35 davem Exp $ +/* $Id: dtlb_miss.S,v 1.12 1997/06/26 12:47:08 jj Exp $ * dtlb_miss.S: Data TLB miss code, this is included directly * into the trap table. * @@ -19,9 +19,11 @@ * } * goto longer_processing; * } else { - * if(fault_address >= KERNBASE && - * fault_address < VMALLOC_START) { - * tlb_load(__pa(fault_address) | PAGE_KERNEL); + * if(fault_address >= PAGE_OFFSET) { + * pte_val = PAGE_KERNEL; + * if (fault_address & 0x10000000000) + * pte_val = PAGE_KERNEL_IO; + * tlb_load(__pa(fault_address) | pte_val); * return_from_trap(); * } else { * pgd = pgd_offset(swapper_pg_dir, fault_address); @@ -32,9 +34,9 @@ * This is optimized for user TLB misses on purpose. */ -#define KERN_HIGHBITS (_PAGE_VALID | _PAGE_SZ4MB) +#define KERN_HIGHBITS ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000) #define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W) -#define KERN_LOWBITS_IO (_PAGE_E | _PAGE_P | _PAGE_W) +#define KERN_LOWBITS_IO ((_PAGE_E | _PAGE_P | _PAGE_W) ^ KERN_LOWBITS) /* ICACHE line 1 */ /*0x00*/ ldxa [%g0] ASI_DMMU, %g1 ! Get TAG_TARGET @@ -57,17 +59,17 @@ 1:/*0x3c*/ retry ! Trap return 3: /* ICACHE line 3 */ - /*0x40*/ sllx %g1, 43, %g5 ! This gets >= VMALLOC_START... - /*0x44*/ brlz,pn %g5, 4f ! ...if now less than zero. - /*0x48*/ andncc %g1, 0x3ff, %g0 ! Slick trick... - /*0x4c*/ be,pn %xcc, 4f ! Yes, it is some PROM mapping - /*0x50*/ srlx %g5, 21, %g5 ! This is now physical page - /*0x54*/ sethi %uhi(KERN_HIGHBITS), %g1 ! Construct PTE - /*0x58*/ sllx %g1, 32, %g1 ! Move priv bits up - /*0x5c*/ or %g1, %g5, %g1 ! Or in the page + /*0x40*/ sllx %g1, 22, %g5 ! This is now physical page + PAGE_OFFSET + /*0x44*/ brgez,pn %g5, 4f ! If >= 0, then walk down page tables + /*0x48*/ sethi %uhi(KERN_HIGHBITS), %g1 ! Construct PTE ^ PAGE_OFFSET + /*0x4c*/ andcc %g3, 0x80, %g0 ! Slick trick... + /*0x50*/ sllx %g1, 32, %g1 ! Move high bits up + /*0x54*/ or %g1, (KERN_LOWBITS), %g1 ! Assume not IO + /*0x58*/ bne,a,pn %icc, 5f ! Is it an IO page? + /*0x5c*/ xor %g1, (KERN_LOWBITS_IO), %g1 ! Aha, it is IO... /* ICACHE line 4 */ - /*0x60*/ or %g1, (KERN_LOWBITS), %g1 ! Set low priv bits +5:/*0x60*/ xor %g1, %g5, %g1 ! Slick trick II... /*0x64*/ stxa %g1, [%g0] ASI_DTLB_DATA_IN ! TLB load /*0x68*/ retry ! Trap return 4:/*0x6c*/ ldxa [%g0] ASI_DMMU_TSB_8KB_PTR, %g1 ! For PTE offset @@ -78,3 +80,4 @@ #undef KERN_HIGHBITS #undef KERN_LOWBITS +#undef KERN_LOWBITS_IO diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index 0d95e1b75..a410cfe80 100644 --- a/arch/sparc64/kernel/entry.S +++ b/arch/sparc64/kernel/entry.S @@ -1,7 +1,7 @@ -/* $Id: entry.S,v 1.31 1997/06/02 06:33:25 davem Exp $ +/* $Id: entry.S,v 1.50 1997/07/15 16:53:00 davem Exp $ * arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points. * - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -25,7 +25,6 @@ #define NR_SYSCALLS 256 /* Each OS is different... */ .text - .align 4 .globl sparc64_dtlb_prot_catch, sparc64_dtlb_refbit_catch .globl sparc64_itlb_refbit_catch @@ -38,24 +37,27 @@ * to update the dirty bit) and since we left crap in the sfsr * it will not get updated properly. */ + .align 32 sparc64_dtlb_prot_catch: wr %g0, ASI_DMMU, %asi rdpr %pstate, %g1 wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate rdpr %tl, %g3 ldxa [%g0 + TLB_TAG_ACCESS] %asi, %g5 - ldxa [%g0 + TLB_SFSR] %asi, %g4 - cmp %g3, 1 stxa %g0, [%g0 + TLB_SFSR] %asi + membar #Sync + cmp %g3, 1 + bgu,a,pn %icc, winfix_trampoline rdpr %tpc, %g3 ba,pt %xcc, etrap rd %pc, %g7 - b,a,pt %xcc, 1f - + b,pt %xcc, 1f + mov 1, %o2 sparc64_dtlb_refbit_catch: srlx %g5, 9, %g4 and %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9), %g4 + cmp %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9) be,a,pt %xcc, 2f mov 1, %g4 @@ -64,23 +66,24 @@ sparc64_dtlb_refbit_catch: wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate rdpr %tl, %g3 ldxa [%g0 + TLB_TAG_ACCESS] %asi, %g5 + cmp %g3, 1 - clr %g4 ! sfsr not updated for tlb misses - bgu,a,pn %icc, winfix_trampoline + bgu,pn %icc, winfix_trampoline rdpr %tpc, %g3 - ba,pt %xcc, etrap + b,pt %xcc, etrap rd %pc, %g7 -1: - mov %l5, %o4 ! raw tag access - mov %l4, %o5 ! raw sfsr - srlx %l5, PAGE_SHIFT, %o3 - clr %o1 ! text_fault == 0 - sllx %o3, PAGE_SHIFT, %o3 ! address - and %l4, 0x4, %o2 ! write == sfsr.W + clr %o2 +1: srlx %l5, PAGE_SHIFT, %o1 + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + call do_sparc64_fault - add %sp, STACK_BIAS + REGWIN_SZ, %o0 ! pt_regs ptr - ba,pt %xcc, rtrap + sllx %o1, PAGE_SHIFT, %o1 + b,pt %xcc, rtrap clr %l6 + nop + nop + nop + nop sparc64_itlb_refbit_catch: srlx %g5, 9, %g4 @@ -90,47 +93,119 @@ sparc64_itlb_refbit_catch: mov 1, %g4 rdpr %pstate, %g1 wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate - ba,pt %xcc, etrap - rd %pc, %g7 + rdpr %tpc, %g5 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC], %o3 - mov 1, %o1 ! text_fault == 1 - clr %o2 ! write == 0 - clr %o4 ! tag access (N/A) - clr %o5 ! raw sfsr (N/A) - call do_sparc64_fault - add %sp, STACK_BIAS + REGWIN_SZ, %o0 ! pt_regs ptr - ba,pt %xcc, rtrap - clr %l6 - -2: - sllx %g4, 63, %g4 ! _PAGE_VALID + b,pt %xcc, etrap + rd %pc, %g7 + b,pt %xcc, 1b + clr %o2 +2: sllx %g4, 63, %g4 ! _PAGE_VALID or %g5, _PAGE_ACCESSED, %g5 or %g5, %g4, %g5 stxa %g5, [%g3 + %g1] ASI_PHYS_USE_EC ! store new PTE + stxa %g5, [%g0] ASI_DTLB_DATA_IN ! TLB load retry - -3: - sllx %g4, 63, %g4 ! _PAGE_VALID +3: sllx %g4, 63, %g4 ! _PAGE_VALID or %g5, _PAGE_ACCESSED, %g5 or %g5, %g4, %g5 stxa %g5, [%g3 + %g1] ASI_PHYS_USE_EC ! store new PTE stxa %g5, [%g0] ASI_ITLB_DATA_IN ! TLB load retry + /* This is trivial with the new code... */ + .align 32 + .globl do_fpdis +do_fpdis: + wr %g0, FPRS_FEF, %fprs + ldx [%g6 + AOFF_task_flags], %g2 + sethi %hi(0x00100000), %g4 ! XXX PF_USEDFPU + andcc %g2, %g4, %g0 + + bne,a,pt %xcc, fpload_fromkstk + sethi %hi((((PAGE_SIZE<<1)-((64*4)+(2*8))) & ~(64 - 1))), %g2 + fzero %f0 + fzero %f2 + faddd %f0, %f2, %f4 + fmuld %f0, %f2, %f6 + faddd %f0, %f2, %f8 + fmuld %f0, %f2, %f10 + + faddd %f0, %f2, %f12 + fmuld %f0, %f2, %f14 + faddd %f0, %f2, %f16 + fmuld %f0, %f2, %f18 + faddd %f0, %f2, %f20 + fmuld %f0, %f2, %f22 + faddd %f0, %f2, %f24 + fmuld %f0, %f2, %f26 + + faddd %f0, %f2, %f28 + fmuld %f0, %f2, %f30 + faddd %f0, %f2, %f32 + fmuld %f0, %f2, %f34 + faddd %f0, %f2, %f36 + fmuld %f0, %f2, %f38 + faddd %f0, %f2, %f40 + fmuld %f0, %f2, %f42 + + faddd %f0, %f2, %f44 + fmuld %f0, %f2, %f46 + ldx [%g6 + AOFF_task_flags], %g2 + faddd %f0, %f2, %f48 + fmuld %f0, %f2, %f50 + or %g2, %g4, %g2 + faddd %f0, %f2, %f52 + fmuld %f0, %f2, %f54 + + stx %g2, [%g6 + AOFF_task_flags] + faddd %f0, %f2, %f56 + sethi %hi(empty_zero_page), %g3 + fmuld %f0, %f2, %f58 + + faddd %f0, %f2, %f60 + ldx [%g3], %fsr ! wheee, empty_zero_page + b,pt %xcc, fpdis_exit + wr %g0, 0, %gsr + +fpload_fromkstk: + or %g2, %lo((((PAGE_SIZE<<1)-((64*4)+(2*8))) & ~(64 - 1))), %g2 + add %g6, %g2, %g2 + mov SECONDARY_CONTEXT, %g3 + stxa %g0, [%g3] ASI_DMMU + flush %g2 + wr %g0, ASI_BLK_S, %asi ! grrr, where is ASI_BLK_NUCLEUS 8-( + membar #StoreLoad | #LoadLoad + + ldda [%g2 + 0x000] %asi, %f0 + ldda [%g2 + 0x040] %asi, %f16 + ldda [%g2 + 0x080] %asi, %f32 + ldda [%g2 + 0x0c0] %asi, %f48 + ldx [%g2 + 0x100], %fsr + ldx [%g2 + 0x108], %g2 + membar #Sync + wr %g2, 0, %gsr +fpdis_exit: + rdpr %tstate, %g3 + sethi %hi(TSTATE_PEF), %g4 + or %g3, %g4, %g3 ! anal... + wrpr %g3, %tstate + retry + +#ifdef __SMP__ /* Note check out head.h, this code isn't even used for UP, * for SMP things will be different. In particular the data * registers for cross calls will be: * - * DATA 0: Address of function to call - * DATA 1: Argument 1, place in %g6 - * DATA 2: Argument 2, place in %g7 + * DATA 0: [low 32-bits] Address of function to call, jmp to this + * [high 32-bits] MMU Context Argument 0, place in %g5 + * DATA 1: Address Argument 1, place in %g6 + * DATA 2: Address Argument 2, place in %g7 * * With this method we can do most of the cross-call tlb/cache - * flushing in very quickly. + * flushing very quickly. */ - .align 4 + .align 32 .globl do_ivec do_ivec: ldxa [%g0] ASI_INTR_RECEIVE, %g1 @@ -139,16 +214,14 @@ do_ivec: mov 0x40, %g2 /* Load up Interrupt Vector Data 0 register. */ - sethi %uhi(ivector_to_mask), %g4 + sethi %hi(KERNBASE), %g4 ldxa [%g2] ASI_UDB_INTR_R, %g3 - or %g4, %ulo(ivector_to_mask), %g4 + cmp %g3, %g4 + bgeu,pn %xcc, do_ivec_xcall + nop and %g3, 0x7ff, %g3 - sllx %g4, 32, %g4 - sethi %hi(ivector_to_mask), %g5 sllx %g3, 3, %g3 - or %g5, %lo(ivector_to_mask), %g5 - add %g5, %g4, %g4 - ldx [%g4 + %g3], %g2 + ldx [%g1 + %g3], %g2 brz,pn %g2, do_ivec_spurious nop @@ -163,9 +236,17 @@ do_ivec_return: stxa %g0, [%g0] ASI_INTR_RECEIVE membar #Sync retry - +do_ivec_xcall: + srlx %g3, 32, %g5 + add %g2, 0x10, %g2 + sra %g3, 0, %g3 + ldxa [%g2] ASI_UDB_INTR_R, %g6 + add %g2, 0x10, %g2 + jmpl %g3, %g0 + ldxa [%g2] ASI_UDB_INTR_R, %g7 do_ivec_spurious: stxa %g0, [%g0] ASI_INTR_RECEIVE + membar #Sync rdpr %pstate, %g1 wrpr %g1, PSTATE_IG | PSTATE_AG, %pstate ba,pt %xcc, etrap @@ -174,8 +255,132 @@ do_ivec_spurious: add %sp, STACK_BIAS + REGWIN_SZ, %o0 ba,pt %xcc, rtrap clr %l6 +#endif /* __SMP__ */ + + .globl getcc, setcc +getcc: + ldx [%o0 + PT_V9_TSTATE], %o1 + srlx %o1, 32, %o1 + and %o1, 0xf, %o1 + retl + stx %o1, [%o0 + PT_V9_G1] +setcc: + ldx [%o0 + PT_V9_TSTATE], %o1 + ldx [%o0 + PT_V9_G1], %o2 + or %g0, %ulo(TSTATE_ICC), %o3 + sllx %o3, 32, %o3 + andn %o1, %o3, %o1 + sllx %o2, 32, %o2 + and %o2, %o3, %o2 + or %o1, %o2, %o1 + retl + stx %o1, [%o0 + PT_V9_TSTATE] + +#ifdef CONFIG_BLK_DEV_FD + .globl floppy_hardint +floppy_hardint: + sethi %hi(doing_pdma), %g1 + ld [%g1 + %lo(doing_pdma)], %g2 + brz,pn %g2, floppy_dosoftint + sethi %hi(fdc_status), %g3 + ldx [%g3 + %lo(fdc_status)], %g3 + sethi %hi(pdma_vaddr), %g5 + ldx [%g5 + %lo(pdma_vaddr)], %g4 + sethi %hi(pdma_size), %g5 + ldx [%g5 + %lo(pdma_size)], %g5 + +next_byte: + ldub [%g3], %g7 + andcc %g7, 0x80, %g0 + be,pn %icc, floppy_fifo_emptied + andcc %g7, 0x20, %g0 + be,pn %icc, floppy_overrun + andcc %g7, 0x40, %g0 + be,pn %icc, floppy_write + sub %g5, 1, %g5 + + ldub [%g3 + 1], %g7 + orcc %g0, %g5, %g0 + stb %g7, [%g4] + bne,pn %xcc, next_byte + add %g4, 1, %g4 + + b,pt %xcc, floppy_tdone + nop + +floppy_write: + ldub [%g4], %g7 + orcc %g0, %g5, %g0 + stb %g7, [%g3 + 1] + bne,pn %xcc, next_byte + add %g4, 1, %g4 + +floppy_tdone: + sethi %hi(pdma_vaddr), %g1 + stx %g4, [%g1 + %lo(pdma_vaddr)] + sethi %hi(pdma_size), %g1 + stx %g5, [%g1 + %lo(pdma_size)] + sethi %hi(auxio_register), %g1 + ldx [%g1 + %lo(auxio_register)], %g7 + ldub [%g7], %g5 + or %g5, 0xc2, %g5 + stb %g5, [%g7] + andn %g5, 0x02, %g5 + + nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; + + stb %g5, [%g7] + sethi %hi(doing_pdma), %g1 + b,pt %xcc, floppy_dosoftint + st %g0, [%g1 + %lo(doing_pdma)] + +floppy_fifo_emptied: + sethi %hi(pdma_vaddr), %g1 + stx %g4, [%g1 + %lo(pdma_vaddr)] + sethi %hi(pdma_size), %g1 + stx %g5, [%g1 + %lo(pdma_size)] + sethi %hi(irq_action), %g1 + or %g1, %lo(irq_action), %g1 + ldx [%g1 + (11 << 3)], %g3 ! irqaction[floppy_irq] + ldx [%g3 + 0x10], %g4 ! action->mask + st %g0, [%g4] ! SYSIO_ICLR_IDLE + membar #Sync ! probably not needed... + retry + +floppy_overrun: + sethi %hi(pdma_vaddr), %g1 + stx %g4, [%g1 + %lo(pdma_vaddr)] + sethi %hi(pdma_size), %g1 + stx %g5, [%g1 + %lo(pdma_size)] + sethi %hi(doing_pdma), %g1 + st %g0, [%g1 + %lo(doing_pdma)] + +floppy_dosoftint: + rdpr %pil, %g2 + wrpr %g0, 15, %pil + b,pt %xcc, etrap_irq + rd %pc, %g7 + + mov 11, %o0 + mov 0, %o1 + call sparc_floppy_irq + add %sp, STACK_BIAS + REGWIN_SZ, %o2 - .globl do_mna + b,pt %xcc, rtrap + clr %l6 + +#endif /* CONFIG_BLK_DEV_FD */ + + /* XXX Here is stuff we still need to write... -DaveM XXX */ + .globl indirect_syscall, netbsd_syscall, solaris_syscall +indirect_syscall: +netbsd_syscall: +solaris_syscall: + retl + nop + + .globl do_mna do_mna: rdpr %tl, %g3 cmp %g3, 1 @@ -195,187 +400,239 @@ breakpoint_trap: ba,pt %xcc, rtrap nop - .globl sys_pipe, sys_execve, sys_sigpause, sys_nis_syscall - .globl sys_sigsuspend, sys_sigreturn - .globl sys32_execve, sys_ptrace - -sys_pipe: - sethi %hi(sparc_pipe), %g1 - add %g1, %g4, %g1 - jmpl %g1 + %lo(sparc_pipe), %g0 - add %sp, STACK_BIAS + REGWIN_SZ, %o0 - -sys_nis_syscall: - sethi %hi(c_sys_nis_syscall), %g1 - add %g1, %g4, %g1 - jmpl %g1 + %lo(c_sys_nis_syscall), %g0 - add %sp, STACK_BIAS + REGWIN_SZ, %o0 - -sys_execve: - sethi %hi(sparc_execve), %g1 - add %g1, %g4, %g1 - jmpl %g1 + %lo(sparc_execve), %g0 - add %sp, STACK_BIAS + REGWIN_SZ, %o0 - -sys32_execve: - sethi %hi(sparc32_execve), %g1 - add %g1, %g4, %g1 - jmpl %g1 + %lo(sparc32_execve), %g0 - add %sp, STACK_BIAS + REGWIN_SZ, %o0 - -sys_sigpause: - /* NOTE: %o0 has a correct value already */ - call do_sigpause - add %sp, STACK_BIAS + REGWIN_SZ, %o1 - - ld [%curptr + AOFF_task_flags], %l5 - andcc %l5, 0x20, %g0 - be,pt %icc, rtrap - clr %l6 - call syscall_trace + /* SunOS uses syscall zero as the 'indirect syscall' it looks + * like indir_syscall(scall_num, arg0, arg1, arg2...); etc. + * This is complete brain damage. + */ + .globl sunos_indir +sunos_indir: + srl %o0, 0, %o0 + mov %o7, %l4 + cmp %o0, NR_SYSCALLS + blu,a,pt %icc, 1f + sll %o0, 0x3, %o0 + sethi %hi(sunos_nosys), %l6 + b,pt %xcc, 2f + or %l6, %lo(sunos_nosys), %l6 +1: sethi %hi(sunos_sys_table), %l7 + or %l7, %lo(sunos_sys_table), %l7 + ldx [%l7 + %o0], %l6 +2: mov %o1, %o0 + mov %o2, %o1 + mov %o3, %o2 + mov %o4, %o3 + mov %o5, %o4 + call %l6 + mov %l4, %o7 + + .globl sunos_getpid +sunos_getpid: + call sys_getppid nop - ba,pt %xcc, rtrap - clr %l6 - -sys_sigsuspend: - call do_sigsuspend - add %sp, STACK_BIAS + REGWIN_SZ, %o0 - - ld [%curptr + AOFF_task_flags], %l5 - andcc %l5, 0x20, %g0 - be,pt %icc, rtrap - clr %l6 - call syscall_trace + call sys_getpid + stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1] + b,pt %xcc, ret_sys_call + stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] + + /* SunOS getuid() returns uid in %o0 and euid in %o1 */ + .globl sunos_getuid +sunos_getuid: + call sys_geteuid nop - ba,pt %xcc, rtrap - clr %l6 - -sys_sigreturn: - call do_sigreturn - add %sp, STACK_BIAS + REGWIN_SZ, %o0 - - ld [%curptr + AOFF_task_flags], %l5 - andcc %l5, 0x20, %g0 - be,pt %icc, rtrap - clr %l6 - call syscall_trace + call sys_getuid + stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1] + b,pt %xcc, ret_sys_call + stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] + + /* SunOS getgid() returns gid in %o0 and egid in %o1 */ + .globl sunos_getgid +sunos_getgid: + call sys_getegid nop - ba,pt %xcc, rtrap - clr %l6 + call sys_getgid + stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1] + b,pt %xcc, ret_sys_call + stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] -sys_ptrace: - call do_ptrace - add %sp, STACK_BIAS + REGWIN_SZ, %o0 + /* SunOS's execv() call only specifies the argv argument, the + * environment settings are the same as the calling processes. + */ + .globl sunos_execv +sunos_execv: + sethi %hi(sparc32_execve), %g1 + stx %g0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2] + jmpl %g1 + %lo(sparc32_execve), %g0 + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + + .globl sys_pipe, sys_execve, sys_sigpause, sys_nis_syscall + .globl sys_sigsuspend, sys_sigreturn + .globl sys32_execve, sys_ptrace + .align 32 +sys_pipe: sethi %hi(sparc_pipe), %g1 + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + jmpl %g1 + %lo(sparc_pipe), %g0 + nop +sys_nis_syscall:sethi %hi(c_sys_nis_syscall), %g1 + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + jmpl %g1 + %lo(c_sys_nis_syscall), %g0 + nop + +sys_execve: sethi %hi(sparc_execve), %g1 + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + jmpl %g1 + %lo(sparc_execve), %g0 + nop +sys32_execve: sethi %hi(sparc32_execve), %g1 + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + jmpl %g1 + %lo(sparc32_execve), %g0 + nop + + /* NOTE: %o0 has a correct value already */ +sys_sigpause: call do_sigpause + add %sp, STACK_BIAS + REGWIN_SZ, %o1 + ldx [%curptr + AOFF_task_flags], %l5 + andcc %l5, 0x20, %g0 + be,pt %icc, rtrap + clr %l6 + call syscall_trace + nop + + ba,pt %xcc, rtrap + clr %l6 +linux_sparc_ni_syscall: + sethi %hi(sys_ni_syscall), %l7 + b,pt %xcc,syscall_is_too_hard + or %l7, %lo(sys_ni_syscall), %l7 + nop + + .align 32 +sys_sigsuspend: call do_sigsuspend + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + ldx [%curptr + AOFF_task_flags], %l5 + andcc %l5, 0x20, %g0 + be,pt %icc, rtrap + clr %l6 + call syscall_trace + nop + + ba,pt %xcc, rtrap + clr %l6 - ld [%curptr + AOFF_task_flags], %l5 - andcc %l5, 0x20, %g0 - be,pt %icc, rtrap - clr %l6 - call syscall_trace - nop - ba,pt %xcc, rtrap - clr %l6 + .align 32 +sys_sigreturn: call do_sigreturn + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + ldx [%curptr + AOFF_task_flags], %l5 + andcc %l5, 0x20, %g0 + be,pt %icc, rtrap + clr %l6 + call syscall_trace + nop + + ba,pt %xcc, rtrap + clr %l6 + + .align 32 +sys_ptrace: call do_ptrace + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + ldx [%curptr + AOFF_task_flags], %l5 + andcc %l5, 0x20, %g0 + be,pt %icc, rtrap + clr %l6 + call syscall_trace + nop + + ba,pt %xcc, rtrap + clr %l6 - /* This is how fork() was meant to be done, 12 instruction entry. -DaveM */ + /* This is how fork() was meant to be done, 12 instruction entry. + * + * I questioned the following code briefly, let me clear things + * up so you must not reason on it like I did. + * + * Know the fork_kpsr etc. we use in the sparc32 port? We don't + * need it here because the only piece of window state we copy to + * the child is the CWP register. Even if the parent sleeps, + * we are safe because we stuck it into pt_regs of the parent + * so it will not change. + * + * XXX This raises the question, whether we can do the same on + * XXX sparc32 to get rid of fork_kpsr _and_ fork_kwim. The + * XXX answer is yes. We stick fork_kpsr in UREG_G0 and + * XXX fork_kwim in UREG_G1 (global registers are considered + * XXX volatile across a system call in the sparc ABI I think + * XXX if it isn't we can use regs->y instead, anyone who depends + * XXX upon the Y register being preserved across a fork deserves + * XXX to lose). + * + * In fact we should take advantage of that fact for other things + * during system calls... + */ .globl sys_fork, sys_vfork, sys_clone + .globl ret_from_syscall, ret_from_smpfork + .align 32 sys_fork: -sys_vfork: - mov SIGCHLD, %o0 - clr %o1 -sys_clone: - mov %o7, %l5 - save %sp, -REGWIN_SZ, %sp - flushw - restore %g0, %g0, %g0 - rdpr %cwp, %o4 - add %sp, STACK_BIAS + REGWIN_SZ, %o2 - movrz %o1, %fp, %o1 - - /* Don't try this at home. */ - stx %o4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G0] - call do_fork - mov %l5, %o7 - -linux_sparc_ni_syscall: - sethi %hi(sys_ni_syscall), %l7 - or %l7, %lo(sys_ni_syscall), %l7 - ba,pt %xcc,syscall_is_too_hard - add %l7, %g4, %l7 - -linux_fast_syscall: - andn %l7, 3, %l7 - mov %i0, %o0 - mov %i1, %o1 - mov %i2, %o2 - jmpl %l7 + %g0, %g0 - mov %i3, %o3 +sys_vfork: mov SIGCHLD, %o0 + clr %o1 +sys_clone: mov %o7, %l5 +/*???*/ save %sp, -REGWIN_SZ, %sp + flushw +/*???*/ restore %g0, %g0, %g0 + rdpr %cwp, %o4 + add %sp, STACK_BIAS + REGWIN_SZ, %o2 + + movrz %o1, %fp, %o1 + stx %o4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G0] + call do_fork + mov %l5, %o7 +#ifdef __SMP__ +ret_from_smpfork: + sethi %hi(scheduler_lock), %o4 + membar #StoreStore | #LoadStore + stb %g0, [%o4 + %lo(scheduler_lock)] +#endif +ret_from_syscall: + b,pt %xcc, ret_sys_call + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0 linux_syscall_trace: - call syscall_trace - nop - mov %i0, %o0 - mov %i1, %o1 - mov %i2, %o2 - mov %i3, %o3 - ba,pt %xcc, 2f - mov %i4, %o4 - - .globl ret_from_syscall -ret_from_syscall: - ba,pt %xcc, ret_sys_call - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0 + call syscall_trace + nop + mov %i0, %o0 + mov %i1, %o1 + mov %i2, %o2 + mov %i3, %o3 + b,pt %xcc, 2f + mov %i4, %o4 /* Linux native and SunOS system calls enter here... */ - .align 4 - .globl linux_sparc_syscall + .align 32 + .globl linux_sparc_syscall, syscall_is_too_hard, ret_sys_call linux_sparc_syscall: /* Direct access to user regs, must faster. */ - cmp %g1, NR_SYSCALLS - add %l7, %g4, %l7 - bgeu,pn %xcc, linux_sparc_ni_syscall - sll %g1, 3, %l4 - ldx [%l7 + %l4], %l7 - andcc %l7, 1, %g0 - bne,pn %icc, linux_fast_syscall - /* Just do the next insn in the delay slot */ - - .globl syscall_is_too_hard + cmp %g1, NR_SYSCALLS ! IEU1 Group + bgeu,pn %xcc, linux_sparc_ni_syscall ! CTI + mov %i0, %o0 ! IEU0 + sll %g1, 3, %l4 ! IEU0 Group + mov %i1, %o1 ! IEU1 + ldx [%l7 + %l4], %l7 ! Load syscall_is_too_hard: -#ifdef SYSCALL_TRACING /* Debugging... */ - mov %g1, %o0 ! o0=scall, o1=ptregs - call syscall_trace_entry - add %sp, STACK_BIAS + REGWIN_SZ, %o1 -#endif - mov %i0, %o0 - mov %i1, %o1 - mov %i2, %o2 - - ldx [%curptr + AOFF_task_flags], %l5 - mov %i3, %o3 - mov %i4, %o4 - andcc %l5, 0x20, %g0 - bne,pn %icc, linux_syscall_trace - mov %i0, %l5 -2: - call %l7 - mov %i5, %o5 - -#ifdef SYSCALL_TRACING /* Debugging... */ - call syscall_trace_exit ! o0=sysret, o1=ptregs - add %sp, STACK_BIAS + REGWIN_SZ, %o1 -#endif + mov %i2, %o2 ! IEU0 Group + ldx [%curptr + AOFF_task_flags], %l5 ! Load + + st %g0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_FPRS] + mov %i3, %o3 ! IEU1 + mov %i4, %o4 ! IEU0 Group + andcc %l5, 0x20, %g0 ! IEU1 2 bubbles + bne,pn %icc, linux_syscall_trace ! CTI Group + mov %i0, %l5 ! IEU0 +2: call %l7 ! CTI Group brk forced + mov %i5, %o5 ! IEU0 stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] - .globl ret_sys_call ret_sys_call: ldx [%curptr + AOFF_task_flags], %l6 - ldx [%curptr + AOFF_task_tss + AOFF_thread_flags], %l2 + sra %o0, 0, %o0 mov %ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2 - and %l2, SPARC_FLAG_32BIT, %l2 ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %g3 - brnz,a,pn %l2, 1f - sra %o0, 0, %o0 -1: cmp %o0, -ENOIOCTLCMD sllx %g2, 32, %g2 bgeu,pn %xcc, 1f @@ -383,13 +640,12 @@ ret_sys_call: /* System call success, clear Carry condition code. */ andn %g3, %g2, %g3 - clr %l6 stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE] bne,pn %icc, linux_syscall_trace2 ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 ! pc = npc add %l1, 0x4, %l2 !npc = npc+4 stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC] - ba,pt %xcc, rtrap + b,pt %xcc, rtrap_clr_l6 stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC] 1: /* System call failure, set Carry condition code. @@ -403,10 +659,10 @@ ret_sys_call: bne,pn %icc, linux_syscall_trace2 ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 ! pc = npc add %l1, 0x4, %l2 !npc = npc+4 + stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC] - ba,pt %xcc, rtrap + b,pt %xcc, rtrap stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC] - linux_syscall_trace2: call syscall_trace add %l1, 0x4, %l2 /* npc = npc+4 */ @@ -414,4 +670,15 @@ linux_syscall_trace2: ba,pt %xcc, rtrap stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC] -/* End of entry.S */ + .align 32 + .globl __flushw_user +__flushw_user: +1: save %sp, -128, %sp + rdpr %otherwin, %g1 + brnz,pt %g1, 1b + add %g2, 1, %g2 +1: sub %g2, 1, %g2 + brnz,pt %g2, 1b + restore %g0, %g0, %g0 +2: retl + mov %g3, %o7 diff --git a/arch/sparc64/kernel/etrap.S b/arch/sparc64/kernel/etrap.S index efb1b48fc..4daf30e21 100644 --- a/arch/sparc64/kernel/etrap.S +++ b/arch/sparc64/kernel/etrap.S @@ -1,4 +1,4 @@ -/* $Id: etrap.S,v 1.21 1997/06/02 06:33:28 davem Exp $ +/* $Id: etrap.S,v 1.30 1997/06/30 10:31:37 jj Exp $ * etrap.S: Preparing for entry into the kernel on Sparc V9. * * Copyright (C) 1996, 1997 David S. Miller (davem@caip.rutgers.edu) @@ -12,88 +12,121 @@ #include <asm/spitfire.h> #include <asm/head.h> - /* We assume that pstate, when entering this, has AG and - * IE bits set, MG and IG clear. - * - * We also guarentee for caller that AG %g4 and %g5 will have - * their values preserved and left in %l4 and %l5 respectively - * for him (fault handling needs this). - */ +#define FPUREG_SZ ((64 * 4) + (2 * 8)) +#define TASK_REGOFF ((((PAGE_SIZE<<1)-FPUREG_SZ)&~(64-1)) - \ + TRACEREG_SZ-REGWIN_SZ) - .text - .align 32 - .globl etrap, etrap_irq, etraptl1 -etrap: - rdpr %pil, %g2 -etrap_irq: - rdpr %tstate, %g1 - sllx %g2, 20, %g2 - or %g1, %g2, %g1 - andcc %g1, TSTATE_PRIV, %g0 - bne,a,pn %xcc, 1f - sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2 - rd %pic, %g3 + .text + .align 32 + .globl etrap, etrap_irq, etraptl1 - sethi %hi((PAGE_SIZE<<1)-TRACEREG_SZ-REGWIN_SZ), %g2 - or %g2, %lo((PAGE_SIZE<<1)-TRACEREG_SZ-REGWIN_SZ), %g2 - add %g3, %g2, %g2 -1: stx %g1, [%g2 + REGWIN_SZ + PT_V9_TSTATE] - rdpr %tpc, %g1 - rdpr %tnpc, %g3 - stx %g1, [%g2 + REGWIN_SZ + PT_V9_TPC] - rd %y, %g1 +etrap: rdpr %pil, %g2 +etrap_irq: rdpr %tstate, %g1 + sllx %g2, 20, %g2 + or %g1, %g2, %g1 + andcc %g1, TSTATE_PRIV, %g0 + bne,pn %xcc, etrap_maybe_fpu + sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2 + sethi %hi(TASK_REGOFF), %g2 - stx %g3, [%g2 + REGWIN_SZ + PT_V9_TNPC] - stx %g1, [%g2 + REGWIN_SZ + PT_V9_Y] - save %g2, -STACK_BIAS, %sp ! The ordering of these two instructions - rdpr %pstate, %g1 ! is critical, see winfixup.S for details - bne,pn %xcc, 2f - rdpr %canrestore, %g3 - rdpr %wstate, %g6 - wrpr %g0, 7, %cleanwin + or %g2, %lo(TASK_REGOFF), %g2 + add %g6, %g2, %g2 +etrap_maybe_fpu:rd %fprs, %g3 + brnz,pn %g3, etrap_save_fpu + st %g0, [%g2 + REGWIN_SZ + PT_V9_FPRS] +etrap_after_fpu:rdpr %tpc, %g3 + stx %g1, [%g2 + REGWIN_SZ + PT_V9_TSTATE] + rdpr %tnpc, %g1 - wrpr %g0, 0, %canrestore - sll %g6, 3, %g6 - wrpr %g3, 0, %otherwin - wrpr %g6, %wstate - sethi %uhi(KERNBASE), %g3 - sllx %g3, 32, %g3 - mov PRIMARY_CONTEXT, %g2 - stxa %g0, [%g2] ASI_DMMU + stx %g3, [%g2 + REGWIN_SZ + PT_V9_TPC] + rd %y, %g3 + stx %g1, [%g2 + REGWIN_SZ + PT_V9_TNPC] + st %g3, [%g2 + REGWIN_SZ + PT_V9_Y] + save %g2, -STACK_BIAS, %sp ! The ordering here is + rdpr %pstate, %g1 ! critical, see winfixup + bne,pn %xcc, 2f + rdpr %canrestore, %g3 - flush %g3 -2: wrpr %g0, 0x0, %tl - mov %g1, %l1 - mov %g4, %l4 - mov %g5, %l5 - mov %g7, %l2 - wrpr %l1, PSTATE_AG, %pstate - stx %g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1] + rdpr %wstate, %g2 + wrpr %g0, 7, %cleanwin + wrpr %g0, 0, %canrestore + sll %g2, 3, %g2 + wrpr %g3, 0, %otherwin + wrpr %g2, 0, %wstate + wr %g0, ASI_DMMU, %asi + ldxa [%g0 + PRIMARY_CONTEXT] %asi, %g2 - stx %g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2] - stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3] - stx %g4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4] - stx %g5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5] - stx %g6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6] - stx %g7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7] - stx %i0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] - stx %i1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1] + stxa %g0, [%g0 + PRIMARY_CONTEXT] %asi + stxa %g2, [%g0 + SECONDARY_CONTEXT] %asi + flush %g6 +2: wrpr %g0, 0x0, %tl + or %g1, 0, %l1 + add %g4, 0, %l4 + or %g5, 0, %l5 + add %g7, 0, %l2 - stx %i2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2] - stx %i3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3] - stx %i4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4] - stx %i5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5] - stx %i6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6] - stx %i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7] - wrpr %l1, (PSTATE_IE | PSTATE_AG), %pstate - sethi %uhi(KERNBASE), %g4 + or %g6, 0, %l6 + wrpr %l1, (PSTATE_AG|PSTATE_RMO), %pstate + stx %g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1] + stx %g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2] + stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3] + stx %g4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4] + stx %g5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5] + stx %g6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6] - rd %pic, %g6 - jmpl %l2 + 0x4, %g0 - sllx %g4, 32, %g4 -etraptl1: - rdpr %tstate, %g1 - sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2 - ba,pt %xcc, 1b - andcc %g1, TSTATE_PRIV, %g0 - nop + stx %g7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7] + stx %i0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] + stx %i1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1] + stx %i2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2] + stx %i3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3] + stx %i4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4] + sethi %uhi(PAGE_OFFSET), %g4 + stx %i5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5] + + stx %i6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6] + sllx %g4, 32, %g4 + stx %i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7] + wrpr %l1, (PSTATE_IE|PSTATE_AG|PSTATE_RMO), %pstate + jmpl %l2 + 0x4, %g0 + mov %l6, %g6 +etrap_save_fpu: and %g3, FPRS_FEF, %g3 + brz,pn %g3, 2f + + nop + be,a,pt %xcc, 3f + add %g2, (TRACEREG_SZ + REGWIN_SZ), %g2 + wr %g0, ASI_BLK_P, %asi + add %g2, ((TRACEREG_SZ+REGWIN_SZ)-FPUREG_SZ), %g2 + andn %g2, (64 - 1), %g2 +1: st %g3, [%g2 - 0x4 /*REGWIN_SZ + PT_V9_FPRS*/] + rd %gsr, %g3 + + stx %fsr, [%g2 + 0x100] + stx %g3, [%g2 + 0x108] + membar #StoreStore | #LoadStore + stda %f0, [%g2 + 0x000] %asi + stda %f16, [%g2 + 0x040] %asi + stda %f32, [%g2 + 0x080] %asi + stda %f48, [%g2 + 0x0c0] %asi + membar #Sync + + sub %g2, (TRACEREG_SZ + REGWIN_SZ), %g2 +2: b,pt %xcc, etrap_after_fpu + wr %g0, 0, %fprs +3: /* Because Ultra lacks ASI_BLK_NUCLEUS a hack has to take place. */ + mov SECONDARY_CONTEXT, %g3 + stxa %g0, [%g3] ASI_DMMU + flush %g2 + wr %g0, ASI_BLK_S, %asi + nop + + b,pt %xcc, 1b + mov FPRS_FEF, %g3 + nop +etraptl1: rdpr %tstate, %g1 + sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2 + ba,pt %xcc, etrap_maybe_fpu + andcc %g1, TSTATE_PRIV, %g0 + nop +#undef TASK_REGOFF +#undef FPUREG_SZ diff --git a/arch/sparc64/kernel/hack.S b/arch/sparc64/kernel/hack.S deleted file mode 100644 index 843221395..000000000 --- a/arch/sparc64/kernel/hack.S +++ /dev/null @@ -1,170 +0,0 @@ -/* <hack> - This is just a huge ugly hack to get things compiled. - Hopefully will disappear quickly, once we get everything - to compile... */ - .text - .align 8 - .globl breakpoint -breakpoint: retl;nop - .globl do_cee -do_cee: retl;nop - .globl do_cee_tl1 -do_cee_tl1: retl;nop - .globl do_dae_tl1 -do_dae_tl1: retl;nop - .globl do_div0_tl1 -do_div0_tl1: retl;nop - .globl do_fpdis_tl1 -do_fpdis_tl1: retl;nop - .globl do_fpieee_tl1 -do_fpieee_tl1: retl;nop - .globl do_fpother_tl1 -do_fpother_tl1: retl;nop - .globl do_iae_tl1 -do_iae_tl1: retl;nop - .globl do_ill_tl1 -do_ill_tl1: retl;nop - .globl do_irq_tl1 -do_irq_tl1: retl;nop - .globl do_lddfmna -do_lddfmna: retl;nop - .globl do_lddfmna_tl1 -do_lddfmna_tl1: retl;nop - .globl do_paw -do_paw: retl;nop - .globl do_paw_tl1 -do_paw_tl1: retl;nop - .globl do_stdfmna -do_stdfmna: retl;nop - .globl do_stdfmna_tl1 -do_stdfmna_tl1: retl;nop - .globl do_tof_tl1 -do_tof_tl1: retl;nop - .globl do_vaw -do_vaw: retl;nop - .globl do_vaw_tl1 -do_vaw_tl1: retl;nop - .globl floppy_hardint -floppy_hardint: retl;nop - .globl get_cpuid -get_cpuid: retl;mov 0, %o0 - .globl getcc -getcc: retl;nop - .globl halt -halt: retl;nop - .globl indirect_syscall -indirect_syscall: retl;nop - .globl install_linux_ticker -install_linux_ticker: retl;nop - .globl install_obp_ticker -install_obp_ticker: retl;nop - .globl linux_dbvec -linux_dbvec: retl;nop - .globl linux_num_cpus -linux_num_cpus: retl;nop - .globl netbsd_syscall -netbsd_syscall: retl;nop - .globl setcc -setcc: retl;nop - .globl solaris_syscall -solaris_syscall: retl;nop - .globl sunos_mmap -sunos_mmap: retl;nop - .globl sunos_syscall -sunos_syscall: retl;nop - .globl svr4_getcontext -svr4_getcontext: retl;nop - .globl svr4_setcontext -svr4_setcontext: retl;nop - .globl sunos_accept -sunos_accept: retl;nop - .globl sunos_audit -sunos_audit: retl;nop - .globl sunos_brk -sunos_brk: retl;nop - .globl sunos_execv -sunos_execv: retl;nop - .globl sunos_fpathconf -sunos_fpathconf: retl;nop - .globl sunos_getdents -sunos_getdents: retl;nop - .globl sunos_getdirentries -sunos_getdirentries: retl;nop - .globl sunos_getdomainname -sunos_getdomainname: retl;nop - .globl sunos_getdtablesize -sunos_getdtablesize: retl;nop - .globl sunos_getgid -sunos_getgid: retl;nop - .globl sunos_gethostid -sunos_gethostid: retl;nop - .globl sunos_getpid -sunos_getpid: retl;nop - .globl sunos_getsockopt -sunos_getsockopt: retl;nop - .globl sunos_getuid -sunos_getuid: retl;nop - .globl sunos_indir -sunos_indir: retl;nop - .globl sunos_ioctl -sunos_ioctl: retl;nop - .globl sunos_killpg -sunos_killpg: retl;nop - .globl sunos_madvise -sunos_madvise: retl;nop - .globl sunos_mctl -sunos_mctl: retl;nop - .globl sunos_mincore -sunos_mincore: retl;nop - .globl sunos_mount -sunos_mount: retl;nop - .globl sunos_nop -sunos_nop: retl;nop - .globl sunos_nosys -sunos_nosys: retl;nop - .globl sunos_open -sunos_open: retl;nop - .globl sunos_pathconf -sunos_pathconf: retl;nop - .globl sunos_poll -sunos_poll: retl;nop - .globl sunos_read -sunos_read: retl;nop - .globl sunos_readv -sunos_readv: retl;nop - .globl sunos_recv -sunos_recv: retl;nop - .globl sunos_sbrk -sunos_sbrk: retl;nop - .globl sunos_select -sunos_select: retl;nop - .globl sunos_semsys -sunos_semsys: retl;nop - .globl sunos_send -sunos_send: retl;nop - .globl sunos_setpgrp -sunos_setpgrp: retl;nop - .globl sunos_setsockopt -sunos_setsockopt: retl;nop - .globl sunos_shmsys -sunos_shmsys: retl;nop - .globl sunos_sigaction -sunos_sigaction: retl;nop - .globl sunos_sigblock -sunos_sigblock: retl;nop - .globl sunos_sigsetmask -sunos_sigsetmask: retl;nop - .globl sunos_sstk -sunos_sstk: retl;nop - .globl sunos_sysconf -sunos_sysconf: retl;nop - .globl sunos_uname -sunos_uname: retl;nop - .globl sunos_vadvise -sunos_vadvise: retl;nop - .globl sunos_wait4 -sunos_wait4: retl;nop - .globl sunos_write -sunos_write: retl;nop - .globl sunos_writev -sunos_writev: retl;nop diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S index 3844c24c3..0ed975aff 100644 --- a/arch/sparc64/kernel/head.S +++ b/arch/sparc64/kernel/head.S @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.31 1997/05/30 22:35:28 davem Exp $ +/* $Id: head.S,v 1.43 1997/07/07 03:05:25 davem Exp $ * head.S: Initial boot code for the Sparc64 port of Linux. * * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu) @@ -8,20 +8,25 @@ */ #include <linux/version.h> +#include <linux/errno.h> +#include <asm/asm_offsets.h> +#include <asm/asi.h> #include <asm/pstate.h> #include <asm/ptrace.h> #include <asm/spitfire.h> #include <asm/page.h> #include <asm/pgtable.h> #include <asm/errno.h> +#include <asm/signal.h> +#include <asm/processor.h> #include <asm/lsu.h> #include <asm/head.h> /* This section from from _start to sparc64_boot_end should fit into - * 0xffff.f800.0000.4000 to 0xffff.f800.0000.8000 and will be sharing space - * with bootup_user_stack, which is from 0xffff.f800.0000.4000 to - * 0xffff.f800.0000.6000 and bootup_kernel_stack, which is from - * 0xffff.f800.0000.6000 to 0xffff.f800.0000.8000. + * 0x0000.0000.0040.4000 to 0x0000.0000.0040.8000 and will be sharing space + * with bootup_user_stack, which is from 0x0000.0000.0040.4000 to + * 0x0000.0000.0040.6000 and bootup_kernel_stack, which is from + * 0x0000.0000.0040.6000 to 0x0000.0000.0040.8000. */ .text @@ -31,7 +36,7 @@ start: _stext: stext: bootup_user_stack: -! 0xfffff80000004000 +! 0x0000000000404000 b sparc64_boot flushw /* Flush register file. */ @@ -41,10 +46,11 @@ bootup_user_stack: */ .global root_flags, ram_flags, root_dev .global ramdisk_image, ramdisk_size + .globl silo_args .ascii "HdrS" .word LINUX_VERSION_CODE - .half 0x0201 /* HdrS version */ + .half 0x0202 /* HdrS version */ root_flags: .half 1 root_dev: @@ -55,7 +61,8 @@ ramdisk_image: .word 0 ramdisk_size: .word 0 - .xword reboot_command + .xword reboot_command + .xword bootstr_len /* We must be careful, 32-bit OpenBOOT will get confused if it * tries to save away a register window to a 64-bit kernel @@ -80,26 +87,7 @@ sparc64_boot: * Again, typically PROM has left %pil at 13 or similar, and * (PSTATE_PRIV | PSTATE_PEF | PSTATE_IE) in %pstate. */ - wrpr %g0, 0xf, %pil /* Interrupts off. */ - wrpr %g0, (PSTATE_PRIV|PSTATE_PEF), %pstate - - /* Check if we are mapped where we expect to be in virtual - * memory. The Solaris /boot elf format bootloader - * will peek into our elf header and load us where - * we want to be, otherwise we have to re-map. - */ -current_pc: - rd %pc, %g3 - sethi %uhi(KERNBASE), %g4 - sllx %g4, 32, %g4 - - /* Check the run time program counter. */ - - set current_pc, %g5 - add %g5, %g4, %g5 - cmp %g3, %g5 - be %xcc, sun4u_init - nop + wrpr %g0, (PSTATE_PRIV|PSTATE_PEF|PSTATE_IE), %pstate create_mappings: /* %g5 holds the tlb data */ @@ -136,15 +124,10 @@ create_mappings: cmp %g1, %g2 be,a,pn %xcc, got_tlbentry ldxa [%l0] ASI_ITLB_DATA_ACCESS, %g1 - cmp %l1, (63 << 3) + cmp %l0, (63 << 3) blu,pt %xcc, 1b add %l0, (1 << 3), %l0 -boot_failed: - /* Debugging 8-) */ - set 0xdeadbeef, %g1 - t 0x11 - got_tlbentry: /* Nops here again, perhaps Cheetah/Blackbird are better behaved... */ nop @@ -159,33 +142,73 @@ got_tlbentry: or %g5, %g1, %g5 /* Or it into TAG being built. */ + clr %l0 /* TLB entry walker. */ + sethi %hi(KERNBASE), %g3 /* 4M lower limit */ + sethi %hi(KERNBASE<<1), %g7 /* 8M upper limit */ + mov TLB_TAG_ACCESS, %l7 +1: + /* Yes, the nops seem to be necessary for now, don't ask me why. -DaveM */ + ldxa [%l0] ASI_ITLB_TAG_READ, %g1 + nop + nop + nop + andn %g1, %l2, %g1 /* Get vaddr */ + cmp %g1, %g3 + blu,pn %xcc, 2f + cmp %g1, %g7 + bgeu,pn %xcc, 2f + nop + stxa %g0, [%l7] ASI_IMMU + stxa %g0, [%l0] ASI_ITLB_DATA_ACCESS +2: + cmp %l0, (63 << 3) + blu,pt %xcc, 1b + add %l0, (1 << 3), %l0 + + nop; nop; nop + + clr %l0 /* TLB entry walker. */ +1: + /* Yes, the nops seem to be necessary for now, don't ask me why. -DaveM */ + ldxa [%l0] ASI_DTLB_TAG_READ, %g1 + nop + nop + nop + andn %g1, %l2, %g1 /* Get vaddr */ + cmp %g1, %g3 + blu,pn %xcc, 2f + cmp %g1, %g7 + bgeu,pn %xcc, 2f + nop + stxa %g0, [%l7] ASI_DMMU + stxa %g0, [%l0] ASI_DTLB_DATA_ACCESS +2: + cmp %l0, (63 << 3) + blu,pt %xcc, 1b + add %l0, (1 << 3), %l0 + + nop; nop; nop + + /* PROM never puts any TLB entries into the MMU with the lock bit - * set. So we gladly use tlb entry 63 for KERNBASE, 62 for - * boot time locked PROM CIF handler page, we remove the locked - * bit for the CIF page in paging_init(). + * set. So we gladly use tlb entry 63 for KERNBASE. */ - mov TLB_TAG_ACCESS, %g3 - mov (63 << 3), %g7 - stxa %g4, [%g3] ASI_IMMU /* KERNBASE into TLB TAG */ - stxa %g5, [%g7] ASI_ITLB_DATA_ACCESS /* TTE into TLB DATA */ - membar #Sync - /* Same for DTLB */ - stxa %g4, [%g3] ASI_DMMU /* KERNBASE into TLB TAG */ + sethi %hi(KERNBASE), %g3 + mov (63 << 3), %g7 + stxa %g3, [%l7] ASI_DMMU /* KERNBASE into TLB TAG */ stxa %g5, [%g7] ASI_DTLB_DATA_ACCESS /* TTE into TLB DATA */ membar #Sync - - /* Kill instruction prefetch queues. */ - flush %g4 + stxa %g3, [%l7] ASI_IMMU /* KERNBASE into TLB TAG */ + stxa %g5, [%g7] ASI_ITLB_DATA_ACCESS /* TTE into TLB DATA */ membar #Sync - - ba,pt %xcc, go_to_highmem + flush %g3 + membar #Sync + ba,pt %xcc, 1f nop - -go_to_highmem: - /* Now do a non-relative jump so that PC is in high-memory */ +1: set sun4u_init, %g2 - jmpl %g2 + %g4, %g0 + jmpl %g2 + %g0, %g0 nop sun4u_init: @@ -198,42 +221,16 @@ sun4u_init: stxa %g0, [%g7] ASI_DMMU membar #Sync - /* The lock bit has to be removed from this page later on, - * but before firing up init we will use PROM a lot, so we - * lock it there now... - */ - - /* Compute PROM CIF interface page TTE. */ - sethi %hi(__p1275_loc), %g7 - or %g7, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W | _PAGE_L), %g7 - sethi %uhi(_PAGE_VALID), %g5 - sethi %hi(0x8000), %g3 - sllx %g5, 32, %g5 - mov TLB_TAG_ACCESS, %g6 - or %g5, %g7, %g5 - add %g5, %g1, %g5 /* Add in physbase. */ - - mov (62 << 3), %g7 /* TLB entry 62 */ - stxa %g3, [%g6] ASI_IMMU /* CIF page into TLB TAG */ - stxa %g5, [%g7] ASI_ITLB_DATA_ACCESS /* TTE into TLB DATA */ - membar #Sync - - /* Same for DTLB */ - stxa %g3, [%g6] ASI_DMMU /* CIF page into TLB TAG */ - stxa %g5, [%g7] ASI_DTLB_DATA_ACCESS /* TTE into TLB DATA */ - membar #Sync - - /* Kill instruction prefetch queues. */ - flush %g3 - membar #Sync + sethi %uhi(PAGE_OFFSET), %g4 + sllx %g4, 32, %g4 /* We are now safely (we hope) in Nucleus context (0), rewrite * the KERNBASE TTE's so they no longer have the global bit set. * Don't forget to setup TAG_ACCESS first 8-) */ mov TLB_TAG_ACCESS, %g2 - stxa %g4, [%g2] ASI_IMMU - stxa %g4, [%g2] ASI_DMMU + stxa %g3, [%g2] ASI_IMMU + stxa %g3, [%g2] ASI_DMMU mov (63 << 3), %g7 ldxa [%g7] ASI_ITLB_DATA_ACCESS, %g1 @@ -247,30 +244,22 @@ sun4u_init: membar #Sync /* Kill instruction prefetch queues. */ - flush %g4 + flush %g3 membar #Sync - /* Compute the number of windows in this machine - * store this in nwindows and nwindowsm1 - */ - rdpr %ver, %g1 /* Get VERSION register. */ - sethi %hi(nwindows), %g2 - and %g1, VERS_MAXWIN, %g5 - or %g2,%lo(nwindows),%g2 - add %g5, 1, %g6 - add %g2, (nwindows - nwindowsm1), %g3 - stx %g6, [%g2 + %g4] - stx %g5, [%g3 + %g4] - sethi %hi(init_task_union), %g6 or %g6, %lo(init_task_union), %g6 - add %g6, %g4, %g6 ! g6 usage is fixed as well mov %sp, %l6 mov %o4, %l7 +#if 0 /* We don't do it like this anymore, but for historical hack value + * I leave this snippet here to show how crazy we can be sometimes. 8-) + */ + /* Setup "Linux Current Register", thanks Sun 8-) */ wr %g0, 0x1, %pcr wr %g6, 0x0, %pic +#endif mov 1, %g5 sllx %g5, (PAGE_SHIFT + 1), %g5 @@ -291,23 +280,19 @@ sun4u_init: add %l1, %l2, %l1 andn %l1, %l2, %l1 add %l2, 1, %l2 - add %l0, %g4, %o0 + add %l0, %g0, %o0 1: - clr %o1 - sethi %hi(PAGE_SIZE), %o2 - or %o2, %lo(PAGE_SIZE), %o2 - call __memset + mov %l2, %o1 + call __bzero add %l0, %l2, %l0 cmp %l0, %l1 blu,pt %xcc, 1b - add %l0, %g4, %o0 + add %l0, %g0, %o0 /* Now clear empty_zero_page */ - clr %o1 - sethi %hi(PAGE_SIZE), %o2 - or %o2, %lo(PAGE_SIZE), %o2 - call __memset - mov %g4, %o0 + mov %l2, %o1 + call __bzero + mov %g3, %o0 mov %l6, %o1 ! OpenPROM stack call prom_init @@ -320,36 +305,45 @@ sun4u_init: .globl setup_tba setup_tba: + save %sp, -160, %sp + + rdpr %tba, %g7 + sethi %hi(prom_tba), %o1 + or %o1, %lo(prom_tba), %o1 + stx %g7, [%o1] + + /* Setup "Linux" globals 8-) */ + rdpr %pstate, %o1 + mov %g6, %o2 + wrpr %o1, (PSTATE_AG|PSTATE_IE), %pstate sethi %hi(sparc64_ttable_tl0), %g5 - add %g5, %g4, %g5 wrpr %g5, %tba + mov %o2, %g6 /* Set up MMU globals */ - rdpr %pstate, %o1 - wrpr %o1, PSTATE_MG, %pstate + wrpr %o1, (PSTATE_MG|PSTATE_IE), %pstate /* PGD/PMD offset mask, used by TLB miss handlers. */ sethi %hi(0x1ff8), %g2 or %g2, %lo(0x1ff8), %g2 /* Kernel PGDIR used by TLB miss handlers. */ - mov %o0, %g6 + mov %i0, %g6 /* To catch bootup bugs, this is user PGDIR for TLB miss handlers. */ clr %g7 /* Setup Interrupt globals */ - wrpr %o1, PSTATE_IG, %pstate - sethi %uhi(ivector_to_mask), %g4 - or %g4, %ulo(ivector_to_mask), %g4 + wrpr %o1, (PSTATE_IG|PSTATE_IE), %pstate sethi %hi(ivector_to_mask), %g5 - or %g5, %lo(ivector_to_mask), %g5 - or %g5, %g4, %g1 /* IVECTOR table */ + or %g5, %lo(ivector_to_mask), %g1 /* IVECTOR table */ mov 0x40, %g2 /* INTR data 0 register */ - andn %o1, PSTATE_IE, %o1 + /* Ok, we're done setting up all the state our trap mechanims needs, + * now get back into normal globals and let the PROM know what it up. + */ wrpr %g0, %g0, %wstate - wrpr %o1, %g0, %pstate + wrpr %o1, PSTATE_IE, %pstate /* Zap TSB BASE to zero with TSB_size==1. */ mov TSB_REG, %o4 @@ -359,8 +353,16 @@ setup_tba: membar #Sync - retl - nop + sethi %hi(sparc64_ttable_tl0), %g5 + call prom_set_trap_table + mov %g5, %o0 + + rdpr %pstate, %o1 + or %o1, PSTATE_IE, %o1 + wrpr %o1, 0, %pstate + + ret + restore sparc64_boot_end: .skip 0x2000 + _start - sparc64_boot_end @@ -369,18 +371,21 @@ bootup_user_stack_end: bootup_kernel_stack: .skip 0x2000 -! 0xfffff80000008000 +! 0x0000000000408000 #include "ttable.S" +#include "etrap.S" +#include "rtrap.S" +#include "winfixup.S" +#include "entry.S" /* This is just anal retentiveness on my part... */ .align 16384 .data .align 8 - .globl nwindows, nwindowsm1 -nwindows: .xword 0 -nwindowsm1: .xword 0 + .globl prom_tba +prom_tba: .xword 0 .section ".fixup",#alloc,#execinstr .globl __ret_efault __ret_efault: diff --git a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c index d3792dec6..b7a0f312d 100644 --- a/arch/sparc64/kernel/ioctl32.c +++ b/arch/sparc64/kernel/ioctl32.c @@ -1,4 +1,4 @@ -/* $Id: ioctl32.c,v 1.8 1997/06/04 13:05:15 jj Exp $ +/* $Id: ioctl32.c,v 1.13 1997/07/17 02:20:38 davem Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -20,9 +20,16 @@ #include <linux/kd.h> #include <linux/route.h> #include <linux/netlink.h> +#include <linux/vt.h> +#include <linux/fs.h> +#include <linux/fd.h> #include <asm/types.h> #include <asm/uaccess.h> +#include <asm/fbio.h> +#include <asm/kbio.h> +#include <asm/vuid_event.h> +#include <asm/rtc.h> /* As gcc will warn about casting u32 to some ptr, we have to cast it to * unsigned long first, and that's what is A() for. @@ -370,14 +377,122 @@ static inline int hdio_getgeo(unsigned int fd, u32 arg) return err; } +struct fbcmap32 { + int index; /* first element (0 origin) */ + int count; + u32 red; + u32 green; + u32 blue; +}; + +#define FBIOPUTCMAP32 _IOW('F', 3, struct fbcmap32) +#define FBIOGETCMAP32 _IOW('F', 4, struct fbcmap32) + +static inline int fbiogetputcmap(unsigned int fd, unsigned int cmd, u32 arg) +{ + struct fbcmap f; + int ret; + char red[256], green[256], blue[256]; + u32 r, g, b; + unsigned long old_fs = get_fs(); + + if (get_user(f.index, &(((struct fbcmap32 *)A(arg))->index)) || + __get_user(f.count, &(((struct fbcmap32 *)A(arg))->count)) || + __get_user(r, &(((struct fbcmap32 *)A(arg))->red)) || + __get_user(g, &(((struct fbcmap32 *)A(arg))->green)) || + __get_user(b, &(((struct fbcmap32 *)A(arg))->blue))) + return -EFAULT; + if ((f.index < 0) || (f.index > 255)) return -EINVAL; + if (f.index + f.count > 256) + f.count = 256 - f.index; + if (cmd == FBIOPUTCMAP32) { + if (copy_from_user (red, (char *)A(r), f.count) || + copy_from_user (green, (char *)A(g), f.count) || + copy_from_user (blue, (char *)A(b), f.count)) + return -EFAULT; + } + f.red = red; f.green = green; f.blue = blue; + set_fs (KERNEL_DS); + ret = sys_ioctl (fd, (cmd == FBIOPUTCMAP32) ? FBIOPUTCMAP : FBIOGETCMAP, (long)&f); + set_fs (old_fs); + if (!ret && cmd == FBIOGETCMAP32) { + if (copy_to_user ((char *)A(r), red, f.count) || + copy_to_user ((char *)A(g), green, f.count) || + copy_to_user ((char *)A(b), blue, f.count)) + return -EFAULT; + } + return ret; +} + +struct fbcursor32 { + short set; /* what to set, choose from the list above */ + short enable; /* cursor on/off */ + struct fbcurpos pos; /* cursor position */ + struct fbcurpos hot; /* cursor hot spot */ + struct fbcmap32 cmap; /* color map info */ + struct fbcurpos size; /* cursor bit map size */ + u32 image; /* cursor image bits */ + u32 mask; /* cursor mask bits */ +}; + +#define FBIOSCURSOR32 _IOW('F', 24, struct fbcursor32) +#define FBIOGCURSOR32 _IOW('F', 25, struct fbcursor32) + +static inline int fbiogscursor(unsigned int fd, unsigned int cmd, u32 arg) +{ + struct fbcursor f; + int ret; + char red[2], green[2], blue[2]; + char image[128], mask[128]; + u32 r, g, b; + u32 m, i; + unsigned long old_fs = get_fs(); + + if (copy_from_user (&f, (struct fbcursor32 *)A(arg), 2 * sizeof (short) + 2 * sizeof(struct fbcurpos)) || + __get_user(f.size.fbx, &(((struct fbcursor32 *)A(arg))->size.fbx)) || + __get_user(f.size.fby, &(((struct fbcursor32 *)A(arg))->size.fby)) || + __get_user(f.cmap.index, &(((struct fbcursor32 *)A(arg))->cmap.index)) || + __get_user(f.cmap.count, &(((struct fbcursor32 *)A(arg))->cmap.count)) || + __get_user(r, &(((struct fbcursor32 *)A(arg))->cmap.red)) || + __get_user(g, &(((struct fbcursor32 *)A(arg))->cmap.green)) || + __get_user(b, &(((struct fbcursor32 *)A(arg))->cmap.blue)) || + __get_user(m, &(((struct fbcursor32 *)A(arg))->mask)) || + __get_user(i, &(((struct fbcursor32 *)A(arg))->image))) + return -EFAULT; + if (f.set & FB_CUR_SETCMAP) { + if ((uint) f.size.fby > 32) + return -EINVAL; + if (copy_from_user (mask, (char *)A(m), f.size.fby * 4) || + copy_from_user (image, (char *)A(i), f.size.fby * 4)) + return -EFAULT; + f.image = image; f.mask = mask; + } + if (f.set & FB_CUR_SETCMAP) { + if (copy_from_user (red, (char *)A(r), 2) || + copy_from_user (green, (char *)A(g), 2) || + copy_from_user (blue, (char *)A(b), 2)) + return -EFAULT; + f.cmap.red = red; f.cmap.green = green; f.cmap.blue = blue; + } + set_fs (KERNEL_DS); + ret = sys_ioctl (fd, FBIOSCURSOR, (long)&f); + set_fs (old_fs); + return ret; +} + asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) { struct file * filp; int error = -EBADF; lock_kernel(); - if (fd >= NR_OPEN || !(filp = current->files->fd[fd])) + if(fd >= NR_OPEN) + goto out; + + filp = current->files->fd[fd]; + if(!filp) goto out; + if (!filp->f_op || !filp->f_op->ioctl) { error = sys_ioctl (fd, cmd, (unsigned long)arg); goto out; @@ -431,6 +546,15 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) case BLKGETSIZE: error = w_long(fd, cmd, arg); goto out; + + case FBIOPUTCMAP32: + case FBIOGETCMAP32: + error = fbiogetputcmap(fd, cmd, arg); + goto out; + + case FBIOSCURSOR32: + error = fbiogscursor(fd, cmd, arg); + goto out; /* List here exlicitly which ioctl's are known to have * compatable types passed or none at all... @@ -471,6 +595,17 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) case TIOCSPGRP: case TIOCGPGRP: case TIOCSCTTY: + + /* Big F */ + case FBIOGTYPE: + case FBIOSATTR: + case FBIOGATTR: + case FBIOSVIDEO: + case FBIOGVIDEO: + case FBIOGCURSOR32: /* This is not implemented yet. Later it should be converted... */ + case FBIOSCURPOS: + case FBIOGCURPOS: + case FBIOGCURMAX: /* Little f */ case FIOCLEX: @@ -479,6 +614,19 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) case FIONBIO: case FIONREAD: /* This is also TIOCINQ */ + /* 0x00 */ + case FIBMAP: + case FIGETBSZ: + + /* 0x02 -- Floppy ioctls */ + case FDSETEMSGTRESH: + case FDFLUSH: + case FDSETMAXERRS: + case FDGETMAXERRS: + case FDGETDRVTYP: + case FDEJECT: + /* XXX The rest need struct floppy_* translations. */ + /* 0x12 */ case BLKRRPART: case BLKFLSBUF: @@ -495,6 +643,59 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) case KDSIGACCEPT: case KDGETKEYCODE: case KDSETKEYCODE: + case KIOCSOUND: + case KDMKTONE: + case KDGKBTYPE: + case KDSETMODE: + case KDGETMODE: + case KDSKBMODE: + case KDGKBMODE: + case KDSKBMETA: + case KDGKBMETA: + case KDGKBENT: + case KDSKBENT: + case KDGKBSENT: + case KDSKBSENT: + case KDGKBDIACR: + case KDSKBDIACR: + case KDGKBLED: + case KDSKBLED: + case KDGETLED: + case KDSETLED: + + /* Little k */ + case KIOCTYPE: + case KIOCLAYOUT: + case KIOCGTRANS: + case KIOCTRANS: + case KIOCCMD: + case KIOCSDIRECT: + case KIOCSLED: + case KIOCGLED: + case KIOCSRATE: + case KIOCGRATE: + + /* Big V */ + case VT_SETMODE: + case VT_GETMODE: + case VT_GETSTATE: + case VT_OPENQRY: + case VT_ACTIVATE: + case VT_WAITACTIVE: + case VT_RELDISP: + case VT_DISALLOCATE: + case VT_RESIZE: + case VT_RESIZEX: + case VT_LOCKSWITCH: + case VT_UNLOCKSWITCH: + + /* Little v */ + case VUIDSFORMAT: + case VUIDGFORMAT: + + /* Little p (/dev/rtc etc.) */ + case RTCGET: + case RTCSET: /* Socket level stuff */ case FIOSETOWN: diff --git a/arch/sparc64/kernel/ioport.c b/arch/sparc64/kernel/ioport.c index 2f94e9102..390c33517 100644 --- a/arch/sparc64/kernel/ioport.c +++ b/arch/sparc64/kernel/ioport.c @@ -1,4 +1,4 @@ -/* $Id: ioport.c,v 1.7 1997/04/10 05:13:01 davem Exp $ +/* $Id: ioport.c,v 1.10 1997/06/30 09:24:02 jj Exp $ * ioport.c: Simple io mapping allocator. * * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) @@ -64,13 +64,7 @@ void *sparc_alloc_io (u32 address, void *virtual, int len, char *name, /* Tell Linux resource manager about the mapping */ request_region ((vaddr | offset), len, name); } else { - vaddr = occupy_region(sparc_iobase_vaddr, IOBASE_END, - (offset + len + PAGE_SIZE-1) & PAGE_MASK, PAGE_SIZE, name); - if (vaddr == 0) { - /* Usually we cannot see printks in this case. */ - prom_printf("alloc_io: cannot occupy %d region\n", len); - prom_halt(); - } + return __va(addr); } base_address = vaddr; @@ -88,6 +82,9 @@ void sparc_free_io (void *virtual, int len) { unsigned long vaddr = (unsigned long) virtual & PAGE_MASK; unsigned long plen = (((unsigned long)virtual & ~PAGE_MASK) + len + PAGE_SIZE-1) & PAGE_MASK; + + if (virtual >= PAGE_OFFSET + 0x10000000000UL) + return; release_region(vaddr, plen); diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index 3c9b1a89e..c4e7f0e74 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.13 1997/05/27 07:54:28 davem Exp $ +/* $Id: irq.c,v 1.16 1997/07/11 03:03:08 davem Exp $ * irq.c: UltraSparc IRQ handling/init/registry. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -47,7 +47,8 @@ unsigned long ivector_to_mask[NUM_IVECS]; static struct irqaction static_irqaction[MAX_STATIC_ALLOC]; static int static_irq_count = 0; -static struct irqaction *irq_action[NR_IRQS+1] = { +/* XXX Must be exported so that fast IRQ handlers can get at it... -DaveM */ +struct irqaction *irq_action[NR_IRQS+1] = { NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL }; @@ -279,13 +280,13 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *) /* If this is flagged as statically allocated then we use our * private struct which is never freed. */ - if(irqflags & SA_STATIC_ALLOC) + if(irqflags & SA_STATIC_ALLOC) { if(static_irq_count < MAX_STATIC_ALLOC) action = &static_irqaction[static_irq_count++]; else printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed " "using kmalloc\n", irq, name); - + } if(action == NULL) action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL); @@ -464,14 +465,101 @@ void sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs) } #endif -/* XXX This needs to be written for floppy driver, and soon will be necessary - * XXX for serial driver as well. +/* The following assumes that the branch lies before the place we + * are branching to. This is the case for a trap vector... + * You have been warned. */ +#define SPARC_BRANCH(dest_addr, inst_addr) \ + (0x10800000 | ((((dest_addr)-(inst_addr))>>2)&0x3fffff)) + +#define SPARC_NOP (0x01000000) + +static void install_fast_irq(unsigned int cpu_irq, + void (*handler)(int, void *, struct pt_regs *)) +{ + extern unsigned long sparc64_ttable_tl0; + unsigned long ttent = (unsigned long) &sparc64_ttable_tl0; + unsigned int *insns; + + ttent += 0x820; + ttent += (cpu_irq - 1) << 5; + insns = (unsigned int *) ttent; + insns[0] = SPARC_BRANCH(((unsigned long) handler), + ((unsigned long)&insns[0])); + insns[1] = SPARC_NOP; + __asm__ __volatile__("flush %0" : : "r" (ttent)); +} + int request_fast_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char *name) { - return -1; + struct irqaction *action; + unsigned long flags; + unsigned int cpu_irq, *imap, *iclr; + + /* XXX This really is not the way to do it, the "right way" + * XXX is to have drivers set SA_SBUS or something like that + * XXX in irqflags and we base our decision here on whether + * XXX that flag bit is set or not. + * + * In this case nobody can have a fast interrupt at the level + * where TICK interrupts live. + */ + if(irq == 14) + return -EINVAL; + cpu_irq = ino_to_pil[irq]; + + if(!handler) + return -EINVAL; + imap = irq_to_imap(irq); + action = *(cpu_irq + irq_action); + if(action) { + if(action->flags & SA_SHIRQ) + panic("Trying to register fast irq when already shared.\n"); + if(irqflags & SA_SHIRQ) + panic("Trying to register fast irq as shared.\n"); + printk("request_fast_irq: Trying to register yet already owned.\n"); + return -EBUSY; + } + save_and_cli(flags); + if(irqflags & SA_STATIC_ALLOC) { + if(static_irq_count < MAX_STATIC_ALLOC) + action = &static_irqaction[static_irq_count++]; + else + printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed " + "using kmalloc\n", irq, name); + } + if(action == NULL) + action = (struct irqaction *)kmalloc(sizeof(struct irqaction), + GFP_KERNEL); + if(!action) { + restore_flags(flags); + return -ENOMEM; + } + install_fast_irq(cpu_irq, handler); + + if(imap) { + int ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)); + + ivector_to_mask[ivindex] = (1 << cpu_irq); + iclr = imap_to_iclr(imap); + action->mask = (unsigned long) iclr; + irqflags |= SA_SYSIO_MASKED; + } else + action->mask = 0; + + action->handler = handler; + action->flags = irqflags; + action->dev_id = NULL; + action->name = name; + action->next = NULL; + + *(cpu_irq + irq_action) = action; + + enable_irq(irq); + restore_flags(flags); + return 0; } /* We really don't need these at all on the Sparc. We only have @@ -496,27 +584,31 @@ static unsigned long tick_offset; /* XXX This doesn't belong here, just do this cruft in the timer.c handler code. */ static void timer_handler(int irq, void *dev_id, struct pt_regs *regs) { - extern void timer_interrupt(int, void *, struct pt_regs *); - unsigned long compare; - if (!(get_softint () & 1)) { /* Just to be sure... */ clear_softint(1 << 14); printk("Spurious level14 at %016lx\n", regs->tpc); return; - } + } else { + unsigned long compare, tick; + + do { + extern void timer_interrupt(int, void *, struct pt_regs *); - timer_interrupt(irq, dev_id, regs); + timer_interrupt(irq, dev_id, regs); - /* Acknowledge INT_TIMER */ - clear_softint(1 << 0); + /* Acknowledge INT_TIMER */ + clear_softint(1 << 0); - /* Set up for next timer tick. */ - __asm__ __volatile__("rd %%tick_cmpr, %0\n\t" - "add %0, %1, %0\n\t" - "wr %0, 0x0, %%tick_cmpr" - : "=r" (compare) - : "r" (tick_offset)); + /* Set up for next timer tick. */ + __asm__ __volatile__("rd %%tick_cmpr, %0\n\t" + "add %0, %2, %0\n\t" + "wr %0, 0x0, %%tick_cmpr\n\t" + "rd %%tick, %1" + : "=&r" (compare), "=r" (tick) + : "r" (tick_offset)); + } while(tick >= compare); + } } /* This is called from time_init() to get the jiffies timer going. */ @@ -558,6 +650,8 @@ struct sun5_timer { volatile u32 limit1, _unused3; } *prom_timers; +static u32 prom_limit0, prom_limit1; + static void map_prom_timers(void) { unsigned int addr[3]; @@ -582,7 +676,7 @@ static void map_prom_timers(void) prom_timers = (struct sun5_timer *) 0; return; } - prom_timers = (struct sun5_timer *) addr[0]; + prom_timers = (struct sun5_timer *) ((unsigned long)addr[0]); } static void kill_prom_timer(void) @@ -590,24 +684,39 @@ static void kill_prom_timer(void) if(!prom_timers) return; + /* Save them away for later. */ + prom_limit0 = prom_timers->limit0; + prom_limit1 = prom_timers->limit1; + /* Just as in sun4c/sun4m PROM uses timer which ticks at IRQ 14. * We turn both off here just to be paranoid. */ prom_timers->limit0 = 0; prom_timers->limit1 = 0; + + /* Wheee, eat the interrupt packet too... */ + __asm__ __volatile__(" + mov 0x40, %%g2 + ldxa [%%g0] %0, %%g1 + ldxa [%%g2] %1, %%g1 + stxa %%g0, [%%g0] %0 + membar #Sync +" : /* no outputs */ + : "i" (ASI_INTR_RECEIVE), "i" (ASI_UDB_INTR_R) + : "g1", "g2"); } -#if 0 /* Unused at this time. -DaveM */ -static void enable_prom_timer(void) +void enable_prom_timer(void) { if(!prom_timers) return; - /* Set it to fire off every 10ms. */ - prom_timers->limit1 = 0xa000270f; + /* Set it to whatever was there before. */ + prom_timers->limit1 = prom_limit1; prom_timers->count1 = 0; + prom_timers->limit0 = prom_limit0; + prom_timers->count0 = 0; } -#endif __initfunc(void init_IRQ(void)) { diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index cc8183618..89f63f78f 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.17 1997/06/02 06:33:32 davem Exp $ +/* $Id: process.c,v 1.29 1997/07/17 02:20:40 davem Exp $ * arch/sparc64/kernel/process.c * * Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu) @@ -17,6 +17,8 @@ #include <linux/sched.h> #include <linux/kernel.h> #include <linux/mm.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> #include <linux/stddef.h> #include <linux/unistd.h> #include <linux/ptrace.h> @@ -137,7 +139,7 @@ void machine_restart(char * cmd) prom_reboot(cmd); if (*reboot_command) prom_reboot(reboot_command); - prom_feval ("reset"); + prom_reboot(""); panic("Reboot failed!"); } @@ -146,8 +148,55 @@ void machine_power_off(void) machine_halt(); } -void show_regwindow(struct reg_window *rw) +static void show_regwindow32(struct pt_regs *regs) { + struct reg_window32 *rw; + struct reg_window32 r_w; + unsigned long old_fs; + + __asm__ __volatile__ ("flushw"); + rw = (struct reg_window32 *)((long)(unsigned)regs->u_regs[14]); + old_fs = get_fs(); + set_fs (USER_DS); + if (copy_from_user (&r_w, rw, sizeof(r_w))) { + set_fs (old_fs); + return; + } + rw = &r_w; + set_fs (old_fs); + printk("l0: %016x l1: %016x l2: %016x l3: %016x\n" + "l4: %016x l5: %016x l6: %016x l7: %016x\n", + rw->locals[0], rw->locals[1], rw->locals[2], rw->locals[3], + rw->locals[4], rw->locals[5], rw->locals[6], rw->locals[7]); + printk("i0: %016x i1: %016x i2: %016x i3: %016x\n" + "i4: %016x i5: %016x i6: %016x i7: %016x\n", + rw->ins[0], rw->ins[1], rw->ins[2], rw->ins[3], + rw->ins[4], rw->ins[5], rw->ins[6], rw->ins[7]); +} + +static void show_regwindow(struct pt_regs *regs) +{ + struct reg_window *rw; + struct reg_window r_w; + unsigned long old_fs; + + if ((regs->tstate & TSTATE_PRIV) || !(current->tss.flags & SPARC_FLAG_32BIT)) { + __asm__ __volatile__ ("flushw"); + rw = (struct reg_window *)(regs->u_regs[14] + STACK_BIAS); + if (!(regs->tstate & TSTATE_PRIV)) { + old_fs = get_fs(); + set_fs (USER_DS); + if (copy_from_user (&r_w, rw, sizeof(r_w))) { + set_fs (old_fs); + return; + } + rw = &r_w; + set_fs (old_fs); + } + } else { + show_regwindow32(regs); + return; + } printk("l0: %016lx l1: %016lx l2: %016lx l3: %016lx\n", rw->locals[0], rw->locals[1], rw->locals[2], rw->locals[3]); printk("l4: %016lx l5: %016lx l6: %016lx l7: %016lx\n", @@ -158,18 +207,6 @@ void show_regwindow(struct reg_window *rw) rw->ins[4], rw->ins[5], rw->ins[6], rw->ins[7]); } -void show_regwindow32(struct reg_window32 *rw) -{ - printk("l0: %08x l1: %08x l2: %08x l3: %08x\n" - "l4: %08x l5: %08x l6: %08x l7: %08x\n", - rw->locals[0], rw->locals[1], rw->locals[2], rw->locals[3], - rw->locals[4], rw->locals[5], rw->locals[6], rw->locals[7]); - printk("i0: %08x i1: %08x i2: %08x i3: %08x\n" - "i4: %08x i5: %08x i6: %08x i7: %08x\n", - rw->ins[0], rw->ins[1], rw->ins[2], rw->ins[3], - rw->ins[4], rw->ins[5], rw->ins[6], rw->ins[7]); -} - void show_stackframe(struct sparc_stackf *sf) { unsigned long size; @@ -228,10 +265,7 @@ void show_stackframe32(struct sparc_stackf32 *sf) void show_regs(struct pt_regs * regs) { -#if __MPP__ - printk("CID: %d\n",mpp_cid()); -#endif - printk("TSTATE: %016lx TPC: %016lx TNPC: %016lx Y: %016lx\n", regs->tstate, + printk("TSTATE: %016lx TPC: %016lx TNPC: %016lx Y: %08x\n", regs->tstate, regs->tpc, regs->tnpc, regs->y); printk("g0: %016lx g1: %016lx g2: %016lx g3: %016lx\n", regs->u_regs[0], regs->u_regs[1], regs->u_regs[2], @@ -245,16 +279,11 @@ void show_regs(struct pt_regs * regs) printk("o4: %016lx o5: %016lx sp: %016lx ret_pc: %016lx\n", regs->u_regs[12], regs->u_regs[13], regs->u_regs[14], regs->u_regs[15]); -#if 0 - show_regwindow((struct reg_window *)(regs->u_regs[14] + STACK_BIAS)); -#endif + show_regwindow(regs); } void show_regs32(struct pt_regs32 *regs) { -#if __MPP__ - printk("CID: %d\n",mpp_cid()); -#endif printk("PSR: %08x PC: %08x NPC: %08x Y: %08x\n", regs->psr, regs->pc, regs->npc, regs->y); printk("g0: %08x g1: %08x g2: %08x g3: %08x\n", @@ -269,7 +298,6 @@ void show_regs32(struct pt_regs32 *regs) printk("o4: %08x o5: %08x sp: %08x ret_pc: %08x\n", regs->u_regs[12], regs->u_regs[13], regs->u_regs[14], regs->u_regs[15]); - show_regwindow32((struct reg_window32 *)((unsigned long)regs->u_regs[14])); } void show_thread(struct thread_struct *tss) @@ -290,46 +318,22 @@ void show_thread(struct thread_struct *tss) continue; printk("reg_window[%d]:\n", i); printk("stack ptr: 0x%016lx\n", tss->rwbuf_stkptrs[i]); - show_regwindow(&tss->reg_window[i]); } printk("w_saved: 0x%08lx\n", tss->w_saved); - /* XXX missing: float_regs */ - printk("fsr: 0x%016lx\n", tss->fsr); - printk("sstk_info.stack: 0x%016lx\n", (unsigned long)tss->sstk_info.the_stack); printk("sstk_info.status: 0x%016lx\n", (unsigned long)tss->sstk_info.cur_status); - printk("flags: 0x%016lx\n", tss->flags); - printk("current_ds: 0x%016x\n", tss->current_ds); + printk("flags: 0x%08x\n", tss->flags); + printk("current_ds: 0x%016lx\n", tss->current_ds); /* XXX missing: core_exec */ } -/* - * Free current thread data structures etc.. - */ +/* Free current thread data structures etc.. */ void exit_thread(void) { -#ifndef __SMP__ - if(last_task_used_math == current) { -#else - if(current->flags & PF_USEDFPU) { -#endif - fprs_write(FPRS_FEF); - if(current->tss.flags & SPARC_FLAG_32BIT) - fpsave32((unsigned long *)¤t->tss.float_regs[0], - ¤t->tss.fsr); - else - fpsave((unsigned long *)¤t->tss.float_regs[0], - ¤t->tss.fsr); -#ifndef __SMP__ - last_task_used_math = NULL; -#else - current->flags &= ~PF_USEDFPU; -#endif - } } void flush_thread(void) @@ -338,28 +342,12 @@ void flush_thread(void) current->tss.sstk_info.cur_status = 0; current->tss.sstk_info.the_stack = 0; - /* No new signal delivery by default */ + /* No new signal delivery by default. */ current->tss.new_signal = 0; -#ifndef __SMP__ - if(last_task_used_math == current) { -#else - if(current->flags & PF_USEDFPU) { -#endif - fprs_write(FPRS_FEF); - if(current->tss.flags & SPARC_FLAG_32BIT) - fpsave32((unsigned long *)¤t->tss.float_regs[0], - ¤t->tss.fsr); - else - fpsave((unsigned long *)¤t->tss.float_regs[0], - ¤t->tss.fsr); -#ifndef __SMP__ - last_task_used_math = NULL; -#else - current->flags &= ~PF_USEDFPU; -#endif - } + current->flags &= ~PF_USEDFPU; /* Now, this task is no longer a kernel thread. */ + current->tss.current_ds = USER_DS; if(current->tss.flags & SPARC_FLAG_KTHREAD) { current->tss.flags &= ~SPARC_FLAG_KTHREAD; @@ -368,78 +356,38 @@ void flush_thread(void) */ get_mmu_context(current); } - current->tss.current_ds = USER_DS; - spitfire_set_secondary_context (current->mm->context); + current->tss.ctx = current->mm->context & 0x1fff; + spitfire_set_secondary_context (current->tss.ctx); + __asm__ __volatile__("flush %g6"); } -static __inline__ void copy_regs(struct pt_regs *dst, struct pt_regs *src) +/* It's a bit more tricky when 64-bit tasks are involved... */ +static unsigned long clone_stackframe(unsigned long csp, unsigned long psp) { - __asm__ __volatile__("ldd\t[%1 + 0x00], %%g2\n\t" - "ldd\t[%1 + 0x08], %%g4\n\t" - "ldd\t[%1 + 0x10], %%o4\n\t" - "std\t%%g2, [%0 + 0x00]\n\t" - "std\t%%g4, [%0 + 0x08]\n\t" - "std\t%%o4, [%0 + 0x10]\n\t" - "ldd\t[%1 + 0x18], %%g2\n\t" - "ldd\t[%1 + 0x20], %%g4\n\t" - "ldd\t[%1 + 0x28], %%o4\n\t" - "std\t%%g2, [%0 + 0x18]\n\t" - "std\t%%g4, [%0 + 0x20]\n\t" - "std\t%%o4, [%0 + 0x28]\n\t" - "ldd\t[%1 + 0x30], %%g2\n\t" - "ldd\t[%1 + 0x38], %%g4\n\t" - "ldd\t[%1 + 0x40], %%o4\n\t" - "std\t%%g2, [%0 + 0x30]\n\t" - "std\t%%g4, [%0 + 0x38]\n\t" - "ldd\t[%1 + 0x48], %%g2\n\t" - "std\t%%o4, [%0 + 0x40]\n\t" - "std\t%%g2, [%0 + 0x48]\n\t" : : - "r" (dst), "r" (src) : - "g2", "g3", "g4", "g5", "o4", "o5"); -} - -static __inline__ void copy_regwin(struct reg_window *dst, struct reg_window *src) -{ - __asm__ __volatile__("ldd\t[%1 + 0x00], %%g2\n\t" - "ldd\t[%1 + 0x08], %%g4\n\t" - "ldd\t[%1 + 0x10], %%o4\n\t" - "std\t%%g2, [%0 + 0x00]\n\t" - "std\t%%g4, [%0 + 0x08]\n\t" - "std\t%%o4, [%0 + 0x10]\n\t" - "ldd\t[%1 + 0x18], %%g2\n\t" - "ldd\t[%1 + 0x20], %%g4\n\t" - "ldd\t[%1 + 0x28], %%o4\n\t" - "std\t%%g2, [%0 + 0x18]\n\t" - "std\t%%g4, [%0 + 0x20]\n\t" - "std\t%%o4, [%0 + 0x28]\n\t" - "ldd\t[%1 + 0x30], %%g2\n\t" - "ldd\t[%1 + 0x38], %%g4\n\t" - "std\t%%g2, [%0 + 0x30]\n\t" - "std\t%%g4, [%0 + 0x38]\n\t" : : - "r" (dst), "r" (src) : - "g2", "g3", "g4", "g5", "o4", "o5"); -} - -static __inline__ struct sparc_stackf * -clone_stackframe(struct sparc_stackf *dst, struct sparc_stackf *src) -{ - struct sparc_stackf *sp; - -#if 0 - unsigned long size; - size = ((unsigned long)src->fp) - ((unsigned long)src); - sp = (struct sparc_stackf *)(((unsigned long)dst) - size); - - if (copy_to_user(sp, src, size)) - return 0; - if (put_user(dst, &sp->fp)) + unsigned long fp, distance, rval; + + if(!(current->tss.flags & SPARC_FLAG_32BIT)) { + csp += STACK_BIAS; + psp += STACK_BIAS; + __get_user(fp, &(((struct reg_window *)psp)->ins[6])); + } else + __get_user(fp, &(((struct reg_window32 *)psp)->ins[6])); + distance = fp - psp; + rval = (csp - distance); + if(copy_in_user(rval, psp, distance)) return 0; -#endif - return sp; + if(current->tss.flags & SPARC_FLAG_32BIT) { + if(put_user(((u32)csp), &(((struct reg_window32 *)rval)->ins[6]))) + return 0; + return rval; + } else { + if(put_user(((u64)csp - STACK_BIAS), + &(((struct reg_window *)rval)->ins[6]))) + return 0; + return rval - STACK_BIAS; + } } -/* #define DEBUG_WINFIXUPS */ - /* Standard stuff. */ static inline void shift_window_buffer(int first_win, int last_win, struct thread_struct *tp) @@ -461,16 +409,16 @@ void synchronize_user_stack(void) flush_user_windows(); if((window = tp->w_saved) != 0) { int winsize = REGWIN_SZ; + int bias = 0; -#ifdef DEBUG_WINFIXUPS - printk("sus(%d", (int)window); -#endif if(tp->flags & SPARC_FLAG_32BIT) winsize = REGWIN32_SZ; + else + bias = STACK_BIAS; window -= 1; do { - unsigned long sp = tp->rwbuf_stkptrs[window]; + unsigned long sp = (tp->rwbuf_stkptrs[window] + bias); struct reg_window *rwin = &tp->reg_window[window]; if(!copy_to_user((char *)sp, rwin, winsize)) { @@ -478,9 +426,6 @@ void synchronize_user_stack(void) tp->w_saved--; } } while(window--); -#ifdef DEBUG_WINFIXUPS - printk(")"); -#endif } } @@ -489,18 +434,18 @@ void fault_in_user_windows(struct pt_regs *regs) struct thread_struct *tp = ¤t->tss; unsigned long window; int winsize = REGWIN_SZ; + int bias = 0; if(tp->flags & SPARC_FLAG_32BIT) winsize = REGWIN32_SZ; + else + bias = STACK_BIAS; flush_user_windows(); window = tp->w_saved; -#ifdef DEBUG_WINFIXUPS - printk("fiuw(%d", (int)window); -#endif if(window != 0) { window -= 1; do { - unsigned long sp = tp->rwbuf_stkptrs[window]; + unsigned long sp = (tp->rwbuf_stkptrs[window] + bias); struct reg_window *rwin = &tp->reg_window[window]; if(copy_to_user((char *)sp, rwin, winsize)) @@ -508,9 +453,6 @@ void fault_in_user_windows(struct pt_regs *regs) } while(window--); } current->tss.w_saved = 0; -#ifdef DEBUG_WINFIXUPS - printk(")"); -#endif } /* Copy a Sparc thread. The fork() return value conventions @@ -530,97 +472,49 @@ extern void ret_from_syscall(void); int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, struct task_struct *p, struct pt_regs *regs) { - struct pt_regs *childregs; - struct reg_window *new_stack, *old_stack; unsigned long stack_offset; - -#ifndef __SMP__ - if(last_task_used_math == current) { -#else - if(current->flags & PF_USEDFPU) { -#endif - fprs_write(FPRS_FEF); - fpsave((unsigned long *)&p->tss.float_regs[0], &p->tss.fsr); -#ifdef __SMP__ - current->flags &= ~PF_USEDFPU; -#endif - } + char *child_trap_frame; + int tframe_size; /* Calculate offset to stack_frame & pt_regs */ - stack_offset = ((PAGE_SIZE<<1) - TRACEREG_SZ); - - if(regs->tstate & TSTATE_PRIV) - stack_offset -= REGWIN_SZ; - - childregs = ((struct pt_regs *) (((unsigned long)p) + stack_offset)); - *childregs = *regs; - new_stack = (((struct reg_window *) childregs) - 1); - old_stack = (((struct reg_window *) regs) - 1); - *new_stack = *old_stack; - - p->tss.ksp = ((unsigned long) new_stack) - STACK_BIAS; + stack_offset = (((PAGE_SIZE << 1) - + ((sizeof(unsigned int)*64) + (2*sizeof(unsigned long)))) & + ~(64 - 1)) - (TRACEREG_SZ+REGWIN_SZ); + tframe_size = (TRACEREG_SZ + REGWIN_SZ) + + (sizeof(unsigned int) * 64) + (2 * sizeof(unsigned long)); + child_trap_frame = ((char *)p) + stack_offset; + memcpy(child_trap_frame, (((struct reg_window *)regs)-1), tframe_size); + p->tss.ksp = ((unsigned long) child_trap_frame) - STACK_BIAS; p->tss.kpc = ((unsigned long) ret_from_syscall) - 0x8; - p->tss.kregs = childregs; - - /* Don't look... */ + p->tss.kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct reg_window)); p->tss.cwp = regs->u_regs[UREG_G0]; - - /* tss.wstate was copied by do_fork() */ - if(regs->tstate & TSTATE_PRIV) { - childregs->u_regs[UREG_FP] = p->tss.ksp; + p->tss.kregs->u_regs[UREG_FP] = p->tss.ksp; p->tss.flags |= SPARC_FLAG_KTHREAD; p->tss.current_ds = KERNEL_DS; - childregs->u_regs[UREG_G6] = (unsigned long) p; + p->tss.ctx = 0; + p->tss.kregs->u_regs[UREG_G6] = (unsigned long) p; } else { - childregs->u_regs[UREG_FP] = sp; + p->tss.kregs->u_regs[UREG_FP] = sp; p->tss.flags &= ~SPARC_FLAG_KTHREAD; p->tss.current_ds = USER_DS; - -#if 0 + p->tss.ctx = (p->mm->context & 0x1fff); if (sp != regs->u_regs[UREG_FP]) { - struct sparc_stackf *childstack; - struct sparc_stackf *parentstack; - - /* - * This is a clone() call with supplied user stack. - * Set some valid stack frames to give to the child. - */ - childstack = (struct sparc_stackf *)sp; - parentstack = (struct sparc_stackf *)regs->u_regs[UREG_FP]; + unsigned long csp; -#if 0 - printk("clone: parent stack:\n"); - show_stackframe(parentstack); -#endif - - childstack = clone_stackframe(childstack, parentstack); - if (!childstack) + csp = clone_stackframe(sp, regs->u_regs[UREG_FP]); + if(!csp) return -EFAULT; - -#if 0 - printk("clone: child stack:\n"); - show_stackframe(childstack); -#endif - - childregs->u_regs[UREG_FP] = (unsigned long)childstack; + p->tss.kregs->u_regs[UREG_FP] = csp; } -#endif } /* Set the return value for the child. */ - childregs->u_regs[UREG_I0] = current->pid; - childregs->u_regs[UREG_I1] = 1; + p->tss.kregs->u_regs[UREG_I0] = current->pid; + p->tss.kregs->u_regs[UREG_I1] = 1; - /* Set the return value for the parent. */ + /* Set the second return value for the parent. */ regs->u_regs[UREG_I1] = 0; -#if 0 - printk("CHILD register dump\n"); - show_regs(childregs); - show_regwindow(new_stack); - while(1) - barrier(); -#endif return 0; } @@ -676,11 +570,19 @@ asmlinkage int sparc_execve(struct pt_regs *regs) if(regs->u_regs[UREG_G1] == 0) base = 1; - error = getname((char *) regs->u_regs[base + UREG_I0], &filename); - if(error) - return error; + lock_kernel(); + filename = getname((char *)regs->u_regs[base + UREG_I0]); + error = PTR_ERR(filename); + if(IS_ERR(filename)) + goto out; error = do_execve(filename, (char **) regs->u_regs[base + UREG_I1], (char **) regs->u_regs[base + UREG_I2], regs); putname(filename); + if(!error) { + fprs_write(0); + regs->fprs = 0; + } +out: + unlock_kernel(); return error; } diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index 24fe052cd..ac91df894 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c @@ -100,7 +100,16 @@ static inline void put_long(struct task_struct * tsk, struct vm_area_struct * vm /* this is a hack for non-kernel-mapped video buffers and similar */ flush_cache_page(vma, addr); if (MAP_NR(page) < max_mapnr) { - *(unsigned long *) (page + (addr & ~PAGE_MASK)) = data; + unsigned long pgaddr; + + pgaddr = page + (addr & ~PAGE_MASK); + *(unsigned long *) (pgaddr) = data; + + __asm__ __volatile__(" + membar #StoreStore + flush %0 +" : : "r" (pgaddr & ~7) : "memory"); + flush_page_to_ram(page); } /* we're bypassing pagetables, so we have to set the dirty bit ourselves */ @@ -138,7 +147,16 @@ static inline void put_int(struct task_struct * tsk, struct vm_area_struct * vma /* this is a hack for non-kernel-mapped video buffers and similar */ flush_cache_page(vma, addr); if (MAP_NR(page) < max_mapnr) { - *(unsigned int *) (page + (addr & ~PAGE_MASK)) = data; + unsigned long pgaddr; + + pgaddr = page + (addr & ~PAGE_MASK); + *(unsigned int *) (pgaddr) = data; + + __asm__ __volatile__(" + membar #StoreStore + flush %0 +" : : "r" (pgaddr & ~7) : "memory"); + flush_page_to_ram(page); } /* we're bypassing pagetables, so we have to set the dirty bit ourselves */ @@ -570,6 +588,21 @@ asmlinkage void do_ptrace(struct pt_regs *regs) pt_error_return(regs, ESRCH); goto out; } + + if(!(child->tss.flags & SPARC_FLAG_32BIT) && + ((request == PTRACE_READDATA64) || + (request == PTRACE_WRITEDATA64) || + (request == PTRACE_READTEXT64) || + (request == PTRACE_WRITETEXT64) || + (request == PTRACE_PEEKTEXT64) || + (request == PTRACE_POKETEXT64) || + (request == PTRACE_PEEKDATA64) || + (request == PTRACE_POKEDATA64))) { + addr = regs->u_regs[UREG_G2]; + addr2 = regs->u_regs[UREG_G3]; + request -= 30; /* wheee... */ + } + switch(request) { case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: { @@ -641,195 +674,207 @@ asmlinkage void do_ptrace(struct pt_regs *regs) goto out; } - case PTRACE_GETREGS: - if (current->tss.flags & SPARC_FLAG_32BIT) { - struct pt_regs32 *pregs = (struct pt_regs32 *) addr; - struct pt_regs *cregs = child->tss.kregs; - int rval; - - if (__put_user(tstate_to_psr(cregs->tstate), (&pregs->psr)) || - __put_user(cregs->tpc, (&pregs->pc)) || - __put_user(cregs->tnpc, (&pregs->npc)) || - __put_user(cregs->y, (&pregs->y))) { + case PTRACE_GETREGS: { + struct pt_regs32 *pregs = (struct pt_regs32 *) addr; + struct pt_regs *cregs = child->tss.kregs; + int rval; + + if (__put_user(tstate_to_psr(cregs->tstate), (&pregs->psr)) || + __put_user(cregs->tpc, (&pregs->pc)) || + __put_user(cregs->tnpc, (&pregs->npc)) || + __put_user(cregs->y, (&pregs->y))) { + pt_error_return(regs, EFAULT); + goto out; + } + for(rval = 1; rval < 16; rval++) + if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) { pt_error_return(regs, EFAULT); goto out; } - for(rval = 1; rval < 16; rval++) - if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) { - pt_error_return(regs, EFAULT); - goto out; - } - pt_succ_return(regs, 0); + pt_succ_return(regs, 0); #ifdef DEBUG_PTRACE - printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]); + printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]); #endif + goto out; + } + + case PTRACE_GETREGS64: { + struct pt_regs *pregs = (struct pt_regs *) addr; + struct pt_regs *cregs = child->tss.kregs; + int rval; + + if (__put_user(cregs->tstate, (&pregs->tstate)) || + __put_user(cregs->tpc, (&pregs->tpc)) || + __put_user(cregs->tnpc, (&pregs->tnpc)) || + __put_user(cregs->y, (&pregs->y))) { + pt_error_return(regs, EFAULT); goto out; - } else { - struct pt_regs *pregs = (struct pt_regs *) addr; - struct pt_regs *cregs = child->tss.kregs; - int rval; - - if (__put_user(cregs->tstate, (&pregs->tstate)) || - __put_user(cregs->tpc, (&pregs->tpc)) || - __put_user(cregs->tnpc, (&pregs->tnpc)) || - __put_user(cregs->y, (&pregs->y))) { + } + for(rval = 1; rval < 16; rval++) + if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) { pt_error_return(regs, EFAULT); goto out; } - for(rval = 1; rval < 16; rval++) - if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) { - pt_error_return(regs, EFAULT); - goto out; - } - pt_succ_return(regs, 0); + pt_succ_return(regs, 0); #ifdef DEBUG_PTRACE - printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]); + printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]); #endif + goto out; + } + + case PTRACE_SETREGS: { + struct pt_regs32 *pregs = (struct pt_regs32 *) addr; + struct pt_regs *cregs = child->tss.kregs; + unsigned int psr, pc, npc, y; + int i; + + /* Must be careful, tracing process can only set certain + * bits in the psr. + */ + if (__get_user(psr, (&pregs->psr)) || + __get_user(pc, (&pregs->pc)) || + __get_user(npc, (&pregs->npc)) || + __get_user(y, (&pregs->y))) { + pt_error_return(regs, EFAULT); goto out; } - - case PTRACE_SETREGS: - if (current->tss.flags & SPARC_FLAG_32BIT) { - struct pt_regs32 *pregs = (struct pt_regs32 *) addr; - struct pt_regs *cregs = child->tss.kregs; - unsigned int psr, pc, npc, y; - int i; - - /* Must be careful, tracing process can only set certain - * bits in the psr. - */ - if (__get_user(psr, (&pregs->psr)) || - __get_user(pc, (&pregs->pc)) || - __get_user(npc, (&pregs->npc)) || - __get_user(y, (&pregs->y))) { + cregs->tstate &= ~(TSTATE_ICC); + cregs->tstate |= psr_to_tstate_icc(psr); + if(!((pc | npc) & 3)) { + cregs->tpc = pc; + cregs->tnpc = npc; + } + cregs->y = y; + for(i = 1; i < 16; i++) + if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) { pt_error_return(regs, EFAULT); goto out; } - cregs->tstate &= ~(TSTATE_ICC); - cregs->tstate |= psr_to_tstate_icc(psr); - if(!((pc | npc) & 3)) { - cregs->tpc = pc; - cregs->tpc = npc; - } - cregs->y = y; - for(i = 1; i < 16; i++) - if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) { - pt_error_return(regs, EFAULT); - goto out; - } - pt_succ_return(regs, 0); - goto out; - } else { - struct pt_regs *pregs = (struct pt_regs *) addr; - struct pt_regs *cregs = child->tss.kregs; - unsigned long tstate, tpc, tnpc, y; - int i; + pt_succ_return(regs, 0); + goto out; + } - /* Must be careful, tracing process can only set certain - * bits in the psr. - */ - if (__get_user(tstate, (&pregs->tstate)) || - __get_user(tpc, (&pregs->tpc)) || - __get_user(tnpc, (&pregs->tnpc)) || - __get_user(y, (&pregs->y))) { - pt_error_return(regs, EFAULT); - goto out; - } - tstate &= (TSTATE_ICC | TSTATE_XCC); - cregs->tstate &= ~(TSTATE_ICC | TSTATE_XCC); - cregs->tstate |= tstate; - if(!((tpc | tnpc) & 3)) { - cregs->tpc = tpc; - cregs->tnpc = tnpc; - } - cregs->y = y; - for(i = 1; i < 16; i++) - if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) { - pt_error_return(regs, EFAULT); - goto out; - } - pt_succ_return(regs, 0); + case PTRACE_SETREGS64: { + struct pt_regs *pregs = (struct pt_regs *) addr; + struct pt_regs *cregs = child->tss.kregs; + unsigned long tstate, tpc, tnpc, y; + int i; + + /* Must be careful, tracing process can only set certain + * bits in the psr. + */ + if (__get_user(tstate, (&pregs->tstate)) || + __get_user(tpc, (&pregs->tpc)) || + __get_user(tnpc, (&pregs->tnpc)) || + __get_user(y, (&pregs->y))) { + pt_error_return(regs, EFAULT); goto out; } - - case PTRACE_GETFPREGS: - if (current->tss.flags & SPARC_FLAG_32BIT) { - struct fps { - unsigned int regs[32]; - unsigned int fsr; - unsigned int flags; - unsigned int extra; - unsigned int fpqd; - struct fq { - unsigned int insnaddr; - unsigned int insn; - } fpq[16]; - } *fps = (struct fps *) addr; - - if (copy_to_user(&fps->regs[0], &child->tss.float_regs[0], (32 * sizeof(unsigned int))) || - __put_user(child->tss.fsr, (&fps->fsr)) || - __put_user(0, (&fps->fpqd)) || - __put_user(0, (&fps->flags)) || - __put_user(0, (&fps->extra)) || - clear_user(&fps->fpq[0], 32 * sizeof(unsigned int))) { + tstate &= (TSTATE_ICC | TSTATE_XCC); + cregs->tstate &= ~(TSTATE_ICC | TSTATE_XCC); + cregs->tstate |= tstate; + if(!((tpc | tnpc) & 3)) { + cregs->tpc = tpc; + cregs->tnpc = tnpc; + } + cregs->y = y; + for(i = 1; i < 16; i++) + if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) { pt_error_return(regs, EFAULT); goto out; } - pt_succ_return(regs, 0); + pt_succ_return(regs, 0); + goto out; + } + + case PTRACE_GETFPREGS: { + struct fps { + unsigned int regs[32]; + unsigned int fsr; + unsigned int flags; + unsigned int extra; + unsigned int fpqd; + struct fq { + unsigned int insnaddr; + unsigned int insn; + } fpq[16]; + } *fps = (struct fps *) addr; + unsigned long *fpregs = (unsigned long *)(child->tss.kregs+1); + + if (copy_to_user(&fps->regs[0], fpregs, + (32 * sizeof(unsigned int))) || + __put_user(((unsigned int)fpregs[32]), (&fps->fsr)) || + __put_user(0, (&fps->fpqd)) || + __put_user(0, (&fps->flags)) || + __put_user(0, (&fps->extra)) || + clear_user(&fps->fpq[0], 32 * sizeof(unsigned int))) { + pt_error_return(regs, EFAULT); goto out; - } else { - struct fps { - unsigned int regs[64]; - unsigned long fsr; - } *fps = (struct fps *) addr; + } + pt_succ_return(regs, 0); + goto out; + } - if (copy_to_user(&fps->regs[0], &child->tss.float_regs[0], (64 * sizeof(unsigned int))) || - __put_user(child->tss.fsr, (&fps->fsr))) { - pt_error_return(regs, EFAULT); - goto out; - } - pt_succ_return(regs, 0); + case PTRACE_GETFPREGS64: { + struct fps { + unsigned int regs[64]; + unsigned long fsr; + } *fps = (struct fps *) addr; + unsigned long *fpregs = (unsigned long *)(child->tss.kregs+1); + + if (copy_to_user(&fps->regs[0], fpregs, + (64 * sizeof(unsigned int))) || + __put_user(fpregs[32], (&fps->fsr))) { + pt_error_return(regs, EFAULT); goto out; } + pt_succ_return(regs, 0); + goto out; + } - case PTRACE_SETFPREGS: - if (current->tss.flags & SPARC_FLAG_32BIT) { - struct fps { - unsigned int regs[32]; - unsigned int fsr; - unsigned int flags; - unsigned int extra; - unsigned int fpqd; - struct fq { - unsigned int insnaddr; - unsigned int insn; - } fpq[16]; - } *fps = (struct fps *) addr; - unsigned fsr; - - if (copy_from_user(&child->tss.float_regs[0], &fps->regs[0], (32 * sizeof(unsigned int))) || - __get_user(fsr, (&fps->fsr))) { - pt_error_return(regs, EFAULT); - goto out; - } - child->tss.fsr &= 0xffffffff00000000UL; - child->tss.fsr |= fsr; - pt_succ_return(regs, 0); + case PTRACE_SETFPREGS: { + struct fps { + unsigned int regs[32]; + unsigned int fsr; + unsigned int flags; + unsigned int extra; + unsigned int fpqd; + struct fq { + unsigned int insnaddr; + unsigned int insn; + } fpq[16]; + } *fps = (struct fps *) addr; + unsigned long *fpregs = (unsigned long *)(child->tss.kregs+1); + unsigned fsr; + + if (copy_from_user(fpregs, &fps->regs[0], + (32 * sizeof(unsigned int))) || + __get_user(fsr, (&fps->fsr))) { + pt_error_return(regs, EFAULT); goto out; - } else { - struct fps { - unsigned int regs[64]; - unsigned long fsr; - } *fps = (struct fps *) addr; + } + fpregs[32] &= 0xffffffff00000000UL; + fpregs[32] |= fsr; + pt_succ_return(regs, 0); + goto out; + } - if (copy_from_user(&child->tss.float_regs[0], &fps->regs[0], (64 * sizeof(unsigned int))) || - __get_user(child->tss.fsr, (&fps->fsr))) { - pt_error_return(regs, EFAULT); - goto out; - } - pt_succ_return(regs, 0); + case PTRACE_SETFPREGS64: { + struct fps { + unsigned int regs[64]; + unsigned long fsr; + } *fps = (struct fps *) addr; + unsigned long *fpregs = (unsigned long *)(child->tss.kregs+1); + + if (copy_from_user(fpregs, &fps->regs[0], + (64 * sizeof(unsigned int))) || + __get_user(fpregs[32], (&fps->fsr))) { + pt_error_return(regs, EFAULT); goto out; } + pt_succ_return(regs, 0); + goto out; + } case PTRACE_READTEXT: case PTRACE_READDATA: { @@ -1022,7 +1067,10 @@ asmlinkage void syscall_trace(void) current->pid, current->exit_code); #endif if (current->exit_code) { - set_bit(current->exit_code + 31, ¤t->signal); + /* 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/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S index 165b17ef0..9f087a969 100644 --- a/arch/sparc64/kernel/rtrap.S +++ b/arch/sparc64/kernel/rtrap.S @@ -1,4 +1,4 @@ -/* $Id: rtrap.S,v 1.21 1997/06/02 07:26:54 davem Exp $ +/* $Id: rtrap.S,v 1.28 1997/06/30 10:31:39 jj Exp $ * rtrap.S: Preparing for return from trap on Sparc V9. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -11,121 +11,124 @@ #include <asm/spitfire.h> #include <asm/head.h> - /* We assume here that this is entered with AG, MG and IG bits - * in pstate clear. - */ + .text + .align 32 + .globl rtrap_clr_l6, rtrap +#define PTREGS_OFF (STACK_BIAS + REGWIN_SZ) +rtrap_clr_l6: ba,pt %xcc, rtrap + clr %l6 +rtrap: sethi %hi(bh_active), %l2 + sethi %hi(bh_mask), %l1 + ldx [%l2 + %lo(bh_active)], %l4 + ldx [%l1 + %lo(bh_mask)], %l7 - .text - .align 32 - .globl rtrap_clr_l6, rtrap -rtrap_clr_l6: - ba,pt %xcc, rtrap - clr %l6 -rtrap: sethi %hi(bh_active), %l2 - or %l2, %lo(bh_active), %l2 - sethi %hi(bh_mask), %l1 - or %l1, %lo(bh_mask), %l1 - ldx [%l2 + %g4], %l3 - ldx [%l1 + %g4], %l4 + andcc %l4, %l7, %g0 + be,pt %xcc, 2f + nop + call do_bottom_half + nop +2: ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %l1 + sethi %hi(0xf << 20), %l4 + andcc %l1, TSTATE_PRIV, %l3 - andcc %l3, %l4, %g0 - be,pt %xcc, 2f - nop - call do_bottom_half - nop -2: ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %l1 - sethi %hi(0xf << 20), %l4 - andcc %l1, TSTATE_PRIV, %l3 + and %l1, %l4, %l4 + rdpr %pstate, %l7 + andn %l1, %l4, %l1 + be,pt %icc, to_user + andn %l7, PSTATE_IE, %l7 +rt_continue: ld [%sp + PTREGS_OFF + PT_V9_FPRS], %l2 + ld [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0 + ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1 - and %l1, %l4, %l4 - rdpr %pstate, %l7 - andn %l1, %l4, %l1 - be,pt %icc, to_user - andn %l7, PSTATE_IE, %l7 -3: ldx [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1], %g1 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2], %g2 + brnz,pn %l2, rt_fpu_restore + ldx [%sp + PTREGS_OFF + PT_V9_G2], %g2 +rt_after_fpu: ldx [%sp + PTREGS_OFF + PT_V9_G3], %g3 + mov %g6, %l6 + ldx [%sp + PTREGS_OFF + PT_V9_G4], %g4 + ldx [%sp + PTREGS_OFF + PT_V9_G5], %g5 + ldx [%sp + PTREGS_OFF + PT_V9_G6], %g6 + ldx [%sp + PTREGS_OFF + PT_V9_G7], %g7 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3], %g3 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4], %g4 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5], %g5 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6], %g6 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7], %g7 - wrpr %l7, PSTATE_AG, %pstate - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %i0 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1], %i1 + wrpr %l7, PSTATE_AG, %pstate + ldx [%sp + PTREGS_OFF + PT_V9_I0], %i0 + ldx [%sp + PTREGS_OFF + PT_V9_I1], %i1 + ldx [%sp + PTREGS_OFF + PT_V9_I2], %i2 + ldx [%sp + PTREGS_OFF + PT_V9_I3], %i3 + ldx [%sp + PTREGS_OFF + PT_V9_I4], %i4 + ldx [%sp + PTREGS_OFF + PT_V9_I5], %i5 + ldx [%sp + PTREGS_OFF + PT_V9_I6], %i6 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2], %i2 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3], %i3 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4], %i4 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5], %i5 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6], %i6 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7], %i7 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_Y], %o3 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC], %l2 + ldx [%sp + PTREGS_OFF + PT_V9_I7], %i7 + ld [%sp + PTREGS_OFF + PT_V9_Y], %o3 + ldx [%sp + PTREGS_OFF + PT_V9_TPC], %l2 + ldx [%sp + PTREGS_OFF + PT_V9_TNPC], %o2 + wr %o3, %g0, %y + srl %l4, 20, %l4 + wrpr %l4, 0x0, %pil + wrpr %g0, 0x1, %tl - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %o2 - wr %o3, %g0, %y - srl %l4, 20, %l4 - wrpr %l4, 0x0, %pil - wrpr %g0, 0x1, %tl - wrpr %l1, %g0, %tstate - wrpr %l2, %g0, %tpc - mov PRIMARY_CONTEXT, %l7 + wrpr %l1, %g0, %tstate + wrpr %l2, %g0, %tpc + mov PRIMARY_CONTEXT, %l7 + brnz,pn %l3, kern_rtt + wrpr %o2, %g0, %tnpc + stxa %l0, [%l7] ASI_DMMU + flush %l6 + rdpr %wstate, %l1 - wrpr %o2, %g0, %tnpc - brnz,a,pn %l3, 1f - restore - sethi %uhi(KERNBASE), %l5 - sllx %l5, 32, %l5 - stxa %l0, [%l7] ASI_DMMU - flush %l5 - rdpr %wstate, %l1 + rdpr %otherwin, %l2 + srl %l1, 3, %l1 + wrpr %l2, %g0, %canrestore + wrpr %l1, %g0, %wstate + wrpr %g0, %g0, %otherwin + restore + rdpr %canrestore, %g1 + wrpr %g1, 0x0, %cleanwin - rdpr %otherwin, %l2 - srl %l1, 3, %l1 - wrpr %l2, %g0, %canrestore - wrpr %l1, %g0, %wstate - wrpr %g0, %g0, %otherwin - restore - rdpr %canrestore, %g1 - wrpr %g1, 0x0, %cleanwin + retry +kern_rtt: restore + retry +to_user: sethi %hi(need_resched), %l0 + ld [%l0 + %lo(need_resched)], %l0 + wrpr %l7, PSTATE_IE, %pstate + brz,pt %l0, check_signal + ldx [%g6 + AOFF_task_signal], %l0 -1: retry -to_user: - sethi %hi(need_resched), %l0 - or %l0, %lo(need_resched), %l0 - ld [%l0 + %g4], %l0 - wrpr %l7, PSTATE_IE, %pstate - brz,pt %l0, check_signal - ldx [%g6 + AOFF_task_signal], %l0 - nop + call schedule + nop + ldx [%g6 + AOFF_task_signal], %l0 + nop +check_signal: ldx [%g6 + AOFF_task_blocked], %o0 + andncc %l0, %o0, %g0 + be,pt %xcc, check_user_wins + ldx [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2 - call schedule - nop - ba,pt %xcc, check_signal - ldx [%g6 + AOFF_task_signal], %l0 -check_signal: - ldx [%g6 + AOFF_task_blocked], %o0 - andncc %l0, %o0, %g0 - be,a,pt %xcc, check_user_wins - ldx [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2 - - mov %l5, %o2 - mov %l6, %o3 - call do_signal - add %sp, STACK_BIAS + REGWIN_SZ, %o1 - ldx [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2 - clr %l6 + mov %l5, %o2 + mov %l6, %o3 + call do_signal + add %sp, STACK_BIAS + REGWIN_SZ, %o1 + ldx [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2 + clr %l6 check_user_wins: - brz,pt %o2, 3b - nop + brz,pt %o2, rt_continue + nop + + call fault_in_user_windows + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + ba,a,pt %xcc, rt_continue +rt_fpu_restore: wr %g0, FPRS_FEF, %fprs + add %sp, PTREGS_OFF + TRACEREG_SZ, %g4 + wr %g0, ASI_BLK_P, %asi + + membar #StoreLoad | #LoadLoad + ldda [%g4 + 0x000] %asi, %f0 + ldda [%g4 + 0x040] %asi, %f16 + ldda [%g4 + 0x080] %asi, %f32 + ldda [%g4 + 0x0c0] %asi, %f48 + ldx [%g4 + 0x100], %fsr + ldx [%g4 + 0x108], %g3 + membar #Sync - call fault_in_user_windows - add %sp, STACK_BIAS + REGWIN_SZ, %o0 - ba,a,pt %xcc, 3b - nop - nop - nop - nop - nop + b,pt %xcc, rt_after_fpu + wr %g3, 0, %gsr +#undef PTREGS_OFF diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c index 832d3b97f..680baf7de 100644 --- a/arch/sparc64/kernel/setup.c +++ b/arch/sparc64/kernel/setup.c @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.7 1997/05/20 07:58:56 jj Exp $ +/* $Id: setup.c,v 1.10 1997/07/08 11:07:47 jj Exp $ * linux/arch/sparc64/kernel/setup.c * * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) @@ -35,6 +35,7 @@ #include <asm/page.h> #include <asm/pgtable.h> #include <asm/idprom.h> +#include <asm/head.h> struct screen_info screen_info = { 0, 0, /* orig-x, orig-y */ @@ -62,7 +63,6 @@ unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end) */ extern unsigned long sparc64_ttable_tl0; -extern void breakpoint(void); #if CONFIG_SUN_CONSOLE extern void console_restore_palette(void); #endif @@ -108,23 +108,13 @@ static int console_fb = 0; #endif static unsigned long memory_size = 0; +/* XXX Implement this at some point... */ void kernel_enter_debugger(void) { -#if 0 - if (boot_flags & BOOTME_KGDB) { - printk("KGDB: Entered\n"); - breakpoint(); - } -#endif } int obp_system_intr(void) { - if (boot_flags & BOOTME_KGDB) { - printk("KGDB: system interrupted\n"); - breakpoint(); - return 1; - } if (boot_flags & BOOTME_DEBUG) { printk("OBP: system interrupted\n"); prom_halt(); @@ -148,7 +138,7 @@ __initfunc(static void process_switch(char c)) break; case 'h': prom_printf("boot_flags_init: Halt!\n"); - halt(); + prom_halt(); break; default: printk("Unknown boot switch (-%c)\n", c); @@ -266,23 +256,9 @@ __initfunc(void setup_arch(char **cmdline_p, *cmdline_p = prom_getbootargs(); strcpy(saved_command_line, *cmdline_p); - prom_printf("BOOT: args[%s] saved[%s]\n", *cmdline_p, saved_command_line); - printk("ARCH: SUN4U\n"); boot_flags_init(*cmdline_p); -#if 0 - if((boot_flags&BOOTME_DEBUG) && (linux_dbvec!=0) && - ((*(short *)linux_dbvec) != -1)) { - printk("Booted under KADB. Syncing trap table.\n"); - (*(linux_dbvec->teach_debugger))(); - } - if((boot_flags & BOOTME_KGDB)) { - set_debug_traps(); - prom_printf ("Breakpoint!\n"); - breakpoint(); - } -#endif idprom_init(); total = prom_probe_memory(); @@ -313,7 +289,7 @@ __initfunc(void setup_arch(char **cmdline_p, *memory_start_p = PAGE_ALIGN(((unsigned long) &end)); *memory_end_p = (end_of_phys_memory + PAGE_OFFSET); -#ifndef NO_DAVEM_DEBUGGING +#ifdef DAVEM_DEBUGGING prom_printf("phys_base[%016lx] memory_start[%016lx] memory_end[%016lx]\n", phys_base, *memory_start_p, *memory_end_p); #endif @@ -328,8 +304,11 @@ __initfunc(void setup_arch(char **cmdline_p, #endif #ifdef CONFIG_BLK_DEV_INITRD if (ramdisk_image) { - initrd_start = ramdisk_image; - if (initrd_start < PAGE_OFFSET) initrd_start += PAGE_OFFSET; + unsigned long start = 0; + + if (ramdisk_image >= (unsigned long)&end - 2 * PAGE_SIZE) + ramdisk_image -= KERNBASE; + initrd_start = ramdisk_image + phys_base + PAGE_OFFSET; initrd_end = initrd_start + ramdisk_size; if (initrd_end > *memory_end_p) { printk(KERN_CRIT "initrd extends beyond end of memory " @@ -337,9 +316,11 @@ __initfunc(void setup_arch(char **cmdline_p, initrd_end,*memory_end_p); initrd_start = 0; } - if (initrd_start >= *memory_start_p && initrd_start < *memory_start_p + 2 * PAGE_SIZE) { + if (initrd_start) + start = ramdisk_image + KERNBASE; + if (start >= *memory_start_p && start < *memory_start_p + 2 * PAGE_SIZE) { initrd_below_start_ok = 1; - *memory_start_p = PAGE_ALIGN (initrd_end); + *memory_start_p = PAGE_ALIGN (start + ramdisk_size); } } #endif @@ -424,7 +405,11 @@ extern char *mmu_info(void); int get_cpuinfo(char *buffer) { - int cpuid=get_cpuid(); +#ifndef __SMP__ + int cpuid=0; +#else +#error SMP not supported on sparc64 yet +#endif return sprintf(buffer, "cpu\t\t: %s\n" "fpu\t\t: %s\n" diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c index fe4615a6b..cfc55fc2e 100644 --- a/arch/sparc64/kernel/signal.c +++ b/arch/sparc64/kernel/signal.c @@ -1,4 +1,4 @@ -/* $Id: signal.c,v 1.6 1997/05/29 12:44:48 jj Exp $ +/* $Id: signal.c,v 1.20 1997/07/14 03:10:28 davem Exp $ * arch/sparc64/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -8,6 +8,7 @@ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ +#include <linux/config.h> #include <linux/sched.h> #include <linux/kernel.h> #include <linux/signal.h> @@ -23,6 +24,7 @@ #include <asm/svr4.h> #include <asm/pgtable.h> #include <asm/fpumacro.h> +#include <asm/uctx.h> #include <asm/smp_lock.h> #define _S(nr) (1<<((nr)-1)) @@ -38,6 +40,124 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs, /* This turned off for production... */ /* #define DEBUG_SIGNALS 1 */ +/* {set, get}context() needed for 64-bit SparcLinux userland. */ +asmlinkage void sparc64_set_context(struct pt_regs *regs) +{ + struct ucontext *ucp = (struct ucontext *) regs->u_regs[UREG_I0]; + struct thread_struct *tp = ¤t->tss; + mc_gregset_t *grp; + unsigned long pc, npc, tstate; + unsigned long fp, i7; + unsigned char fenab; + + __asm__ __volatile__("flushw"); + if(tp->w_saved || + (((unsigned long)ucp) & (sizeof(unsigned long)-1)) || + (!__access_ok((unsigned long)ucp, sizeof(*ucp)))) + do_exit(SIGSEGV); + grp = &ucp->uc_mcontext.mc_gregs; + __get_user(pc, &((*grp)[MC_PC])); + __get_user(npc, &((*grp)[MC_NPC])); + if((pc | npc) & 3) + do_exit(SIGSEGV); + if(regs->u_regs[UREG_I1]) { + __get_user(current->blocked, &ucp->uc_sigmask); + current->blocked &= _BLOCKABLE; + } + regs->tpc = pc; + regs->tnpc = npc; + __get_user(regs->y, &((*grp)[MC_Y])); + __get_user(tstate, &((*grp)[MC_Y])); + regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC); + regs->tstate |= (tstate & (TSTATE_ICC | TSTATE_XCC)); + __get_user(regs->u_regs[UREG_G1], (&(*grp)[MC_G1])); + __get_user(regs->u_regs[UREG_G2], (&(*grp)[MC_G2])); + __get_user(regs->u_regs[UREG_G3], (&(*grp)[MC_G3])); + __get_user(regs->u_regs[UREG_G4], (&(*grp)[MC_G4])); + __get_user(regs->u_regs[UREG_G5], (&(*grp)[MC_G5])); + __get_user(regs->u_regs[UREG_G6], (&(*grp)[MC_G6])); + __get_user(regs->u_regs[UREG_G7], (&(*grp)[MC_G7])); + __get_user(regs->u_regs[UREG_I0], (&(*grp)[MC_O0])); + __get_user(regs->u_regs[UREG_I1], (&(*grp)[MC_O1])); + __get_user(regs->u_regs[UREG_I2], (&(*grp)[MC_O2])); + __get_user(regs->u_regs[UREG_I3], (&(*grp)[MC_O3])); + __get_user(regs->u_regs[UREG_I4], (&(*grp)[MC_O4])); + __get_user(regs->u_regs[UREG_I5], (&(*grp)[MC_O5])); + __get_user(regs->u_regs[UREG_I6], (&(*grp)[MC_O6])); + __get_user(regs->u_regs[UREG_I7], (&(*grp)[MC_O7])); + + __get_user(fp, &(ucp->uc_mcontext.mc_fp)); + __get_user(i7, &(ucp->uc_mcontext.mc_i7)); + __put_user(fp, (&(((struct reg_window *)(STACK_BIAS+regs->u_regs[UREG_I6]))->ins[6]))); + __put_user(i7, (&(((struct reg_window *)(STACK_BIAS+regs->u_regs[UREG_I6]))->ins[7]))); + + __get_user(fenab, &(ucp->uc_mcontext.mc_fpregs.mcfpu_enab)); + if(fenab) { + unsigned long *fpregs = (unsigned long *)(regs+1); + copy_from_user(fpregs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs), + (sizeof(unsigned long) * 32)); + __get_user(fpregs[32], &(ucp->uc_mcontext.mc_fpregs.mcfpu_fsr)); + __get_user(fpregs[33], &(ucp->uc_mcontext.mc_fpregs.mcfpu_gsr)); + regs->fprs = FPRS_FEF; + } +} + +asmlinkage void sparc64_get_context(struct pt_regs *regs) +{ + struct ucontext *ucp = (struct ucontext *) regs->u_regs[UREG_I0]; + struct thread_struct *tp = ¤t->tss; + mc_gregset_t *grp; + mcontext_t *mcp; + unsigned long fp, i7; + unsigned char fenab = (current->flags & PF_USEDFPU); + + synchronize_user_stack(); + if(tp->w_saved || clear_user(ucp, sizeof(*ucp))) + do_exit(SIGSEGV); + mcp = &ucp->uc_mcontext; + grp = &mcp->mc_gregs; + + /* Skip over the trap instruction, first. */ + regs->tpc = regs->tnpc; + regs->tnpc += 4; + + __put_user(current->blocked, &ucp->uc_sigmask); + __put_user(regs->tstate, &((*grp)[MC_TSTATE])); + __put_user(regs->tpc, &((*grp)[MC_PC])); + __put_user(regs->tnpc, &((*grp)[MC_NPC])); + __put_user(regs->y, &((*grp)[MC_Y])); + __put_user(regs->u_regs[UREG_G1], &((*grp)[MC_G1])); + __put_user(regs->u_regs[UREG_G2], &((*grp)[MC_G2])); + __put_user(regs->u_regs[UREG_G3], &((*grp)[MC_G3])); + __put_user(regs->u_regs[UREG_G4], &((*grp)[MC_G4])); + __put_user(regs->u_regs[UREG_G5], &((*grp)[MC_G5])); + __put_user(regs->u_regs[UREG_G6], &((*grp)[MC_G6])); + __put_user(regs->u_regs[UREG_G6], &((*grp)[MC_G7])); + __put_user(regs->u_regs[UREG_I0], &((*grp)[MC_O0])); + __put_user(regs->u_regs[UREG_I1], &((*grp)[MC_O1])); + __put_user(regs->u_regs[UREG_I2], &((*grp)[MC_O2])); + __put_user(regs->u_regs[UREG_I3], &((*grp)[MC_O3])); + __put_user(regs->u_regs[UREG_I4], &((*grp)[MC_O4])); + __put_user(regs->u_regs[UREG_I5], &((*grp)[MC_O5])); + __put_user(regs->u_regs[UREG_I6], &((*grp)[MC_O6])); + __put_user(regs->u_regs[UREG_I7], &((*grp)[MC_O7])); + + __get_user(fp, (&(((struct reg_window *)(STACK_BIAS+regs->u_regs[UREG_I6]))->ins[6]))); + __get_user(i7, (&(((struct reg_window *)(STACK_BIAS+regs->u_regs[UREG_I6]))->ins[7]))); + __put_user(fp, &(mcp->mc_fp)); + __put_user(i7, &(mcp->mc_i7)); + + __put_user(fenab, &(mcp->mc_fpregs.mcfpu_enab)); + if(fenab) { + unsigned long *fpregs = (unsigned long *)(regs+1); + copy_to_user(&(mcp->mc_fpregs.mcfpu_fregs), fpregs, + (sizeof(unsigned long) * 32)); + __put_user(fpregs[32], &(mcp->mc_fpregs.mcfpu_fsr)); + __put_user(fpregs[33], &(mcp->mc_fpregs.mcfpu_gsr)); + __put_user(FPRS_FEF, &(mcp->mc_fpregs.mcfpu_fprs)); + } +} + /* * The new signal frame, intended to be used for Linux applications only * (we have enough in there to work with clone). @@ -65,7 +185,8 @@ asmlinkage void _sigpause_common(unsigned int set, struct pt_regs *regs) #ifdef CONFIG_SPARC32_COMPAT if (current->tss.flags & SPARC_FLAG_32BIT) { - extern asmlinkage void _sigpause32_common(unsigned int, struct pt_regs *); + extern asmlinkage void _sigpause32_common(unsigned int, + struct pt_regs *); _sigpause32_common(set, regs); return; } @@ -111,22 +232,12 @@ asmlinkage void do_sigsuspend(struct pt_regs *regs) static inline void restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu) { -#ifdef __SMP__ - if (current->flags & PF_USEDFPU) - regs->tstate &= ~(TSTATE_PEF); -#else - if (current == last_task_used_math) { - last_task_used_math = 0; - regs->tstate &= ~(TSTATE_PEF); - } -#endif - current->used_math = 1; - current->flags &= ~PF_USEDFPU; - - copy_from_user(¤t->tss.float_regs[0], - &fpu->si_float_regs[0], + unsigned long *fpregs = (unsigned long *)(regs+1); + copy_from_user(fpregs, &fpu->si_float_regs[0], (sizeof(unsigned int) * 64)); - __get_user(current->tss.fsr, &fpu->si_fsr); + __get_user(fpregs[32], &fpu->si_fsr); + __get_user(fpregs[33], &fpu->si_gsr); + regs->fprs = FPRS_FEF; } void do_sigreturn(struct pt_regs *regs) @@ -139,24 +250,25 @@ void do_sigreturn(struct pt_regs *regs) #ifdef CONFIG_SPARC32_COMPAT if (current->tss.flags & SPARC_FLAG_32BIT) { extern asmlinkage void do_sigreturn32(struct pt_regs *); - do_sigreturn32(regs); - return; + return do_sigreturn32(regs); } #endif synchronize_user_stack (); - sf = (struct new_signal_frame *) regs->u_regs [UREG_FP]; + sf = (struct new_signal_frame *) + (regs->u_regs [UREG_FP] + STACK_BIAS); + /* 1. Make sure we are not getting garbage from the user */ - if (verify_area (VERIFY_READ, sf, sizeof (*sf))){ + if (verify_area (VERIFY_READ, sf, sizeof (*sf))) goto segv; - } - if (((unsigned long) sf) & 3){ + + if (((unsigned long) sf) & 3) goto segv; - } + get_user(tpc, &sf->info.si_regs.tpc); __get_user(tnpc, &sf->info.si_regs.tnpc); - if ((tpc | tnpc) & 3){ + if ((tpc | tnpc) & 3) goto segv; - } + regs->tpc = tpc; regs->tnpc = tnpc; @@ -165,9 +277,9 @@ void do_sigreturn(struct pt_regs *regs) __get_user(tstate, &sf->info.si_regs.tstate); copy_from_user(regs->u_regs, sf->info.si_regs.u_regs, sizeof(regs->u_regs)); - /* User can only change condition codes and FPU enabling in %tstate. */ - regs->tstate &= ~(TSTATE_ICC | TSTATE_PEF); - regs->tstate |= (tstate & (TSTATE_ICC | TSTATE_PEF)); + /* User can only change condition codes in %tstate. */ + regs->tstate &= ~(TSTATE_ICC); + regs->tstate |= (tstate & TSTATE_ICC); __get_user(fpu_save, &sf->fpu_save); if (fpu_save) @@ -191,27 +303,12 @@ static int invalid_frame_pointer(void *fp, int fplen) static inline void save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu) { -#ifdef __SMP__ - if (current->flags & PF_USEDFPU) { - fprs_write(FPRS_FEF); - fpsave((unsigned long *)¤t->tss.float_regs[0], - ¤t->tss.fsr); - regs->tstate &= ~(TSTATE_PEF); - current->flags &= ~(PF_USEDFPU); - } -#else - if (current == last_task_used_math) { - fprs_write(FPRS_FEF); - fpsave((unsigned long *)¤t->tss.float_regs[0], - ¤t->tss.fsr); - last_task_used_math = 0; - regs->tstate &= ~(TSTATE_PEF); - } -#endif - copy_to_user(&fpu->si_float_regs[0], ¤t->tss.float_regs[0], + unsigned long *fpregs = (unsigned long *)(regs+1); + copy_to_user(&fpu->si_float_regs[0], fpregs, (sizeof(unsigned int) * 64)); - __put_user(current->tss.fsr, &fpu->si_fsr); - current->used_math = 0; + __put_user(fpregs[32], &fpu->si_fsr); + __put_user(fpregs[33], &fpu->si_gsr); + regs->fprs = 0; } static inline void @@ -220,33 +317,29 @@ new_setup_frame(struct sigaction *sa, struct pt_regs *regs, { struct new_signal_frame *sf; int sigframe_size; - unsigned long tmp; - int i; /* 1. Make sure everything is clean */ synchronize_user_stack(); sigframe_size = NF_ALIGNEDSZ; - if (!current->used_math) + if (!(current->flags & PF_USEDFPU)) sigframe_size -= sizeof(__siginfo_fpu_t); - sf = (struct new_signal_frame *)(regs->u_regs[UREG_FP] - sigframe_size); + sf = (struct new_signal_frame *) + (regs->u_regs[UREG_FP] + STACK_BIAS - sigframe_size); - if (invalid_frame_pointer (sf, sigframe_size)){ - lock_kernel (); - do_exit(SIGILL); - } + if (invalid_frame_pointer (sf, sigframe_size)) + goto sigill; - if (current->tss.w_saved != 0){ + if (current->tss.w_saved != 0) { printk ("%s[%d]: Invalid user stack frame for " "signal delivery.\n", current->comm, current->pid); - lock_kernel (); - do_exit (SIGILL); + goto sigill; } /* 2. Save the current process state */ copy_to_user(&sf->info.si_regs, regs, sizeof (*regs)); - if (current->used_math) { + if (current->flags & PF_USEDFPU) { save_fpu_state(regs, &sf->fpu_state); __put_user((u64)&sf->fpu_state, &sf->fpu_save); } else { @@ -254,17 +347,17 @@ new_setup_frame(struct sigaction *sa, struct pt_regs *regs, } __put_user(oldmask, &sf->info.si_mask); - for (i = 0; i < sizeof(struct reg_window)/8; i++) { - __get_user(tmp, (((u64 *)regs->u_regs[UREG_FP])+i)); - __put_user(tmp, (((u64 *)sf)+i)); - } + + copy_in_user((u64 *)sf, + (u64 *)(regs->u_regs[UREG_FP]+STACK_BIAS), + sizeof(struct reg_window)); /* 3. return to kernel instructions */ __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */ __put_user(0x91d02011, &sf->insns[1]); /* t 0x11 */ /* 4. signal handler back-trampoline and parameters */ - regs->u_regs[UREG_FP] = (unsigned long) sf; + regs->u_regs[UREG_FP] = ((unsigned long) sf) - STACK_BIAS; regs->u_regs[UREG_I0] = signo; regs->u_regs[UREG_I1] = (unsigned long) &sf->info; regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2); @@ -274,15 +367,27 @@ new_setup_frame(struct sigaction *sa, struct pt_regs *regs, regs->tnpc = (regs->tpc + 4); /* Flush instruction space. */ - __asm__ __volatile__(" - membar #StoreStore - stxa %%g0, [%0] %2 - stxa %%g0, [%1] %2 - flush %%g4 - " : /* no outputs */ - : "r" (((unsigned long)&(sf->insns[0])) & ~(PAGE_MASK)), - "r" ((((unsigned long)&(sf->insns[0])) & ~(PAGE_MASK)) + PAGE_SIZE), - "i" (ASI_IC_TAG)); + { + unsigned long address = ((unsigned long)&(sf->insns[0])); + pgd_t *pgdp = pgd_offset(current->mm, address); + pmd_t *pmdp = pmd_offset(pgdp, address); + pte_t *ptep = pte_offset(pmdp, address); + + if(pte_present(*ptep)) { + unsigned long page = pte_page(*ptep); + + __asm__ __volatile__(" + membar #StoreStore + flush %0 + %1" + : : "r" (page), "r" (address & (PAGE_SIZE - 1)) + : "memory"); + } + } + return; + +sigill: + lock_kernel(); + do_exit(SIGILL); } static inline void handle_signal(unsigned long signr, struct sigaction *sa, @@ -291,8 +396,11 @@ static inline void handle_signal(unsigned long signr, struct sigaction *sa, new_setup_frame(sa, regs, signr, oldmask); if(sa->sa_flags & SA_ONESHOT) sa->sa_handler = NULL; - if(!(sa->sa_flags & SA_NOMASK)) + 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 orig_i0, struct pt_regs *regs, @@ -334,7 +442,11 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs, #endif while ((signr = current->signal & mask) != 0) { signr = ffz(~signr); - clear_bit(signr + 32, ¤t->signal); + + spin_lock_irq(¤t->sigmask_lock); + current->signal &= ~(1 << signr); + spin_unlock_irq(¤t->sigmask_lock); + sa = current->sig->action + signr; signr++; if ((current->flags & PF_PTRACED) && signr != SIGKILL) { @@ -348,7 +460,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; @@ -391,8 +505,10 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs, case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS: if(current->binfmt && current->binfmt->core_dump) { + lock_kernel(); if(current->binfmt->core_dump(signr, regs)) signr |= 0x80; + unlock_kernel(); } #ifdef DEBUG_SIGNALS /* Very useful to debug dynamic linker problems */ @@ -401,9 +517,15 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs, #endif /* fall through */ default: + spin_lock_irq(¤t->sigmask_lock); current->signal |= _S(signr & 0x7f); + spin_unlock_irq(¤t->sigmask_lock); + current->flags |= PF_SIGNALED; + + lock_kernel(); do_exit(signr); + unlock_kernel(); } } if(restart_syscall) diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c index c0454658b..5135c2ae5 100644 --- a/arch/sparc64/kernel/signal32.c +++ b/arch/sparc64/kernel/signal32.c @@ -1,4 +1,4 @@ -/* $Id: signal32.c,v 1.13 1997/06/01 05:46:09 davem Exp $ +/* $Id: signal32.c,v 1.26 1997/07/14 03:10:31 davem Exp $ * arch/sparc64/kernel/signal32.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -67,13 +67,12 @@ struct signal_sframe32 { * (we have enough in there to work with clone). * All the interesting bits are in the info field. */ - struct new_signal_frame32 { struct sparc_stackf32 ss; __siginfo32_t info; /* __siginfo_fpu32_t * */ u32 fpu_save; unsigned int insns [2]; - __siginfo_fpu32_t fpu_state; + __siginfo_fpu_t fpu_state; }; /* Align macros */ @@ -115,25 +114,12 @@ asmlinkage void _sigpause32_common(unsigned int set, struct pt_regs *regs) } } -static inline void -restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu32_t *fpu) +static inline void restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t *fpu) { -#ifdef __SMP__ - if (current->flags & PF_USEDFPU) - regs->tstate &= ~(TSTATE_PEF); -#else - if (current == last_task_used_math) { - last_task_used_math = 0; - regs->tstate &= ~(TSTATE_PEF); - } -#endif - current->used_math = 1; - current->flags &= ~PF_USEDFPU; - - copy_from_user(¤t->tss.float_regs[0], - &fpu->si_float_regs[0], - (sizeof(unsigned int) * 32)); - __get_user(current->tss.fsr, &fpu->si_fsr); + unsigned long *fpregs = (unsigned long *)(regs + 1); + copy_from_user(fpregs, &fpu->si_float_regs[0], (sizeof(unsigned int) * 64)); + __get_user(fpregs[32], &fpu->si_fsr); + __get_user(fpregs[33], &fpu->si_gsr); } void do_new_sigreturn32(struct pt_regs *regs) @@ -142,6 +128,7 @@ void do_new_sigreturn32(struct pt_regs *regs) unsigned int psr; unsigned pc, npc, fpu_save, mask; + regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL; sf = (struct new_signal_frame32 *) regs->u_regs [UREG_FP]; /* 1. Make sure we are not getting garbage from the user */ @@ -178,12 +165,12 @@ void do_new_sigreturn32(struct pt_regs *regs) __get_user(regs->u_regs[UREG_I6], &sf->info.si_regs.u_regs[UREG_I6]); __get_user(regs->u_regs[UREG_I7], &sf->info.si_regs.u_regs[UREG_I7]); - /* User can only change condition codes and FPU enabling in %tstate. */ - regs->tstate &= ~(TSTATE_ICC | TSTATE_PEF); + /* User can only change condition codes in %tstate. */ + regs->tstate &= ~(TSTATE_ICC); regs->tstate |= psr_to_tstate_icc(psr); if (psr & PSR_EF) - regs->tstate |= TSTATE_PEF; + regs->fprs = FPRS_FEF; __get_user(fpu_save, &sf->fpu_save); if (fpu_save) @@ -206,7 +193,8 @@ asmlinkage void do_sigreturn32(struct pt_regs *regs) if (current->tss.new_signal) return do_new_sigreturn32(regs); - scptr = (struct sigcontext32 *) regs->u_regs[UREG_I0]; + scptr = (struct sigcontext32 *) + (regs->u_regs[UREG_I0] & 0x00000000ffffffffUL); /* Check sanity of the user arg. */ if(verify_area(VERIFY_READ, scptr, sizeof(struct sigcontext32)) || (((unsigned long) scptr) & 3)) @@ -257,9 +245,9 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, #endif int old_status = current->tss.sstk_info.cur_status; unsigned psr; - int i; synchronize_user_stack(); + regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL; sframep = (struct signal_sframe32 *) regs->u_regs[UREG_FP]; sframep = (struct signal_sframe32 *) (((unsigned long) sframep)-SF_ALIGNEDSZ); if (invalid_frame_pointer (sframep, sizeof(*sframep))){ @@ -285,6 +273,8 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, __put_user(pc, &sc->sigc_pc); __put_user(npc, &sc->sigc_npc); psr = tstate_to_psr (regs->tstate); + if(current->flags & PF_USEDFPU) + psr |= PSR_EF; __put_user(psr, &sc->sigc_psr); __put_user(regs->u_regs[UREG_G1], &sc->sigc_g1); __put_user(regs->u_regs[UREG_I0], &sc->sigc_o0); @@ -301,13 +291,9 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, } else #endif - /* XXX Perhaps we need a copy_in_user()? -DaveM */ - for (i = 0; i < 16; i++) { - u32 temp; - - get_user (temp, (((u32 *)(regs->u_regs[UREG_FP]))+i)); - put_user (temp, (((u32 *)sframep)+i)); - } + copy_in_user((u32 *)sframep, + (u32 *)(regs->u_regs[UREG_FP]), + sizeof(struct reg_window32)); current->tss.w_saved = 0; /* So process is allowed to execute. */ __put_user(signr, &sframep->sig_num); @@ -329,35 +315,17 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, } -static inline void -save_fpu_state32(struct pt_regs *regs, __siginfo_fpu32_t *fpu) +static inline void save_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t *fpu) { -#ifdef __SMP__ - if (current->flags & PF_USEDFPU) { - fprs_write(FPRS_FEF); - fpsave32((unsigned long *)¤t->tss.float_regs[0], - ¤t->tss.fsr); - regs->tstate &= ~(TSTATE_PEF); - current->flags &= ~(PF_USEDFPU); - } -#else - if (current == last_task_used_math) { - fprs_write(FPRS_FEF); - fpsave32((unsigned long *)¤t->tss.float_regs[0], - ¤t->tss.fsr); - last_task_used_math = 0; - regs->tstate &= ~(TSTATE_PEF); - } -#endif - copy_to_user(&fpu->si_float_regs[0], ¤t->tss.float_regs[0], - (sizeof(unsigned int) * 32)); - __put_user(current->tss.fsr, &fpu->si_fsr); - current->used_math = 0; + unsigned long *fpregs = (unsigned long *)(regs+1); + copy_to_user(&fpu->si_float_regs[0], fpregs, (sizeof(unsigned int) * 64)); + __put_user(fpregs[32], &fpu->si_fsr); + __put_user(fpregs[33], &fpu->si_gsr); + regs->fprs = 0; } -static inline void -new_setup_frame32(struct sigaction *sa, struct pt_regs *regs, - int signo, unsigned long oldmask) +static inline void new_setup_frame32(struct sigaction *sa, struct pt_regs *regs, + int signo, unsigned long oldmask) { struct new_signal_frame32 *sf; int sigframe_size; @@ -367,21 +335,26 @@ new_setup_frame32(struct sigaction *sa, struct pt_regs *regs, /* 1. Make sure everything is clean */ synchronize_user_stack(); sigframe_size = NF_ALIGNEDSZ; - if (!current->used_math) - sigframe_size -= sizeof(__siginfo_fpu32_t); + if (!(current->flags & PF_USEDFPU)) + sigframe_size -= sizeof(__siginfo_fpu_t); + regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL; sf = (struct new_signal_frame32 *)(regs->u_regs[UREG_FP] - sigframe_size); if (invalid_frame_pointer (sf, sigframe_size)) { - lock_kernel (); - do_exit(SIGILL); +#ifdef DEBUG_SIGNALS + printk("new_setup_frame32(%s:%d): invalid_frame_pointer(%p, %d)\n", + current->comm, current->pid, sf, sigframe_size); +#endif + goto sigill; } if (current->tss.w_saved != 0) { +#ifdef DEBUG_SIGNALS printk ("%s[%d]: Invalid user stack frame for " "signal delivery.\n", current->comm, current->pid); - lock_kernel (); - do_exit (SIGILL); +#endif + goto sigill; } /* 2. Save the current process state */ @@ -389,11 +362,13 @@ new_setup_frame32(struct sigaction *sa, struct pt_regs *regs, __put_user(regs->tnpc, &sf->info.si_regs.npc); __put_user(regs->y, &sf->info.si_regs.y); psr = tstate_to_psr (regs->tstate); + if(current->flags & PF_USEDFPU) + psr |= PSR_EF; __put_user(psr, &sf->info.si_regs.psr); for (i = 0; i < 16; i++) __put_user(regs->u_regs[i], &sf->info.si_regs.u_regs[i]); - if (current->used_math) { + if (psr & PSR_EF) { save_fpu_state32(regs, &sf->fpu_state); __put_user((u64)&sf->fpu_state, &sf->fpu_save); } else { @@ -402,13 +377,9 @@ new_setup_frame32(struct sigaction *sa, struct pt_regs *regs, __put_user(oldmask, &sf->info.si_mask); - /* XXX Perhaps we need a copy_in_user()? -DaveM */ - for (i = 0; i < sizeof(struct reg_window32)/4; i++) { - u32 tmp; - - __get_user(tmp, (((u32 *)regs->u_regs[UREG_FP])+i)); - __put_user(tmp, (((u32 *)sf)+i)); - } + copy_in_user((u32 *)sf, + (u32 *)(regs->u_regs[UREG_FP]), + sizeof(struct reg_window32)); /* 3. return to kernel instructions */ __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */ @@ -425,15 +396,27 @@ new_setup_frame32(struct sigaction *sa, struct pt_regs *regs, regs->tnpc = (regs->tpc + 4); /* Flush instruction space. */ - __asm__ __volatile__(" - membar #StoreStore - stxa %%g0, [%0] %2 - stxa %%g0, [%1] %2 - flush %%g4 - " : /* no outputs */ - : "r" (((unsigned long)&(sf->insns[0])) & ~(PAGE_MASK)), - "r" ((((unsigned long)&(sf->insns[0])) & ~(PAGE_MASK)) + PAGE_SIZE), - "i" (ASI_IC_TAG)); + { + unsigned long address = ((unsigned long)&(sf->insns[0])); + pgd_t *pgdp = pgd_offset(current->mm, address); + pmd_t *pmdp = pmd_offset(pgdp, address); + pte_t *ptep = pte_offset(pmdp, address); + + if(pte_present(*ptep)) { + unsigned long page = pte_page(*ptep); + + __asm__ __volatile__(" + membar #StoreStore + flush %0 + %1" + : : "r" (page), "r" (address & (PAGE_SIZE - 1)) + : "memory"); + } + } + return; + +sigill: + lock_kernel(); + do_exit(SIGILL); } /* Setup a Solaris stack frame */ @@ -454,6 +437,7 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, int i; synchronize_user_stack(); + regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL; sfp = (svr4_signal_frame_t *) regs->u_regs[UREG_FP] - REGWIN_SZ; sfp = (svr4_signal_frame_t *) (((unsigned long) sfp)-SVR4_SF_ALIGNED); @@ -485,6 +469,8 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, __put_user(regs->tpc, &((*gr) [SVR4_PC])); __put_user(regs->tnpc, &((*gr) [SVR4_NPC])); psr = tstate_to_psr (regs->tstate); + if(current->flags & PF_USEDFPU) + psr |= PSR_EF; __put_user(psr, &((*gr) [SVR4_PSR])); __put_user(regs->y, &((*gr) [SVR4_Y])); @@ -546,7 +532,8 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, #endif /* Arguments passed to signal handler */ if (regs->u_regs [14]){ - struct reg_window32 *rw = (struct reg_window32 *) regs->u_regs [14]; + struct reg_window32 *rw = (struct reg_window32 *) + (regs->u_regs [14] & 0x00000000ffffffffUL); __put_user(signr, &rw->ins [0]); __put_user((u64)si, &rw->ins [1]); @@ -583,7 +570,9 @@ svr4_getcontext32(svr4_ucontext_t *uc, struct pt_regs *regs) /* Store registers */ __put_user(regs->tpc, &uc->mcontext.greg [SVR4_PC]); __put_user(regs->tnpc, &uc->mcontext.greg [SVR4_NPC]); - __put_user(tstate_to_psr(regs->tstate), &uc->mcontext.greg [SVR4_PSR]); + __put_user((tstate_to_psr(regs->tstate) | + ((current->flags & PF_USEDFPU) ? PSR_EF : 0)), + &uc->mcontext.greg [SVR4_PSR]); __put_user(regs->y, &uc->mcontext.greg [SVR4_Y]); /* Copy g [1..7] and o [0..7] registers */ @@ -619,16 +608,16 @@ asmlinkage int svr4_setcontext32(svr4_ucontext_t *c, struct pt_regs *regs) if (tp->w_saved){ printk ("Uh oh, w_saved is: 0x%lx\n", tp->w_saved); - do_exit(SIGSEGV); + goto sigsegv; } if (((unsigned long) c) & 3){ printk ("Unaligned structure passed\n"); - do_exit (SIGSEGV); + goto sigsegv; } if(!__access_ok((unsigned long)c, sizeof(*c))) { /* Miguel, add nice debugging msg _here_. ;-) */ - do_exit(SIGSEGV); + goto sigsegv; } /* Check for valid PC and nPC */ @@ -637,7 +626,7 @@ asmlinkage int svr4_setcontext32(svr4_ucontext_t *c, struct pt_regs *regs) __get_user(npc, &((*gr)[SVR4_NPC])); if((pc | npc) & 3) { printk ("setcontext, PC or nPC were bogus\n"); - do_exit (SIGSEGV); + goto sigsegv; } /* Retrieve information from passed ucontext */ /* note that nPC is ored a 1, this is used to inform entry.S */ @@ -650,14 +639,19 @@ asmlinkage int svr4_setcontext32(svr4_ucontext_t *c, struct pt_regs *regs) __get_user(psr, &((*gr) [SVR4_PSR])); regs->tstate &= ~(TSTATE_ICC); regs->tstate |= psr_to_tstate_icc(psr); + if(psr & PSR_EF) + regs->fprs = FPRS_FEF; /* Restore g[1..7] and o[0..7] registers */ for (i = 0; i < 7; i++) - __put_user(regs->u_regs[UREG_G1+i], (&(*gr)[SVR4_G1])+i); + __get_user(regs->u_regs[UREG_G1+i], (&(*gr)[SVR4_G1])+i); for (i = 0; i < 8; i++) - __put_user(regs->u_regs[UREG_I0+i], (&(*gr)[SVR4_O0])+i); + __get_user(regs->u_regs[UREG_I0+i], (&(*gr)[SVR4_O0])+i); return -EINTR; +sigsegv: + lock_kernel(); + do_exit(SIGSEGV); } static inline void handle_signal32(unsigned long signr, struct sigaction *sa, @@ -674,8 +668,11 @@ static inline void handle_signal32(unsigned long signr, struct sigaction *sa, } if(sa->sa_flags & SA_ONESHOT) sa->sa_handler = NULL; - if(!(sa->sa_flags & SA_NOMASK)) + 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_restart32(unsigned long orig_i0, struct pt_regs *regs, @@ -711,7 +708,11 @@ asmlinkage int do_signal32(unsigned long oldmask, struct pt_regs * regs, while ((signr = current->signal & mask) != 0) { signr = ffz(~signr); - clear_bit(signr + 32, ¤t->signal); + + spin_lock_irq(¤t->sigmask_lock); + current->signal &= ~(1 << signr); + spin_unlock_irq(¤t->sigmask_lock); + sa = current->sig->action + signr; signr++; if ((current->flags & PF_PTRACED) && signr != SIGKILL) { @@ -725,7 +726,9 @@ asmlinkage int do_signal32(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; @@ -768,8 +771,10 @@ asmlinkage int do_signal32(unsigned long oldmask, struct pt_regs * regs, case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS: if(current->binfmt && current->binfmt->core_dump) { + lock_kernel(); if(current->binfmt->core_dump(signr, regs)) signr |= 0x80; + unlock_kernel(); } #ifdef DEBUG_SIGNALS /* Very useful to debug dynamic linker problems */ @@ -778,9 +783,15 @@ asmlinkage int do_signal32(unsigned long oldmask, struct pt_regs * regs, #endif /* fall through */ default: + spin_lock_irq(¤t->sigmask_lock); current->signal |= _S(signr & 0x7f); + spin_unlock_irq(¤t->sigmask_lock); + current->flags |= PF_SIGNALED; + + lock_kernel(); do_exit(signr); + unlock_kernel(); } } if(restart_syscall) @@ -805,9 +816,10 @@ struct sigstack32 { int cur_status; }; -asmlinkage int -sys32_sigstack(struct sigstack32 *ssptr, struct sigstack32 *ossptr) +asmlinkage int sys32_sigstack(u32 u_ssptr, u32 u_ossptr) { + struct sigstack32 *ssptr = (struct sigstack32 *)((unsigned long)(u_ssptr)); + struct sigstack32 *ossptr = (struct sigstack32 *)((unsigned long)(u_ossptr)); int ret = -EFAULT; lock_kernel(); diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c new file mode 100644 index 000000000..88d7a8ecf --- /dev/null +++ b/arch/sparc64/kernel/smp.c @@ -0,0 +1,347 @@ +/* smp.c: Sparc64 SMP support. + * + * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + */ + +#define __KERNEL_SYSCALLS__ +#include <linux/unistd.h> + +extern int linux_num_cpus; +extern void calibrate_delay(void); + +volatile int smp_processors_ready = 0; +unsigned long cpu_present_map = 0; +int smp_num_cpus = 1; +int smp_threads_ready = 0; + +struct cpuinfo_sparc64 cpu_data[NR_CPUS]; +static unsigned char boot_cpu_id = 0; +static int smp_activated = 0; + +volatile int cpu_number_map[NR_CPUS]; +volatile int cpu_logical_map[NR_CPUS]; + +struct klock_info klock_info = { KLOCK_CLEAR, 0 }; + +static volatile int smp_commenced = 0; + +void smp_setup(char *str, int *ints) +{ + /* XXX implement me XXX */ +} + +static char smp_buf[512]; + +char *smp_info(void) +{ + /* XXX not SMP safe and need to support up to 64 penguins */ + sprintf(smp_buf, +" CPU0\t\tCPU1\t\tCPU2\t\tCPU3\n" +"State: %s\t\t%s\t\t%s\t\t%s\n", +(cpu_present_map & 1) ? ((klock_info.akp == 0) ? "akp" : "online") : "offline", +(cpu_present_map & 2) ? ((klock_info.akp == 1) ? "akp" : "online") : "offline", +(cpu_present_map & 4) ? ((klock_info.akp == 2) ? "akp" : "online") : "offline", +(cpu_present_map & 8) ? ((klock_info.akp == 3) ? "akp" : "online") : "offline"); + return smp_buf; +} + +void smp_store_cpu_info(int id) +{ + cpu_data[id].udelay_val = loops_per_sec; +} + +void smp_commence(void) +{ + local_flush_cache_all(); + local_flush_tlb_all(); + smp_commenced = 1; + local_flush_cache_all(); + local_flush_tlb_all(); +} + +static void smp_setup_percpu_timer(void); + +static volatile unsigned long callin_flag = 0; + +void smp_callin(void) +{ + int cpuid = hard_smp_processor_id(); + + local_flush_cache_all(); + local_flush_tlb_all(); + + smp_setup_percpu_timer(); + + calibrate_delay(); + smp_store_cpu_info(cpuid); + callin_flag = 1; + __asm__ __volatile__("membar #Sync\n\t" + "flush %g6" : : : "memory"); + + while(!task[cpuid]) + barrier(); + current = task[cpuid]; + + while(!smp_commenced) + barrier(); + + __sti(); +} + +extern int cpu_idle(void *unused); +extern void init_IRQ(void); + +void initialize_secondary(void) +{ +} + +int start_secondary(void *unused) +{ + trap_init(); + init_IRQ(); + smp_callin(); + return cpu_idle(NULL); +} + +extern struct prom_cpuinfo linux_cpus[NR_CPUS]; + +void smp_boot_cpus(void) +{ + int cpucount = 0, i, first, prev; + + printk("Entering UltraSMPenguin Mode...\n"); + __sti(); + cpu_present_map = 0; + for(i = 0; i < linux_num_cpus; i++) + cpu_present_map |= (1 << i); + for(i = 0; i < NR_CPUS; i++) { + cpu_number_map[i] = -1; + cpu_logical_map[i] = -1; + } + cpu_number_map[boot_cpu_id] = 0; + cpu_logical_map[0] = boot_cpu_id; + klock_info.akp = boot_cpu_id; + current->processor = boot_cpu_id; + smp_store_cpu_info(boot_cpu_id); + smp_setup_percpu_timer(); + + if(linux_num_cpus == 1) + return; + + for(i = 0; i < NR_CPUS; i++) { + if(i == boot_cpu_id) + continue; + + if(cpu_present_map & (1 << i)) { + extern unsigned long sparc64_cpu_startup; + unsigned long entry = (unsigned long)&sparc_cpu_startup; + struct task_struct *p; + int timeout; + + kernel_thread(start_secondary, NULL, CLONE_PID); + p = task[++cpucount]; + p->processor = i; + prom_startcpu(linux_cpus[i].prom_node, entry, i); + for(timeout = 0; timeout < 5000000; timeout++) { + if(cpu_callin_map[i]) + break; + udelay(100); + } + if(cpu_callin_map[i]) { + /* XXX fix this */ + cpu_number_map[i] = i; + cpu_logical_map[i] = i; + } else { + cpucount--; + printk("Processor %d is stuck.\n", i); + } + } + if(!(cpu_callin_map[i])) { + cpu_present_map &= ~(1 << i); + cpu_number_map[i] = -1; + } + } + if(cpucount == 0) { + printk("Error: only one processor found.\n"); + cpu_present_map = (1 << smp_processor_id()); + } else { + unsigned long bogosum = 0; + + for(i = 0; i < NR_CPUS; i++) { + if(cpu_present_map & (1 << i)) + bogosum += cpu_data[i].udelay_val; + } + printk("Total of %d processors activated (%lu.%02lu BogoMIPS).\n", + cpucount + 1, + (bogosum + 2500)/500000, + ((bogosum + 2500)/5000)%100); + smp_activated = 1; + smp_num_cpus = cpucount + 1; + } + smp_processors_ready = 1; +} + +/* XXX deprecated interface... */ +void smp_message_pass(int target, int msg, unsigned long data, int wait) +{ + printk("smp_message_pass() called, this is bad, spinning.\n"); + __sti(); + while(1) + barrier(); +} + +/* XXX Make it fast later. */ +void smp_cross_call(unsigned long *func, u32 ctx, u64 data1, u64 data2) +{ + if(smp_processors_ready) { + unsigned long mask; + u64 data0 = (((unsigned long)ctx)<<32 | + (((unsigned long)func) & 0xffffffff)); + u64 pstate; + int i, ncpus = smp_num_cpus; + + __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate)); + mask = (cpu_present_map & ~(1 << smp_processor_id())); + for(i = 0; i < ncpus; i++) { + if(mask & (1 << i)) { + u64 target = mid<<14 | 0x70; + u64 result; + + __asm__ __volatile__(" + wrpr %0, %1, %%pstate + wrpr %%g0, %2, %%asi + stxa %3, [0x40] %%asi + stxa %4, [0x50] %%asi + stxa %5, [0x60] %%asi + stxa %%g0, [%6] %7 + membar #Sync" + : /* No outputs */ + : "r" (pstate), "i" (PSTATE_IE), "i" (ASI_UDB_INTR_W), + "r" (data0), "r" (data1), "r" (data2), + "r" (target), "i" (ASI_UDB_INTR_W)); + + /* NOTE: PSTATE_IE is still clear. */ + do { + __asm__ __volatile__("ldxa [%%g0] %1, %0", + : "=r" (result) + : "i" (ASI_INTR_DISPATCH_STAT)); + } while(result & 0x1); + __asm__ __volatile__("wrpr %0, 0x0, %%pstate" + : : "r" (pstate)); + if(result & 0x2) + panic("Penguin NACK's master!"); + } + } + + /* NOTE: Caller runs local copy on master. */ + } +} + +extern unsigned long xcall_flush_tlb_page; +extern unsigned long xcall_flush_tlb_mm; +extern unsigned long xcall_flush_tlb_range; +extern unsigned long xcall_flush_tlb_all; +extern unsigned long xcall_flush_cache_all; + +void smp_flush_cache_all(void) +{ + smp_cross_call(&xcall_flush_cache_all, 0, 0, 0); +} + +void smp_flush_tlb_all(void) +{ + smp_cross_call(&xcall_flush_tlb_all, 0, 0, 0); +} + +void smp_flush_tlb_mm(struct mm_struct *mm) +{ + u32 ctx = mm->context & 0x1fff; + if(mm->cpu_vm_mask != (1 << smp_processor_id())) + smp_cross_call(&xcall_flush_tlb_mm, ctx, 0, 0); + __flush_tlb_mm(ctx); +} + +void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start, + unsigned long end) +{ + u32 ctx = mm->context & 0x1fff; + if(mm->cpu_vm_mask != (1 << smp_processor_id())) + smp_cross_call(&xcall_flush_tlb_range, ctx, start, end); + __flush_tlb_range(ctx, start, end); +} + +void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +{ + struct mm_struct *mm = vma->vm_mm; + u32 ctx = mm->context & 0x1fff; + + if(mm->cpu_vm_mask != (1 << smp_processor_id())) + smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0); + __flush_tlb_page(ctx, page); +} + +static spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED; + +static inline void sparc64_do_profile(unsigned long pc) +{ + if(prof_buffer && current->pid) { + extern int _stext; + + pc -= (unsigned long) &_stext; + pc >>= prof_shift; + + spin_lock(&ticker_lock); + if(pc < prof_len) + prof_buffer[pc]++; + else + prof_buffer[prof_len - 1]++; + spin_unlock(&ticker_lock); + } +} + +unsigned int prof_multiplier[NR_CPUS]; +unsigned int prof_counter[NR_CPUS]; + +extern void update_one_process(struct task_struct *p, unsigned long ticks, + unsigned long user, unsigned long system); + +void smp_percpu_timer_interrupt(struct pt_regs *regs) +{ + int cpu = smp_processor_id(); + + clear_profile_irq(cpu); + if(!user_mode(regs)) + sparc_do_profile(regs->pc); + if(!--prof_counter[cpu]) { + int user = user_mode(regs); + if(current->pid) { + update_one_process(current, 1, user, !user); + if(--current->counter < 0) { + current->counter = 0; + need_resched = 1; + } + + spin_lock(&ticker_lock); + if(user) { + if(current->priority < DEF_PRIORITY) + kstat.cpu_nice++; + else + kstat.cpu_user++; + } else { + kstat.cpu_system++; + } + spin_unlock(&ticker_lock); + } + prof_counter[cpu] = prof_multiplier[cpu]; + } +} + +static void smp_setup_percpu_timer(void) +{ + /* XXX implement me */ +} + +int setup_profiling_timer(unsigned int multiplier) +{ + /* XXX implement me */ +} diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index 91426c814..990202bac 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c @@ -1,5 +1,5 @@ -/* $Id: sparc64_ksyms.c,v 1.4 1997/04/14 17:04:43 jj Exp $ - * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support. +/* $Id: sparc64_ksyms.c,v 1.11 1997/07/14 23:58:20 davem Exp $ + * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) @@ -18,6 +18,8 @@ #include <asm/pgtable.h> #include <asm/io.h> #include <asm/irq.h> +#include <asm/softirq.h> +#include <asm/hardirq.h> #include <asm/idprom.h> #include <asm/svr4.h> #include <asm/head.h> @@ -38,19 +40,17 @@ struct poll { short revents; }; -extern int svr4_getcontext (svr4_ucontext_t *, struct pt_regs *); -extern int svr4_setcontext (svr4_ucontext_t *, struct pt_regs *); extern unsigned long sunos_mmap(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long); void _sigpause_common (unsigned int set, struct pt_regs *); -extern void __copy_1page(void *, const void *); -extern void *bzero_1page(void *); +extern void *__bzero_1page(void *); extern void *__bzero(void *, size_t); extern void *__memscan_zero(void *, size_t); extern void *__memscan_generic(void *, int, size_t); extern int __memcmp(const void *, const void *, __kernel_size_t); extern int __strncmp(const char *, const char *, __kernel_size_t); extern unsigned int __csum_partial_copy_sparc_generic (const char *, char *); +extern char saved_command_line[]; extern void bcopy (const char *, char *, int); extern int __ashrdi3(int, int); @@ -75,32 +75,24 @@ EXPORT_SYMBOL(klock_info); EXPORT_SYMBOL_PRIVATE(_lock_kernel); EXPORT_SYMBOL_PRIVATE(_unlock_kernel); +EXPORT_SYMBOL_PRIVATE(flushw_user); + EXPORT_SYMBOL(mstk48t02_regs); EXPORT_SYMBOL(request_fast_irq); EXPORT_SYMBOL(sparc_alloc_io); EXPORT_SYMBOL(sparc_free_io); -#if 0 -EXPORT_SYMBOL(io_remap_page_range); -EXPORT_SYMBOL(mmu_unlockarea); -EXPORT_SYMBOL(mmu_lockarea); +EXPORT_SYMBOL(local_irq_count); +EXPORT_SYMBOL(__sparc64_bh_counter); +EXPORT_SYMBOL(sparc_ultra_unmapioaddr); EXPORT_SYMBOL(mmu_get_scsi_sgl); EXPORT_SYMBOL(mmu_get_scsi_one); -EXPORT_SYMBOL(mmu_release_scsi_sgl); -EXPORT_SYMBOL(mmu_release_scsi_one); -#endif EXPORT_SYMBOL(sparc_dvma_malloc); -#if 0 -EXPORT_SYMBOL(sun4c_unmapioaddr); -EXPORT_SYMBOL(srmmu_unmapioaddr); -#endif #if CONFIG_SBUS EXPORT_SYMBOL(SBus_chain); EXPORT_SYMBOL(dma_chain); #endif /* Solaris/SunOS binary compatibility */ -EXPORT_SYMBOL(svr4_setcontext); -EXPORT_SYMBOL(svr4_getcontext); EXPORT_SYMBOL(_sigpause_common); EXPORT_SYMBOL(sunos_mmap); @@ -119,7 +111,7 @@ EXPORT_SYMBOL(prom_getproplen); EXPORT_SYMBOL(prom_getproperty); EXPORT_SYMBOL(prom_node_has_property); EXPORT_SYMBOL(prom_setprop); -EXPORT_SYMBOL(prom_getbootargs); +EXPORT_SYMBOL(saved_command_line); EXPORT_SYMBOL(prom_getname); EXPORT_SYMBOL(prom_feval); EXPORT_SYMBOL(prom_getstring); @@ -148,10 +140,9 @@ EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(strspn); /* Special internal versions of library functions. */ -EXPORT_SYMBOL(__copy_1page); EXPORT_SYMBOL(__memcpy); EXPORT_SYMBOL(__memset); -EXPORT_SYMBOL(bzero_1page); +EXPORT_SYMBOL(__bzero_1page); EXPORT_SYMBOL(__bzero); EXPORT_SYMBOL(__memscan_zero); EXPORT_SYMBOL(__memscan_generic); diff --git a/arch/sparc64/kernel/sunos_ioctl32.c b/arch/sparc64/kernel/sunos_ioctl32.c new file mode 100644 index 000000000..311110d3c --- /dev/null +++ b/arch/sparc64/kernel/sunos_ioctl32.c @@ -0,0 +1,281 @@ +/* $Id: sunos_ioctl32.c,v 1.1 1997/07/18 06:26:42 ralf Exp $ + * sunos_ioctl32.c: SunOS ioctl compatability on sparc64. + * + * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) + * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu) + */ + +#include <asm/uaccess.h> + +#include <linux/sched.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/termios.h> +#include <linux/ioctl.h> +#include <linux/route.h> +#include <linux/sockios.h> +#include <linux/if.h> +#include <linux/netdevice.h> +#include <linux/if_arp.h> +#include <linux/fs.h> +#include <linux/mm.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> +#include <asm/kbio.h> + +#define A(x) ((unsigned long)x) + +#define SUNOS_NR_OPEN 256 + +struct rtentry32 { + u32 rt_pad1; + struct sockaddr rt_dst; /* target address */ + struct sockaddr rt_gateway; /* gateway addr (RTF_GATEWAY) */ + struct sockaddr rt_genmask; /* target network mask (IP) */ + unsigned short rt_flags; + short rt_pad2; + u32 rt_pad3; + unsigned char rt_tos; + unsigned char rt_class; + short rt_pad4; + short rt_metric; /* +1 for binary compatibility! */ + /* char * */ u32 rt_dev; /* forcing the device at add */ + u32 rt_mtu; /* per route MTU/Window */ + u32 rt_window; /* Window clamping */ + unsigned short rt_irtt; /* Initial RTT */ + +}; + +struct ifmap32 { + u32 mem_start; + u32 mem_end; + unsigned short base_addr; + unsigned char irq; + unsigned char dma; + unsigned char port; +}; + +struct ifreq32 { +#define IFHWADDRLEN 6 +#define IFNAMSIZ 16 + union { + char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + } ifr_ifrn; + union { + struct sockaddr ifru_addr; + struct sockaddr ifru_dstaddr; + struct sockaddr ifru_broadaddr; + struct sockaddr ifru_netmask; + struct sockaddr ifru_hwaddr; + short ifru_flags; + int ifru_ivalue; + int ifru_mtu; + struct ifmap32 ifru_map; + char ifru_slave[IFNAMSIZ]; /* Just fits the size */ + __kernel_caddr_t32 ifru_data; + } ifr_ifru; +}; + +struct ifconf32 { + int ifc_len; /* size of buffer */ + __kernel_caddr_t32 ifcbuf; +}; + +extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); + +extern asmlinkage int sys32_ioctl(unsigned int, unsigned int, u32); +extern asmlinkage int sys_setsid(void); + +asmlinkage int sunos_ioctl (int fd, u32 cmd, u32 arg) +{ + struct file *filp; + int ret = -EBADF; + + lock_kernel(); + if(fd >= SUNOS_NR_OPEN) + goto out; + + filp = current->files->fd[fd]; + if(!filp) + goto out; + + if(cmd == TIOCSETD) { + unsigned long old_fs = get_fs(); + int *p, ntty = N_TTY; + int tmp; + + p = (int *)A(arg); + ret = -EFAULT; + if(get_user(tmp, p)) + goto out; + if(tmp == 2) { + set_fs(KERNEL_DS); + ret = sys_ioctl(fd, cmd, (unsigned long) &ntty); + set_fs(old_fs); + ret = (ret == -EINVAL ? -EOPNOTSUPP : ret); + goto out; + } + } + if(cmd == TIOCNOTTY) { + ret = sys_setsid(); + goto out; + } + switch(cmd) { + case _IOW('r', 10, struct rtentry32): + ret = sys32_ioctl(fd, SIOCADDRT, arg); + goto out; + case _IOW('r', 11, struct rtentry32): + ret = sys32_ioctl(fd, SIOCDELRT, arg); + goto out; + + case _IOW('i', 12, struct ifreq32): + ret = sys32_ioctl(fd, SIOCSIFADDR, arg); + goto out; + case _IOWR('i', 13, struct ifreq32): + ret = sys32_ioctl(fd, SIOCGIFADDR, arg); + goto out; + case _IOW('i', 14, struct ifreq32): + ret = sys32_ioctl(fd, SIOCSIFDSTADDR, arg); + goto out; + case _IOWR('i', 15, struct ifreq32): + ret = sys32_ioctl(fd, SIOCGIFDSTADDR, arg); + goto out; + case _IOW('i', 16, struct ifreq32): + ret = sys32_ioctl(fd, SIOCSIFFLAGS, arg); + goto out; + case _IOWR('i', 17, struct ifreq32): + ret = sys32_ioctl(fd, SIOCGIFFLAGS, arg); + goto out; + case _IOW('i', 18, struct ifreq32): + ret = sys32_ioctl(fd, SIOCSIFMEM, arg); + goto out; + case _IOWR('i', 19, struct ifreq32): + ret = sys32_ioctl(fd, SIOCGIFMEM, arg); + goto out; + + case _IOWR('i', 20, struct ifconf32): + ret = sys32_ioctl(fd, SIOCGIFCONF, arg); + goto out; + + case _IOW('i', 21, struct ifreq): /* SIOCSIFMTU */ + ret = sys_ioctl(fd, SIOCSIFMTU, arg); + goto out; + case _IOWR('i', 22, struct ifreq): /* SIOCGIFMTU */ + ret = sys_ioctl(fd, SIOCGIFMTU, arg); + goto out; + + case _IOWR('i', 23, struct ifreq32): + ret = sys32_ioctl(fd, SIOCGIFBRDADDR, arg); + goto out; + case _IOW('i', 24, struct ifreq32): + ret = sys32_ioctl(fd, SIOCGIFBRDADDR, arg); + goto out; + case _IOWR('i', 25, struct ifreq32): + ret = sys32_ioctl(fd, SIOCGIFNETMASK, arg); + goto out; + case _IOW('i', 26, struct ifreq32): + ret = sys32_ioctl(fd, SIOCSIFNETMASK, arg); + goto out; + case _IOWR('i', 27, struct ifreq32): + ret = sys32_ioctl(fd, SIOCGIFMETRIC, arg); + goto out; + case _IOW('i', 28, struct ifreq32): + ret = sys32_ioctl(fd, SIOCSIFMETRIC, arg); + goto out; + + case _IOW('i', 30, struct arpreq): + ret = sys32_ioctl(fd, SIOCSARP, arg); + goto out; + case _IOWR('i', 31, struct arpreq): + ret = sys32_ioctl(fd, SIOCGARP, arg); + goto out; + case _IOW('i', 32, struct arpreq): + ret = sys32_ioctl(fd, SIOCDARP, arg); + goto out; + + case _IOW('i', 40, struct ifreq32): /* SIOCUPPER */ + case _IOW('i', 41, struct ifreq32): /* SIOCLOWER */ + case _IOW('i', 44, struct ifreq32): /* SIOCSETSYNC */ + case _IOW('i', 45, struct ifreq32): /* SIOCGETSYNC */ + case _IOW('i', 46, struct ifreq32): /* SIOCSSDSTATS */ + case _IOW('i', 47, struct ifreq32): /* SIOCSSESTATS */ + case _IOW('i', 48, struct ifreq32): /* SIOCSPROMISC */ + ret = -EOPNOTSUPP; + goto out; + + case _IOW('i', 49, struct ifreq32): + ret = sys32_ioctl(fd, SIOCADDMULTI, arg); + goto out; + case _IOW('i', 50, struct ifreq32): + ret = sys32_ioctl(fd, SIOCDELMULTI, arg); + goto out; + + /* FDDI interface ioctls, unsupported. */ + + case _IOW('i', 51, struct ifreq32): /* SIOCFDRESET */ + case _IOW('i', 52, struct ifreq32): /* SIOCFDSLEEP */ + case _IOW('i', 53, struct ifreq32): /* SIOCSTRTFMWAR */ + case _IOW('i', 54, struct ifreq32): /* SIOCLDNSTRTFW */ + case _IOW('i', 55, struct ifreq32): /* SIOCGETFDSTAT */ + case _IOW('i', 56, struct ifreq32): /* SIOCFDNMIINT */ + case _IOW('i', 57, struct ifreq32): /* SIOCFDEXUSER */ + case _IOW('i', 58, struct ifreq32): /* SIOCFDGNETMAP */ + case _IOW('i', 59, struct ifreq32): /* SIOCFDGIOCTL */ + printk("FDDI ioctl, returning EOPNOTSUPP\n"); + ret = -EOPNOTSUPP; + goto out; + + case _IOW('t', 125, int): + /* More stupid tty sunos ioctls, just + * say it worked. + */ + ret = 0; + goto out; + + /* Non posix grp */ + case _IOW('t', 118, int): { + int oldval, newval, *ptr; + + cmd = TIOCSPGRP; + ptr = (int *) A(arg); + ret = -EFAULT; + if(get_user(oldval, ptr)) + goto out; + ret = sys32_ioctl(fd, cmd, arg); + __get_user(newval, ptr); + if(newval == -1) { + __put_user(oldval, ptr); + ret = -EIO; + } + if(ret == -ENOTTY) + ret = -EIO; + goto out; + } + + case _IOR('t', 119, int): { + int oldval, newval, *ptr; + + cmd = TIOCGPGRP; + ptr = (int *) A(arg); + ret = -EFAULT; + if(get_user(oldval, ptr)) + goto out; + ret = sys32_ioctl(fd, cmd, arg); + __get_user(newval, ptr); + if(newval == -1) { + __put_user(oldval, ptr); + ret = -EIO; + } + if(ret == -ENOTTY) + ret = -EIO; + goto out; + } + }; + + ret = sys32_ioctl(fd, cmd, arg); + /* so stupid... */ + ret = (ret == -EINVAL ? -EOPNOTSUPP : ret); +out: + unlock_kernel(); + return ret; +} diff --git a/arch/sparc64/kernel/sys32.S b/arch/sparc64/kernel/sys32.S new file mode 100644 index 000000000..ddd726069 --- /dev/null +++ b/arch/sparc64/kernel/sys32.S @@ -0,0 +1,427 @@ +/* $Id: sys32.S,v 1.1 1997/07/18 06:26:42 ralf Exp $ + * sys32.S: I-cache tricks for 32-bit compatability layer simple + * conversions. + * + * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + */ + + .text + + .align 32 + .globl sys32_mmap, sys32_mprotect, sys32_munmap, sys32_msync + .globl sys32_mlock, sys32_munlock, sys32_mremap, sparc32_brk +sys32_mmap: + srl %o0, 0, %o0 ! IEU0 Group + sethi %hi(0xffffffff), %g2 ! IEU1 + srl %o1, 0, %o1 ! IEU0 Group + or %g2, %lo(0xffffffff), %g2 ! IEU1 + srl %o2, 0, %o2 ! IEU0 Group + mov %o7, %g1 ! IEU1 + and %o3, %g2, %o3 ! IEU0 Group + and %o4, %g2, %o4 ! IEU1 + and %o5, %g2, %o5 ! IEU0 Group + call sys_mmap ! CTI Group brk forced + mov %g1, %o7 ! IEU0 Group (regdep) +sys32_mprotect: + srl %o0, 0, %o0 + mov %o7, %g1 + srl %o1, 0, %o1 + srl %o2, 0, %o2 + call sys_mprotect + mov %g1, %o7 +sys32_munmap: + srl %o0, 0, %o0 + mov %o7, %g1 + srl %o1, 0, %o1 + call sys_munmap + mov %g1, %o7 +sparc32_brk: + srl %o0, 0, %o0 + mov %o7, %g1 + call sys_brk + mov %g1, %o7 +sys32_msync: + srl %o0, 0, %o0 + mov %o7, %g1 + srl %o1, 0, %o1 + call sys_msync + mov %g1, %o7 +sys32_mlock: + srl %o0, 0, %o0 + mov %o7, %g1 + srl %o1, 0, %o1 + call sys_mlock + mov %g1, %o7 +sys32_munlock: + srl %o0, 0, %o0 + mov %o7, %g1 + srl %o1, 0, %o1 + call sys_munlock + mov %g1, %o7 +sys32_mremap: + srl %o0, 0, %o0 + mov %o7, %g1 + srl %o1, 0, %o1 + srl %o2, 0, %o2 + srl %o3, 0, %o3 + call sys_mremap + mov %g1, %o7 + + .align 32 + .globl sys32_read, sys32_write, sys32_open, sys32_access + .globl sys32_chdir, sys32_lseek, sys32_llseek, sys32_poll + .globl sys32_readlink, sys32_unlink, sys32_rmdir, sys32_symlink + .globl sys32_link, sys32_rename, sys32_truncate, sys32_ftruncate + .globl sys32_chroot, sys32_chmod, sys32_chown, sys32_creat + .globl sys32_mkdir, sys32_mknod, sys32_utimes, sys32_ustat +sys32_read: + srl %o1, 0, %o1 + mov %o7, %g1 + srl %o2, 0, %o2 + call sys_read + mov %g1, %o7 +sys32_write: + srl %o1, 0, %o1 + mov %o7, %g1 + srl %o2, 0, %o2 + call sys_write + mov %g1, %o7 +sys32_open: + srl %o0, 0, %o0 + mov %o7, %g1 + call sys_open + mov %g1, %o7 +sys32_access: + srl %o0, 0, %o0 + mov %o7, %g1 + call sys_access + mov %g1, %o7 +sys32_chdir: + srl %o0, 0, %o0 + mov %o7, %g1 + call sys_chdir + mov %g1, %o7 +sys32_lseek: + sra %o1, 0, %o1 + mov %o7, %g1 + call sys_lseek + mov %g1, %o7 +sys32_llseek: + srl %o1, 0, %o1 + mov %o7, %g1 + srl %o2, 0, %o2 + srl %o3, 0, %o3 + call sys_llseek + mov %g1, %o7 +sys32_poll: + srl %o0, 0, %o0 + mov %o7, %g1 + call sys_poll + mov %g1, %o7 +sys32_readlink: + srl %o0, 0, %o0 + mov %o7, %g1 + srl %o1, 0, %o1 + call sys_readlink + mov %g1, %o7 +sys32_unlink: + srl %o0, 0, %o0 + mov %o7, %g1 + call sys_unlink + mov %g1, %o7 +sys32_rmdir: + srl %o0, 0, %o0 + mov %o7, %g1 + call sys_rmdir + mov %g1, %o7 +sys32_symlink: + srl %o0, 0, %o0 + mov %o7, %g1 + srl %o1, 0, %o1 + call sys_symlink + mov %g1, %o7 +sys32_link: + srl %o0, 0, %o0 + mov %o7, %g1 + srl %o1, 0, %o1 + call sys_link + mov %g1, %o7 +sys32_rename: + srl %o0, 0, %o0 + mov %o7, %g1 + srl %o1, 0, %o1 + call sys_rename + mov %g1, %o7 + nop +sys32_truncate: + srl %o0, 0, %o0 + mov %o7, %g1 + srl %o1, 0, %o1 + call sys_truncate + mov %g1, %o7 +sys32_ftruncate: + srl %o1, 0, %o1 + mov %o7, %g1 + call sys_ftruncate + mov %g1, %o7 +sys32_chroot: + srl %o0, 0, %o0 + mov %o7, %g1 + call sys_chroot + mov %g1, %o7 +sys32_chmod: + sll %o1, 16, %o1 + mov %o7, %g1 + srl %o0, 0, %o0 + srl %o1, 16, %o1 + call sys_chmod + mov %g1, %o7 +sys32_chown: + sll %o1, 16, %o1 + mov %o7, %g1 + sll %o2, 16, %o2 + srl %o0, 0, %o0 + srl %o1, 16, %o1 + srl %o2, 16, %o2 + call sys_chown + mov %g1, %o7 +sys32_creat: + srl %o0, 0, %o0 + mov %o7, %g1 + call sys_creat + mov %g1, %o7 +sys32_mkdir: + srl %o0, 0, %o0 + mov %o7, %g1 + call sys_mkdir + mov %g1, %o7 +sys32_mknod: + sll %o2, 16, %o2 + mov %o7, %g1 + srl %o0, 0, %o0 + srl %o2, 16, %o2 + call sys_mknod + mov %g1, %o7 +sys32_utimes: + srl %o0, 0, %o0 + mov %o7, %g1 + srl %o1, 0, %o1 + call sys_utimes + mov %g1, %o7 +sys32_ustat: + srl %o1, 0, %o1 + mov %o7, %g1 + call sys_ustat + mov %g1, %o7 + + .align 32 + .globl sys32_bind, sys32_accept, sys32_connect, sys32_getsockname + .globl sys32_getpeername, sys32_send, sys32_sendto, sys32_recv + .globl sys32_recvfrom, sys32_setsockopt, sys32_getsockopt +sys32_bind: + srl %o1, 0, %o1 + mov %o7, %g1 + call sys_bind + mov %g1, %o7 +sys32_accept: + srl %o1, 0, %o1 + mov %o7, %g1 + srl %o2, 0, %o2 + call sys_accept + mov %g1, %o7 +sys32_connect: + srl %o1, 0, %o1 + mov %o7, %g1 + call sys_connect + mov %g1, %o7 +sys32_getsockname: + srl %o1, 0, %o1 + mov %o7, %g1 + srl %o2, 0, %o2 + call sys_getsockname + mov %g1, %o7 +sys32_getpeername: + srl %o1, 0, %o1 + mov %o7, %g1 + srl %o2, 0, %o2 + call sys_getpeername + mov %g1, %o7 +sys32_send: + srl %o1, 0, %o1 + mov %o7, %g1 + srl %o2, 0, %o2 + call sys_send + mov %g1, %o7 +sys32_sendto: + srl %o1, 0, %o1 + mov %o7, %g1 + srl %o2, 0, %o2 + srl %o4, 0, %o4 + call sys_sendto + mov %g1, %o7 +sys32_recv: + srl %o1, 0, %o1 + mov %o7, %g1 + srl %o2, 0, %o2 + call sys_recv + mov %g1, %o7 +sys32_recvfrom: + srl %o1, 0, %o1 + mov %o7, %g1 + srl %o2, 0, %o2 + srl %o4, 0, %o4 + srl %o5, 0, %o5 + call sys_recvfrom + mov %g1, %o7 +sys32_setsockopt: + srl %o3, 0, %o3 + mov %o7, %g1 + call sys_setsockopt + mov %g1, %o7 +sys32_getsockopt: + srl %o3, 0, %o3 + mov %o7, %g1 + srl %o4, 0, %o4 + call sys_setsockopt + mov %g1, %o7 + + .align 32 + .globl sys32_gettimeofday, sys32_settimeofday +sys32_gettimeofday: + srl %o0, 0, %o0 + mov %o7, %g1 + srl %o1, 0, %o1 + call sys_gettimeofday + mov %g1, %o7 +sys32_settimeofday: + srl %o0, 0, %o0 + mov %o7, %g1 + srl %o1, 0, %o1 + call sys_settimeofday + mov %g1, %o7 + + .globl sys32_bdflush, sys32_uselib, sys32_umount, sys32_syslog + .globl sys32_personality, sys32_waitpid, sys32_getitimer + .globl sys32_setitimer, sys32_sched_setscheduler + .globl sys32_sched_setparam, sys32_sched_getparam, sys32_signal + .globl sys32_reboot, sys32_acct, sys32_newuname, sys32_olduname + .globl sys32_sethostname, sys32_gethostname, sys32_setdomainname + .globl sys32_time, sys32_swapoff, sys32_swapon, sys32_nfsservctl + .globl sys32_create_module, sys32_init_module, sys32_delete_module +sys32_bdflush: + sra %o1, 0, %o1 + mov %o7, %g1 + call sys_bdflush + mov %g1, %o7 +sys32_uselib: + srl %o0, 0, %o0 + mov %o7, %g1 + call sys_uselib + mov %g1, %o7 +sys32_umount: + srl %o0, 0, %o0 + mov %o7, %g1 + call sys_umount + mov %g1, %o7 +sys32_syslog: + srl %o1, 0, %o1 + mov %o7, %g1 + call sys_syslog + mov %g1, %o7 +sys32_personality: + srl %o0, 0, %o0 + mov %o7, %g1 + call sys_personality + mov %g1, %o7 +sys32_waitpid: + srl %o1, 0, %o1 + mov %o7, %g1 + call sys_waitpid + mov %g1, %o7 +sys32_getitimer: + srl %o1, 0, %o1 + mov %o7, %g1 + call sys_getitimer + mov %g1, %o7 +sys32_setitimer: + srl %o1, 0, %o1 + mov %o7, %g1 + srl %o2, 0, %o2 + call sys_setitimer + mov %g1, %o7 +sys32_sched_setscheduler: + srl %o2, 0, %o2 + mov %o7, %g1 + call sys_sched_setscheduler + mov %g1, %o7 +sys32_sched_setparam: + srl %o1, 0, %o1 + mov %o7, %g1 + call sys_sched_setparam + mov %g1, %o7 +sys32_sched_getparam: + srl %o1, 0, %o1 + mov %o7, %g1 + call sys_sched_getparam + mov %g1, %o7 +sys32_signal: + srl %o1, 0, %o1 + mov %o7, %g1 + call sys_signal + mov %g1, %o7 +sys32_reboot: + srl %o3, 0, %o3 + mov %o7, %g1 + call sys_reboot + mov %g1, %o7 +sys32_acct: + srl %o0, 0, %o0 + mov %o7, %g1 + call sys_acct + mov %g1, %o7 +sys32_newuname: + srl %o0, 0, %o0 + mov %o7, %g1 + call sys_newuname + mov %g1, %o7 +sys32_olduname: + srl %o0, 0, %o0 + mov %o7, %g1 + call sys_olduname + mov %g1, %o7 +sys32_sethostname: + srl %o0, 0, %o0 + mov %o7, %g1 + call sys_sethostname + mov %g1, %o7 +sys32_gethostname: + srl %o0, 0, %o0 + mov %o7, %g1 + call sys_gethostname + mov %g1, %o7 +sys32_setdomainname: + srl %o0, 0, %o0 + mov %o7, %g1 + call sys_setdomainname + mov %g1, %o7 +sys32_time: + srl %o0, 0, %o0 + mov %o7, %g1 + call sys_time + mov %g1, %o7 +sys32_swapoff: + srl %o0, 0, %o0 + mov %o7, %g1 + call sys_swapoff + mov %g1, %o7 +sys32_swapon: + srl %o0, 0, %o0 + mov %o7, %g1 + call sys_swapon + mov %g1, %o7 +sys32_nfsservctl: + srl %o1, 0, %o1 + mov %o7, %g1 + srl %o2, 0, %o2 + call sys_nfsservctl + mov %g1, %o7 diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c index 851d1550c..c827df7a1 100644 --- a/arch/sparc64/kernel/sys_sparc.c +++ b/arch/sparc64/kernel/sys_sparc.c @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.1 1997/04/09 08:25:18 jj Exp $ +/* $Id: sys_sparc.c,v 1.2 1997/07/05 09:52:34 davem Exp $ * linux/arch/sparc64/kernel/sys_sparc.c * * This file contains various random system calls that @@ -9,7 +9,6 @@ #include <linux/errno.h> #include <linux/types.h> #include <linux/sched.h> -#include <linux/config.h> #include <linux/fs.h> #include <linux/mm.h> #include <linux/sem.h> diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index 59815b7a8..1f607da98 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -1,4 +1,4 @@ -/* $Id: sys_sparc32.c,v 1.26 1997/06/04 13:05:21 jj Exp $ +/* $Id: sys_sparc32.c,v 1.43 1997/07/17 02:20:45 davem Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -8,6 +8,7 @@ * environment. */ +#include <linux/config.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/signal.h> @@ -30,11 +31,13 @@ #include <linux/ncp_fs.h> #include <linux/quota.h> #include <linux/file.h> +#include <linux/module.h> #include <asm/types.h> #include <asm/poll.h> #include <asm/ipc.h> #include <asm/uaccess.h> +#include <asm/fpumacro.h> /* As gcc will warn about casting u32 to some ptr, we have to cast it to * unsigned long first, and that's what is A() for. @@ -372,11 +375,12 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u switch (version) { case 0: default: { unsigned long raddr; + u32 *uptr = (u32 *) A(((u32)third)); err = sys_shmat (first, (char *)A(ptr), second, &raddr); if (err) goto out; err = -EFAULT; - if(put_user (raddr, ((u32 *)A(third)))) + if(put_user (raddr, uptr)) goto out; err = 0; goto out; @@ -469,32 +473,6 @@ out: return err; } -extern asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long off); - -asmlinkage unsigned long sys32_mmap(u32 addr, u32 len, u32 prot, - u32 flags, u32 fd, u32 off) -{ - return sys_mmap((unsigned long)addr, (unsigned long)len, - (unsigned long)prot, (unsigned long)flags, - (unsigned long)fd, (unsigned long)off); -} - -extern asmlinkage int sys_bdflush(int func, long data); - -asmlinkage int sys32_bdflush(int func, s32 data) -{ - return sys_bdflush(func, (long)data); -} - -extern asmlinkage int sys_uselib(const char * library); - -asmlinkage int sys32_uselib(u32 library) -{ - return sys_uselib((const char *)A(library)); -} - static inline int get_flock(struct flock *kfl, struct flock32 *ufl) { if(get_user(kfl->l_type, &ufl->l_type) || @@ -544,55 +522,6 @@ asmlinkage long sys32_fcntl(unsigned int fd, unsigned int cmd, u32 arg) } } -extern asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev); - -asmlinkage int sys32_mknod(u32 filename, int mode, __kernel_dev_t32 dev) -{ - return sys_mknod((const char *)A(filename), mode, dev); -} - -extern asmlinkage int sys_mkdir(const char * pathname, int mode); - -asmlinkage int sys32_mkdir(u32 pathname, int mode) -{ - return sys_mkdir((const char *)A(pathname), mode); -} - -extern asmlinkage int sys_rmdir(const char * pathname); - -asmlinkage int sys32_rmdir(u32 pathname) -{ - return sys_rmdir((const char *)A(pathname)); -} - -extern asmlinkage int sys_unlink(const char * pathname); - -asmlinkage int sys32_unlink(u32 pathname) -{ - return sys_unlink((const char *)A(pathname)); -} - -extern asmlinkage int sys_symlink(const char * oldname, const char * newname); - -asmlinkage int sys32_symlink(u32 oldname, u32 newname) -{ - return sys_symlink((const char *)A(oldname), (const char *)A(newname)); -} - -extern asmlinkage int sys_link(const char * oldname, const char * newname); - -asmlinkage int sys32_link(u32 oldname, u32 newname) -{ - return sys_link((const char *)A(oldname), (const char *)A(newname)); -} - -extern asmlinkage int sys_rename(const char * oldname, const char * newname); - -asmlinkage int sys32_rename(u32 oldname, u32 newname) -{ - return sys_rename((const char *)A(oldname), (const char *)A(newname)); -} - struct dqblk32 { __u32 dqb_bhardlimit; __u32 dqb_bsoftlimit; @@ -701,20 +630,6 @@ asmlinkage int sys32_fstatfs(unsigned int fd, u32 buf) return ret; } -extern asmlinkage int sys_truncate(const char * path, unsigned long length); - -asmlinkage int sys32_truncate(u32 path, u32 length) -{ - return sys_truncate((const char *)A(path), (unsigned long)length); -} - -extern asmlinkage int sys_ftruncate(unsigned int fd, unsigned long length); - -asmlinkage int sys32_ftruncate(unsigned int fd, u32 length) -{ - return sys_ftruncate(fd, (unsigned long)length); -} - extern asmlinkage int sys_utime(char * filename, struct utimbuf * times); asmlinkage int sys32_utime(u32 filename, u32 times) @@ -741,96 +656,6 @@ asmlinkage int sys32_utime(u32 filename, u32 times) return ret; } -extern asmlinkage int sys_utimes(char * filename, struct timeval * utimes); - -asmlinkage int sys32_utimes(u32 filename, u32 utimes) -{ - /* struct timeval is the same :)) */ - return sys_utimes((char *)A(filename), (struct timeval *)A(utimes)); -} - -extern asmlinkage int sys_access(const char * filename, int mode); - -asmlinkage int sys32_access(u32 filename, int mode) -{ - return sys_access((const char *)A(filename), mode); -} - -extern asmlinkage int sys_chdir(const char * filename); - -asmlinkage int sys32_chdir(u32 filename) -{ - return sys_chdir((const char *)A(filename)); -} - -extern asmlinkage int sys_chroot(const char * filename); - -asmlinkage int sys32_chroot(u32 filename) -{ - return sys_chroot((const char *)A(filename)); -} - -extern asmlinkage int sys_chmod(const char * filename, mode_t mode); - -asmlinkage int sys32_chmod(u32 filename, __kernel_mode_t32 mode) -{ - return sys_chmod((const char *)A(filename), mode); -} - -extern asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group); - -asmlinkage int sys32_chown(u32 filename, __kernel_uid_t32 user, __kernel_gid_t32 group) -{ - return sys_chown((const char *)A(filename), user, group); -} - -extern asmlinkage int sys_open(const char * filename,int flags,int mode); - -asmlinkage int sys32_open(u32 filename, int flags, int mode) -{ - return sys_open((const char *)A(filename), flags, mode); -} - -extern asmlinkage int sys_creat(const char * pathname, int mode); - -asmlinkage int sys32_creat(u32 pathname, int mode) -{ - return sys_creat((const char *)A(pathname), mode); -} - -extern asmlinkage long sys_lseek(unsigned int fd, off_t offset, unsigned int origin); - -asmlinkage long sys32_lseek(unsigned int fd, s32 offset, unsigned int origin) -{ - return sys_lseek(fd, (off_t)offset, origin); -} - -extern asmlinkage int sys_llseek(unsigned int fd, unsigned long offset_high, - unsigned long offset_low, - loff_t *result, unsigned int origin); - -asmlinkage int sys32_llseek(unsigned int fd, u32 offset_high, - u32 offset_low, u32 result, unsigned int origin) -{ - /* loff_t is the same :)) */ - return sys_llseek(fd, (unsigned long)offset_high, (unsigned long)offset_low, - (loff_t *)A(result), origin); -} - -extern asmlinkage long sys_read(unsigned int fd, char * buf, unsigned long count); - -asmlinkage long sys32_read(unsigned int fd, u32 buf, u32 count) -{ - return sys_read(fd, (char *)A(buf), (unsigned long)count); -} - -extern asmlinkage long sys_write(unsigned int fd, const char * buf, unsigned long count); - -asmlinkage long sys32_write(unsigned int fd, u32 buf, u32 count) -{ - return sys_write(fd, (const char *)A(buf), (unsigned long)count); -} - struct iovec32 { u32 iov_base; __kernel_size_t32 iov_len; }; typedef long (*IO_fn_t)(struct inode *, struct file *, char *, unsigned long); @@ -934,14 +759,29 @@ static long do_readv_writev32(int type, struct inode *inode, struct file *file, asmlinkage long sys32_readv(int fd, u32 vector, u32 count) { struct file *file; + struct dentry *dentry; struct inode *inode; long err = -EBADF; lock_kernel(); - if (fd >= NR_OPEN || !(file = current->files->fd[fd]) || !(inode=file->f_inode)) + if(fd >= NR_OPEN) + goto out; + + file = current->files->fd[fd]; + if(!file) + goto out; + + if(!(file->f_mode & 1)) + goto out; + + dentry = file->f_dentry; + if(!dentry) goto out; - if (!(file->f_mode & 1)) + + inode = dentry->d_inode; + if(!inode) goto out; + err = do_readv_writev32(VERIFY_WRITE, inode, file, (struct iovec32 *)A(vector), count); out: @@ -953,13 +793,28 @@ asmlinkage long sys32_writev(int fd, u32 vector, u32 count) { int error = -EBADF; struct file *file; + struct dentry *dentry; struct inode *inode; lock_kernel(); - if (fd >= NR_OPEN || !(file = current->files->fd[fd]) || !(inode=file->f_inode)) + if(fd >= NR_OPEN) + goto out; + + file = current->files->fd[fd]; + if(!file) + goto out; + + if(!(file->f_mode & 2)) + goto out; + + dentry = file->f_dentry; + if(!dentry) goto out; - if (!(file->f_mode & 2)) + + inode = dentry->d_inode; + if(!inode) goto out; + down(&inode->i_sem); error = do_readv_writev32(VERIFY_READ, inode, file, (struct iovec32 *)A(vector), count); @@ -1008,21 +863,34 @@ asmlinkage int old32_readdir(unsigned int fd, u32 dirent, unsigned int count) { int error = -EBADF; struct file * file; + struct dentry * dentry; + struct inode * inode; struct readdir_callback32 buf; lock_kernel(); - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) + if(fd >= NR_OPEN) goto out; - error = -ENOTDIR; - if (!file->f_op || !file->f_op->readdir) + + file = current->files->fd[fd]; + if(!file) goto out; - error = verify_area(VERIFY_WRITE, (void *)A(dirent), - sizeof(struct old_linux_dirent32)); - if (error) + + dentry = file->f_dentry; + if(!dentry) + goto out; + + inode = dentry->d_inode; + if(!inode) goto out; + buf.count = 0; buf.dirent = (struct old_linux_dirent32 *)A(dirent); - error = file->f_op->readdir(file->f_inode, file, &buf, fillonedir); + + error = -ENOTDIR; + if (!file->f_op || !file->f_op->readdir) + goto out; + + error = file->f_op->readdir(inode, file, &buf, fillonedir); if (error < 0) goto out; error = buf.count; @@ -1072,30 +940,43 @@ static int filldir(void * __buf, const char * name, int namlen, off_t offset, in asmlinkage int sys32_getdents(unsigned int fd, u32 dirent, unsigned int count) { struct file * file; + struct dentry * dentry; + struct inode *inode; struct linux_dirent32 * lastdirent; struct getdents_callback32 buf; int error = -EBADF; lock_kernel(); - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) + if(fd >= NR_OPEN) goto out; - error = -ENOTDIR; - if (!file->f_op || !file->f_op->readdir) + + file = current->files->fd[fd]; + if(!file) + goto out; + + dentry = file->f_dentry; + if(!dentry) goto out; - error = verify_area(VERIFY_WRITE, (void *)A(dirent), count); - if (error) + + inode = dentry->d_inode; + if(!inode) goto out; + buf.current_dir = (struct linux_dirent32 *) A(dirent); buf.previous = NULL; buf.count = count; buf.error = 0; - error = file->f_op->readdir(file->f_inode, file, &buf, filldir); + + error = -ENOTDIR; + if (!file->f_op || !file->f_op->readdir) + goto out; + + error = file->f_op->readdir(inode, file, &buf, filldir); if (error < 0) goto out; lastdirent = buf.previous; - if (!lastdirent) { - error = buf.error; - } else { + error = buf.error; + if(lastdirent) { put_user(file->f_pos, &lastdirent->d_off); error = count - buf.count; } @@ -1196,13 +1077,6 @@ out: return ret; } -extern asmlinkage int sys_poll(struct pollfd * ufds, unsigned int nfds, int timeout); - -asmlinkage int sys32_poll(u32 ufds, unsigned int nfds, int timeout) -{ - return sys_poll((struct pollfd *)A(ufds), nfds, timeout); -} - static inline int putstat(struct stat32 *ubuf, struct stat *kbuf) { if (put_user (kbuf->st_dev, &ubuf->st_dev) || @@ -1280,13 +1154,6 @@ asmlinkage int sys32_newfstat(unsigned int fd, u32 statbuf) return ret; } -extern asmlinkage int sys_readlink(const char * path, char * buf, int bufsiz); - -asmlinkage int sys32_readlink(u32 path, u32 buf, int bufsiz) -{ - return sys_readlink((const char *)A(path), (char *)A(buf), bufsiz); -} - extern asmlinkage int sys_sysfs(int option, ...); asmlinkage int sys32_sysfs(int option, ...) @@ -1312,42 +1179,162 @@ asmlinkage int sys32_sysfs(int option, ...) return ret; } -extern asmlinkage int sys_ustat(dev_t dev, struct ustat * ubuf); +struct ncp_mount_data32 { + int version; + unsigned int ncp_fd; + __kernel_uid_t32 mounted_uid; + __kernel_pid_t32 wdog_pid; + unsigned char mounted_vol[NCP_VOLNAME_LEN + 1]; + unsigned int time_out; + unsigned int retry_count; + unsigned int flags; + __kernel_uid_t32 uid; + __kernel_gid_t32 gid; + __kernel_mode_t32 file_mode; + __kernel_mode_t32 dir_mode; +}; -asmlinkage int sys32_ustat(dev_t dev, u32 ubuf) +static void *do_ncp_super_data_conv(void *raw_data) { - /* ustat is the same :)) */ - return sys_ustat(dev, (struct ustat *)A(ubuf)); + struct ncp_mount_data *n = (struct ncp_mount_data *)raw_data; + struct ncp_mount_data32 *n32 = (struct ncp_mount_data32 *)raw_data; + + n->dir_mode = n32->dir_mode; + n->file_mode = n32->file_mode; + n->gid = n32->gid; + n->uid = n32->uid; + memmove (n->mounted_vol, n32->mounted_vol, (sizeof (n32->mounted_vol) + 3 * sizeof (unsigned int))); + n->wdog_pid = n32->wdog_pid; + n->mounted_uid = n32->mounted_uid; + return raw_data; } -extern asmlinkage int sys_umount(char * name); +struct smb_mount_data32 { + int version; + unsigned int fd; + __kernel_uid_t32 mounted_uid; + struct sockaddr_in addr; + char server_name[17]; + char client_name[17]; + char service[64]; + char root_path[64]; + char username[64]; + char password[64]; + char domain[64]; + unsigned short max_xmit; + __kernel_uid_t32 uid; + __kernel_gid_t32 gid; + __kernel_mode_t32 file_mode; + __kernel_mode_t32 dir_mode; +}; -asmlinkage int sys32_umount(u32 name) +static void *do_smb_super_data_conv(void *raw_data) { - return sys_umount((char *)A(name)); -} + struct smb_mount_data *s = (struct smb_mount_data *)raw_data; + struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data; -extern asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type, - unsigned long new_flags, void *data); + s->dir_mode = s32->dir_mode; + s->file_mode = s32->file_mode; + s->gid = s32->gid; + s->uid = s32->uid; + memmove (&s->addr, &s32->addr, (((long)&s->uid) - ((long)&s->addr))); + s->mounted_uid = s32->mounted_uid; + return raw_data; +} -asmlinkage int sys32_mount(u32 dev_name, u32 dir_name, u32 type, u32 new_flags, u32 data) +static int copy_mount_stuff_to_kernel(const void *user, unsigned long *kernel) { - return sys_mount((char *)A(dev_name), (char *)A(dir_name), (char *)A(type), - (unsigned long)new_flags, (void *)A(data)); + int i; + unsigned long page; + struct vm_area_struct *vma; + + *kernel = 0; + if(!user) + return 0; + vma = find_vma(current->mm, (unsigned long)user); + if(!vma || (unsigned long)user < vma->vm_start) + return -EFAULT; + if(!(vma->vm_flags & VM_READ)) + return -EFAULT; + i = vma->vm_end - (unsigned long) user; + if(PAGE_SIZE <= (unsigned long) i) + i = PAGE_SIZE - 1; + if(!(page = __get_free_page(GFP_KERNEL))) + return -ENOMEM; + if(copy_from_user((void *) page, user, i)) { + free_page(page); + return -EFAULT; + } + *kernel = page; + return 0; } -extern asmlinkage int sys_syslog(int type, char * bug, int count); +extern asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type, + unsigned long new_flags, void *data); + +#define SMBFS_NAME "smbfs" +#define NCPFS_NAME "ncpfs" -asmlinkage int sys32_syslog(int type, u32 bug, int count) +asmlinkage int sys32_mount(u32 dev_name, u32 dir_name, u32 type, u32 new_flags, u32 data) { - return sys_syslog(type, (char *)A(bug), count); -} + unsigned long type_page; + int err, is_smb, is_ncp; -extern asmlinkage int sys_personality(unsigned long personality); + if(!suser()) + return -EPERM; + is_smb = is_ncp = 0; + err = copy_mount_stuff_to_kernel((const void *)A(type), &type_page); + if(err) + return err; + if(type_page) { + is_smb = !strcmp((char *)type_page, SMBFS_NAME); + is_ncp = !strcmp((char *)type_page, NCPFS_NAME); + } + if(!is_smb && !is_ncp) { + if(type_page) + free_page(type_page); + return sys_mount((char *)A(dev_name), (char *)A(dir_name), + (char *)A(type), (unsigned long)new_flags, + (void *)A(data)); + } else { + unsigned long dev_page, dir_page, data_page; + int old_fs; -asmlinkage int sys32_personality(u32 personality) -{ - return sys_personality((unsigned long)personality); + err = copy_mount_stuff_to_kernel((const void *)A(dev_name), &dev_page); + if(err) + goto out; + err = copy_mount_stuff_to_kernel((const void *)A(dir_name), &dir_page); + if(err) + goto dev_out; + err = copy_mount_stuff_to_kernel((const void *)A(data), &data_page); + if(err) + goto dir_out; + if(is_ncp) + do_ncp_super_data_conv((void *)data_page); + else if(is_smb) + do_smb_super_data_conv((void *)data_page); + else + panic("Tell DaveM he fucked up..."); + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_mount((char *)dev_page, (char *)dir_page, + (char *)type_page, (unsigned long)new_flags, + (void *)data_page); + set_fs(old_fs); + + if(data_page) + free_page(data_page); + dir_out: + if(dir_page) + free_page(dir_page); + dev_out: + if(dev_page) + free_page(dev_page); + out: + if(type_page) + free_page(type_page); + return err; + } } struct rusage32 { @@ -1416,13 +1403,6 @@ asmlinkage int sys32_wait4(__kernel_pid_t32 pid, u32 stat_addr, int options, u32 } } -extern asmlinkage int sys_waitpid(pid_t pid,unsigned int * stat_addr, int options); - -asmlinkage int sys32_waitpid(__kernel_pid_t32 pid, u32 stat_addr, int options) -{ - return sys_waitpid(pid, (unsigned int *)A(stat_addr), options); -} - struct sysinfo32 { s32 uptime; u32 loads[3]; @@ -1462,46 +1442,6 @@ asmlinkage int sys32_sysinfo(u32 info) return ret; } -extern asmlinkage int sys_getitimer(int which, struct itimerval *value); - -asmlinkage int sys32_getitimer(int which, u32 value) -{ - /* itimerval is the same :)) */ - return sys_getitimer(which, (struct itimerval *)A(value)); -} - -extern asmlinkage int sys_setitimer(int which, struct itimerval *value, - struct itimerval *ovalue); - -asmlinkage int sys32_setitimer(int which, u32 value, u32 ovalue) -{ - return sys_setitimer(which, (struct itimerval *)A(value), - (struct itimerval *)A(ovalue)); -} - -extern asmlinkage int sys_sched_setscheduler(pid_t pid, int policy, - struct sched_param *param); - -asmlinkage int sys32_sched_setscheduler(__kernel_pid_t32 pid, int policy, u32 param) -{ - /* sched_param is the same :)) */ - return sys_sched_setscheduler(pid, policy, (struct sched_param *)A(param)); -} - -extern asmlinkage int sys_sched_setparam(pid_t pid, struct sched_param *param); - -asmlinkage int sys32_sched_setparam(__kernel_pid_t32 pid, u32 param) -{ - return sys_sched_setparam(pid, (struct sched_param *)A(param)); -} - -extern asmlinkage int sys_sched_getparam(pid_t pid, struct sched_param *param); - -asmlinkage int sys32_sched_getparam(__kernel_pid_t32 pid, u32 param) -{ - return sys_sched_getparam(pid, (struct sched_param *)A(param)); -} - struct timespec32 { s32 tv_sec; s32 tv_nsec; @@ -1577,25 +1517,29 @@ asmlinkage int sys32_sigpending(u32 set) return ret; } -extern asmlinkage unsigned long sys_signal(int signum, __sighandler_t handler); +extern asmlinkage int sys_setreuid(uid_t ruid, uid_t euid); -asmlinkage unsigned long sys32_signal(int signum, u32 handler) +asmlinkage int sys32_setreuid(__kernel_uid_t32 ruid, __kernel_uid_t32 euid) { - return sys_signal(signum, (__sighandler_t)A(handler)); -} - -extern asmlinkage int sys_reboot(int magic1, int magic2, int cmd, void * arg); + uid_t sruid, seuid; -asmlinkage int sys32_reboot(int magic1, int magic2, int cmd, u32 arg) -{ - return sys_reboot(magic1, magic2, cmd, (void *)A(arg)); + sruid = (ruid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)ruid); + seuid = (euid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)euid); + return sys_setreuid(sruid, seuid); } -extern asmlinkage int sys_acct(const char *name); +extern asmlinkage int sys_setresuid(uid_t ruid, uid_t euid, uid_t suid); -asmlinkage int sys32_acct(u32 name) +asmlinkage int sys32_setresuid(__kernel_uid_t32 ruid, + __kernel_uid_t32 euid, + __kernel_uid_t32 suid) { - return sys_acct((const char *)A(name)); + uid_t sruid, seuid, ssuid; + + sruid = (ruid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)ruid); + seuid = (euid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)euid); + ssuid = (suid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)suid); + return sys_setresuid(sruid, seuid, ssuid); } extern asmlinkage int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); @@ -1654,7 +1598,7 @@ asmlinkage int sys32_getgroups(int gidsetsize, u32 grouplist) set_fs (KERNEL_DS); ret = sys_getgroups(gidsetsize, gl); set_fs (old_fs); - if (ret > 0 && ret <= NGROUPS) + if (gidsetsize && ret > 0 && ret <= NGROUPS) for (i = 0; i < ret; i++, grouplist += sizeof(__kernel_gid_t32)) if (__put_user (gl[i], (__kernel_gid_t32 *)A(grouplist))) return -EFAULT; @@ -1680,41 +1624,8 @@ asmlinkage int sys32_setgroups(int gidsetsize, u32 grouplist) return ret; } -extern asmlinkage int sys_newuname(struct new_utsname * name); - -asmlinkage int sys32_newuname(u32 name) -{ - /* utsname is the same :)) */ - return sys_newuname((struct new_utsname *)A(name)); -} - -extern asmlinkage int sys_olduname(struct oldold_utsname * name); - -asmlinkage int sys32_olduname(u32 name) -{ - return sys_olduname((struct oldold_utsname *)A(name)); -} - -extern asmlinkage int sys_sethostname(char *name, int len); - -asmlinkage int sys32_sethostname(u32 name, int len) -{ - return sys_sethostname((char *)A(name), len); -} - -extern asmlinkage int sys_gethostname(char *name, int len); - -asmlinkage int sys32_gethostname(u32 name, int len) -{ - return sys_gethostname((char *)A(name), len); -} - -extern asmlinkage int sys_setdomainname(char *name, int len); - -asmlinkage int sys32_setdomainname(u32 name, int len) -{ - return sys_setdomainname((char *)A(name), len); -} +#define RLIM_INFINITY32 0x7fffffff +#define RESOURCE32(x) ((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x) struct rlimit32 { s32 rlim_cur; @@ -1733,8 +1644,8 @@ asmlinkage int sys32_getrlimit(unsigned int resource, u32 rlim) ret = sys_getrlimit(resource, &r); set_fs (old_fs); if (!ret && ( - put_user (r.rlim_cur, &(((struct rlimit32 *)A(rlim))->rlim_cur)) || - __put_user (r.rlim_max, &(((struct rlimit32 *)A(rlim))->rlim_max)))) + put_user (RESOURCE32(r.rlim_cur), &(((struct rlimit32 *)A(rlim))->rlim_cur)) || + __put_user (RESOURCE32(r.rlim_max), &(((struct rlimit32 *)A(rlim))->rlim_max)))) return -EFAULT; return ret; } @@ -1751,6 +1662,10 @@ asmlinkage int sys32_setrlimit(unsigned int resource, u32 rlim) if (get_user (r.rlim_cur, &(((struct rlimit32 *)A(rlim))->rlim_cur)) || __get_user (r.rlim_max, &(((struct rlimit32 *)A(rlim))->rlim_max))) return -EFAULT; + if (r.rlim_cur == RLIM_INFINITY32) + r.rlim_cur = RLIM_INFINITY; + if (r.rlim_max == RLIM_INFINITY32) + r.rlim_max = RLIM_INFINITY; set_fs (KERNEL_DS); ret = sys_setrlimit(resource, &r); set_fs (old_fs); @@ -1772,28 +1687,6 @@ asmlinkage int sys32_getrusage(int who, u32 ru) return ret; } -extern asmlinkage int sys_time(int * tloc); - -asmlinkage int sys32_time(u32 tloc) -{ - return sys_time((int *)A(tloc)); -} - -extern asmlinkage int sys_gettimeofday(struct timeval *tv, struct timezone *tz); - -asmlinkage int sys32_gettimeofday(u32 tv, u32 tz) -{ - /* both timeval and timezone are ok :)) */ - return sys_gettimeofday((struct timeval *)A(tv), (struct timezone *)A(tz)); -} - -extern asmlinkage int sys_settimeofday(struct timeval *tv, struct timezone *tz); - -asmlinkage int sys32_settimeofday(u32 tv, u32 tz) -{ - return sys_settimeofday((struct timeval *)A(tv), (struct timezone *)A(tz)); -} - struct timex32 { unsigned int modes; s32 offset; @@ -1865,170 +1758,6 @@ asmlinkage int sys32_adjtimex(u32 txc_p) return ret; } -extern asmlinkage int sys_msync(unsigned long start, size_t len, int flags); - -asmlinkage int sys32_msync(u32 start, __kernel_size_t32 len, int flags) -{ - return sys_msync((unsigned long)start, (size_t)len, flags); -} - -extern asmlinkage int sys_mlock(unsigned long start, size_t len); - -asmlinkage int sys32_mlock(u32 start, __kernel_size_t32 len) -{ - return sys_mlock((unsigned long)start, (size_t)len); -} - -extern asmlinkage int sys_munlock(unsigned long start, size_t len); - -asmlinkage int sys32_munlock(u32 start, __kernel_size_t32 len) -{ - return sys_munlock((unsigned long)start, (size_t)len); -} - -extern asmlinkage unsigned long sys_brk(unsigned long brk); - -asmlinkage unsigned long sparc32_brk(u32 brk) -{ - return sys_brk((unsigned long)brk); -} - -extern asmlinkage int sys_munmap(unsigned long addr, size_t len); - -asmlinkage int sys32_munmap(u32 addr, __kernel_size_t32 len) -{ - return sys_munmap((unsigned long)addr, (size_t)len); -} - -extern asmlinkage int sys_mprotect(unsigned long start, size_t len, unsigned long prot); - -asmlinkage int sys32_mprotect(u32 start, __kernel_size_t32 len, u32 prot) -{ - return sys_mprotect((unsigned long)start, (size_t)len, (unsigned long)prot); -} - -extern asmlinkage unsigned long sys_mremap(unsigned long addr, unsigned long old_len, - unsigned long new_len, unsigned long flags); - -asmlinkage unsigned long sys32_mremap(u32 addr, u32 old_len, u32 new_len, u32 flags) -{ - return sys_mremap((unsigned long)addr, (unsigned long)old_len, - (unsigned long)new_len, (unsigned long)flags); -} - -extern asmlinkage int sys_swapoff(const char * specialfile); - -asmlinkage int sys32_swapoff(u32 specialfile) -{ - return sys_swapoff((const char *)A(specialfile)); -} - -extern asmlinkage int sys_swapon(const char * specialfile, int swap_flags); - -asmlinkage int sys32_swapon(u32 specialfile, int swap_flags) -{ - return sys_swapon((const char *)A(specialfile), swap_flags); -} - -extern asmlinkage int sys_bind(int fd, struct sockaddr *umyaddr, int addrlen); - -asmlinkage inline int sys32_bind(int fd, u32 umyaddr, int addrlen) -{ - /* sockaddr is the same :)) */ - return sys_bind(fd, (struct sockaddr *)A(umyaddr), addrlen); -} - -extern asmlinkage int sys_accept(int fd, struct sockaddr *upeer_sockaddr, - int *upeer_addrlen); - -asmlinkage inline int sys32_accept(int fd, u32 upeer_sockaddr, u32 upeer_addrlen) -{ - return sys_accept(fd, (struct sockaddr *)A(upeer_sockaddr), - (int *)A(upeer_addrlen)); -} - -extern asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen); - -asmlinkage inline int sys32_connect(int fd, u32 uservaddr, int addrlen) -{ - return sys_connect(fd, (struct sockaddr *)A(uservaddr), addrlen); -} - -extern asmlinkage int sys_getsockname(int fd, struct sockaddr *usockaddr, - int *usockaddr_len); - -asmlinkage int sys32_getsockname(int fd, u32 usockaddr, u32 usockaddr_len) -{ - return sys_getsockname(fd, (struct sockaddr *)A(usockaddr), - (int *)A(usockaddr_len)); -} - -extern asmlinkage int sys_getpeername(int fd, struct sockaddr *usockaddr, - int *usockaddr_len); - -asmlinkage int sys32_getpeername(int fd, u32 usockaddr, u32 usockaddr_len) -{ - return sys_getpeername(fd, (struct sockaddr *)A(usockaddr), - (int *)A(usockaddr_len)); -} - -extern asmlinkage int sys_send(int fd, void * buff, size_t len, unsigned flags); - -asmlinkage inline int sys32_send(int fd, u32 buff, - __kernel_size_t32 len, unsigned flags) -{ - return sys_send(fd, (void *)A(buff), (size_t)len, flags); -} - -extern asmlinkage int sys_sendto(int fd, void * buff, size_t len, unsigned flags, - struct sockaddr *addr, int addr_len); - -asmlinkage inline int sys32_sendto(int fd, u32 buff, __kernel_size_t32 len, - unsigned flags, u32 addr, int addr_len) -{ - return sys_sendto(fd, (void *)A(buff), (size_t)len, flags, - (struct sockaddr *)A(addr), addr_len); -} - -extern asmlinkage int sys_recv(int fd, void * ubuf, size_t size, unsigned flags); - -asmlinkage inline int sys32_recv(int fd, u32 ubuf, - __kernel_size_t32 size, unsigned flags) -{ - return sys_recv(fd, (void *)A(ubuf), (size_t)size, flags); -} - -extern asmlinkage int sys_recvfrom(int fd, void * ubuf, size_t size, unsigned flags, - struct sockaddr *addr, int *addr_len); - -asmlinkage inline int sys32_recvfrom(int fd, u32 ubuf, __kernel_size_t32 size, - unsigned flags, u32 addr, u32 addr_len) -{ - return sys_recvfrom(fd, (void *)A(ubuf), (size_t)size, flags, - (struct sockaddr *)A(addr), (int *)A(addr_len)); -} - -extern asmlinkage int sys_setsockopt(int fd, int level, int optname, - char *optval, int optlen); - -asmlinkage inline int sys32_setsockopt(int fd, int level, int optname, - u32 optval, int optlen) -{ - /* XXX handle ip_fw32->ip_fw conversion for IP firewalling and accounting. - Do it using some macro in ip_sockglue.c - Other optval arguments are mostly just ints or 32<->64bit transparent */ - return sys_setsockopt(fd, level, optname, (char *)A(optval), optlen); -} - -extern asmlinkage int sys_getsockopt(int fd, int level, int optname, - char *optval, int *optlen); - -asmlinkage inline int sys32_getsockopt(int fd, int level, int optname, - u32 optval, u32 optlen) -{ - return sys_getsockopt(fd, level, optname, (char *)A(optval), (int *)A(optlen)); -} - /* XXX This really belongs in some header file... -DaveM */ #define MAX_SOCK_ADDR 128 /* 108 for Unix domain - 16 for IP, 16 for IPX, @@ -2052,11 +1781,11 @@ extern __inline__ struct socket *sockfd_lookup(int fd, int *err) return NULL; } - inode = file->f_inode; + inode = file->f_dentry->d_inode; if (!inode || !inode->i_sock || !socki_lookup(inode)) { *err = -ENOTSOCK; - fput(file,inode); + fput(file); return NULL; } @@ -2065,7 +1794,7 @@ extern __inline__ struct socket *sockfd_lookup(int fd, int *err) extern __inline__ void sockfd_put(struct socket *sock) { - fput(sock->file,sock->inode); + fput(sock->file); } struct msghdr32 { @@ -2293,6 +2022,24 @@ static unsigned char nargs[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)}; #undef AL +extern asmlinkage int sys32_bind(int fd, u32 umyaddr, int addrlen); +extern asmlinkage int sys32_connect(int fd, u32 uservaddr, int addrlen); +extern asmlinkage int sys32_accept(int fd, u32 upeer_sockaddr, u32 upeer_addrlen); +extern asmlinkage int sys32_getsockname(int fd, u32 usockaddr, u32 usockaddr_len); +extern asmlinkage int sys32_getpeername(int fd, u32 usockaddr, u32 usockaddr_len); +extern asmlinkage int sys32_send(int fd, u32 buff, __kernel_size_t32 len, + unsigned flags); +extern asmlinkage int sys32_sendto(int fd, u32 buff, __kernel_size_t32 len, + unsigned flags, u32 addr, int addr_len); +extern asmlinkage int sys32_recv(int fd, u32 ubuf, __kernel_size_t32 size, + unsigned flags); +extern asmlinkage int sys32_recvfrom(int fd, u32 ubuf, __kernel_size_t32 size, + unsigned flags, u32 addr, u32 addr_len); +extern asmlinkage int sys32_setsockopt(int fd, int level, int optname, + u32 optval, int optlen); +extern asmlinkage int sys32_getsockopt(int fd, int level, int optname, + u32 optval, u32 optlen); + extern asmlinkage int sys_socket(int family, int type, int protocol); extern asmlinkage int sys_socketpair(int family, int type, int protocol, int usockvec[2]); @@ -2389,7 +2136,7 @@ asmlinkage int sparc32_sigaction (int signum, u32 action, u32 oldaction) old_sa.sa_mask = (sigset_t32)(p->sa_mask); old_sa.sa_flags = (unsigned)(p->sa_flags); old_sa.sa_restorer = (unsigned)(u64)(p->sa_restorer); - if (copy_to_user(A(oldaction), p, sizeof(struct sigaction32))) + if (copy_to_user(A(oldaction), &old_sa, sizeof(struct sigaction32))) goto out; } @@ -2407,14 +2154,6 @@ out: return err; } -extern asmlinkage int sys_nfsservctl(int cmd, void *argp, void *resp); - -asmlinkage int sys32_nfsservctl(int cmd, u32 argp, u32 resp) -{ - /* XXX handle argp and resp args */ - return sys_nfsservctl(cmd, (void *)A(argp), (void *)A(resp)); -} - /* * count32() counts the number of arguments/envelopes */ @@ -2485,25 +2224,33 @@ static inline int do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs) { struct linux_binprm bprm; + struct dentry * dentry; int retval; int i; bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *); for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */ bprm.page[i] = 0; - retval = open_namei(filename, 0, 0, &bprm.inode, NULL); - if (retval) + + dentry = open_namei(filename, 0, 0); + retval = PTR_ERR(dentry); + if (IS_ERR(dentry)) return retval; + + bprm.dentry = dentry; bprm.filename = filename; bprm.sh_bang = 0; bprm.java = 0; bprm.loader = 0; bprm.exec = 0; - bprm.dont_iput = 0; - if ((bprm.argc = count32(argv)) < 0) + if ((bprm.argc = count32(argv)) < 0) { + dput(dentry); return bprm.argc; - if ((bprm.envc = count32(envp)) < 0) + } + if ((bprm.envc = count32(envp)) < 0) { + dput(dentry); return bprm.envc; + } retval = prepare_binprm(&bprm); @@ -2523,8 +2270,9 @@ do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs) return retval; /* Something went wrong, return the inode and free the argument pages*/ - if(!bprm.dont_iput) - iput(bprm.inode); + if(bprm.dentry) + dput(bprm.dentry); + for (i=0 ; i<MAX_ARG_PAGES ; i++) free_page(bprm.page[i]); return(retval); @@ -2543,81 +2291,231 @@ asmlinkage int sparc32_execve(struct pt_regs *regs) if((u32)regs->u_regs[UREG_G1] == 0) base = 1; - error = getname((char *)(unsigned long)(u32)regs->u_regs[base + UREG_I0], &filename); - if(error) - return error; + lock_kernel(); + filename = getname((char *)(unsigned long)(u32)regs->u_regs[base + UREG_I0]); + error = PTR_ERR(filename); + if(IS_ERR(filename)) + goto out; error = do_execve32(filename, (u32 *)A((u32)regs->u_regs[base + UREG_I1]), (u32 *)A((u32)regs->u_regs[base + UREG_I2]), regs); putname(filename); + + if(!error) { + fprs_write(0); + regs->fprs = 0; + } +out: + unlock_kernel(); return error; } -/* Modules will be supported with 64bit modutils only */ -asmlinkage int sys32_no_modules(void) +#ifdef CONFIG_MODULES + +extern asmlinkage unsigned long sys_create_module(const char *name_user, size_t size); + +asmlinkage unsigned long sys32_create_module(u32 name_user, __kernel_size_t32 size) { - return -ENOSYS; + return sys_create_module((const char *)A(name_user), (size_t)size); } -struct ncp_mount_data32 { - int version; - unsigned int ncp_fd; - __kernel_uid_t32 mounted_uid; - __kernel_pid_t32 wdog_pid; - unsigned char mounted_vol[NCP_VOLNAME_LEN + 1]; - unsigned int time_out; - unsigned int retry_count; - unsigned int flags; - __kernel_uid_t32 uid; - __kernel_gid_t32 gid; - __kernel_mode_t32 file_mode; - __kernel_mode_t32 dir_mode; -}; +extern asmlinkage int sys_init_module(const char *name_user, struct module *mod_user); -void *do_ncp_super_data_conv(void *raw_data) +/* Hey, when you're trying to init module, take time and prepare us a nice 64bit + * module structure, even if from 32bit modutils... Why to pollute kernel... :)) + */ +asmlinkage int sys32_init_module(u32 nameuser, u32 mod_user) { - struct ncp_mount_data *n = (struct ncp_mount_data *)raw_data; - struct ncp_mount_data32 *n32 = (struct ncp_mount_data32 *)raw_data; + return sys_init_module((const char *)A(nameuser), (struct module *)A(mod_user)); +} - n->dir_mode = n32->dir_mode; - n->file_mode = n32->file_mode; - n->gid = n32->gid; - n->uid = n32->uid; - memmove (n->mounted_vol, n32->mounted_vol, (sizeof (n32->mounted_vol) + 3 * sizeof (unsigned int))); - n->wdog_pid = n32->wdog_pid; - n->mounted_uid = n32->mounted_uid; - return raw_data; +extern asmlinkage int sys_delete_module(const char *name_user); + +asmlinkage int sys32_delete_module(u32 name_user) +{ + return sys_delete_module((const char *)A(name_user)); } -struct smb_mount_data32 { - int version; - unsigned int fd; - __kernel_uid_t32 mounted_uid; - struct sockaddr_in addr; - char server_name[17]; - char client_name[17]; - char service[64]; - char root_path[64]; - char username[64]; - char password[64]; - char domain[64]; - unsigned short max_xmit; - __kernel_uid_t32 uid; - __kernel_gid_t32 gid; - __kernel_mode_t32 file_mode; - __kernel_mode_t32 dir_mode; +struct module_info32 { + u32 addr; + u32 size; + u32 flags; + s32 usecount; }; -void *do_smb_super_data_conv(void *raw_data) +extern asmlinkage int sys_query_module(const char *name_user, int which, char *buf, size_t bufsize, size_t *ret); + +asmlinkage int sys32_query_module(u32 name_user, int which, u32 buf, __kernel_size_t32 bufsize, u32 retv) { - struct smb_mount_data *s = (struct smb_mount_data *)raw_data; - struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data; + char *buff; + unsigned long old_fs = get_fs(); + size_t val; + int ret, i, j; + unsigned long *p; + char *usernam = NULL; + int bufsiz = bufsize; + struct module_info mi; + + switch (which) { + case 0: return sys_query_module ((const char *)A(name_user), which, (char *)A(buf), (size_t)bufsize, (size_t *)A(retv)); + case QM_SYMBOLS: + bufsiz <<= 1; + case QM_MODULES: + case QM_REFS: + case QM_DEPS: + if (name_user && (ret = getname32 (name_user, &usernam))) + return ret; + buff = kmalloc (bufsiz, GFP_KERNEL); + if (!buff) { + if (name_user) putname32 (usernam); + return -ENOMEM; + } +qmsym_toshort: + set_fs (KERNEL_DS); + ret = sys_query_module (usernam, which, buff, bufsiz, &val); + set_fs (old_fs); + if (which != QM_SYMBOLS) { + if (ret == -ENOSPC || !ret) { + if (put_user (val, (__kernel_size_t32 *)A(retv))) + ret = -EFAULT; + } + if (!ret) { + if (copy_to_user ((char *)A(buf), buff, bufsize)) + ret = -EFAULT; + } + } else { + if (ret == -ENOSPC) { + if (put_user (2 * val, (__kernel_size_t32 *)A(retv))) + ret = -EFAULT; + } + p = (unsigned long *)buff; + if (!ret) { + if (put_user (val, (__kernel_size_t32 *)A(retv))) + ret = -EFAULT; + } + if (!ret) { + j = val * 8; + for (i = 0; i < val; i++, p += 2) { + if (bufsize < (2 * sizeof (u32))) { + bufsiz = 0; + goto qmsym_toshort; + } + if (put_user (p[0], (u32 *)A(buf)) || + __put_user (p[1] - j, (((u32 *)A(buf))+1))) { + ret = -EFAULT; + break; + } + bufsize -= (2 * sizeof (u32)); + buf += (2 * sizeof (u32)); + } + } + if (!ret && val) { + char *strings = buff + ((unsigned long *)buff)[1]; + j = *(p - 1) - ((unsigned long *)buff)[1]; + j = j + strlen (buff + j) + 1; + if (bufsize < j) { + bufsiz = 0; + goto qmsym_toshort; + } + if (copy_to_user ((char *)A(buf), strings, j)) + ret = -EFAULT; + } + } + kfree (buff); + if (name_user) putname32 (usernam); + return ret; + case QM_INFO: + if (name_user && (ret = getname32 (name_user, &usernam))) + return ret; + set_fs (KERNEL_DS); + ret = sys_query_module (usernam, which, (char *)&mi, sizeof (mi), &val); + set_fs (old_fs); + if (!ret) { + if (put_user (sizeof (struct module_info32), (__kernel_size_t32 *)A(retv))) + ret = -EFAULT; + else if (bufsize < sizeof (struct module_info32)) + ret = -ENOSPC; + } + if (!ret) { + if (put_user (mi.addr, &(((struct module_info32 *)A(buf))->addr)) || + __put_user (mi.size, &(((struct module_info32 *)A(buf))->size)) || + __put_user (mi.flags, &(((struct module_info32 *)A(buf))->flags)) || + __put_user (mi.usecount, &(((struct module_info32 *)A(buf))->usecount))) + ret = -EFAULT; + } + if (name_user) putname32 (usernam); + return ret; + default: + return -EINVAL; + } +} - s->dir_mode = s32->dir_mode; - s->file_mode = s32->file_mode; - s->gid = s32->gid; - s->uid = s32->uid; - memmove (&s->addr, &s32->addr, (((long)&s->uid) - ((long)&s->addr))); - s->mounted_uid = s32->mounted_uid; - return raw_data; +struct kernel_sym32 { + u32 value; + char name[60]; +}; + +extern asmlinkage int sys_get_kernel_syms(struct kernel_sym *table); + +asmlinkage int sys32_get_kernel_syms(u32 table) +{ + int len, i; + struct kernel_sym *tbl; + unsigned long old_fs; + + len = sys_get_kernel_syms(NULL); + if (!table) return len; + tbl = kmalloc (len * sizeof (struct kernel_sym), GFP_KERNEL); + if (!tbl) return -ENOMEM; + old_fs = get_fs(); + set_fs (KERNEL_DS); + sys_get_kernel_syms(tbl); + set_fs (old_fs); + for (i = 0; i < len; i++, table += sizeof (struct kernel_sym32)) { + if (put_user (tbl[i].value, &(((struct kernel_sym32 *)A(table))->value)) || + copy_to_user (((struct kernel_sym32 *)A(table))->name, tbl[i].name, 60)) + break; + } + kfree (tbl); + return i; +} + +#else /* CONFIG_MODULES */ + +asmlinkage unsigned long +sys_create_module(const char *name_user, size_t size) +{ + return -ENOSYS; +} + +asmlinkage int +sys_init_module(const char *name_user, struct module *mod_user) +{ + return -ENOSYS; } + +asmlinkage int +sys_delete_module(const char *name_user) +{ + return -ENOSYS; +} + +asmlinkage int +sys_query_module(const char *name_user, int which, char *buf, size_t bufsize, + size_t *ret) +{ + /* Let the program know about the new interface. Not that + it'll do them much good. */ + if (which == 0) + return 0; + + return -ENOSYS; +} + +asmlinkage int +sys_get_kernel_syms(struct kernel_sym *table) +{ + return -ENOSYS; +} + +#endif /* CONFIG_MODULES */ diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c new file mode 100644 index 000000000..3dfdad5a7 --- /dev/null +++ b/arch/sparc64/kernel/sys_sunos32.c @@ -0,0 +1,1511 @@ +/* $Id: sys_sunos32.c,v 1.1 1997/07/18 06:26:43 ralf Exp $ + * sys_sunos32.c: SunOS binary compatability layer on sparc64. + * + * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) + * + * Based upon preliminary work which is: + * + * Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu) + */ + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/types.h> +#include <linux/mman.h> +#include <linux/mm.h> +#include <linux/swap.h> +#include <linux/fs.h> +#include <linux/resource.h> +#include <linux/ipc.h> +#include <linux/shm.h> +#include <linux/msg.h> +#include <linux/sem.h> +#include <linux/signal.h> +#include <linux/uio.h> +#include <linux/utsname.h> +#include <linux/fs.h> +#include <linux/major.h> +#include <linux/stat.h> +#include <linux/malloc.h> +#include <linux/pagemap.h> +#include <linux/errno.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> + +#include <asm/uaccess.h> +#include <asm/page.h> +#include <asm/pgtable.h> +#include <asm/pconf.h> +#include <asm/idprom.h> /* for gethostid() */ +#include <asm/unistd.h> +#include <asm/system.h> + +/* For the nfs mount emulation */ +#include <linux/socket.h> +#include <linux/in.h> +#include <linux/nfs.h> +#include <linux/nfs_mount.h> + +/* for sunos_select */ +#include <linux/time.h> +#include <linux/personality.h> + +#define A(x) ((unsigned long)x) + +#define SUNOS_NR_OPEN 256 + +extern unsigned long get_unmapped_area(unsigned long addr, unsigned long len); + +asmlinkage u32 sunos_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 off) +{ + struct file *file = NULL; + unsigned long retval, ret_type; + + lock_kernel(); + current->personality |= PER_BSD; + if(flags & MAP_NORESERVE) { + printk("%s: unimplemented SunOS MAP_NORESERVE mmap() flag\n", + current->comm); + flags &= ~MAP_NORESERVE; + } + retval = -EBADF; + if(!(flags & MAP_ANONYMOUS)) + if(fd >= SUNOS_NR_OPEN || !(file = current->files->fd[fd])) + goto out; + retval = -ENOMEM; + if(!(flags & MAP_FIXED) && !addr) { + unsigned long attempt = get_unmapped_area(addr, len); + if(!attempt || (attempt >= 0xf0000000UL)) + goto out; + addr = (u32) attempt; + } + if(file->f_dentry && file->f_dentry->d_inode) { + if(MAJOR(file->f_dentry->d_inode->i_rdev) == MEM_MAJOR && + MINOR(file->f_dentry->d_inode->i_rdev) == 5) { + flags |= MAP_ANONYMOUS; + file = 0; + } + } + if(!(flags & MAP_FIXED)) + addr = 0; + ret_type = flags & _MAP_NEW; + flags &= ~_MAP_NEW; + + retval = do_mmap(file, + (unsigned long) addr, (unsigned long) len, + (unsigned long) prot, (unsigned long) flags, + (unsigned long) off); + if(!ret_type) + retval = ((retval < 0xf0000000) ? 0 : retval); +out: + unlock_kernel(); + return (u32) retval; +} + +asmlinkage int sunos_mctl(u32 addr, u32 len, int function, u32 arg) +{ + return 0; +} + +asmlinkage int sunos_brk(u32 baddr) +{ + int freepages, retval = -ENOMEM; + unsigned long rlim; + unsigned long newbrk, oldbrk, brk = (unsigned long) baddr; + + lock_kernel(); + if (brk < current->mm->end_code) + goto out; + newbrk = PAGE_ALIGN(brk); + oldbrk = PAGE_ALIGN(current->mm->brk); + retval = 0; + if (oldbrk == newbrk) { + current->mm->brk = brk; + goto out; + } + /* Always allow shrinking brk. */ + if (brk <= current->mm->brk) { + current->mm->brk = brk; + do_munmap(newbrk, oldbrk-newbrk); + goto out; + } + /* Check against rlimit and stack.. */ + retval = -ENOMEM; + rlim = current->rlim[RLIMIT_DATA].rlim_cur; + if (rlim >= RLIM_INFINITY) + rlim = ~0; + if (brk - current->mm->end_code > rlim) + goto out; + /* Check against existing mmap mappings. */ + if (find_vma_intersection(current->mm, oldbrk, newbrk+PAGE_SIZE)) + goto out; + /* stupid algorithm to decide if we have enough memory: while + * simple, it hopefully works in most obvious cases.. Easy to + * fool it, but this should catch most mistakes. + */ + freepages = buffermem >> PAGE_SHIFT; + freepages += page_cache_size; + freepages >>= 1; + freepages += nr_free_pages; + freepages += nr_swap_pages; + freepages -= num_physpages >> 4; + freepages -= (newbrk-oldbrk) >> PAGE_SHIFT; + if (freepages < 0) + goto out; + /* Ok, we have probably got enough memory - let it rip. */ + current->mm->brk = brk; + do_mmap(NULL, oldbrk, newbrk-oldbrk, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_FIXED|MAP_PRIVATE, 0); + retval = 0; +out: + unlock_kernel(); + return retval; +} + +asmlinkage u32 sunos_sbrk(int increment) +{ + int error, oldbrk; + + /* This should do it hopefully... */ + lock_kernel(); + oldbrk = (int)current->mm->brk; + error = sunos_brk(((int) current->mm->brk) + increment); + if(!error) + error = oldbrk; + unlock_kernel(); + return error; +} + +asmlinkage u32 sunos_sstk(int increment) +{ + lock_kernel(); + printk("%s: Call to sunos_sstk(increment<%d>) is unsupported\n", + current->comm, increment); + unlock_kernel(); + return (u32)-1; +} + +/* Give hints to the kernel as to what paging strategy to use... + * Completely bogus, don't remind me. + */ +#define VA_NORMAL 0 /* Normal vm usage expected */ +#define VA_ABNORMAL 1 /* Abnormal/random vm usage probable */ +#define VA_SEQUENTIAL 2 /* Accesses will be of a sequential nature */ +#define VA_INVALIDATE 3 /* Page table entries should be flushed ??? */ +static char *vstrings[] = { + "VA_NORMAL", + "VA_ABNORMAL", + "VA_SEQUENTIAL", + "VA_INVALIDATE", +}; + +asmlinkage void sunos_vadvise(u32 strategy) +{ + /* I wanna see who uses this... */ + lock_kernel(); + printk("%s: Advises us to use %s paging strategy\n", + current->comm, + strategy <= 3 ? vstrings[strategy] : "BOGUS"); + unlock_kernel(); +} + +/* Same as vadvise, and just as bogus, but for a range of virtual + * process address space. + */ +#define MADV_NORMAL 0 /* Nothing special... */ +#define MADV_RANDOM 1 /* I am emacs... */ +#define MADV_SEQUENTIAL 2 /* I am researcher code... */ +#define MADV_WILLNEED 3 /* Pages in this range will be needed */ +#define MADV_DONTNEED 4 /* Pages in this range won't be needed */ + +static char *mstrings[] = { + "MADV_NORMAL", + "MADV_RANDOM", + "MADV_SEQUENTIAL", + "MADV_WILLNEED", + "MADV_DONTNEED", +}; + +asmlinkage void sunos_madvise(u32 address, u32 len, u32 strategy) +{ + /* I wanna see who uses this... */ + lock_kernel(); + printk("%s: Advises us to use %s paging strategy for addr<%08x> len<%08x>\n", + current->comm, strategy <= 4 ? mstrings[strategy] : "BOGUS", + address, len); + unlock_kernel(); +} + +/* Places into character array, the status of all the pages in the passed + * range from 'addr' to 'addr + len'. -1 on failure, 0 on success... + * The encoding in each character is: + * low-bit is zero == Page is not in physical ram right now + * low-bit is one == Page is currently residing in core + * All other bits are undefined within the character so there... + * Also, if you try to get stats on an area outside of the user vm area + * *or* the passed base address is not aligned on a page boundary you + * get an error. + */ +asmlinkage int sunos_mincore(u32 addr, u32 len, u32 u_array) +{ + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + unsigned long limit; + int num_pages, pnum, retval = -EINVAL; + char *array = (char *)A(u_array); + + lock_kernel(); + if(addr & ~(4096)) + goto out; + num_pages = (len / 4096); + retval = -EFAULT; + if(verify_area(VERIFY_WRITE, array, num_pages)) + goto out; + retval = -ENOMEM; + if((addr >= 0xf0000000) || ((addr + len) > 0xf0000000)) + goto out; /* I'm sure you're curious about kernel mappings.. */ + /* Wheee, go through pte's */ + pnum = 0; + for(limit = addr + len; addr < limit; addr += 4096, pnum++) { + pgdp = pgd_offset(current->mm, addr); + if(pgd_none(*pgdp)) + goto out; /* As per SunOS manpage */ + pmdp = pmd_offset(pgdp, addr); + if(pmd_none(*pmdp)) + goto out; /* As per SunOS manpage */ + ptep = pte_offset(pmdp, addr); + if(pte_none(*ptep)) + goto out; /* As per SunOS manpage */ + /* Page in core or Swapped page? */ + __put_user((pte_present(*ptep) ? 1 : 0), &array[pnum]); + } + retval = 0; /* Success... I think... */ +out: + unlock_kernel(); + return retval; +} + +/* This just wants the soft limit (ie. rlim_cur element) of the RLIMIT_NOFILE + * resource limit and is for backwards compatibility with older sunos + * revs. + */ +asmlinkage int sunos_getdtablesize(void) +{ + return SUNOS_NR_OPEN; +} + +#define _S(nr) (1<<((nr)-1)) + +#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) + +asmlinkage u32 sunos_sigblock(u32 blk_mask) +{ + unsigned long flags; + u32 old; + + lock_kernel(); + save_and_cli(flags); + old = (u32) current->blocked; + current->blocked |= (blk_mask & _BLOCKABLE); + restore_flags(flags); + unlock_kernel(); + return old; +} + +asmlinkage u32 sunos_sigsetmask(u32 newmask) +{ + unsigned long flags; + u32 retval; + + lock_kernel(); + save_and_cli(flags); + retval = (u32) current->blocked; + current->blocked = (newmask & _BLOCKABLE); + restore_flags(flags); + unlock_kernel(); + return retval; +} + +/* SunOS getdents is very similar to the newer Linux (iBCS2 compliant) */ +/* getdents system call, the format of the structure just has a different */ +/* layout (d_off+d_ino instead of d_ino+d_off) */ +struct sunos_dirent { + s32 d_off; + u32 d_ino; + u16 d_reclen; + u16 d_namlen; + char d_name[1]; +}; + +struct sunos_dirent_callback { + struct sunos_dirent *curr; + struct sunos_dirent *previous; + int count; + int error; +}; + +#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de))) +#define ROUND_UP(x) (((x)+sizeof(s32)-1) & ~(sizeof(s32)-1)) + +static int sunos_filldir(void * __buf, const char * name, int namlen, + off_t offset, ino_t ino) +{ + struct sunos_dirent * dirent; + struct sunos_dirent_callback * buf = (struct sunos_dirent_callback *) __buf; + int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1); + + buf->error = -EINVAL; /* only used if we fail.. */ + if (reclen > buf->count) + return -EINVAL; + dirent = buf->previous; + if (dirent) + put_user(offset, &dirent->d_off); + dirent = buf->curr; + buf->previous = dirent; + put_user(ino, &dirent->d_ino); + put_user(namlen, &dirent->d_namlen); + put_user(reclen, &dirent->d_reclen); + copy_to_user(dirent->d_name, name, namlen); + put_user(0, dirent->d_name + namlen); + ((char *) dirent) += reclen; + buf->curr = dirent; + buf->count -= reclen; + return 0; +} + +asmlinkage int sunos_getdents(unsigned int fd, u32 u_dirent, int cnt) +{ + struct file * file; + struct dentry * dentry; + struct inode * inode; + struct sunos_dirent * lastdirent; + struct sunos_dirent_callback buf; + int error = -EBADF; + void *dirent = (void *)A(u_dirent); + + lock_kernel(); + if(fd >= SUNOS_NR_OPEN) + goto out; + + file = current->files->fd[fd]; + if(!file) + goto out; + + dentry = file->f_dentry; + if(!dentry) + goto out; + + inode = dentry->d_inode; + if(!inode) + goto out; + + error = -ENOTDIR; + if (!file->f_op || !file->f_op->readdir) + goto out; + + error = -EINVAL; + if(cnt < (sizeof(struct sunos_dirent) + 255)) + goto out; + + buf.curr = (struct sunos_dirent *) dirent; + buf.previous = NULL; + buf.count = cnt; + buf.error = 0; + + error = file->f_op->readdir(inode, file, &buf, sunos_filldir); + if (error < 0) + goto out; + lastdirent = buf.previous; + error = buf.error; + if (lastdirent) { + put_user(file->f_pos, &lastdirent->d_off); + error = cnt - buf.count; + } +out: + unlock_kernel(); + return error; +} + +/* Old sunos getdirentries, severely broken compatibility stuff here. */ +struct sunos_direntry { + u32 d_ino; + u16 d_reclen; + u16 d_namlen; + char d_name[1]; +}; + +struct sunos_direntry_callback { + struct sunos_direntry *curr; + struct sunos_direntry *previous; + int count; + int error; +}; + +static int sunos_filldirentry(void * __buf, const char * name, int namlen, + off_t offset, ino_t ino) +{ + struct sunos_direntry * dirent; + struct sunos_direntry_callback * buf = (struct sunos_direntry_callback *) __buf; + int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1); + + buf->error = -EINVAL; /* only used if we fail.. */ + if (reclen > buf->count) + return -EINVAL; + dirent = buf->previous; + dirent = buf->curr; + buf->previous = dirent; + put_user(ino, &dirent->d_ino); + put_user(namlen, &dirent->d_namlen); + put_user(reclen, &dirent->d_reclen); + copy_to_user(dirent->d_name, name, namlen); + put_user(0, dirent->d_name + namlen); + ((char *) dirent) += reclen; + buf->curr = dirent; + buf->count -= reclen; + return 0; +} + +asmlinkage int sunos_getdirentries(unsigned int fd, u32 u_dirent, + int cnt, u32 u_basep) +{ + struct file * file; + struct dentry * dentry; + struct inode * inode; + struct sunos_direntry * lastdirent; + struct sunos_direntry_callback buf; + int error = -EBADF; + void *dirent = (void *) A(u_dirent); + unsigned int *basep = (unsigned int *)A(u_basep); + + lock_kernel(); + if(fd >= SUNOS_NR_OPEN) + goto out; + + file = current->files->fd[fd]; + if(!file) + goto out; + + dentry = file->f_dentry; + if(!dentry) + goto out; + + inode = dentry->d_inode; + if(!inode) + goto out; + + error = -ENOTDIR; + if (!file->f_op || !file->f_op->readdir) + goto out; + + error = -EINVAL; + if(cnt < (sizeof(struct sunos_direntry) + 255)) + goto out; + + buf.curr = (struct sunos_direntry *) dirent; + buf.previous = NULL; + buf.count = cnt; + buf.error = 0; + + error = file->f_op->readdir(inode, file, &buf, sunos_filldirentry); + if (error < 0) + goto out; + lastdirent = buf.previous; + error = buf.error; + if (lastdirent) { + put_user(file->f_pos, basep); + error = cnt - buf.count; + } +out: + unlock_kernel(); + return error; +} + +asmlinkage int sunos_getdomainname(u32 u_name, int len) +{ + int nlen = strlen(system_utsname.domainname); + int ret = -EFAULT; + char *name = (char *)A(u_name); + + lock_kernel(); + if (nlen < len) + len = nlen; + + if(len > __NEW_UTS_LEN) + goto out; + if(copy_to_user(name, system_utsname.domainname, len)) + goto out; + ret = 0; +out: + unlock_kernel(); + return ret; +} + +struct sunos_utsname { + char sname[9]; + char nname[9]; + char nnext[56]; + char rel[9]; + char ver[9]; + char mach[9]; +}; + +asmlinkage int sunos_uname(u32 u_name) +{ + struct sunos_utsname *name = (struct sunos_utsname *)A(u_name); + int ret = -EFAULT; + + lock_kernel(); + if(!name) + goto out; + if(copy_to_user(&name->sname[0], + &system_utsname.sysname[0], + sizeof(name->sname) - 1)) + goto out; + copy_to_user(&name->nname[0], + &system_utsname.nodename[0], + sizeof(name->nname) - 1); + put_user('\0', &name->nname[8]); + copy_to_user(&name->rel[0], &system_utsname.release[0], sizeof(name->rel) - 1); + copy_to_user(&name->ver[0], &system_utsname.version[0], sizeof(name->ver) - 1); + copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1); + ret = 0; +out: + unlock_kernel(); + return ret; +} + +asmlinkage int sunos_nosys(void) +{ + struct pt_regs *regs; + + lock_kernel(); + regs = current->tss.kregs; + current->tss.sig_address = regs->tpc; + current->tss.sig_desc = regs->u_regs[UREG_G1]; + send_sig(SIGSYS, current, 1); + printk("Process makes ni_syscall number %d, register dump:\n", + (int) regs->u_regs[UREG_G1]); + show_regs(regs); + unlock_kernel(); + return -ENOSYS; +} + +/* This is not a real and complete implementation yet, just to keep + * the easy SunOS binaries happy. + */ +asmlinkage int sunos_fpathconf(int fd, int name) +{ + int ret; + + lock_kernel(); + switch(name) { + case _PCONF_LINK: + ret = LINK_MAX; + break; + case _PCONF_CANON: + ret = MAX_CANON; + break; + case _PCONF_INPUT: + ret = MAX_INPUT; + break; + case _PCONF_NAME: + ret = NAME_MAX; + break; + case _PCONF_PATH: + ret = PATH_MAX; + break; + case _PCONF_PIPE: + ret = PIPE_BUF; + break; + case _PCONF_CHRESTRICT: /* XXX Investigate XXX */ + ret = 1; + break; + case _PCONF_NOTRUNC: /* XXX Investigate XXX */ + case _PCONF_VDISABLE: + ret = 0; + break; + default: + ret = -EINVAL; + break; + } + unlock_kernel(); + return ret; +} + +asmlinkage int sunos_pathconf(u32 u_path, int name) +{ + int ret; + + lock_kernel(); + ret = sunos_fpathconf(0, name); /* XXX cheese XXX */ + unlock_kernel(); + return ret; +} + +/* SunOS mount system call emulation */ +extern asmlinkage int +sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp); + +asmlinkage int sunos_select(int width, u32 inp, u32 outp, u32 exp, u32 tvp) +{ + int ret; + + /* SunOS binaries expect that select won't change the tvp contents */ + lock_kernel(); + current->personality |= STICKY_TIMEOUTS; + ret = sys32_select (width, inp, outp, exp, tvp); + unlock_kernel(); + return ret; +} + +asmlinkage void sunos_nop(void) +{ + return; +} + +/* XXXXXXXXXX SunOS mount/umount. XXXXXXXXXXX */ +#define SMNT_RDONLY 1 +#define SMNT_NOSUID 2 +#define SMNT_NEWTYPE 4 +#define SMNT_GRPID 8 +#define SMNT_REMOUNT 16 +#define SMNT_NOSUB 32 +#define SMNT_MULTI 64 +#define SMNT_SYS5 128 + +struct sunos_fh_t { + char fh_data [NFS_FHSIZE]; +}; + +struct sunos_nfs_mount_args { + struct sockaddr_in *addr; /* file server address */ + struct nfs_fh *fh; /* File handle to be mounted */ + int flags; /* flags */ + int wsize; /* write size in bytes */ + int rsize; /* read size in bytes */ + int timeo; /* initial timeout in .1 secs */ + int retrans; /* times to retry send */ + char *hostname; /* server's hostname */ + int acregmin; /* attr cache file min secs */ + int acregmax; /* attr cache file max secs */ + int acdirmin; /* attr cache dir min secs */ + int acdirmax; /* attr cache dir max secs */ + char *netname; /* server's netname */ +}; + +extern int do_mount(kdev_t, const char *, const char *, char *, int, void *); +extern dev_t get_unnamed_dev(void); +extern void put_unnamed_dev(dev_t); +extern asmlinkage int sys_mount(char *, char *, char *, unsigned long, void *); +extern asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen); +extern asmlinkage int sys_socket(int family, int type, int protocol); +extern asmlinkage int sys_bind(int fd, struct sockaddr *umyaddr, int addrlen); + + +/* Bind the socket on a local reserved port and connect it to the + * remote server. This on Linux/i386 is done by the mount program, + * not by the kernel. + */ +/* XXXXXXXXXXXXXXXXXXXX */ +static int +sunos_nfs_get_server_fd (int fd, struct sockaddr_in *addr) +{ + struct sockaddr_in local; + struct sockaddr_in server; + int try_port; + int ret; + struct socket *socket; + struct dentry *dentry; + struct inode *inode; + struct file *file; + + file = current->files->fd [fd]; + if(!file) + return 0; + + dentry = file->f_dentry; + if(!dentry) + return 0; + + inode = dentry->d_inode; + if(!inode) + return 0; + + socket = &inode->u.socket_i; + local.sin_family = AF_INET; + local.sin_addr.s_addr = INADDR_ANY; + + /* IPPORT_RESERVED = 1024, can't find the definition in the kernel */ + try_port = 1024; + do { + local.sin_port = htons (--try_port); + ret = socket->ops->bind(socket, (struct sockaddr*)&local, + sizeof(local)); + } while (ret && try_port > (1024 / 2)); + + if (ret) + return 0; + + server.sin_family = AF_INET; + server.sin_addr = addr->sin_addr; + server.sin_port = NFS_PORT; + + /* Call sys_connect */ + ret = socket->ops->connect (socket, (struct sockaddr *) &server, + sizeof (server), file->f_flags); + if (ret < 0) + return 0; + return 1; +} + +/* XXXXXXXXXXXXXXXXXXXX */ +static int get_default (int value, int def_value) +{ + if (value) + return value; + else + return def_value; +} + +/* XXXXXXXXXXXXXXXXXXXX */ +asmlinkage int sunos_nfs_mount(char *dir_name, int linux_flags, void *data) +{ + int ret = -ENODEV; + int server_fd; + char *the_name; + struct nfs_mount_data linux_nfs_mount; + struct sunos_nfs_mount_args *sunos_mount = data; + dev_t dev; + + /* Ok, here comes the fun part: Linux's nfs mount needs a + * socket connection to the server, but SunOS mount does not + * require this, so we use the information on the destination + * address to create a socket and bind it to a reserved + * port on this system + */ + server_fd = sys_socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (server_fd < 0) + return -ENXIO; + + if (!sunos_nfs_get_server_fd (server_fd, sunos_mount->addr)){ + sys_close (server_fd); + return -ENXIO; + } + + /* Now, bind it to a locally reserved port */ + linux_nfs_mount.version = NFS_MOUNT_VERSION; + linux_nfs_mount.flags = sunos_mount->flags; + linux_nfs_mount.addr = *sunos_mount->addr; + linux_nfs_mount.root = *sunos_mount->fh; + linux_nfs_mount.fd = server_fd; + + linux_nfs_mount.rsize = get_default (sunos_mount->rsize, 8192); + linux_nfs_mount.wsize = get_default (sunos_mount->wsize, 8192); + linux_nfs_mount.timeo = get_default (sunos_mount->timeo, 10); + linux_nfs_mount.retrans = sunos_mount->retrans; + + linux_nfs_mount.acregmin = sunos_mount->acregmin; + linux_nfs_mount.acregmax = sunos_mount->acregmax; + linux_nfs_mount.acdirmin = sunos_mount->acdirmin; + linux_nfs_mount.acdirmax = sunos_mount->acdirmax; + + the_name = getname(sunos_mount->hostname); + if(IS_ERR(the_name)) + return -EFAULT; + + strncpy (linux_nfs_mount.hostname, the_name, 254); + linux_nfs_mount.hostname [255] = 0; + putname (the_name); + + dev = get_unnamed_dev (); + + ret = do_mount (dev, "", dir_name, "nfs", linux_flags, &linux_nfs_mount); + if (ret) + put_unnamed_dev(dev); + + return ret; +} + +/* XXXXXXXXXXXXXXXXXXXX */ +asmlinkage int +sunos_mount(char *type, char *dir, int flags, void *data) +{ + int linux_flags = MS_MGC_MSK; /* new semantics */ + int ret = -EINVAL; + char *dev_fname = 0; + + lock_kernel(); + /* We don't handle the integer fs type */ + if ((flags & SMNT_NEWTYPE) == 0) + goto out; + + /* Do not allow for those flags we don't support */ + if (flags & (SMNT_GRPID|SMNT_NOSUB|SMNT_MULTI|SMNT_SYS5)) + goto out; + + if(flags & SMNT_REMOUNT) + linux_flags |= MS_REMOUNT; + if(flags & SMNT_RDONLY) + linux_flags |= MS_RDONLY; + if(flags & SMNT_NOSUID) + linux_flags |= MS_NOSUID; + if(strcmp(type, "ext2") == 0) { + dev_fname = (char *) data; + } else if(strcmp(type, "iso9660") == 0) { + dev_fname = (char *) data; + } else if(strcmp(type, "minix") == 0) { + dev_fname = (char *) data; + } else if(strcmp(type, "nfs") == 0) { + ret = sunos_nfs_mount (dir, flags, data); + goto out; + } else if(strcmp(type, "ufs") == 0) { + printk("Warning: UFS filesystem mounts unsupported.\n"); + ret = -ENODEV; + goto out; + } else if(strcmp(type, "proc")) { + ret = -ENODEV; + goto out; + } + ret = sys_mount(dev_fname, dir, type, linux_flags, NULL); +out: + unlock_kernel(); + return ret; +} + +extern asmlinkage int sys_setsid(void); +extern asmlinkage int sys_setpgid(pid_t, pid_t); + +asmlinkage int sunos_setpgrp(pid_t pid, pid_t pgid) +{ + int ret; + + /* So stupid... */ + lock_kernel(); + if((!pid || pid == current->pid) && + !pgid) { + sys_setsid(); + ret = 0; + } else { + ret = sys_setpgid(pid, pgid); + } + unlock_kernel(); + return ret; +} + +/* So stupid... */ +extern asmlinkage int sys32_wait4(__kernel_pid_t32 pid, + u32 stat_addr, int options, u32 ru); + +asmlinkage int sunos_wait4(__kernel_pid_t32 pid, u32 stat_addr, int options, u32 ru) +{ + int ret; + + lock_kernel(); + ret = sys32_wait4((pid ? pid : ((__kernel_pid_t32)-1)), + stat_addr, options, ru); + unlock_kernel(); + return ret; +} + +extern int kill_pg(int, int, int); +asmlinkage int sunos_killpg(int pgrp, int sig) +{ + int ret; + + lock_kernel(); + ret = kill_pg(pgrp, sig, 0); + unlock_kernel(); + return ret; +} + +asmlinkage int sunos_audit(void) +{ + lock_kernel(); + printk ("sys_audit\n"); + unlock_kernel(); + return -1; +} + +extern asmlinkage u32 sunos_gethostid(void) +{ + u32 ret; + + lock_kernel(); + ret = (((u32)idprom->id_machtype << 24) | ((u32)idprom->id_sernum)); + unlock_kernel(); + return ret; +} + +/* sysconf options, for SunOS compatibility */ +#define _SC_ARG_MAX 1 +#define _SC_CHILD_MAX 2 +#define _SC_CLK_TCK 3 +#define _SC_NGROUPS_MAX 4 +#define _SC_OPEN_MAX 5 +#define _SC_JOB_CONTROL 6 +#define _SC_SAVED_IDS 7 +#define _SC_VERSION 8 + +extern asmlinkage s32 sunos_sysconf (int name) +{ + s32 ret; + + lock_kernel(); + switch (name){ + case _SC_ARG_MAX: + ret = ARG_MAX; + break; + case _SC_CHILD_MAX: + ret = CHILD_MAX; + break; + case _SC_CLK_TCK: + ret = HZ; + break; + case _SC_NGROUPS_MAX: + ret = NGROUPS_MAX; + break; + case _SC_OPEN_MAX: + ret = OPEN_MAX; + break; + case _SC_JOB_CONTROL: + ret = 1; /* yes, we do support job control */ + break; + case _SC_SAVED_IDS: + ret = 1; /* yes, we do support saved uids */ + break; + case _SC_VERSION: + /* mhm, POSIX_VERSION is in /usr/include/unistd.h + * should it go on /usr/include/linux? + */ + ret = 199009; + break; + default: + ret = -1; + break; + }; + unlock_kernel(); + return ret; +} + +extern asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg); +extern asmlinkage int sys_semget (key_t key, int nsems, int semflg); +extern asmlinkage int sys_semop (int semid, struct sembuf *tsops, unsigned nsops); + +asmlinkage int sunos_semsys(int op, u32 arg1, u32 arg2, u32 arg3, u32 ptr) +{ + union semun arg4; + int ret; + + lock_kernel(); + switch (op) { + case 0: + /* Most arguments match on a 1:1 basis but cmd doesn't */ + switch(arg3) { + case 4: + arg3=GETPID; break; + case 5: + arg3=GETVAL; break; + case 6: + arg3=GETALL; break; + case 3: + arg3=GETNCNT; break; + case 7: + arg3=GETZCNT; break; + case 8: + arg3=SETVAL; break; + case 9: + arg3=SETALL; break; + } + /* sys_semctl(): */ + arg4.__pad=(void *)A(ptr); /* value to modify semaphore to */ + ret = sys_semctl((int)arg1, (int)arg2, (int)arg3, arg4); + break; + case 1: + /* sys_semget(): */ + ret = sys_semget((key_t)arg1, (int)arg2, (int)arg3); + break; + case 2: + /* sys_semop(): */ + ret = sys_semop((int)arg1, (struct sembuf *)A(arg2), (unsigned)arg3); + break; + default: + ret = -EINVAL; + break; + }; + unlock_kernel(); + return ret; +} + +struct msgbuf32 { + s32 mtype; + char mtext[1]; +}; + +struct ipc_perm32 +{ + key_t key; + __kernel_uid_t32 uid; + __kernel_gid_t32 gid; + __kernel_uid_t32 cuid; + __kernel_gid_t32 cgid; + __kernel_mode_t32 mode; + unsigned short seq; +}; + +struct msqid_ds32 +{ + struct ipc_perm32 msg_perm; + u32 msg_first; + u32 msg_last; + __kernel_time_t32 msg_stime; + __kernel_time_t32 msg_rtime; + __kernel_time_t32 msg_ctime; + u32 wwait; + u32 rwait; + unsigned short msg_cbytes; + unsigned short msg_qnum; + unsigned short msg_qbytes; + __kernel_ipc_pid_t32 msg_lspid; + __kernel_ipc_pid_t32 msg_lrpid; +}; + +static inline int sunos_msqid_get(struct msqid_ds32 *user, + struct msqid_ds *kern) +{ + if(get_user(kern->msg_perm.key, &user->msg_perm.key) || + __get_user(kern->msg_perm.uid, &user->msg_perm.uid) || + __get_user(kern->msg_perm.gid, &user->msg_perm.gid) || + __get_user(kern->msg_perm.cuid, &user->msg_perm.cuid) || + __get_user(kern->msg_perm.cgid, &user->msg_perm.cgid) || + __get_user(kern->msg_stime, &user->msg_stime) || + __get_user(kern->msg_rtime, &user->msg_rtime) || + __get_user(kern->msg_ctime, &user->msg_ctime) || + __get_user(kern->msg_ctime, &user->msg_cbytes) || + __get_user(kern->msg_ctime, &user->msg_qnum) || + __get_user(kern->msg_ctime, &user->msg_qbytes) || + __get_user(kern->msg_ctime, &user->msg_lspid) || + __get_user(kern->msg_ctime, &user->msg_lrpid)) + return -EFAULT; + return 0; +} + +static inline int sunos_msqid_put(struct msqid_ds32 *user, + struct msqid_ds *kern) +{ + if(put_user(kern->msg_perm.key, &user->msg_perm.key) || + __put_user(kern->msg_perm.uid, &user->msg_perm.uid) || + __put_user(kern->msg_perm.gid, &user->msg_perm.gid) || + __put_user(kern->msg_perm.cuid, &user->msg_perm.cuid) || + __put_user(kern->msg_perm.cgid, &user->msg_perm.cgid) || + __put_user(kern->msg_stime, &user->msg_stime) || + __put_user(kern->msg_rtime, &user->msg_rtime) || + __put_user(kern->msg_ctime, &user->msg_ctime) || + __put_user(kern->msg_ctime, &user->msg_cbytes) || + __put_user(kern->msg_ctime, &user->msg_qnum) || + __put_user(kern->msg_ctime, &user->msg_qbytes) || + __put_user(kern->msg_ctime, &user->msg_lspid) || + __put_user(kern->msg_ctime, &user->msg_lrpid)) + return -EFAULT; + return 0; +} + +static inline int sunos_msgbuf_get(struct msgbuf32 *user, struct msgbuf *kern, int len) +{ + if(get_user(kern->mtype, &user->mtype) || + __copy_from_user(kern->mtext, &user->mtext, len)) + return -EFAULT; + return 0; +} + +static inline int sunos_msgbuf_put(struct msgbuf32 *user, struct msgbuf *kern, int len) +{ + if(put_user(kern->mtype, &user->mtype) || + __copy_to_user(user->mtext, kern->mtext, len)) + return -EFAULT; + return 0; +} + +extern asmlinkage int sys_msgget (key_t key, int msgflg); +extern asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp, + size_t msgsz, long msgtyp, int msgflg); +extern asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp, + size_t msgsz, int msgflg); +extern asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf); + +asmlinkage int sunos_msgsys(int op, u32 arg1, u32 arg2, u32 arg3, u32 arg4) +{ + struct sparc_stackf32 *sp; + struct msqid_ds kds; + struct msgbuf *kmbuf; + unsigned long old_fs = get_fs(); + u32 arg5; + int rval; + + lock_kernel(); + switch(op) { + case 0: + rval = sys_msgget((key_t)arg1, (int)arg2); + break; + case 1: + if(!sunos_msqid_get((struct msqid_ds32 *)A(arg3), &kds)) { + set_fs(KERNEL_DS); + rval = sys_msgctl((int)arg1, (int)arg2, + (struct msqid_ds *)A(arg3)); + set_fs(old_fs); + if(!rval) + rval = sunos_msqid_put((struct msqid_ds32 *)A(arg3), + &kds); + } else + rval = -EFAULT; + break; + case 2: + rval = -EFAULT; + kmbuf = (struct msgbuf *)kmalloc(sizeof(struct msgbuf) + arg3, + GFP_KERNEL); + if(!kmbuf) + break; + sp = (struct sparc_stackf32 *) + (current->tss.kregs->u_regs[UREG_FP] & 0xffffffffUL); + if(get_user(arg5, &sp->xxargs[0])) { + rval = -EFAULT; + break; + } + set_fs(KERNEL_DS); + rval = sys_msgrcv((int)arg1, kmbuf, (size_t)arg3, + (long)arg4, (int)arg5); + set_fs(old_fs); + if(!rval) + rval = sunos_msgbuf_put((struct msgbuf32 *)A(arg2), + kmbuf, arg3); + kfree(kmbuf); + break; + case 3: + rval = -EFAULT; + kmbuf = (struct msgbuf *)kmalloc(sizeof(struct msgbuf) + arg3, + GFP_KERNEL); + if(!kmbuf || sunos_msgbuf_get((struct msgbuf32 *)A(arg2), + kmbuf, arg3)) + break; + set_fs(KERNEL_DS); + rval = sys_msgsnd((int)arg1, kmbuf, (size_t)arg3, (int)arg4); + set_fs(old_fs); + kfree(kmbuf); + break; + default: + rval = -EINVAL; + break; + } + unlock_kernel(); + return rval; +} + +struct shmid_ds32 { + struct ipc_perm32 shm_perm; + int shm_segsz; + __kernel_time_t32 shm_atime; + __kernel_time_t32 shm_dtime; + __kernel_time_t32 shm_ctime; + __kernel_ipc_pid_t32 shm_cpid; + __kernel_ipc_pid_t32 shm_lpid; + unsigned short shm_nattch; + unsigned short shm_npages; + u32 shm_pages; + u32 attaches; +}; + +static inline int sunos_shmid_get(struct shmid_ds32 *user, + struct shmid_ds *kern) +{ + if(get_user(kern->shm_perm.key, &user->shm_perm.key) || + __get_user(kern->shm_perm.uid, &user->shm_perm.uid) || + __get_user(kern->shm_perm.gid, &user->shm_perm.gid) || + __get_user(kern->shm_perm.cuid, &user->shm_perm.cuid) || + __get_user(kern->shm_perm.cgid, &user->shm_perm.cgid) || + __get_user(kern->shm_segsz, &user->shm_segsz) || + __get_user(kern->shm_atime, &user->shm_atime) || + __get_user(kern->shm_dtime, &user->shm_dtime) || + __get_user(kern->shm_ctime, &user->shm_ctime) || + __get_user(kern->shm_cpid, &user->shm_cpid) || + __get_user(kern->shm_lpid, &user->shm_lpid) || + __get_user(kern->shm_nattch, &user->shm_nattch) || + __get_user(kern->shm_npages, &user->shm_npages)) + return -EFAULT; + return 0; +} + +static inline int sunos_shmid_put(struct shmid_ds32 *user, + struct shmid_ds *kern) +{ + if(put_user(kern->shm_perm.key, &user->shm_perm.key) || + __put_user(kern->shm_perm.uid, &user->shm_perm.uid) || + __put_user(kern->shm_perm.gid, &user->shm_perm.gid) || + __put_user(kern->shm_perm.cuid, &user->shm_perm.cuid) || + __put_user(kern->shm_perm.cgid, &user->shm_perm.cgid) || + __put_user(kern->shm_segsz, &user->shm_segsz) || + __put_user(kern->shm_atime, &user->shm_atime) || + __put_user(kern->shm_dtime, &user->shm_dtime) || + __put_user(kern->shm_ctime, &user->shm_ctime) || + __put_user(kern->shm_cpid, &user->shm_cpid) || + __put_user(kern->shm_lpid, &user->shm_lpid) || + __put_user(kern->shm_nattch, &user->shm_nattch) || + __put_user(kern->shm_npages, &user->shm_npages)) + return -EFAULT; + return 0; +} + +extern asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr); +extern asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf); +extern asmlinkage int sys_shmdt (char *shmaddr); +extern asmlinkage int sys_shmget (key_t key, int size, int shmflg); + +asmlinkage int sunos_shmsys(int op, u32 arg1, u32 arg2, u32 arg3) +{ + struct shmid_ds ksds; + unsigned long raddr, old_fs = get_fs(); + int rval; + + lock_kernel(); + switch(op) { + case 0: + /* sys_shmat(): attach a shared memory area */ + rval = sys_shmat((int)arg1,(char *)A(arg2),(int)arg3,&raddr); + if(!rval) + rval = (int) raddr; + break; + case 1: + /* sys_shmctl(): modify shared memory area attr. */ + if(!sunos_shmid_get((struct shmid_ds32 *)A(arg3), &ksds)) { + set_fs(KERNEL_DS); + rval = sys_shmctl((int)arg1,(int)arg2, &ksds); + set_fs(old_fs); + if(!rval) + rval = sunos_shmid_put((struct shmid_ds32 *)A(arg3), + &ksds); + } else + rval = -EFAULT; + break; + case 2: + /* sys_shmdt(): detach a shared memory area */ + rval = sys_shmdt((char *)A(arg1)); + break; + case 3: + /* sys_shmget(): get a shared memory area */ + rval = sys_shmget((key_t)arg1,(int)arg2,(int)arg3); + break; + default: + rval = -EINVAL; + break; + }; + unlock_kernel(); + return rval; +} + +asmlinkage int sunos_open(u32 filename, int flags, int mode) +{ + int ret; + + lock_kernel(); + current->personality |= PER_BSD; + ret = sys_open ((char *)A(filename), flags, mode); + unlock_kernel(); + return ret; +} + +#define SUNOS_EWOULDBLOCK 35 + +/* see the sunos man page read(2v) for an explanation + of this garbage. We use O_NDELAY to mark + file descriptors that have been set non-blocking + using 4.2BSD style calls. (tridge) */ + +static inline int check_nonblock(int ret, int fd) +{ + if (ret == -EAGAIN && (current->files->fd[fd]->f_flags & O_NDELAY)) + return -SUNOS_EWOULDBLOCK; + return ret; +} + +extern asmlinkage int sys32_read(unsigned int fd, u32 buf, int count); +extern asmlinkage int sys32_write(unsigned int fd, u32 buf,int count); +extern asmlinkage int sys32_recv(int fd, u32 ubuf, int size, unsigned flags); +extern asmlinkage int sys32_send(int fd, u32 buff, int len, unsigned flags); +extern asmlinkage int sys32_accept(int fd, u32 sa, u32 addrlen); +extern asmlinkage int sys32_readv(u32 fd, u32 vector, s32 count); +extern asmlinkage int sys32_writev(u32 fd, u32 vector, s32 count); + +asmlinkage int sunos_read(unsigned int fd, u32 buf, int count) +{ + int ret; + + lock_kernel(); + ret = check_nonblock(sys32_read(fd, buf, count), fd); + unlock_kernel(); + return ret; +} + +asmlinkage int sunos_readv(u32 fd, u32 vector, s32 count) +{ + int ret; + + lock_kernel(); + ret = check_nonblock(sys32_readv(fd, vector, count), fd); + lock_kernel(); + return ret; +} + +asmlinkage int sunos_write(unsigned int fd, u32 buf, int count) +{ + int ret; + + lock_kernel(); + ret = check_nonblock(sys32_write(fd, buf, count), fd); + unlock_kernel(); + return ret; +} + +asmlinkage int sunos_writev(u32 fd, u32 vector, s32 count) +{ + int ret; + + lock_kernel(); + ret = check_nonblock(sys32_writev(fd, vector, count), fd); + unlock_kernel(); + return ret; +} + +asmlinkage int sunos_recv(int fd, u32 ubuf, int size, unsigned flags) +{ + int ret; + + lock_kernel(); + ret = check_nonblock(sys32_recv(fd, ubuf, size, flags), fd); + unlock_kernel(); + return ret; +} + +asmlinkage int sunos_send(int fd, u32 buff, int len, unsigned flags) +{ + int ret; + + lock_kernel(); + ret = check_nonblock(sys32_send(fd, buff, len, flags), fd); + unlock_kernel(); + return ret; +} + +asmlinkage int sunos_accept(int fd, u32 sa, u32 addrlen) +{ + int ret; + + lock_kernel(); + ret = check_nonblock(sys32_accept(fd, sa, addrlen), fd); + unlock_kernel(); + return ret; +} + +#define SUNOS_SV_INTERRUPT 2 + +extern void check_pending(int signum); + +asmlinkage int sunos_sigaction(int signum, u32 action, u32 oldaction) +{ + struct sigaction32 new_sa, old_sa; + struct sigaction *p; + const int sigaction_size = sizeof (struct sigaction32) - sizeof (u32); + + current->personality |= PER_BSD; + if(signum < 1 || signum > 32) + return -EINVAL; + + p = signum - 1 + current->sig->action; + + if(action) { + if (signum==SIGKILL || signum==SIGSTOP) + return -EINVAL; + memset(&new_sa, 0, sizeof(struct sigaction32)); + if(copy_from_user(&new_sa, (struct sigaction32 *)A(action), + sigaction_size)) + return -EFAULT; + if (((__sighandler_t)A(new_sa.sa_handler) != SIG_DFL) && + (__sighandler_t)A(new_sa.sa_handler) != SIG_IGN) { + if(verify_area(VERIFY_READ, + (__sighandler_t)A(new_sa.sa_handler), 1)) + return -EFAULT; + } + new_sa.sa_flags ^= SUNOS_SV_INTERRUPT; + } + + if (oldaction) { + /* In the clone() case we could copy half consistant + * state to the user, however this could sleep and + * deadlock us if we held the signal lock on SMP. So for + * now I take the easy way out and do no locking. + * But then again we don't support SunOS lwp's anyways ;-) + */ + old_sa.sa_handler = (unsigned)(u64)(p->sa_handler); + old_sa.sa_mask = (sigset_t32)(p->sa_mask); + old_sa.sa_flags = (unsigned)(p->sa_flags); + + if (old_sa.sa_flags & SA_RESTART) + old_sa.sa_flags &= ~SA_RESTART; + else + old_sa.sa_flags |= SUNOS_SV_INTERRUPT; + if (copy_to_user((struct sigaction32 *)A(oldaction), + &old_sa, sigaction_size)) + return -EFAULT; + } + + if (action) { + spin_lock_irq(¤t->sig->siglock); + p->sa_handler = (__sighandler_t)A(new_sa.sa_handler); + p->sa_mask = (sigset_t)(new_sa.sa_mask); + p->sa_flags = new_sa.sa_flags; + p->sa_restorer = (void (*)(void))0; + check_pending(signum); + spin_unlock_irq(¤t->sig->siglock); + } + return 0; +} + + +extern asmlinkage int sys32_setsockopt(int fd, int level, int optname, + u32 optval, int optlen); +extern asmlinkage int sys32_getsockopt(int fd, int level, int optname, + u32 optval, u32 optlen); + +asmlinkage int sunos_setsockopt(int fd, int level, int optname, u32 optval, + int optlen) +{ + int tr_opt = optname; + int ret; + + lock_kernel(); + if (level == SOL_IP) { + /* Multicast socketopts (ttl, membership) */ + if (tr_opt >=2 && tr_opt <= 6) + tr_opt += 30; + } + ret = sys32_setsockopt(fd, level, tr_opt, optval, optlen); + unlock_kernel(); + return ret; +} + +asmlinkage int sunos_getsockopt(int fd, int level, int optname, + u32 optval, u32 optlen) +{ + int tr_opt = optname; + int ret; + + lock_kernel(); + if (level == SOL_IP) { + /* Multicast socketopts (ttl, membership) */ + if (tr_opt >=2 && tr_opt <= 6) + tr_opt += 30; + } + ret = sys32_getsockopt(fd, level, tr_opt, optval, optlen); + unlock_kernel(); + return ret; +} diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S index a74d0ffbd..eda0ff326 100644 --- a/arch/sparc64/kernel/systbls.S +++ b/arch/sparc64/kernel/systbls.S @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.13 1997/06/04 13:05:29 jj Exp $ +/* $Id: systbls.S,v 1.21 1997/07/05 07:09:17 davem Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -30,7 +30,7 @@ sys_call_table32: /*50*/ .xword sys_getegid, sys32_acct, sys_nis_syscall, sys_nis_syscall, sys32_ioctl .xword sys32_reboot, sys_nis_syscall, sys32_symlink, sys32_readlink, sys32_execve /*60*/ .xword sys_umask, sys32_chroot, sys32_newfstat, sys_nis_syscall, sys_getpagesize - .xword sys_nis_syscall, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall + .xword sys32_msync, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall /*70*/ .xword sys_nis_syscall, sys32_mmap, sys_nis_syscall, sys32_munmap, sys32_mprotect .xword sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys32_getgroups /*80*/ .xword sys32_setgroups, sys_getpgrp, sys_nis_syscall, sys32_setitimer, sys_nis_syscall @@ -42,7 +42,7 @@ sys_call_table32: /*110*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall .xword sys_nis_syscall, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_nis_syscall /*120*/ .xword sys32_readv, sys32_writev, sys32_settimeofday, sys_fchown, sys_fchmod - .xword sys_nis_syscall, sys_setreuid, sys_setregid, sys32_rename, sys32_truncate + .xword sys_nis_syscall, sys32_setreuid, sys_setregid, sys32_rename, sys32_truncate /*130*/ .xword sys32_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall .xword sys_nis_syscall, sys32_mkdir, sys32_rmdir, sys_nis_syscall, sys_nis_syscall /*140*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getrlimit @@ -53,15 +53,15 @@ sys_call_table32: .xword sys32_quotactl, sys_nis_syscall, sys32_mount, sys32_ustat, sys_nis_syscall /*170*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getdents .xword sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall -/*180*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_sigpending, sys32_no_modules +/*180*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_sigpending, sys32_query_module .xword sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_newuname -/*190*/ .xword sys32_no_modules, sys32_personality, sys_prof, sys_break, sys_lock +/*190*/ .xword sys32_init_module, sys32_personality, sys_prof, sys_break, sys_lock .xword sys_mpx, sys_ulimit, sys_getppid, sparc32_sigaction, sys_sgetmask /*200*/ .xword sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys32_uselib, old32_readdir .xword sys_nis_syscall, sys32_socketcall, sys32_syslog, sys32_olduname, sys_nis_syscall /*210*/ .xword sys_idle, sys_nis_syscall, sys32_waitpid, sys32_swapoff, sys32_sysinfo .xword sys32_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex -/*220*/ .xword sys32_sigprocmask, sys32_no_modules, sys32_no_modules, sys32_no_modules, sys_getpgid +/*220*/ .xword sys32_sigprocmask, sys32_create_module, sys32_delete_module, sys32_get_kernel_syms, sys_getpgid .xword sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid /*230*/ .xword sys32_llseek, sys32_time, sys_nis_syscall, sys_stime, sys_nis_syscall .xword sys_nis_syscall, sys32_llseek, sys32_mlock, sys32_munlock, sys_mlockall @@ -94,29 +94,29 @@ sys_call_table: /*80*/ .xword sys_setgroups, sys_getpgrp, sys_nis_syscall, sys_setitimer, sys_nis_syscall .xword sys_swapon, sys_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall /*90*/ .xword sys_dup2, sys_nis_syscall, sys_fcntl, sys_select, sys_nis_syscall - .xword sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall -/*100*/ .xword sys_getpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall - .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall -/*110*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall - .xword sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_nis_syscall, sys_nis_syscall + .xword sys_fsync, sys_setpriority, sys_socket, sys_connect, sys_accept +/*100*/ .xword sys_getpriority, sys_send, sys_recv, sys_nis_syscall, sys_bind + .xword sys_setsockopt, sys_listen, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall +/*110*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_recvmsg, sys_sendmsg + .xword sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_getsockopt, sys_nis_syscall /*120*/ .xword sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod - .xword sys_nis_syscall, sys_setreuid, sys_setregid, sys_rename, sys_truncate -/*130*/ .xword sys_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall - .xword sys_nis_syscall, sys_mkdir, sys_rmdir, sys_nis_syscall, sys_nis_syscall -/*140*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getrlimit + .xword sys_recvfrom, sys_setreuid, sys_setregid, sys_rename, sys_truncate +/*130*/ .xword sys_ftruncate, sys_flock, sys_nis_syscall, sys_sendto, sys_shutdown + .xword sys_socketpair, sys_mkdir, sys_rmdir, sys_nis_syscall, sys_nis_syscall +/*140*/ .xword sys_nis_syscall, sys_getpeername, sys_nis_syscall, sys_nis_syscall, sys_getrlimit .xword sys_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall -/*150*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall +/*150*/ .xword sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall .xword sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_umount /*160*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_setdomainname, sys_nis_syscall .xword sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall /*170*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents .xword sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall -/*180*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_sigpending, sys_nis_syscall +/*180*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_sigpending, sys_query_module .xword sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_newuname /*190*/ .xword sys_init_module, sys_personality, sys_prof, sys_break, sys_lock .xword sys_mpx, sys_ulimit, sys_getppid, sparc_sigaction, sys_sgetmask /*200*/ .xword sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, sys_nis_syscall - .xword sys_nis_syscall, sys_socketcall, sys_syslog, sys_nis_syscall, sys_nis_syscall + .xword sys_nis_syscall, sys_nis_syscall, sys_syslog, sys_nis_syscall, sys_nis_syscall /*210*/ .xword sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo .xword sys_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys_adjtimex /*220*/ .xword sys_sigprocmask, sys_create_module, sys_delete_module, sys_get_kernel_syms, sys_getpgid @@ -130,72 +130,72 @@ sys_call_table: /* Now the 32-bit SunOS syscall table. */ - .align 4 + .align 8 .globl sunos_sys_table sunos_sys_table: /*0*/ .xword sunos_indir, sys_exit, sys_fork .xword sunos_read, sunos_write, sunos_open - .xword sys_close, sunos_wait4, sys_creat - .xword sys_link, sys_unlink, sunos_execv - .xword sys_chdir, sunos_nosys, sys_mknod - .xword sys_chmod, sys_chown, sunos_brk - .xword sunos_nosys, sys_lseek, sunos_getpid + .xword sys_close, sunos_wait4, sys32_creat + .xword sys32_link, sys32_unlink, sunos_execv + .xword sys32_chdir, sunos_nosys, sys32_mknod + .xword sys32_chmod, sys32_chown, sunos_brk + .xword sunos_nosys, sys32_lseek, sunos_getpid .xword sunos_nosys, sunos_nosys, sunos_nosys .xword sunos_getuid, sunos_nosys, sys_ptrace .xword sunos_nosys, sunos_nosys, sunos_nosys .xword sunos_nosys, sunos_nosys, sunos_nosys - .xword sys_access, sunos_nosys, sunos_nosys - .xword sys_sync, sys_kill, sys_newstat - .xword sunos_nosys, sys_newlstat, sys_dup + .xword sys32_access, sunos_nosys, sunos_nosys + .xword sys_sync, sys_kill, sys32_newstat + .xword sunos_nosys, sys32_newlstat, sys_dup .xword sys_pipe, sunos_nosys, sys_profil .xword sunos_nosys, sunos_nosys, sunos_getgid .xword sunos_nosys, sunos_nosys -/*50*/ .xword sunos_nosys, sys_acct, sunos_nosys - .xword sunos_mctl, sunos_ioctl, sys_reboot - .xword sunos_nosys, sys_symlink, sys_readlink - .xword sys32_execve, sys_umask, sys_chroot - .xword sys_newfstat, sunos_nosys, sys_getpagesize - .xword sys_msync, sys_vfork, sunos_nosys +/*50*/ .xword sunos_nosys, sys32_acct, sunos_nosys + .xword sunos_mctl, sunos_ioctl, sys32_reboot + .xword sunos_nosys, sys32_symlink, sys32_readlink + .xword sys32_execve, sys_umask, sys32_chroot + .xword sys32_newfstat, sunos_nosys, sys_getpagesize + .xword sys32_msync, sys_vfork, sunos_nosys .xword sunos_nosys, sunos_sbrk, sunos_sstk - .xword sunos_mmap, sunos_vadvise, sys_munmap - .xword sys_mprotect, sunos_madvise, sys_vhangup - .xword sunos_nosys, sunos_mincore, sys_getgroups - .xword sys_setgroups, sys_getpgrp, sunos_setpgrp - .xword sys_setitimer, sunos_nosys, sys_swapon - .xword sys_getitimer, sys_gethostname, sys_sethostname + .xword sunos_mmap, sunos_vadvise, sys32_munmap + .xword sys32_mprotect, sunos_madvise, sys_vhangup + .xword sunos_nosys, sunos_mincore, sys32_getgroups + .xword sys32_setgroups, sys_getpgrp, sunos_setpgrp + .xword sys32_setitimer, sunos_nosys, sys32_swapon + .xword sys32_getitimer, sys32_gethostname, sys32_sethostname .xword sunos_getdtablesize, sys_dup2, sunos_nop - .xword sys_fcntl, sunos_select, sunos_nop + .xword sys32_fcntl, sunos_select, sunos_nop .xword sys_fsync, sys_setpriority, sys_socket - .xword sys_connect, sunos_accept + .xword sys32_connect, sunos_accept /*100*/ .xword sys_getpriority, sunos_send, sunos_recv - .xword sunos_nosys, sys_bind, sunos_setsockopt + .xword sunos_nosys, sys32_bind, sunos_setsockopt .xword sys_listen, sunos_nosys, sunos_sigaction .xword sunos_sigblock, sunos_sigsetmask, sys_sigpause - .xword sys_sigstack, sys_recvmsg, sys_sendmsg - .xword sunos_nosys, sys_gettimeofday, sys_getrusage + .xword sys32_sigstack, sys32_recvmsg, sys32_sendmsg + .xword sunos_nosys, sys_gettimeofday, sys32_getrusage .xword sunos_getsockopt, sunos_nosys, sunos_readv .xword sunos_writev, sys_settimeofday, sys_fchown - .xword sys_fchmod, sys_recvfrom, sys_setreuid - .xword sys_setregid, sys_rename, sys_truncate - .xword sys_ftruncate, sys_flock, sunos_nosys - .xword sys_sendto, sys_shutdown, sys_socketpair - .xword sys_mkdir, sys_rmdir, sys_utimes - .xword sys_sigreturn, sunos_nosys, sys_getpeername - .xword sunos_gethostid, sunos_nosys, sys_getrlimit - .xword sys_setrlimit, sunos_killpg, sunos_nosys + .xword sys_fchmod, sys32_recvfrom, sys32_setreuid + .xword sys_setregid, sys32_rename, sys32_truncate + .xword sys32_ftruncate, sys_flock, sunos_nosys + .xword sys32_sendto, sys_shutdown, sys_socketpair + .xword sys32_mkdir, sys32_rmdir, sys32_utimes + .xword sys_sigreturn, sunos_nosys, sys32_getpeername + .xword sunos_gethostid, sunos_nosys, sys32_getrlimit + .xword sys32_setrlimit, sunos_killpg, sunos_nosys .xword sunos_nosys, sunos_nosys -/*150*/ .xword sys_getsockname, sunos_nosys, sunos_nosys - .xword sunos_poll, sunos_nosys, sunos_nosys - .xword sunos_getdirentries, sys_statfs, sys_fstatfs - .xword sys_umount, sunos_nosys, sunos_nosys - .xword sunos_getdomainname, sys_setdomainname - .xword sunos_nosys, sys_quotactl, sunos_nosys - .xword sunos_mount, sys_ustat, sunos_semsys +/*150*/ .xword sys32_getsockname, sunos_nosys, sunos_nosys + .xword sys32_poll, sunos_nosys, sunos_nosys + .xword sunos_getdirentries, sys32_statfs, sys32_fstatfs + .xword sys32_umount, sunos_nosys, sunos_nosys + .xword sunos_getdomainname, sys32_setdomainname + .xword sunos_nosys, sys32_quotactl, sunos_nosys + .xword sunos_mount, sys32_ustat, sunos_semsys .xword sunos_nosys, sunos_shmsys, sunos_audit .xword sunos_nosys, sunos_getdents, sys_setsid .xword sys_fchdir, sunos_nosys, sunos_nosys .xword sunos_nosys, sunos_nosys, sunos_nosys - .xword sunos_nosys, sys_sigpending, sunos_nosys + .xword sunos_nosys, sys32_sigpending, sunos_nosys .xword sys_setpgid, sunos_pathconf, sunos_fpathconf .xword sunos_sysconf, sunos_uname, sunos_nosys .xword sunos_nosys, sunos_nosys, sunos_nosys diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index 3f15fcb54..ad40a5fb5 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.2 1997/04/10 03:02:35 davem Exp $ +/* $Id: time.c,v 1.3 1997/06/17 13:25:29 jj Exp $ * time.c: UltraSparc timer and TOD clock support. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -146,9 +146,6 @@ static int has_low_battery(void) return (data1 == data2); /* Was the write blocked? */ } -/* XXX HACK HACK HACK, delete me soon */ -static struct linux_prom_ranges XXX_sbus_ranges[PROMREG_MAX]; -static int XXX_sbus_nranges; /* Probe for the real time clock chip. */ __initfunc(static void clock_probe(void)) @@ -157,6 +154,10 @@ __initfunc(static void clock_probe(void)) char model[128]; int node, sbusnd, err; + /* XXX HACK HACK HACK, delete me soon */ + struct linux_prom_ranges XXX_sbus_ranges[PROMREG_MAX]; + int XXX_sbus_nranges; + node = prom_getchild(prom_root_node); sbusnd = prom_searchsiblings(node, "sbus"); node = prom_getchild(sbusnd); diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index 824a3ddb4..ac3e79958 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c @@ -1,14 +1,15 @@ -/* $Id: traps.c,v 1.19 1997/06/05 06:22:49 davem Exp $ - * arch/sparc/kernel/traps.c +/* $Id: traps.c,v 1.29 1997/07/05 09:52:38 davem Exp $ + * arch/sparc64/kernel/traps.c * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ /* - * I hate traps on the sparc, grrr... + * I like traps on v9, :)))) */ +#include <linux/config.h> #include <linux/sched.h> /* for jiffies */ #include <linux/kernel.h> #include <linux/signal.h> @@ -123,6 +124,8 @@ void syscall_trace_entry(unsigned long g1, struct pt_regs *regs) int i; #endif + if(strcmp(current->comm, "bash.sunos")) + return; printk("SYS[%s:%d]: PC(%016lx) <%3d> ", current->comm, current->pid, regs->tpc, (int)g1); #ifdef VERBOSE_SYSCALL_TRACING @@ -153,53 +156,12 @@ void syscall_trace_entry(unsigned long g1, struct pt_regs *regs) unsigned long syscall_trace_exit(unsigned long retval, struct pt_regs *regs) { - printk("ret[%016lx]\n", retval); + if(!strcmp(current->comm, "bash.sunos")) + printk("ret[%016lx]\n", retval); return retval; } #endif /* SYSCALL_TRACING */ -#if 0 -void user_rtrap_report(struct pt_regs *regs) -{ - static int hits = 0; - - /* Bwahhhhrggg... */ - if(regs->tpc == 0x1f294UL && ++hits == 2) { - register unsigned long ctx asm("o4"); - register unsigned long paddr asm("o5"); - unsigned long cwp, wstate; - - printk("RT[%016lx:%016lx] ", regs->tpc, regs->u_regs[UREG_I6]); - __asm__ __volatile__("rdpr %%cwp, %0" : "=r" (cwp)); - __asm__ __volatile__("rdpr %%wstate, %0" : "=r" (wstate)); - printk("CWP[%d] WSTATE[%016lx]\n" - "TSS( ksp[%016lx] kpc[%016lx] wstate[%016lx] w_saved[%d] flgs[%x]" - " cur_ds[%d] )\n", cwp, wstate, - current->tss.ksp, current->tss.kpc, current->tss.wstate, - (int) current->tss.w_saved, current->tss.flags, - current->tss.current_ds); - __asm__ __volatile__(" - rdpr %%pstate, %%o3 - wrpr %%o3, %2, %%pstate - mov %%g7, %%o5 - mov 0x10, %%o4 - ldxa [%%o4] %3, %%o4 - wrpr %%o3, 0x0, %%pstate - " : "=r" (ctx), "=r" (paddr) - : "i" (PSTATE_MG|PSTATE_IE), "i" (ASI_DMMU)); - - printk("MMU[ppgd(%016lx)sctx(%d)] ", paddr, ctx); - printk("mm->context(%016lx) mm->pgd(%p)\n", - current->mm->context, current->mm->pgd); - printk("TASK: signal[%016lx] blocked[%016lx]\n", - current->signal, current->blocked); - show_regs(regs); - while(1) - barrier(); - } -} -#endif - void bad_trap (struct pt_regs *regs, long lvl) { lock_kernel (); @@ -221,168 +183,44 @@ void bad_trap_tl1 (struct pt_regs *regs, long lvl) { char buffer[24]; - lock_kernel (); + lock_kernel(); sprintf (buffer, "Bad trap %lx at tl>0", lvl); die_if_kernel (buffer, regs); + unlock_kernel(); } void data_access_exception (struct pt_regs *regs) { - lock_kernel (); - printk ("Unhandled data access exception "); - printk("sfsr %016lx sfar %016lx\n", spitfire_get_dsfsr(), spitfire_get_sfar()); - die_if_kernel("Data access exception", regs); + send_sig(SIGSEGV, current, 1); } void do_dae(struct pt_regs *regs) { - printk("DAE: at %016lx\n", regs->tpc); - while(1) - barrier(); + send_sig(SIGSEGV, current, 1); } void instruction_access_exception (struct pt_regs *regs) { - lock_kernel (); - printk ("Unhandled instruction access exception "); - printk("sfsr %016lx\n", spitfire_get_isfsr()); - die_if_kernel("Instruction access exception", regs); + send_sig(SIGSEGV, current, 1); } void do_iae(struct pt_regs *regs) { - printk("IAE at %016lx\n", regs->tpc); - while(1) - barrier(); -} - -static unsigned long init_fsr = 0x0UL; -static unsigned int init_fregs[64] __attribute__ ((aligned (64))) = - { ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, - ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, - ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, - ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, - ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, - ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, - ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, - ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U }; - -void do_fpdis(struct pt_regs *regs) -{ - lock_kernel(); - - regs->tstate |= TSTATE_PEF; - fprs_write(FPRS_FEF); - - /* This is allowed now because the V9 ABI varargs passes floating - * point args in floating point registers, so vsprintf() and sprintf() - * cause problems. Luckily we never actually pass floating point values - * to those routines in the kernel and the code generated just does - * stores of them to the stack. Therefore, for the moment this fix - * is sufficient. -DaveM - */ - if(regs->tstate & TSTATE_PRIV) - goto out; - -#ifndef __SMP__ - if(last_task_used_math == current) - goto out; - if(last_task_used_math) { - struct task_struct *fptask = last_task_used_math; - - if(fptask->tss.flags & SPARC_FLAG_32BIT) - fpsave32((unsigned long *)&fptask->tss.float_regs[0], - &fptask->tss.fsr); - else - fpsave((unsigned long *)&fptask->tss.float_regs[0], - &fptask->tss.fsr); - } - last_task_used_math = current; - if(current->used_math) { - if(current->tss.flags & SPARC_FLAG_32BIT) - fpload32(¤t->tss.float_regs[0], - ¤t->tss.fsr); - else - fpload(¤t->tss.float_regs[0], - ¤t->tss.fsr); - } else { - /* Set inital sane state. */ - fpload(&init_fregs[0], &init_fsr); - current->used_math = 1; - } -#else - if(!current->used_math) { - fpload(&init_fregs[0], &init_fsr); - current->used_math = 1; - } else { - if(current->tss.flags & SPARC_FLAG_32BIT) - fpload32(¤t->tss.float_regs[0], - ¤t->tss.fsr); - else - fpload(¤t->tss.float_regs[0], - ¤t->tss.fsr); - } - current->flags |= PF_USEDFPU; -#endif -#ifndef __SMP__ -out: -#endif - unlock_kernel(); + send_sig(SIGSEGV, current, 1); } -static unsigned long fake_regs[32] __attribute__ ((aligned (8))); -static unsigned long fake_fsr; - void do_fpe_common(struct pt_regs *regs) { - static int calls = 0; -#ifndef __SMP__ - struct task_struct *fpt = last_task_used_math; -#else - struct task_struct *fpt = current; -#endif - - lock_kernel(); - fprs_write(FPRS_FEF); - -#ifndef __SMP__ - if(!fpt) { -#else - if(!(fpt->flags & PF_USEDFPU)) { -#endif - fpsave(&fake_regs[0], &fake_fsr); - regs->tstate &= ~(TSTATE_PEF); - goto out; - } - if(fpt->tss.flags & SPARC_FLAG_32BIT) - fpsave32((unsigned long *)&fpt->tss.float_regs[0], &fpt->tss.fsr); - else - fpsave((unsigned long *)&fpt->tss.float_regs[0], &fpt->tss.fsr); - fpt->tss.sig_address = regs->tpc; - fpt->tss.sig_desc = SUBSIG_FPERROR; -#ifdef __SMP__ - fpt->flags &= ~PF_USEDFPU; -#endif if(regs->tstate & TSTATE_PRIV) { - printk("WARNING: FPU exception from kernel mode. at pc=%016lx\n", - regs->tpc); regs->tpc = regs->tnpc; regs->tnpc += 4; - calls++; - if(calls > 2) - die_if_kernel("Too many Penguin-FPU traps from kernel mode", - regs); - goto out; + } else { + lock_kernel(); + current->tss.sig_address = regs->tpc; + current->tss.sig_desc = SUBSIG_FPERROR; + send_sig(SIGFPE, current, 1); + unlock_kernel(); } - send_sig(SIGFPE, fpt, 1); -#ifndef __SMP__ - last_task_used_math = NULL; -#endif - regs->tstate &= ~TSTATE_PEF; - if(calls > 0) - calls = 0; -out: - unlock_kernel(); } void do_fpieee(struct pt_regs *regs) @@ -397,16 +235,16 @@ void do_fpother(struct pt_regs *regs) void do_tof(struct pt_regs *regs) { - printk("TOF: at %016lx\n", regs->tpc); - while(1) - barrier(); + if(regs->tstate & TSTATE_PRIV) + die_if_kernel("Penguin overflow trap from kernel mode", regs); + current->tss.sig_address = regs->tpc; + current->tss.sig_desc = SUBSIG_TAG; /* as good as any */ + send_sig(SIGEMT, current, 1); } void do_div0(struct pt_regs *regs) { - printk("DIV0: at %016lx\n", regs->tpc); - while(1) - barrier(); + send_sig(SIGILL, current, 1); } void instruction_dump (unsigned int *pc) @@ -426,7 +264,7 @@ void die_if_kernel(char *str, struct pt_regs *regs) /* Amuse the user. */ printk( " \\|/ ____ \\|/\n" -" \"@'/ .` \\`@\"\n" +" \"@'/ .. \\`@\"\n" " /_| \\__/ |_\\\n" " \\__U_/\n"); @@ -437,17 +275,15 @@ void die_if_kernel(char *str, struct pt_regs *regs) struct reg_window *rw = (struct reg_window *) (regs->u_regs[UREG_FP] + STACK_BIAS); - if(rw) { + /* Stop the back trace when we hit userland or we + * find some badly aligned kernel stack. + */ + while(rw && + (((unsigned long) rw) >= PAGE_OFFSET) && + !(((unsigned long) rw) & 0x7)) { printk("Caller[%016lx]\n", rw->ins[7]); rw = (struct reg_window *) (rw->ins[6] + STACK_BIAS); - if(rw) { - printk("Caller[%016lx]\n", rw->ins[7]); - rw = (struct reg_window *) - (rw->ins[6] + STACK_BIAS); - if(rw) - printk("Caller[%016lx]\n", rw->ins[7]); - } } } printk("Instruction DUMP:"); @@ -465,16 +301,6 @@ void do_illegal_instruction(struct pt_regs *regs) lock_kernel(); if(tstate & TSTATE_PRIV) die_if_kernel("Kernel illegal instruction", regs); -#if 1 - { - unsigned int insn; - - printk("Ill instr. at pc=%016lx ", pc); - get_user(insn, ((unsigned int *)pc)); - printk("insn=[%08x]\n", insn); - show_regs(regs); - } -#endif current->tss.sig_address = pc; current->tss.sig_desc = SUBSIG_ILLINST; send_sig(SIGILL, current, 1); @@ -483,13 +309,11 @@ void do_illegal_instruction(struct pt_regs *regs) void mem_address_unaligned(struct pt_regs *regs) { - printk("AIEEE: do_mna at %016lx\n", regs->tpc); - show_regs(regs); if(regs->tstate & TSTATE_PRIV) { - printk("MNA from kernel, spinning\n"); - sti(); - while(1) - barrier(); + extern void kernel_unaligned_trap(struct pt_regs *regs, + unsigned int insn); + + return kernel_unaligned_trap(regs, *((unsigned int *)regs->tpc)); } else { current->tss.sig_address = regs->tpc; current->tss.sig_desc = SUBSIG_PRIVINST; @@ -499,16 +323,17 @@ void mem_address_unaligned(struct pt_regs *regs) void do_privop(struct pt_regs *regs) { - printk("PRIVOP: at %016lx\n", regs->tpc); - while(1) - barrier(); + current->tss.sig_address = regs->tpc; + current->tss.sig_desc = SUBSIG_PRIVINST; + send_sig(SIGILL, current, 1); } void do_privact(struct pt_regs *regs) { - printk("PRIVACT: at %016lx\n", regs->tpc); - while(1) - barrier(); + current->tss.sig_address = regs->tpc; + current->tss.sig_desc = SUBSIG_PRIVINST; + send_sig(SIGILL, current, 1); + unlock_kernel(); } void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc, @@ -537,11 +362,6 @@ void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned lon } current->tss.sig_address = pc; current->tss.sig_desc = SUBSIG_PRIVINST; -#if 0 - show_regs (regs); - instruction_dump ((unsigned long *) regs->tpc); - printk ("do_MNA!\n"); -#endif send_sig(SIGBUS, current, 1); unlock_kernel(); } @@ -554,6 +374,134 @@ void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, unsigned long npc unlock_kernel(); } +/* Trap level 1 stuff or other traps we should never see... */ +void do_cee(struct pt_regs *regs) +{ + die_if_kernel("TL0: Cache Error Exception", regs); +} + +void do_cee_tl1(struct pt_regs *regs) +{ + die_if_kernel("TL1: Cache Error Exception", regs); +} + +void do_dae_tl1(struct pt_regs *regs) +{ + die_if_kernel("TL1: Data Access Exception", regs); +} + +void do_iae_tl1(struct pt_regs *regs) +{ + die_if_kernel("TL1: Instruction Access Exception", regs); +} + +void do_div0_tl1(struct pt_regs *regs) +{ + die_if_kernel("TL1: DIV0 Exception", regs); +} + +void do_fpdis_tl1(struct pt_regs *regs) +{ + die_if_kernel("TL1: FPU Disabled", regs); +} + +void do_fpieee_tl1(struct pt_regs *regs) +{ + die_if_kernel("TL1: FPU IEEE Exception", regs); +} + +void do_fpother_tl1(struct pt_regs *regs) +{ + die_if_kernel("TL1: FPU Other Exception", regs); +} + +void do_ill_tl1(struct pt_regs *regs) +{ + die_if_kernel("TL1: Illegal Instruction Exception", regs); +} + +void do_irq_tl1(struct pt_regs *regs) +{ + die_if_kernel("TL1: IRQ Exception", regs); +} + +void do_lddfmna(struct pt_regs *regs) +{ + die_if_kernel("TL0: LDDF Exception", regs); +} + +void do_lddfmna_tl1(struct pt_regs *regs) +{ + die_if_kernel("TL1: LDDF Exception", regs); +} + +void do_stdfmna(struct pt_regs *regs) +{ + die_if_kernel("TL0: STDF Exception", regs); +} + +void do_stdfmna_tl1(struct pt_regs *regs) +{ + die_if_kernel("TL1: STDF Exception", regs); +} + +void do_paw(struct pt_regs *regs) +{ + die_if_kernel("TL0: Phys Watchpoint Exception", regs); +} + +void do_paw_tl1(struct pt_regs *regs) +{ + die_if_kernel("TL1: Phys Watchpoint Exception", regs); +} + +void do_vaw(struct pt_regs *regs) +{ + die_if_kernel("TL0: Virt Watchpoint Exception", regs); +} + +void do_vaw_tl1(struct pt_regs *regs) +{ + die_if_kernel("TL1: Virt Watchpoint Exception", regs); +} + +void do_tof_tl1(struct pt_regs *regs) +{ + die_if_kernel("TL1: Tag Overflow Exception", regs); +} + +#ifdef CONFIG_EC_FLUSH_TRAP +void cache_flush_trap(struct pt_regs *regs) +{ +#ifndef __SMP__ + unsigned node = linux_cpus[get_cpuid()].prom_node; +#else +#error SMP not supported on sparc64 yet +#endif + int size = prom_getintdefault(node, "ecache-size", 512*1024); + int i, j; + unsigned long addr, page_nr; + + regs->tpc = regs->tnpc; + regs->tnpc = regs->tnpc + 4; + if (!suser()) return; + size >>= PAGE_SHIFT; + addr = PAGE_OFFSET - PAGE_SIZE; + for (i = 0; i < size; i++) { + do { + addr += PAGE_SIZE; + page_nr = MAP_NR(addr); + if (page_nr >= max_mapnr) { + return; + } + } while (!PageReserved (mem_map + page_nr)); + /* E-Cache line size is 64B. Let us pollute it :)) */ + for (j = 0; j < PAGE_SIZE; j += 64) + __asm__ __volatile__ ("ldx [%0 + %1], %%g1" : : "r" (j), "r" (addr) : "g1"); + } +} +#endif + void trap_init(void) { } diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S index 8db708f07..73bda96d9 100644 --- a/arch/sparc64/kernel/ttable.S +++ b/arch/sparc64/kernel/ttable.S @@ -1,9 +1,11 @@ -/* $Id: ttable.S,v 1.13 1997/06/02 06:33:34 davem Exp $ +/* $Id: ttable.S,v 1.18 1997/07/05 09:52:41 davem Exp $ * ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) */ +#include <linux/config.h> + .globl sparc64_ttable_tl0, sparc64_ttable_tl1 sparc64_ttable_tl0: @@ -18,7 +20,7 @@ tl0_privop: TRAP(do_privop) tl0_resv012: BTRAP(0x12) BTRAP(0x13) BTRAP(0x14) BTRAP(0x15) BTRAP(0x16) BTRAP(0x17) tl0_resv018: BTRAP(0x18) BTRAP(0x19) BTRAP(0x1a) BTRAP(0x1b) BTRAP(0x1c) BTRAP(0x1d) tl0_resv01e: BTRAP(0x1e) BTRAP(0x1f) -tl0_fpdis: TRAP(do_fpdis) +tl0_fpdis: TRAP_NOSAVE(do_fpdis) tl0_fpieee: TRAP(do_fpieee) tl0_fpother: TRAP(do_fpother) tl0_tof: TRAP(do_tof) @@ -124,7 +126,13 @@ tl0_resv15a: BTRAP(0x15a) BTRAP(0x15b) BTRAP(0x15c) BTRAP(0x15d) BTRAP(0x15e) tl0_resv15f: BTRAP(0x15f) BTRAP(0x160) BTRAP(0x161) BTRAP(0x162) BTRAP(0x163) tl0_resv164: BTRAP(0x164) BTRAP(0x165) BTRAP(0x166) BTRAP(0x167) BTRAP(0x168) tl0_resv169: BTRAP(0x169) BTRAP(0x16a) BTRAP(0x16b) BTRAP(0x16c) BTRAP(0x16d) -tl0_resv16e: BTRAP(0x16e) BTRAP(0x16f) BTRAP(0x170) BTRAP(0x171) BTRAP(0x172) +tl0_gsctx: TRAP(sparc64_get_context) TRAP(sparc64_set_context) +tl0_resv170: BTRAP(0x170) BTRAP(0x171) +#ifdef CONFIG_EC_FLUSH_TRAP + TRAP(cache_flush_trap) +#else + BTRAP(0x172) +#endif tl0_resv173: BTRAP(0x173) BTRAP(0x174) BTRAP(0x175) BTRAP(0x176) BTRAP(0x177) tl0_resv178: BTRAP(0x178) BTRAP(0x179) BTRAP(0x17a) BTRAP(0x17b) BTRAP(0x17c) tl0_resv17d: BTRAP(0x17d) BTRAP(0x17e) BTRAP(0x17f) @@ -151,7 +159,7 @@ tl1_resv012: BTRAPTL1(0x12) BTRAPTL1(0x13) BTRAPTL1(0x14) BTRAPTL1(0x15) tl1_resv016: BTRAPTL1(0x16) BTRAPTL1(0x17) BTRAPTL1(0x18) BTRAPTL1(0x19) tl1_resv01a: BTRAPTL1(0x1a) BTRAPTL1(0x1b) BTRAPTL1(0x1c) BTRAPTL1(0x1d) tl1_resv01e: BTRAPTL1(0x1e) BTRAPTL1(0x1f) -tl1_fpdis: TRAPTL1(do_fpdis_tl1) +tl1_fpdis: TRAP_NOSAVE(do_fpdis) tl1_fpieee: TRAPTL1(do_fpieee_tl1) tl1_fpother: TRAPTL1(do_fpother_tl1) tl1_tof: TRAPTL1(do_tof_tl1) diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c new file mode 100644 index 000000000..f66889195 --- /dev/null +++ b/arch/sparc64/kernel/unaligned.c @@ -0,0 +1,517 @@ +/* $Id: unaligned.c,v 1.1 1997/07/18 06:26:45 ralf Exp $ + * unaligned.c: Unaligned load/store trap handling with special + * cases for the kernel to do them more quickly. + * + * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + */ + + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <asm/asi.h> +#include <asm/ptrace.h> +#include <asm/processor.h> +#include <asm/system.h> +#include <asm/uaccess.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> + +/* #define DEBUG_MNA */ + +enum direction { + load, /* ld, ldd, ldh, ldsh */ + store, /* st, std, sth, stsh */ + both, /* Swap, ldstub, cas, ... */ + fpload, + fpstore, + invalid, +}; + +#ifdef DEBUG_MNA +static char *dirstrings[] = { + "load", "store", "both", "fpload", "fpstore", "invalid" +}; +#endif + +static inline enum direction decode_direction(unsigned int insn) +{ + unsigned long tmp = (insn >> 21) & 1; + + if(!tmp) + return load; + else { + switch ((insn>>19)&0xf) { + case 15: /* swap* */ + return both; + default: + return store; + } + } +} + +/* 16 = double-word, 8 = extra-word, 4 = word, 2 = half-word */ +static inline int decode_access_size(unsigned int insn) +{ + unsigned int tmp; + + if (((insn >> 19) & 0xf) == 14) + return 8; /* stx* */ + tmp = (insn >> 19) & 3; + if(!tmp) + return 4; + else if(tmp == 3) + return 16; /* ldd/std - Although it is actually 8 */ + else if(tmp == 2) + return 2; + else { + printk("Impossible unaligned trap. insn=%08x\n", insn); + die_if_kernel("Byte sized unaligned access?!?!", current->tss.kregs); + } +} + +static inline int decode_asi(unsigned int insn, struct pt_regs *regs) +{ + if (insn & 0x800000) { + if (insn & 0x2000) + return (unsigned char)(regs->tstate >> 24); /* %asi */ + else + return (unsigned char)(insn >> 5); /* imm_asi */ + } else + return ASI_P; +} + +/* 0x400000 = signed, 0 = unsigned */ +static inline int decode_signedness(unsigned int insn) +{ + return (insn & 0x400000); +} + +static inline void maybe_flush_windows(unsigned int rs1, unsigned int rs2, + unsigned int rd) +{ + if(rs2 >= 16 || rs1 >= 16 || rd >= 16) { + flushw_user(); + } +} + +static inline long sign_extend_imm13(long imm) +{ + return imm << 51 >> 51; +} + +static inline unsigned long fetch_reg(unsigned int reg, struct pt_regs *regs) +{ + struct reg_window *win; + + if(reg < 16) + return (!reg ? 0 : regs->u_regs[reg]); + + /* Ho hum, the slightly complicated case. */ + win = (struct reg_window *) regs->u_regs[UREG_FP]; + return win->locals[reg - 16]; /* yes, I know what this does... */ +} + +static inline unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *regs) +{ + struct reg_window *win; + + if(reg < 16) + return ®s->u_regs[reg]; + win = (struct reg_window *) regs->u_regs[UREG_FP]; + return &win->locals[reg - 16]; +} + +static inline unsigned long compute_effective_address(struct pt_regs *regs, + unsigned int insn) +{ + unsigned int rs1 = (insn >> 14) & 0x1f; + unsigned int rs2 = insn & 0x1f; + unsigned int rd = (insn >> 25) & 0x1f; + + if(insn & 0x2000) { + maybe_flush_windows(rs1, 0, rd); + return (fetch_reg(rs1, regs) + sign_extend_imm13(insn)); + } else { + maybe_flush_windows(rs1, rs2, rd); + return (fetch_reg(rs1, regs) + fetch_reg(rs2, regs)); + } +} + +/* This is just to make gcc think panic does return... */ +static void unaligned_panic(char *str) +{ + panic(str); +} + +#define do_integer_load(dest_reg, size, saddr, is_signed, asi, errh) ({ \ +__asm__ __volatile__ ( \ + "wr %4, 0, %%asi\n\t" \ + "cmp %1, 8\n\t" \ + "bge,pn %%icc, 9f\n\t" \ + " cmp %1, 4\n\t" \ + "be,pt %%icc, 6f\n" \ +"4:\t" " lduba [%2] %%asi, %%l1\n" \ +"5:\t" "lduba [%2 + 1] %%asi, %%l2\n\t" \ + "sll %%l1, 8, %%l1\n\t" \ + "brz,pt %3, 3f\n\t" \ + " add %%l1, %%l2, %%l1\n\t" \ + "sllx %%l1, 48, %%l1\n\t" \ + "srax %%l1, 48, %%l1\n" \ +"3:\t" "ba,pt %%xcc, 0f\n\t" \ + " stx %%l1, [%0]\n" \ +"6:\t" "lduba [%2 + 1] %%asi, %%l2\n\t" \ + "sll %%l1, 24, %%l1\n" \ +"7:\t" "lduba [%2 + 2] %%asi, %%g7\n\t" \ + "sll %%l2, 16, %%l2\n" \ +"8:\t" "lduba [%2 + 3] %%asi, %%g1\n\t" \ + "sll %%g7, 8, %%g7\n\t" \ + "or %%l1, %%l2, %%l1\n\t" \ + "or %%g7, %%g1, %%g7\n\t" \ + "or %%l1, %%g7, %%l1\n\t" \ + "brnz,a,pt %3, 3f\n\t" \ + " sra %%l1, 0, %%l1\n" \ +"3:\t" "ba,pt %%xcc, 0f\n\t" \ + " stx %%l1, [%0]\n" \ +"9:\t" "lduba [%2] %%asi, %%l1\n" \ +"10:\t" "lduba [%2 + 1] %%asi, %%l2\n\t" \ + "sllx %%l1, 56, %%l1\n" \ +"11:\t" "lduba [%2 + 2] %%asi, %%g7\n\t" \ + "sllx %%l2, 48, %%l2\n" \ +"12:\t" "lduba [%2 + 3] %%asi, %%g1\n\t" \ + "sllx %%g7, 40, %%g7\n\t" \ + "sllx %%g1, 32, %%g1\n\t" \ + "or %%l1, %%l2, %%l1\n\t" \ + "or %%g7, %%g1, %%g7\n" \ +"13:\t" "lduba [%2 + 4] %%asi, %%l2\n\t" \ + "or %%l1, %%g7, %%g7\n" \ +"14:\t" "lduba [%2 + 5] %%asi, %%g1\n\t" \ + "sllx %%l2, 24, %%l2\n" \ +"15:\t" "lduba [%2 + 6] %%asi, %%l1\n\t" \ + "sllx %%g1, 16, %%g1\n\t" \ + "or %%g7, %%l2, %%g7\n" \ +"16:\t" "lduba [%2 + 7] %%asi, %%l2\n\t" \ + "sllx %%l1, 8, %%l1\n\t" \ + "or %%g7, %%g1, %%g7\n\t" \ + "or %%l1, %%l2, %%l1\n\t" \ + "or %%g7, %%l1, %%g7\n\t" \ + "cmp %1, 8\n\t" \ + "be,a,pt %%icc, 0f\n\t" \ + " stx %%g7, [%0]\n\t" \ + "srlx %%g7, 32, %%l1\n\t" \ + "sra %%g7, 0, %%g7\n\t" \ + "stx %%l1, [%0]\n\t" \ + "stx %%g7, [%0 + 8]\n" \ +"0:\n\n\t" \ + ".section __ex_table\n\t" \ + ".xword 4b, " #errh "\n\t" \ + ".xword 5b, " #errh "\n\t" \ + ".xword 6b, " #errh "\n\t" \ + ".xword 7b, " #errh "\n\t" \ + ".xword 8b, " #errh "\n\t" \ + ".xword 9b, " #errh "\n\t" \ + ".xword 10b, " #errh "\n\t" \ + ".xword 11b, " #errh "\n\t" \ + ".xword 12b, " #errh "\n\t" \ + ".xword 13b, " #errh "\n\t" \ + ".xword 14b, " #errh "\n\t" \ + ".xword 15b, " #errh "\n\t" \ + ".xword 16b, " #errh "\n\n\t" \ + ".previous\n\t" \ + : : "r" (dest_reg), "r" (size), "r" (saddr), "r" (is_signed), "r" (asi) \ + : "l1", "l2", "g7", "g1", "cc"); \ +}) + +#define store_common(dst_addr, size, src_val, asi, errh) ({ \ +__asm__ __volatile__ ( \ + "wr %3, 0, %%asi\n\t" \ + "ldx [%2], %%l1\n" \ + "cmp %1, 2\n\t" \ + "be,pn %%icc, 2f\n\t" \ + " cmp %1, 4\n\t" \ + "be,pt %%icc, 1f\n\t" \ + " srlx %%l1, 24, %%l2\n\t" \ + "srlx %%l1, 56, %%g1\n\t" \ + "srlx %%l1, 48, %%g7\n" \ +"4:\t" "stba %%g1, [%0] %%asi\n\t" \ + "srlx %%l1, 40, %%g1\n" \ +"5:\t" "stba %%g7, [%0 + 1] %%asi\n\t" \ + "srlx %%l1, 32, %%g7\n" \ +"6:\t" "stba %%g1, [%0 + 2] %%asi\n" \ +"7:\t" "stba %%g7, [%0 + 3] %%asi\n\t" \ + "srlx %%l1, 16, %%g1\n" \ +"8:\t" "stba %%l2, [%0 + 4] %%asi\n\t" \ + "srlx %%l1, 8, %%g7\n" \ +"9:\t" "stba %%g1, [%0 + 5] %%asi\n" \ +"10:\t" "stba %%g7, [%0 + 6] %%asi\n\t" \ + "ba,pt %%xcc, 0f\n" \ +"11:\t" " stba %%l1, [%0 + 7] %%asi\n" \ +"1:\t" "srl %%l1, 16, %%g7\n" \ +"12:\t" "stba %%l2, [%0] %%asi\n\t" \ + "srl %%l1, 8, %%l2\n" \ +"13:\t" "stba %%g7, [%0 + 1] %%asi\n" \ +"14:\t" "stba %%l2, [%0 + 2] %%asi\n\t" \ + "ba,pt %%xcc, 0f\n" \ +"15:\t" " stba %%l1, [%0 + 3] %%asi\n" \ +"2:\t" "srl %%l1, 8, %%l2\n" \ +"16:\t" "stba %%l2, [%0] %%asi\n" \ +"17:\t" "stba %%l1, [%0 + 1] %%asi\n" \ +"0:\n\n\t" \ + ".section __ex_table\n\t" \ + ".xword 4b, " #errh "\n\t" \ + ".xword 5b, " #errh "\n\t" \ + ".xword 6b, " #errh "\n\t" \ + ".xword 7b, " #errh "\n\t" \ + ".xword 8b, " #errh "\n\t" \ + ".xword 9b, " #errh "\n\t" \ + ".xword 10b, " #errh "\n\t" \ + ".xword 11b, " #errh "\n\t" \ + ".xword 12b, " #errh "\n\t" \ + ".xword 13b, " #errh "\n\t" \ + ".xword 14b, " #errh "\n\t" \ + ".xword 15b, " #errh "\n\t" \ + ".xword 16b, " #errh "\n\t" \ + ".xword 17b, " #errh "\n\n\t" \ + ".previous\n\t" \ + : : "r" (dst_addr), "r" (size), "r" (src_val), "r" (asi) \ + : "l1", "l2", "g7", "g1", "cc"); \ +}) + +#define do_integer_store(reg_num, size, dst_addr, regs, asi, errh) ({ \ + unsigned long zero = 0; \ + unsigned long *src_val = &zero; \ + \ + if (size == 16) { \ + size = 8; \ + zero = (((long)(reg_num ? \ + (unsigned)fetch_reg(reg_num, regs) : 0)) << 32) | \ + (unsigned)fetch_reg(reg_num + 1, regs); \ + } else if (reg_num) src_val = fetch_reg_addr(reg_num, regs); \ + store_common(dst_addr, size, src_val, asi, errh); \ +}) + +/* XXX Need to capture/release other cpu's for SMP around this. */ +#define do_atomic(srcdest_reg, mem, errh) ({ \ + unsigned long flags, tmp; \ + \ + save_and_cli(flags); \ + tmp = *srcdest_reg; \ + do_integer_load(srcdest_reg, 4, mem, 0, errh); \ + store_common(mem, 4, &tmp, errh); \ + restore_flags(flags); \ +}) + +static inline void advance(struct pt_regs *regs) +{ + regs->tpc = regs->tnpc; + regs->tnpc += 4; +} + +static inline int floating_point_load_or_store_p(unsigned int insn) +{ + return (insn >> 24) & 1; +} + +static inline int ok_for_kernel(unsigned int insn) +{ + return !floating_point_load_or_store_p(insn); +} + +void kernel_mna_trap_fault(struct pt_regs *regs, unsigned int insn) __asm__ ("kernel_mna_trap_fault"); + +void kernel_mna_trap_fault(struct pt_regs *regs, unsigned int insn) +{ + unsigned long g2 = regs->u_regs [UREG_G2]; + unsigned long fixup = search_exception_table (regs->tpc, &g2); + + if (!fixup) { + unsigned long address = compute_effective_address(regs, insn); + if(address < PAGE_SIZE) { + printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference in mna handler"); + } else + printk(KERN_ALERT "Unable to handle kernel paging request in mna handler"); + printk(KERN_ALERT " at virtual address %016lx\n",address); + printk(KERN_ALERT "current->mm->context = %016lx\n", + (unsigned long) current->mm->context); + printk(KERN_ALERT "current->mm->pgd = %016lx\n", + (unsigned long) current->mm->pgd); + die_if_kernel("Oops", regs); + /* Not reached */ + } + regs->tpc = fixup; + regs->tnpc = regs->tpc + 4; + regs->u_regs [UREG_G2] = g2; +} + +asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn) +{ + enum direction dir = decode_direction(insn); + int size = decode_access_size(insn); + + lock_kernel(); + if(!ok_for_kernel(insn) || dir == both) { + printk("Unsupported unaligned load/store trap for kernel at <%016lx>.\n", + regs->tpc); + unaligned_panic("Wheee. Kernel does fpu/atomic unaligned load/store."); + + __asm__ __volatile__ ("\n" +"kernel_unaligned_trap_fault:\n\t" + "mov %0, %%o0\n\t" + "call kernel_mna_trap_fault\n\t" + " mov %1, %%o1\n\t" + : + : "r" (regs), "r" (insn) + : "o0", "o1", "o2", "o3", "o4", "o5", "o7", + "g1", "g2", "g3", "g4", "g5", "g7", "cc"); + } else { + unsigned long addr = compute_effective_address(regs, insn); + +#ifdef DEBUG_MNA + printk("KMNA: pc=%016lx [dir=%s addr=%016lx size=%d] retpc[%016lx]\n", + regs->tpc, dirstrings[dir], addr, size, regs->u_regs[UREG_RETPC]); +#endif + switch(dir) { + case load: + do_integer_load(fetch_reg_addr(((insn>>25)&0x1f), regs), + size, (unsigned long *) addr, + decode_signedness(insn), decode_asi(insn, regs), + kernel_unaligned_trap_fault); + break; + + case store: + do_integer_store(((insn>>25)&0x1f), size, + (unsigned long *) addr, regs, + decode_asi(insn, regs), + kernel_unaligned_trap_fault); + break; +#if 0 /* unsupported */ + case both: + do_atomic(fetch_reg_addr(((insn>>25)&0x1f), regs), + (unsigned long *) addr, + kernel_unaligned_trap_fault); + break; +#endif + default: + panic("Impossible kernel unaligned trap."); + /* Not reached... */ + } + advance(regs); + } + unlock_kernel(); +} + +#if 0 /* XXX: Implement user mna some day */ +static inline int ok_for_user(struct pt_regs *regs, unsigned int insn, + enum direction dir) +{ + unsigned int reg; + int retval, check = (dir == load) ? VERIFY_READ : VERIFY_WRITE; + int size = ((insn >> 19) & 3) == 3 ? 8 : 4; + + if((regs->pc | regs->npc) & 3) + return 0; + + /* Must verify_area() in all the necessary places. */ +#define WINREG_ADDR(regnum) ((void *)(((unsigned long *)regs->u_regs[UREG_FP])+(regnum))) + retval = 0; + reg = (insn >> 25) & 0x1f; + if(reg >= 16) { + retval = verify_area(check, WINREG_ADDR(reg - 16), size); + if(retval) + return retval; + } + reg = (insn >> 14) & 0x1f; + if(reg >= 16) { + retval = verify_area(check, WINREG_ADDR(reg - 16), size); + if(retval) + return retval; + } + if(!(insn & 0x2000)) { + reg = (insn & 0x1f); + if(reg >= 16) { + retval = verify_area(check, WINREG_ADDR(reg - 16), size); + if(retval) + return retval; + } + } + return retval; +#undef WINREG_ADDR +} + +void user_mna_trap_fault(struct pt_regs *regs, unsigned int insn) __asm__ ("user_mna_trap_fault"); + +void user_mna_trap_fault(struct pt_regs *regs, unsigned int insn) +{ + current->tss.sig_address = regs->pc; + current->tss.sig_desc = SUBSIG_PRIVINST; + send_sig(SIGBUS, current, 1); +} + +asmlinkage void user_unaligned_trap(struct pt_regs *regs, unsigned int insn) +{ + enum direction dir; + + lock_kernel(); + if(!(current->tss.flags & SPARC_FLAG_UNALIGNED) || + (((insn >> 30) & 3) != 3)) + goto kill_user; + dir = decode_direction(insn); + if(!ok_for_user(regs, insn, dir)) { + goto kill_user; + } else { + int size = decode_access_size(insn); + unsigned long addr; + + if(floating_point_load_or_store_p(insn)) { + printk("User FPU load/store unaligned unsupported.\n"); + goto kill_user; + } + + addr = compute_effective_address(regs, insn); + switch(dir) { + case load: + do_integer_load(fetch_reg_addr(((insn>>25)&0x1f), regs), + size, (unsigned long *) addr, + decode_signedness(insn), + user_unaligned_trap_fault); + break; + + case store: + do_integer_store(((insn>>25)&0x1f), size, + (unsigned long *) addr, regs, + user_unaligned_trap_fault); + break; + + case both: + do_atomic(fetch_reg_addr(((insn>>25)&0x1f), regs), + (unsigned long *) addr, + user_unaligned_trap_fault); + break; + + default: + unaligned_panic("Impossible user unaligned trap."); + + __asm__ __volatile__ ("\n" +"user_unaligned_trap_fault:\n\t" + "mov %0, %%o0\n\t" + "call user_mna_trap_fault\n\t" + " mov %1, %%o1\n\t" + : + : "r" (regs), "r" (insn) + : "o0", "o1", "o2", "o3", "o4", "o5", "o7", + "g1", "g2", "g3", "g4", "g5", "g7", "cc"); + goto out; + } + advance(regs); + goto out; + } + +kill_user: + current->tss.sig_address = regs->pc; + current->tss.sig_desc = SUBSIG_PRIVINST; + send_sig(SIGBUS, current, 1); +out: + unlock_kernel(); +} +#endif diff --git a/arch/sparc64/kernel/winfixup.S b/arch/sparc64/kernel/winfixup.S index 2ac19a440..f2c714eae 100644 --- a/arch/sparc64/kernel/winfixup.S +++ b/arch/sparc64/kernel/winfixup.S @@ -1,4 +1,4 @@ -/* $Id: winfixup.S,v 1.8 1997/06/02 06:33:35 davem Exp $ +/* $Id: winfixup.S,v 1.16 1997/07/13 20:02:42 davem Exp $ * * winfixup.S: Handle cases where user stack pointer is found to be bogus. * @@ -31,6 +31,7 @@ fill_fixup: rdpr %tstate, %g1 andcc %g1, TSTATE_PRIV, %g0 + clr %g4 be,pt %xcc, window_scheisse_from_user_common and %g1, TSTATE_CWP, %g1 @@ -53,25 +54,26 @@ fill_fixup: rdpr %wstate, %g2 ! Grab user mode wstate. wrpr %g1, %cwp ! Get into the right window. sll %g2, 3, %g2 ! NORMAL-->OTHER - wrpr %g0, 0x0, %canrestore ! Standard etrap stuff. + wrpr %g0, 0x0, %canrestore ! Standard etrap stuff. + wr %g0, 0x0, %fprs ! zap FPU just in case... wrpr %g2, 0x0, %wstate ! This must be consistant. wrpr %g0, 0x0, %otherwin ! We know this. - sethi %uhi(KERNBASE), %g2 ! Set this up - sllx %g2, 32, %g2 ! for the iflush mov PRIMARY_CONTEXT, %g1 ! Change contexts... stxa %g0, [%g1] ASI_DMMU ! Back into the nucleus. - flush %g2 ! Flush instruction buffers + flush %g6 ! Flush instruction buffers rdpr %pstate, %l1 ! Prepare to change globals. - mov %g4, %o5 ! Setup args for - mov %g5, %o4 ! final call to do_sparc64_fault. + mov %g6, %o7 ! Get current. + mov %g5, %l5 ! Fault address + clr %l4 ! It was a load, not a store wrpr %g0, 0x0, %tl ! Out of trap levels. - wrpr %l1, (PSTATE_IE | PSTATE_AG), %pstate - sethi %uhi(KERNBASE), %g4 ! Restore med-any global reg. - rd %pic, %g6 ! Get current as well. + wrpr %l1, (PSTATE_IE | PSTATE_AG | PSTATE_RMO), %pstate + sethi %uhi(PAGE_OFFSET), %g4 ! Prepare page_offset global reg + mov %o7, %g6 b,pt %xcc, window_scheisse_merge ! And merge. - sllx %g4, 32, %g4 ! Finish med-any reg setup. + + sllx %g4, 32, %g4 ! and finish it... /* Be very careful about usage of the alternate globals here. * You cannot touch %g4/%g5 as that has the fault information @@ -82,17 +84,16 @@ fill_fixup: * do not touch %g7 or %g2 so we handle the two cases fine. */ spill_fixup: - rd %pic, %g1 - ldx [%g1 + AOFF_task_tss + AOFF_thread_flags], %g6 - andcc %g6, SPARC_FLAG_32BIT, %g0 - ldx [%g1 + AOFF_task_tss + AOFF_thread_w_saved], %g6 - sll %g6, 3, %g3 - add %g1, %g3, %g3 + ld [%g6 + AOFF_task_tss + AOFF_thread_flags], %g1 + andcc %g1, SPARC_FLAG_32BIT, %g0 + ldx [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %g1 + sll %g1, 3, %g3 + add %g6, %g3, %g3 stx %sp, [%g3 + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs] - sll %g6, 7, %g3 + sll %g1, 7, %g3 bne,pt %xcc, 1f - add %g1, %g3, %g3 + add %g6, %g3, %g3 stx %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00] stx %l1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08] stx %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10] @@ -110,43 +111,45 @@ spill_fixup: stx %i5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x68] stx %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x70] - stx %i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x78] b,pt %xcc, 2f - add %g6, 1, %g6 -1: std %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00] - std %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08] - std %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10] - std %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18] - - std %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20] - std %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28] - std %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30] - std %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38] - add %g6, 1, %g6 -2: stx %g6, [%g1 + AOFF_task_tss + AOFF_thread_w_saved] + stx %i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x78] +1: stw %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00] + stw %l1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x04] + stw %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08] + stw %l3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x0c] + stw %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10] + + stw %l5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x14] + stw %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18] + stw %l7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x1c] + stw %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20] + stw %i1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x24] + stw %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28] + stw %i3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x2c] + stw %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30] + + stw %i5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x34] + stw %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38] + stw %i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x3c] +2: add %g1, 1, %g1 + stx %g1, [%g6 + AOFF_task_tss + AOFF_thread_w_saved] rdpr %tstate, %g1 - nop - andcc %g1, TSTATE_PRIV, %g0 saved + and %g1, TSTATE_CWP, %g1 be,a,pn %xcc, window_scheisse_from_user_common or %g4, 0x4, %g4 ! we know it was a write retry window_scheisse_from_user_common: - nop wrpr %g1, %cwp - ba,pt %xcc, etrap rd %pc, %g7 - mov %l5, %o4 - mov %l4, %o5 window_scheisse_merge: - srlx %o4, PAGE_SHIFT, %o3 - clr %o1 - sllx %o3, PAGE_SHIFT, %o3 - and %o5, 0x4, %o2 + srlx %l5, PAGE_SHIFT, %o1 + and %l4, 0x4, %o2 + sllx %o1, PAGE_SHIFT, %o1 call do_sparc64_fault add %sp, STACK_BIAS + REGWIN_SZ, %o0 ba,pt %xcc, rtrap @@ -154,6 +157,7 @@ window_scheisse_merge: winfix_trampoline: andn %g3, 0x7f, %g3 add %g3, 0x7c, %g3 + wrpr %g3, %tnpc done @@ -174,32 +178,31 @@ fill_fixup_mna: wrpr %g0, 0x0, %canrestore ! Standard etrap stuff. wrpr %g2, 0x0, %wstate ! This must be consistant. wrpr %g0, 0x0, %otherwin ! We know this. - sethi %uhi(KERNBASE), %g2 ! Set this up - sllx %g2, 32, %g2 ! for the iflush mov PRIMARY_CONTEXT, %g1 ! Change contexts... stxa %g0, [%g1] ASI_DMMU ! Back into the nucleus. - flush %g2 ! Flush instruction buffers + flush %g6 ! Flush instruction buffers rdpr %pstate, %l1 ! Prepare to change globals. mov %g4, %o5 ! Setup args for mov %g5, %o4 ! final call to do_sparc64_fault. + mov %g6, %o7 ! Stash away current. wrpr %g0, 0x0, %tl ! Out of trap levels. - wrpr %l1, (PSTATE_IE | PSTATE_AG), %pstate - sethi %uhi(KERNBASE), %g4 ! Restore med-any global reg. - rd %pic, %g6 ! Get current as well. + wrpr %l1, (PSTATE_IE | PSTATE_AG | PSTATE_RMO), %pstate + sethi %uhi(PAGE_OFFSET), %g4 ! Set page_offset global reg. + mov %o7, %g6 ! Get current back. b,pt %xcc, window_mna_merge ! And merge. - sllx %g4, 32, %g4 ! Finish med-any reg setup. + sllx %g4, 32, %g4 ! Finish it. + spill_fixup_mna: - rd %pic, %g1 - ldx [%g1 + AOFF_task_tss + AOFF_thread_flags], %g6 - andcc %g6, SPARC_FLAG_32BIT, %g0 - ldx [%g1 + AOFF_task_tss + AOFF_thread_w_saved], %g6 - sll %g6, 3, %g3 - add %g1, %g3, %g3 + ld [%g6 + AOFF_task_tss + AOFF_thread_flags], %g1 + andcc %g1, SPARC_FLAG_32BIT, %g0 + ldx [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %g1 + sll %g1, 3, %g3 + add %g6, %g3, %g3 stx %sp, [%g3 + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs] - sll %g6, 7, %g3 + sll %g1, 7, %g3 bne,pt %xcc, 1f - add %g1, %g3, %g3 + add %g6, %g3, %g3 stx %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00] stx %l1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08] stx %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10] @@ -219,7 +222,7 @@ spill_fixup_mna: stx %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x70] stx %i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x78] b,pt %xcc, 2f - add %g6, 1, %g6 + add %g1, 1, %g1 1: std %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00] std %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08] std %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10] @@ -229,8 +232,8 @@ spill_fixup_mna: std %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28] std %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30] std %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38] - add %g6, 1, %g6 -2: stx %g6, [%g1 + AOFF_task_tss + AOFF_thread_w_saved] + add %g1, 1, %g1 +2: stx %g1, [%g6 + AOFF_task_tss + AOFF_thread_w_saved] rdpr %tstate, %g1 nop |