1*f45d9fc9SGennady Sharapov /* 2*f45d9fc9SGennady Sharapov * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) 3*f45d9fc9SGennady Sharapov * Licensed under the GPL 4*f45d9fc9SGennady Sharapov */ 5*f45d9fc9SGennady Sharapov 6*f45d9fc9SGennady Sharapov #include <signal.h> 7*f45d9fc9SGennady Sharapov #include <errno.h> 8*f45d9fc9SGennady Sharapov #include <string.h> 9*f45d9fc9SGennady Sharapov #include <sys/mman.h> 10*f45d9fc9SGennady Sharapov #include <sys/wait.h> 11*f45d9fc9SGennady Sharapov #include <asm/page.h> 12*f45d9fc9SGennady Sharapov #include <asm/unistd.h> 13*f45d9fc9SGennady Sharapov #include "mem_user.h" 14*f45d9fc9SGennady Sharapov #include "mem.h" 15*f45d9fc9SGennady Sharapov #include "skas.h" 16*f45d9fc9SGennady Sharapov #include "user.h" 17*f45d9fc9SGennady Sharapov #include "os.h" 18*f45d9fc9SGennady Sharapov #include "proc_mm.h" 19*f45d9fc9SGennady Sharapov #include "ptrace_user.h" 20*f45d9fc9SGennady Sharapov #include "user_util.h" 21*f45d9fc9SGennady Sharapov #include "kern_util.h" 22*f45d9fc9SGennady Sharapov #include "task.h" 23*f45d9fc9SGennady Sharapov #include "registers.h" 24*f45d9fc9SGennady Sharapov #include "uml-config.h" 25*f45d9fc9SGennady Sharapov #include "sysdep/ptrace.h" 26*f45d9fc9SGennady Sharapov #include "sysdep/stub.h" 27*f45d9fc9SGennady Sharapov 28*f45d9fc9SGennady Sharapov extern unsigned long batch_syscall_stub, __syscall_stub_start; 29*f45d9fc9SGennady Sharapov 30*f45d9fc9SGennady Sharapov extern void wait_stub_done(int pid, int sig, char * fname); 31*f45d9fc9SGennady Sharapov 32*f45d9fc9SGennady Sharapov static inline unsigned long *check_init_stack(struct mm_id * mm_idp, 33*f45d9fc9SGennady Sharapov unsigned long *stack) 34*f45d9fc9SGennady Sharapov { 35*f45d9fc9SGennady Sharapov if(stack == NULL) { 36*f45d9fc9SGennady Sharapov stack = (unsigned long *) mm_idp->stack + 2; 37*f45d9fc9SGennady Sharapov *stack = 0; 38*f45d9fc9SGennady Sharapov } 39*f45d9fc9SGennady Sharapov return stack; 40*f45d9fc9SGennady Sharapov } 41*f45d9fc9SGennady Sharapov 42*f45d9fc9SGennady Sharapov extern int proc_mm; 43*f45d9fc9SGennady Sharapov 44*f45d9fc9SGennady Sharapov int single_count = 0; 45*f45d9fc9SGennady Sharapov int multi_count = 0; 46*f45d9fc9SGennady Sharapov int multi_op_count = 0; 47*f45d9fc9SGennady Sharapov 48*f45d9fc9SGennady Sharapov static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr) 49*f45d9fc9SGennady Sharapov { 50*f45d9fc9SGennady Sharapov unsigned long regs[MAX_REG_NR]; 51*f45d9fc9SGennady Sharapov int n; 52*f45d9fc9SGennady Sharapov long ret, offset; 53*f45d9fc9SGennady Sharapov unsigned long * data; 54*f45d9fc9SGennady Sharapov unsigned long * syscall; 55*f45d9fc9SGennady Sharapov int pid = mm_idp->u.pid; 56*f45d9fc9SGennady Sharapov 57*f45d9fc9SGennady Sharapov if(proc_mm) 58*f45d9fc9SGennady Sharapov #warning Need to look up userspace_pid by cpu 59*f45d9fc9SGennady Sharapov pid = userspace_pid[0]; 60*f45d9fc9SGennady Sharapov 61*f45d9fc9SGennady Sharapov multi_count++; 62*f45d9fc9SGennady Sharapov 63*f45d9fc9SGennady Sharapov get_safe_registers(regs); 64*f45d9fc9SGennady Sharapov regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE + 65*f45d9fc9SGennady Sharapov ((unsigned long) &batch_syscall_stub - 66*f45d9fc9SGennady Sharapov (unsigned long) &__syscall_stub_start); 67*f45d9fc9SGennady Sharapov 68*f45d9fc9SGennady Sharapov n = ptrace_setregs(pid, regs); 69*f45d9fc9SGennady Sharapov if(n < 0) 70*f45d9fc9SGennady Sharapov panic("do_syscall_stub : PTRACE_SETREGS failed, errno = %d\n", 71*f45d9fc9SGennady Sharapov n); 72*f45d9fc9SGennady Sharapov 73*f45d9fc9SGennady Sharapov wait_stub_done(pid, 0, "do_syscall_stub"); 74*f45d9fc9SGennady Sharapov 75*f45d9fc9SGennady Sharapov /* When the stub stops, we find the following values on the 76*f45d9fc9SGennady Sharapov * beginning of the stack: 77*f45d9fc9SGennady Sharapov * (long )return_value 78*f45d9fc9SGennady Sharapov * (long )offset to failed sycall-data (0, if no error) 79*f45d9fc9SGennady Sharapov */ 80*f45d9fc9SGennady Sharapov ret = *((unsigned long *) mm_idp->stack); 81*f45d9fc9SGennady Sharapov offset = *((unsigned long *) mm_idp->stack + 1); 82*f45d9fc9SGennady Sharapov if (offset) { 83*f45d9fc9SGennady Sharapov data = (unsigned long *)(mm_idp->stack + 84*f45d9fc9SGennady Sharapov offset - UML_CONFIG_STUB_DATA); 85*f45d9fc9SGennady Sharapov printk("do_syscall_stub : ret = %d, offset = %d, " 86*f45d9fc9SGennady Sharapov "data = 0x%x\n", ret, offset, data); 87*f45d9fc9SGennady Sharapov syscall = (unsigned long *)((unsigned long)data + data[0]); 88*f45d9fc9SGennady Sharapov printk("do_syscall_stub: syscall %ld failed, return value = " 89*f45d9fc9SGennady Sharapov "0x%lx, expected return value = 0x%lx\n", 90*f45d9fc9SGennady Sharapov syscall[0], ret, syscall[7]); 91*f45d9fc9SGennady Sharapov printk(" syscall parameters: " 92*f45d9fc9SGennady Sharapov "0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n", 93*f45d9fc9SGennady Sharapov syscall[1], syscall[2], syscall[3], 94*f45d9fc9SGennady Sharapov syscall[4], syscall[5], syscall[6]); 95*f45d9fc9SGennady Sharapov for(n = 1; n < data[0]/sizeof(long); n++) { 96*f45d9fc9SGennady Sharapov if(n == 1) 97*f45d9fc9SGennady Sharapov printk(" additional syscall data:"); 98*f45d9fc9SGennady Sharapov if(n % 4 == 1) 99*f45d9fc9SGennady Sharapov printk("\n "); 100*f45d9fc9SGennady Sharapov printk(" 0x%lx", data[n]); 101*f45d9fc9SGennady Sharapov } 102*f45d9fc9SGennady Sharapov if(n > 1) 103*f45d9fc9SGennady Sharapov printk("\n"); 104*f45d9fc9SGennady Sharapov } 105*f45d9fc9SGennady Sharapov else ret = 0; 106*f45d9fc9SGennady Sharapov 107*f45d9fc9SGennady Sharapov *addr = check_init_stack(mm_idp, NULL); 108*f45d9fc9SGennady Sharapov 109*f45d9fc9SGennady Sharapov return ret; 110*f45d9fc9SGennady Sharapov } 111*f45d9fc9SGennady Sharapov 112*f45d9fc9SGennady Sharapov long run_syscall_stub(struct mm_id * mm_idp, int syscall, 113*f45d9fc9SGennady Sharapov unsigned long *args, long expected, void **addr, 114*f45d9fc9SGennady Sharapov int done) 115*f45d9fc9SGennady Sharapov { 116*f45d9fc9SGennady Sharapov unsigned long *stack = check_init_stack(mm_idp, *addr); 117*f45d9fc9SGennady Sharapov 118*f45d9fc9SGennady Sharapov if(done && *addr == NULL) 119*f45d9fc9SGennady Sharapov single_count++; 120*f45d9fc9SGennady Sharapov 121*f45d9fc9SGennady Sharapov *stack += sizeof(long); 122*f45d9fc9SGennady Sharapov stack += *stack / sizeof(long); 123*f45d9fc9SGennady Sharapov 124*f45d9fc9SGennady Sharapov *stack++ = syscall; 125*f45d9fc9SGennady Sharapov *stack++ = args[0]; 126*f45d9fc9SGennady Sharapov *stack++ = args[1]; 127*f45d9fc9SGennady Sharapov *stack++ = args[2]; 128*f45d9fc9SGennady Sharapov *stack++ = args[3]; 129*f45d9fc9SGennady Sharapov *stack++ = args[4]; 130*f45d9fc9SGennady Sharapov *stack++ = args[5]; 131*f45d9fc9SGennady Sharapov *stack++ = expected; 132*f45d9fc9SGennady Sharapov *stack = 0; 133*f45d9fc9SGennady Sharapov multi_op_count++; 134*f45d9fc9SGennady Sharapov 135*f45d9fc9SGennady Sharapov if(!done && ((((unsigned long) stack) & ~PAGE_MASK) < 136*f45d9fc9SGennady Sharapov PAGE_SIZE - 10 * sizeof(long))){ 137*f45d9fc9SGennady Sharapov *addr = stack; 138*f45d9fc9SGennady Sharapov return 0; 139*f45d9fc9SGennady Sharapov } 140*f45d9fc9SGennady Sharapov 141*f45d9fc9SGennady Sharapov return do_syscall_stub(mm_idp, addr); 142*f45d9fc9SGennady Sharapov } 143*f45d9fc9SGennady Sharapov 144*f45d9fc9SGennady Sharapov long syscall_stub_data(struct mm_id * mm_idp, 145*f45d9fc9SGennady Sharapov unsigned long *data, int data_count, 146*f45d9fc9SGennady Sharapov void **addr, void **stub_addr) 147*f45d9fc9SGennady Sharapov { 148*f45d9fc9SGennady Sharapov unsigned long *stack; 149*f45d9fc9SGennady Sharapov int ret = 0; 150*f45d9fc9SGennady Sharapov 151*f45d9fc9SGennady Sharapov /* If *addr still is uninitialized, it *must* contain NULL. 152*f45d9fc9SGennady Sharapov * Thus in this case do_syscall_stub correctly won't be called. 153*f45d9fc9SGennady Sharapov */ 154*f45d9fc9SGennady Sharapov if((((unsigned long) *addr) & ~PAGE_MASK) >= 155*f45d9fc9SGennady Sharapov PAGE_SIZE - (10 + data_count) * sizeof(long)) { 156*f45d9fc9SGennady Sharapov ret = do_syscall_stub(mm_idp, addr); 157*f45d9fc9SGennady Sharapov /* in case of error, don't overwrite data on stack */ 158*f45d9fc9SGennady Sharapov if(ret) 159*f45d9fc9SGennady Sharapov return ret; 160*f45d9fc9SGennady Sharapov } 161*f45d9fc9SGennady Sharapov 162*f45d9fc9SGennady Sharapov stack = check_init_stack(mm_idp, *addr); 163*f45d9fc9SGennady Sharapov *addr = stack; 164*f45d9fc9SGennady Sharapov 165*f45d9fc9SGennady Sharapov *stack = data_count * sizeof(long); 166*f45d9fc9SGennady Sharapov 167*f45d9fc9SGennady Sharapov memcpy(stack + 1, data, data_count * sizeof(long)); 168*f45d9fc9SGennady Sharapov 169*f45d9fc9SGennady Sharapov *stub_addr = (void *)(((unsigned long)(stack + 1) & ~PAGE_MASK) + 170*f45d9fc9SGennady Sharapov UML_CONFIG_STUB_DATA); 171*f45d9fc9SGennady Sharapov 172*f45d9fc9SGennady Sharapov return 0; 173*f45d9fc9SGennady Sharapov } 174*f45d9fc9SGennady Sharapov 175*f45d9fc9SGennady Sharapov int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len, 176*f45d9fc9SGennady Sharapov int r, int w, int x, int phys_fd, unsigned long long offset, 177*f45d9fc9SGennady Sharapov int done, void **data) 178*f45d9fc9SGennady Sharapov { 179*f45d9fc9SGennady Sharapov int prot, ret; 180*f45d9fc9SGennady Sharapov 181*f45d9fc9SGennady Sharapov prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | 182*f45d9fc9SGennady Sharapov (x ? PROT_EXEC : 0); 183*f45d9fc9SGennady Sharapov 184*f45d9fc9SGennady Sharapov if(proc_mm){ 185*f45d9fc9SGennady Sharapov struct proc_mm_op map; 186*f45d9fc9SGennady Sharapov int fd = mm_idp->u.mm_fd; 187*f45d9fc9SGennady Sharapov 188*f45d9fc9SGennady Sharapov map = ((struct proc_mm_op) { .op = MM_MMAP, 189*f45d9fc9SGennady Sharapov .u = 190*f45d9fc9SGennady Sharapov { .mmap = 191*f45d9fc9SGennady Sharapov { .addr = virt, 192*f45d9fc9SGennady Sharapov .len = len, 193*f45d9fc9SGennady Sharapov .prot = prot, 194*f45d9fc9SGennady Sharapov .flags = MAP_SHARED | 195*f45d9fc9SGennady Sharapov MAP_FIXED, 196*f45d9fc9SGennady Sharapov .fd = phys_fd, 197*f45d9fc9SGennady Sharapov .offset= offset 198*f45d9fc9SGennady Sharapov } } } ); 199*f45d9fc9SGennady Sharapov ret = os_write_file(fd, &map, sizeof(map)); 200*f45d9fc9SGennady Sharapov if(ret != sizeof(map)) 201*f45d9fc9SGennady Sharapov printk("map : /proc/mm map failed, err = %d\n", -ret); 202*f45d9fc9SGennady Sharapov else ret = 0; 203*f45d9fc9SGennady Sharapov } 204*f45d9fc9SGennady Sharapov else { 205*f45d9fc9SGennady Sharapov unsigned long args[] = { virt, len, prot, 206*f45d9fc9SGennady Sharapov MAP_SHARED | MAP_FIXED, phys_fd, 207*f45d9fc9SGennady Sharapov MMAP_OFFSET(offset) }; 208*f45d9fc9SGennady Sharapov 209*f45d9fc9SGennady Sharapov ret = run_syscall_stub(mm_idp, STUB_MMAP_NR, args, virt, 210*f45d9fc9SGennady Sharapov data, done); 211*f45d9fc9SGennady Sharapov } 212*f45d9fc9SGennady Sharapov 213*f45d9fc9SGennady Sharapov return ret; 214*f45d9fc9SGennady Sharapov } 215*f45d9fc9SGennady Sharapov 216*f45d9fc9SGennady Sharapov int unmap(struct mm_id * mm_idp, void *addr, unsigned long len, int done, 217*f45d9fc9SGennady Sharapov void **data) 218*f45d9fc9SGennady Sharapov { 219*f45d9fc9SGennady Sharapov int ret; 220*f45d9fc9SGennady Sharapov 221*f45d9fc9SGennady Sharapov if(proc_mm){ 222*f45d9fc9SGennady Sharapov struct proc_mm_op unmap; 223*f45d9fc9SGennady Sharapov int fd = mm_idp->u.mm_fd; 224*f45d9fc9SGennady Sharapov 225*f45d9fc9SGennady Sharapov unmap = ((struct proc_mm_op) { .op = MM_MUNMAP, 226*f45d9fc9SGennady Sharapov .u = 227*f45d9fc9SGennady Sharapov { .munmap = 228*f45d9fc9SGennady Sharapov { .addr = 229*f45d9fc9SGennady Sharapov (unsigned long) addr, 230*f45d9fc9SGennady Sharapov .len = len } } } ); 231*f45d9fc9SGennady Sharapov ret = os_write_file(fd, &unmap, sizeof(unmap)); 232*f45d9fc9SGennady Sharapov if(ret != sizeof(unmap)) 233*f45d9fc9SGennady Sharapov printk("unmap - proc_mm write returned %d\n", ret); 234*f45d9fc9SGennady Sharapov else ret = 0; 235*f45d9fc9SGennady Sharapov } 236*f45d9fc9SGennady Sharapov else { 237*f45d9fc9SGennady Sharapov unsigned long args[] = { (unsigned long) addr, len, 0, 0, 0, 238*f45d9fc9SGennady Sharapov 0 }; 239*f45d9fc9SGennady Sharapov 240*f45d9fc9SGennady Sharapov ret = run_syscall_stub(mm_idp, __NR_munmap, args, 0, 241*f45d9fc9SGennady Sharapov data, done); 242*f45d9fc9SGennady Sharapov } 243*f45d9fc9SGennady Sharapov 244*f45d9fc9SGennady Sharapov return ret; 245*f45d9fc9SGennady Sharapov } 246*f45d9fc9SGennady Sharapov 247*f45d9fc9SGennady Sharapov int protect(struct mm_id * mm_idp, unsigned long addr, unsigned long len, 248*f45d9fc9SGennady Sharapov int r, int w, int x, int done, void **data) 249*f45d9fc9SGennady Sharapov { 250*f45d9fc9SGennady Sharapov struct proc_mm_op protect; 251*f45d9fc9SGennady Sharapov int prot, ret; 252*f45d9fc9SGennady Sharapov 253*f45d9fc9SGennady Sharapov prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | 254*f45d9fc9SGennady Sharapov (x ? PROT_EXEC : 0); 255*f45d9fc9SGennady Sharapov if(proc_mm){ 256*f45d9fc9SGennady Sharapov int fd = mm_idp->u.mm_fd; 257*f45d9fc9SGennady Sharapov 258*f45d9fc9SGennady Sharapov protect = ((struct proc_mm_op) { .op = MM_MPROTECT, 259*f45d9fc9SGennady Sharapov .u = 260*f45d9fc9SGennady Sharapov { .mprotect = 261*f45d9fc9SGennady Sharapov { .addr = 262*f45d9fc9SGennady Sharapov (unsigned long) addr, 263*f45d9fc9SGennady Sharapov .len = len, 264*f45d9fc9SGennady Sharapov .prot = prot } } } ); 265*f45d9fc9SGennady Sharapov 266*f45d9fc9SGennady Sharapov ret = os_write_file(fd, &protect, sizeof(protect)); 267*f45d9fc9SGennady Sharapov if(ret != sizeof(protect)) 268*f45d9fc9SGennady Sharapov printk("protect failed, err = %d", -ret); 269*f45d9fc9SGennady Sharapov else ret = 0; 270*f45d9fc9SGennady Sharapov } 271*f45d9fc9SGennady Sharapov else { 272*f45d9fc9SGennady Sharapov unsigned long args[] = { addr, len, prot, 0, 0, 0 }; 273*f45d9fc9SGennady Sharapov 274*f45d9fc9SGennady Sharapov ret = run_syscall_stub(mm_idp, __NR_mprotect, args, 0, 275*f45d9fc9SGennady Sharapov data, done); 276*f45d9fc9SGennady Sharapov } 277*f45d9fc9SGennady Sharapov 278*f45d9fc9SGennady Sharapov return ret; 279*f45d9fc9SGennady Sharapov } 280*f45d9fc9SGennady Sharapov 281*f45d9fc9SGennady Sharapov void before_mem_skas(unsigned long unused) 282*f45d9fc9SGennady Sharapov { 283*f45d9fc9SGennady Sharapov } 284