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