diff options
author | Ulf Carlsson <md1ulfc@mdstud.chalmers.se> | 2000-03-14 19:28:12 +0000 |
---|---|---|
committer | Ulf Carlsson <md1ulfc@mdstud.chalmers.se> | 2000-03-14 19:28:12 +0000 |
commit | d8f9ccce272840c053e4416324a065b8550bfc81 (patch) | |
tree | b8434416a3f4fce1edbbe9b0697815272e9b14e2 | |
parent | eeea86517aa05f0f49213c5d4fc1b87885d9d685 (diff) |
o Add some systemcalls and another execve (disabled as default).
-rw-r--r-- | arch/mips64/kernel/linux32.c | 269 | ||||
-rw-r--r-- | arch/mips64/kernel/scall_o32.S | 10 |
2 files changed, 273 insertions, 6 deletions
diff --git a/arch/mips64/kernel/linux32.c b/arch/mips64/kernel/linux32.c index 30b940da5..38ec7871b 100644 --- a/arch/mips64/kernel/linux32.c +++ b/arch/mips64/kernel/linux32.c @@ -1,4 +1,4 @@ -/* $Id: linux32.c,v 1.6 2000/02/29 22:57:04 kanoj Exp $ +/* $Id: linux32.c,v 1.7 2000/03/06 23:24:34 ulfc Exp $ * * Conversion between 32-bit and 64-bit native system calls. * @@ -13,10 +13,15 @@ #include <linux/smp_lock.h> #include <linux/highuid.h> #include <linux/dirent.h> +#include <linux/resource.h> +#include <linux/highmem.h> #include <asm/uaccess.h> #include <asm/mman.h> + +#define A(__x) ((unsigned long)(__x)) + /* * Revalidate the inode. This is required for proper NFS attribute caching. */ @@ -174,6 +179,186 @@ asmlinkage int sys_fstat64(unsigned int fd, struct stat *statbuf) return sys_fstat(fd, statbuf); } +#if 0 +/* + * count32() counts the number of arguments/envelopes + */ +static int count32(u32 * argv, int max) +{ + int i = 0; + + if (argv != NULL) { + for (;;) { + u32 p; + /* egcs is stupid */ + if (!access_ok(VERIFY_READ, argv, sizeof (u32))) + return -EFAULT; + __get_user(p,argv); + if (!p) + break; + argv++; + if(++i > max) + return -E2BIG; + } + } + return i; +} + + +/* + * 'copy_strings32()' copies argument/envelope strings from user + * memory to free pages in kernel mem. These are in a format ready + * to be put directly into the top of new user memory. + */ +int copy_strings32(int argc, u32 * argv, struct linux_binprm *bprm) +{ + while (argc-- > 0) { + u32 str; + int len; + unsigned long pos; + + if (get_user(str, argv+argc) || !str || !(len = strnlen_user((char *)A(str), bprm->p))) + return -EFAULT; + if (bprm->p < len) + return -E2BIG; + + bprm->p -= len; + /* XXX: add architecture specific overflow check here. */ + + pos = bprm->p; + while (len > 0) { + char *kaddr; + int i, new, err; + struct page *page; + int offset, bytes_to_copy; + + offset = pos % PAGE_SIZE; + i = pos/PAGE_SIZE; + page = bprm->page[i]; + new = 0; + if (!page) { + page = alloc_page(GFP_HIGHUSER); + bprm->page[i] = page; + if (!page) + return -ENOMEM; + new = 1; + } + kaddr = (char *)kmap(page); + + if (new && offset) + memset(kaddr, 0, offset); + bytes_to_copy = PAGE_SIZE - offset; + if (bytes_to_copy > len) { + bytes_to_copy = len; + if (new) + memset(kaddr+offset+len, 0, PAGE_SIZE-offset-len); + } + err = copy_from_user(kaddr + offset, (char *)A(str), bytes_to_copy); + flush_page_to_ram(page); + kunmap(page); + + if (err) + return -EFAULT; + + pos += bytes_to_copy; + str += bytes_to_copy; + len -= bytes_to_copy; + } + } + return 0; +} + + +/* + * sys_execve32() executes a new program. + */ +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 *); + memset(bprm.page, 0, MAX_ARG_PAGES*sizeof(bprm.page[0])); + + 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.loader = 0; + bprm.exec = 0; + if ((bprm.argc = count32(argv, bprm.p / sizeof(u32))) < 0) { + dput(dentry); + return bprm.argc; + } + + if ((bprm.envc = count32(envp, bprm.p / sizeof(u32))) < 0) { + dput(dentry); + return bprm.envc; + } + + retval = prepare_binprm(&bprm); + if (retval < 0) + goto out; + + retval = copy_strings_kernel(1, &bprm.filename, &bprm); + if (retval < 0) + goto out; + + bprm.exec = bprm.p; + retval = copy_strings32(bprm.envc, envp, &bprm); + if (retval < 0) + goto out; + + retval = copy_strings32(bprm.argc, argv, &bprm); + if (retval < 0) + goto out; + + retval = search_binary_handler(&bprm,regs); + if (retval >= 0) + /* execve success */ + return retval; + +out: + /* Something went wrong, return the inode and free the argument pages*/ + if (bprm.dentry) + dput(bprm.dentry); + + /* Assumes that free_page() can take a NULL argument. */ + /* I hope this is ok for all architectures */ + for (i = 0 ; i < MAX_ARG_PAGES ; i++) + if (bprm.page[i]) + __free_page(bprm.page[i]); + + return retval; +} + +/* + * sys_execve() executes a new program. + */ +asmlinkage int sys32_execve(abi64_no_regargs, struct pt_regs regs) +{ + int error; + char * filename; + + filename = getname((char *) (long)regs.regs[4]); + printk("Executing: %s\n", filename); + error = PTR_ERR(filename); + if (IS_ERR(filename)) + goto out; + error = do_execve32(filename, (u32 *) (long)regs.regs[5], + (u32 *) (long)regs.regs[6], ®s); + putname(filename); + +out: + return error; +} +#else static int nargs(unsigned int arg, char **ap) { @@ -236,6 +421,7 @@ sys32_execve(abi64_no_regargs, struct pt_regs regs) sys_munmap(av, len); return(r); } +#endif struct dirent32 { unsigned int d_ino; @@ -288,3 +474,84 @@ sys32_readdir(unsigned int fd, void * dirent32, unsigned int count) xlate_dirent(&dirent64, dirent32, dirent64.d_reclen); return(n); } + +struct timeval32 +{ + int tv_sec, tv_usec; +}; + + +struct rusage32 { + struct timeval32 ru_utime; + struct timeval32 ru_stime; + int ru_maxrss; + int ru_ixrss; + int ru_idrss; + int ru_isrss; + int ru_minflt; + int ru_majflt; + int ru_nswap; + int ru_inblock; + int ru_oublock; + int ru_msgsnd; + int ru_msgrcv; + int ru_nsignals; + int ru_nvcsw; + int ru_nivcsw; +}; + +static int +put_rusage (struct rusage32 *ru, struct rusage *r) +{ + int err; + + err = put_user (r->ru_utime.tv_sec, &ru->ru_utime.tv_sec); + err |= __put_user (r->ru_utime.tv_usec, &ru->ru_utime.tv_usec); + err |= __put_user (r->ru_stime.tv_sec, &ru->ru_stime.tv_sec); + err |= __put_user (r->ru_stime.tv_usec, &ru->ru_stime.tv_usec); + err |= __put_user (r->ru_maxrss, &ru->ru_maxrss); + err |= __put_user (r->ru_ixrss, &ru->ru_ixrss); + err |= __put_user (r->ru_idrss, &ru->ru_idrss); + err |= __put_user (r->ru_isrss, &ru->ru_isrss); + err |= __put_user (r->ru_minflt, &ru->ru_minflt); + err |= __put_user (r->ru_majflt, &ru->ru_majflt); + err |= __put_user (r->ru_nswap, &ru->ru_nswap); + err |= __put_user (r->ru_inblock, &ru->ru_inblock); + err |= __put_user (r->ru_oublock, &ru->ru_oublock); + err |= __put_user (r->ru_msgsnd, &ru->ru_msgsnd); + err |= __put_user (r->ru_msgrcv, &ru->ru_msgrcv); + err |= __put_user (r->ru_nsignals, &ru->ru_nsignals); + err |= __put_user (r->ru_nvcsw, &ru->ru_nvcsw); + err |= __put_user (r->ru_nivcsw, &ru->ru_nivcsw); + return err; +} + +extern asmlinkage int sys_wait4(pid_t pid,unsigned int * stat_addr, + int options, struct rusage * ru); + +asmlinkage int +sys32_wait4(__kernel_pid_t32 pid, unsigned int *stat_addr, int options, + struct rusage32 *ru) +{ + if (!ru) + return sys_wait4(pid, stat_addr, options, NULL); + else { + struct rusage r; + int ret; + unsigned int status; + mm_segment_t old_fs = get_fs(); + + ret = sys_wait4(pid, stat_addr ? &status : NULL, options, &r); + if (put_rusage (ru, &r)) return -EFAULT; + if (stat_addr && put_user (status, stat_addr)) + return -EFAULT; + return ret; + } +} + +asmlinkage int +sys32_waitpid(__kernel_pid_t32 pid, unsigned int *stat_addr, int options) +{ + return sys32_wait4(pid, stat_addr, options, NULL); +} + diff --git a/arch/mips64/kernel/scall_o32.S b/arch/mips64/kernel/scall_o32.S index 2e6f56ce8..5aa5548c6 100644 --- a/arch/mips64/kernel/scall_o32.S +++ b/arch/mips64/kernel/scall_o32.S @@ -1,4 +1,4 @@ -/* $Id: scall_o32.S,v 1.7 2000/02/18 00:24:30 ralf Exp $ +/* $Id: scall_o32.S,v 1.9 2000/02/29 22:13:07 kanoj Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -72,7 +72,7 @@ stack_done: negu v0 # error sd v0, PT_R0(sp) # set flag for syscall restarting 1: sd v0, PT_R2(sp) # result - + FEXPORT(o32_ret_from_sys_call) lw t0, softirq_state lw t1, softirq_state+4 # unused delay slot @@ -280,7 +280,7 @@ illegal_syscall: sys sys_uselib 1 sys sys_swapon 2 sys sys_reboot 3 - sys old_readdir 3 + sys sys32_readdir 3 sys sys_mmap 6 /* 4090 */ sys sys_munmap 2 sys sys_truncate 2 @@ -305,7 +305,7 @@ illegal_syscall: sys sys_vhangup 0 sys sys_ni_syscall 0 /* was sys_idle */ sys sys_ni_syscall 0 /* sys_vm86 */ - sys sys_wait4 4 + sys sys32_wait4 4 sys sys_swapoff 1 /* 4115 */ sys sys_sysinfo 1 sys sys_ipc 6 @@ -332,7 +332,7 @@ illegal_syscall: sys sys_setfsuid 1 sys sys_setfsgid 1 sys sys_llseek 5 /* 4140 */ - sys sys_getdents 3 + sys sys32_getdents 3 sys sys_select 5 sys sys_flock 2 sys sys_msync 3 |