diff options
Diffstat (limited to 'arch/um/kernel/skas')
-rw-r--r-- | arch/um/kernel/skas/include/skas.h | 33 | ||||
-rw-r--r-- | arch/um/kernel/skas/mem_user.c | 234 | ||||
-rw-r--r-- | arch/um/kernel/skas/tlb.c | 31 |
3 files changed, 168 insertions, 130 deletions
diff --git a/arch/um/kernel/skas/include/skas.h b/arch/um/kernel/skas/include/skas.h index 03c9d99e15e4..060934740f9f 100644 --- a/arch/um/kernel/skas/include/skas.h +++ b/arch/um/kernel/skas/include/skas.h @@ -24,14 +24,14 @@ extern void new_thread_proc(void *stack, void (*handler)(int sig)); extern void remove_sigstack(void); extern void new_thread_handler(int sig); extern void handle_syscall(union uml_pt_regs *regs); -extern void *map(struct mm_id * mm_idp, unsigned long virt, - unsigned long len, int r, int w, int x, int phys_fd, - unsigned long long offset, int done, void *data); -extern void *unmap(struct mm_id * mm_idp, void *addr, - unsigned long len, int done, void *data); -extern void *protect(struct mm_id * mm_idp, unsigned long addr, - unsigned long len, int r, int w, int x, int done, - void *data); +extern int map(struct mm_id * mm_idp, unsigned long virt, + unsigned long len, int r, int w, int x, int phys_fd, + unsigned long long offset, int done, void **data); +extern int unmap(struct mm_id * mm_idp, void *addr, unsigned long len, + int done, void **data); +extern int protect(struct mm_id * mm_idp, unsigned long addr, + unsigned long len, int r, int w, int x, int done, + void **data); extern void user_signal(int sig, union uml_pt_regs *regs, int pid); extern int new_mm(int from, unsigned long stack); extern int start_userspace(unsigned long stub_stack); @@ -39,16 +39,11 @@ extern int copy_context_skas0(unsigned long stack, int pid); extern void get_skas_faultinfo(int pid, struct faultinfo * fi); extern long execute_syscall_skas(void *r); extern unsigned long current_stub_stack(void); +extern long run_syscall_stub(struct mm_id * mm_idp, + int syscall, unsigned long *args, long expected, + void **addr, int done); +extern long syscall_stub_data(struct mm_id * mm_idp, + unsigned long *data, int data_count, + void **addr, void **stub_addr); #endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/skas/mem_user.c b/arch/um/kernel/skas/mem_user.c index c976320ebe84..1d89640bd502 100644 --- a/arch/um/kernel/skas/mem_user.c +++ b/arch/um/kernel/skas/mem_user.c @@ -5,13 +5,14 @@ #include <signal.h> #include <errno.h> +#include <string.h> #include <sys/mman.h> #include <sys/wait.h> #include <asm/page.h> #include <asm/unistd.h> #include "mem_user.h" #include "mem.h" -#include "mm_id.h" +#include "skas.h" #include "user.h" #include "os.h" #include "proc_mm.h" @@ -23,56 +24,99 @@ #include "uml-config.h" #include "sysdep/ptrace.h" #include "sysdep/stub.h" -#include "skas.h" -extern unsigned long syscall_stub, batch_syscall_stub, __syscall_stub_start; +extern unsigned long batch_syscall_stub, __syscall_stub_start; extern void wait_stub_done(int pid, int sig, char * fname); +static inline unsigned long *check_init_stack(struct mm_id * mm_idp, + unsigned long *stack) +{ + if(stack == NULL){ + stack = (unsigned long *) mm_idp->stack + 2; + *stack = 0; + } + return stack; +} + +extern int proc_mm; + int single_count = 0; +int multi_count = 0; +int multi_op_count = 0; -static long one_syscall_stub(struct mm_id * mm_idp, int syscall, - unsigned long *args) +static long do_syscall_stub(struct mm_id *mm_idp, void **addr) { + unsigned long regs[MAX_REG_NR]; + unsigned long *data; + unsigned long *syscall; + long ret, offset; int n, pid = mm_idp->u.pid; - unsigned long regs[MAX_REG_NR]; + + if(proc_mm) +#warning Need to look up userspace_pid by cpu + pid = userspace_pid[0]; + + multi_count++; get_safe_registers(regs); regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE + - ((unsigned long) &syscall_stub - + ((unsigned long) &batch_syscall_stub - (unsigned long) &__syscall_stub_start); - /* XXX Don't have a define for starting a syscall */ - regs[REGS_SYSCALL_NR] = syscall; - regs[REGS_SYSCALL_ARG1] = args[0]; - regs[REGS_SYSCALL_ARG2] = args[1]; - regs[REGS_SYSCALL_ARG3] = args[2]; - regs[REGS_SYSCALL_ARG4] = args[3]; - regs[REGS_SYSCALL_ARG5] = args[4]; - regs[REGS_SYSCALL_ARG6] = args[5]; - n = ptrace_setregs(pid, regs); - if(n < 0){ - printk("one_syscall_stub : PTRACE_SETREGS failed, " - "errno = %d\n", n); - return(n); + n = ptrace_setregs(pid, regs); + if(n < 0) + panic("do_syscall_stub : PTRACE_SETREGS failed, errno = %d\n", + n); + + wait_stub_done(pid, 0, "do_syscall_stub"); + + /* When the stub stops, we find the following values on the + * beginning of the stack: + * (long )return_value + * (long )offset to failed sycall-data (0, if no error) + */ + ret = *((unsigned long *) mm_idp->stack); + offset = *((unsigned long *) mm_idp->stack + 1); + if (offset) { + data = (unsigned long *)(mm_idp->stack + + offset - UML_CONFIG_STUB_DATA); + syscall = (unsigned long *)((unsigned long)data + data[0]); + printk("do_syscall_stub: syscall %ld failed, return value = " + "0x%lx, expected return value = 0x%lx\n", + syscall[0], ret, syscall[7]); + printk(" syscall parameters: " + "0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n", + syscall[1], syscall[2], syscall[3], + syscall[4], syscall[5], syscall[6]); + for(n = 1; n < data[0]/sizeof(long); n++) { + if(n == 1) + printk(" additional syscall data:"); + if(n % 4 == 1) + printk("\n "); + printk(" 0x%lx", data[n]); + } + if(n > 1) + printk("\n"); } + else ret = 0; - wait_stub_done(pid, 0, "one_syscall_stub"); + *addr = check_init_stack(mm_idp, NULL); - return(*((unsigned long *) mm_idp->stack)); + return ret; } -int multi_count = 0; -int multi_op_count = 0; - -static long many_syscall_stub(struct mm_id * mm_idp, int syscall, - unsigned long *args, int done, void **addr_out) +long run_syscall_stub(struct mm_id * mm_idp, int syscall, + unsigned long *args, long expected, void **addr, + int done) { - unsigned long regs[MAX_REG_NR], *stack; - int n, pid = mm_idp->u.pid; + unsigned long *stack = check_init_stack(mm_idp, *addr); + + if(done && *addr == NULL) + single_count++; + + *stack += sizeof(long); + stack += *stack / sizeof(long); - stack = *addr_out; - if(stack == NULL) - stack = (unsigned long *) current_stub_stack(); *stack++ = syscall; *stack++ = args[0]; *stack++ = args[1]; @@ -80,53 +124,55 @@ static long many_syscall_stub(struct mm_id * mm_idp, int syscall, *stack++ = args[3]; *stack++ = args[4]; *stack++ = args[5]; + *stack++ = expected; *stack = 0; multi_op_count++; if(!done && ((((unsigned long) stack) & ~PAGE_MASK) < - PAGE_SIZE - 8 * sizeof(long))){ - *addr_out = stack; + PAGE_SIZE - 10 * sizeof(long))){ + *addr = stack; return 0; } - multi_count++; - get_safe_registers(regs); - regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE + - ((unsigned long) &batch_syscall_stub - - (unsigned long) &__syscall_stub_start); - regs[REGS_SP_INDEX] = UML_CONFIG_STUB_DATA; + return do_syscall_stub(mm_idp, addr); +} - n = ptrace_setregs(pid, regs); - if(n < 0){ - printk("many_syscall_stub : PTRACE_SETREGS failed, " - "errno = %d\n", n); - return(n); - } +long syscall_stub_data(struct mm_id * mm_idp, + unsigned long *data, int data_count, + void **addr, void **stub_addr) +{ + unsigned long *stack; + int ret = 0; + + /* If *addr still is uninitialized, it *must* contain NULL. + * Thus in this case do_syscall_stub correctly won't be called. + */ + if((((unsigned long) *addr) & ~PAGE_MASK) >= + PAGE_SIZE - (10 + data_count) * sizeof(long)) { + ret = do_syscall_stub(mm_idp, addr); + /* in case of error, don't overwrite data on stack */ + if(ret) + return ret; + } - wait_stub_done(pid, 0, "many_syscall_stub"); - stack = (unsigned long *) mm_idp->stack; + stack = check_init_stack(mm_idp, *addr); + *addr = stack; - *addr_out = stack; - return(*stack); -} + *stack = data_count * sizeof(long); -static long run_syscall_stub(struct mm_id * mm_idp, int syscall, - unsigned long *args, void **addr, int done) -{ - long res; + memcpy(stack + 1, data, data_count * sizeof(long)); - if((*addr == NULL) && done) - res = one_syscall_stub(mm_idp, syscall, args); - else res = many_syscall_stub(mm_idp, syscall, args, done, addr); + *stub_addr = (void *)(((unsigned long)(stack + 1) & ~PAGE_MASK) + + UML_CONFIG_STUB_DATA); - return res; + return 0; } -void *map(struct mm_id * mm_idp, unsigned long virt, unsigned long len, - int r, int w, int x, int phys_fd, unsigned long long offset, - int done, void *data) +int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len, + int r, int w, int x, int phys_fd, unsigned long long offset, + int done, void **data) { - int prot, n; + int prot, ret; prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | (x ? PROT_EXEC : 0); @@ -146,29 +192,27 @@ void *map(struct mm_id * mm_idp, unsigned long virt, unsigned long len, .fd = phys_fd, .offset= offset } } } ); - n = os_write_file(fd, &map, sizeof(map)); - if(n != sizeof(map)) - printk("map : /proc/mm map failed, err = %d\n", -n); + ret = os_write_file(fd, &map, sizeof(map)); + if(ret != sizeof(map)) + printk("map : /proc/mm map failed, err = %d\n", -ret); + else ret = 0; } else { - long res; unsigned long args[] = { virt, len, prot, MAP_SHARED | MAP_FIXED, phys_fd, MMAP_OFFSET(offset) }; - res = run_syscall_stub(mm_idp, STUB_MMAP_NR, args, - &data, done); - if((void *) res == MAP_FAILED) - printk("mmap stub failed, errno = %d\n", res); + ret = run_syscall_stub(mm_idp, STUB_MMAP_NR, args, virt, + data, done); } - return data; + return ret; } -void *unmap(struct mm_id * mm_idp, void *addr, unsigned long len, int done, - void *data) +int unmap(struct mm_id * mm_idp, void *addr, unsigned long len, int done, + void **data) { - int n; + int ret; if(proc_mm){ struct proc_mm_op unmap; @@ -180,29 +224,29 @@ void *unmap(struct mm_id * mm_idp, void *addr, unsigned long len, int done, { .addr = (unsigned long) addr, .len = len } } } ); - n = os_write_file(fd, &unmap, sizeof(unmap)); - if(n != sizeof(unmap)) - printk("unmap - proc_mm write returned %d\n", n); + ret = os_write_file(fd, &unmap, sizeof(unmap)); + if(ret != sizeof(unmap)) + printk("unmap - proc_mm write returned %d\n", ret); + else ret = 0; } else { - int res; unsigned long args[] = { (unsigned long) addr, len, 0, 0, 0, 0 }; - res = run_syscall_stub(mm_idp, __NR_munmap, args, - &data, done); - if(res < 0) - printk("munmap stub failed, errno = %d\n", res); + ret = run_syscall_stub(mm_idp, __NR_munmap, args, 0, + data, done); + if(ret < 0) + printk("munmap stub failed, errno = %d\n", ret); } - return data; + return ret; } -void *protect(struct mm_id * mm_idp, unsigned long addr, unsigned long len, - int r, int w, int x, int done, void *data) +int protect(struct mm_id * mm_idp, unsigned long addr, unsigned long len, + int r, int w, int x, int done, void **data) { struct proc_mm_op protect; - int prot, n; + int prot, ret; prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | (x ? PROT_EXEC : 0); @@ -217,21 +261,19 @@ void *protect(struct mm_id * mm_idp, unsigned long addr, unsigned long len, .len = len, .prot = prot } } } ); - n = os_write_file(fd, &protect, sizeof(protect)); - if(n != sizeof(protect)) - panic("protect failed, err = %d", -n); + ret = os_write_file(fd, &protect, sizeof(protect)); + if(ret != sizeof(protect)) + printk("protect failed, err = %d", -ret); + else ret = 0; } else { - int res; unsigned long args[] = { addr, len, prot, 0, 0, 0 }; - res = run_syscall_stub(mm_idp, __NR_mprotect, args, - &data, done); - if(res < 0) - panic("mprotect stub failed, errno = %d\n", res); + ret = run_syscall_stub(mm_idp, __NR_mprotect, args, 0, + data, done); } - return data; + return ret; } void before_mem_skas(unsigned long unused) diff --git a/arch/um/kernel/skas/tlb.c b/arch/um/kernel/skas/tlb.c index 4b5fd2049547..6e84963dfc29 100644 --- a/arch/um/kernel/skas/tlb.c +++ b/arch/um/kernel/skas/tlb.c @@ -18,30 +18,31 @@ #include "os.h" #include "tlb.h" -static void *do_ops(union mm_context *mmu, struct host_vm_op *ops, int last, - int finished, void *flush) +static int do_ops(union mm_context *mmu, struct host_vm_op *ops, int last, + int finished, void **flush) { struct host_vm_op *op; - int i; + int i, ret = 0; - for(i = 0; i <= last; i++){ + for(i = 0; i <= last && !ret; i++){ op = &ops[i]; switch(op->type){ case MMAP: - flush = map(&mmu->skas.id, op->u.mmap.addr, - op->u.mmap.len, op->u.mmap.r, op->u.mmap.w, - op->u.mmap.x, op->u.mmap.fd, - op->u.mmap.offset, finished, flush); + ret = map(&mmu->skas.id, op->u.mmap.addr, + op->u.mmap.len, op->u.mmap.r, op->u.mmap.w, + op->u.mmap.x, op->u.mmap.fd, + op->u.mmap.offset, finished, flush); break; case MUNMAP: - flush = unmap(&mmu->skas.id, (void *) op->u.munmap.addr, - op->u.munmap.len, finished, flush); + ret = unmap(&mmu->skas.id, + (void *) op->u.munmap.addr, + op->u.munmap.len, finished, flush); break; case MPROTECT: - flush = protect(&mmu->skas.id, op->u.mprotect.addr, - op->u.mprotect.len, op->u.mprotect.r, - op->u.mprotect.w, op->u.mprotect.x, - finished, flush); + ret = protect(&mmu->skas.id, op->u.mprotect.addr, + op->u.mprotect.len, op->u.mprotect.r, + op->u.mprotect.w, op->u.mprotect.x, + finished, flush); break; default: printk("Unknown op type %d in do_ops\n", op->type); @@ -49,7 +50,7 @@ static void *do_ops(union mm_context *mmu, struct host_vm_op *ops, int last, } } - return flush; + return ret; } extern int proc_mm; |