1f45d9fc9SGennady Sharapov /* 2*ba180fd4SJeff Dike * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 3f45d9fc9SGennady Sharapov * Licensed under the GPL 4f45d9fc9SGennady Sharapov */ 5f45d9fc9SGennady Sharapov 6*ba180fd4SJeff Dike #include <stddef.h> 7*ba180fd4SJeff Dike #include <unistd.h> 8f45d9fc9SGennady Sharapov #include <errno.h> 9f45d9fc9SGennady Sharapov #include <string.h> 10f45d9fc9SGennady Sharapov #include <sys/mman.h> 11*ba180fd4SJeff Dike #include "init.h" 12*ba180fd4SJeff Dike #include "kern_constants.h" 13*ba180fd4SJeff Dike #include "mm_id.h" 14f45d9fc9SGennady Sharapov #include "os.h" 15f45d9fc9SGennady Sharapov #include "proc_mm.h" 16f45d9fc9SGennady Sharapov #include "ptrace_user.h" 17f45d9fc9SGennady Sharapov #include "registers.h" 18*ba180fd4SJeff Dike #include "skas.h" 19*ba180fd4SJeff Dike #include "user.h" 20f45d9fc9SGennady Sharapov #include "sysdep/ptrace.h" 21f45d9fc9SGennady Sharapov #include "sysdep/stub.h" 22*ba180fd4SJeff Dike #include "uml-config.h" 23f45d9fc9SGennady Sharapov 24f45d9fc9SGennady Sharapov extern unsigned long batch_syscall_stub, __syscall_stub_start; 25f45d9fc9SGennady Sharapov 2616dd07bcSJeff Dike extern void wait_stub_done(int pid); 27f45d9fc9SGennady Sharapov 28f45d9fc9SGennady Sharapov static inline unsigned long *check_init_stack(struct mm_id * mm_idp, 29f45d9fc9SGennady Sharapov unsigned long *stack) 30f45d9fc9SGennady Sharapov { 31f45d9fc9SGennady Sharapov if (stack == NULL) { 32f45d9fc9SGennady Sharapov stack = (unsigned long *) mm_idp->stack + 2; 33f45d9fc9SGennady Sharapov *stack = 0; 34f45d9fc9SGennady Sharapov } 35f45d9fc9SGennady Sharapov return stack; 36f45d9fc9SGennady Sharapov } 37f45d9fc9SGennady Sharapov 3816dd07bcSJeff Dike static unsigned long syscall_regs[MAX_REG_NR]; 3916dd07bcSJeff Dike 4016dd07bcSJeff Dike static int __init init_syscall_regs(void) 4116dd07bcSJeff Dike { 4242daba31SJeff Dike get_safe_registers(syscall_regs); 4316dd07bcSJeff Dike syscall_regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE + 4416dd07bcSJeff Dike ((unsigned long) &batch_syscall_stub - 4516dd07bcSJeff Dike (unsigned long) &__syscall_stub_start); 4616dd07bcSJeff Dike return 0; 4716dd07bcSJeff Dike } 4816dd07bcSJeff Dike 4916dd07bcSJeff Dike __initcall(init_syscall_regs); 5016dd07bcSJeff Dike 51f45d9fc9SGennady Sharapov extern int proc_mm; 52f45d9fc9SGennady Sharapov 53f45d9fc9SGennady Sharapov int single_count = 0; 54f45d9fc9SGennady Sharapov int multi_count = 0; 55f45d9fc9SGennady Sharapov int multi_op_count = 0; 56f45d9fc9SGennady Sharapov 57f45d9fc9SGennady Sharapov static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr) 58f45d9fc9SGennady Sharapov { 59b92c4f92SJeff Dike int n, i; 60f45d9fc9SGennady Sharapov long ret, offset; 61f45d9fc9SGennady Sharapov unsigned long * data; 62f45d9fc9SGennady Sharapov unsigned long * syscall; 6316dd07bcSJeff Dike int err, pid = mm_idp->u.pid; 64f45d9fc9SGennady Sharapov 65f45d9fc9SGennady Sharapov if (proc_mm) 660e7d18b5SMiklos Szeredi /* FIXME: Need to look up userspace_pid by cpu */ 67f45d9fc9SGennady Sharapov pid = userspace_pid[0]; 68f45d9fc9SGennady Sharapov 69f45d9fc9SGennady Sharapov multi_count++; 70f45d9fc9SGennady Sharapov 7116dd07bcSJeff Dike n = ptrace_setregs(pid, syscall_regs); 72b92c4f92SJeff Dike if (n < 0) { 73*ba180fd4SJeff Dike printk(UM_KERN_ERR "Registers - \n"); 74b92c4f92SJeff Dike for (i = 0; i < MAX_REG_NR; i++) 75*ba180fd4SJeff Dike printk(UM_KERN_ERR "\t%d\t0x%lx\n", i, syscall_regs[i]); 76f45d9fc9SGennady Sharapov panic("do_syscall_stub : PTRACE_SETREGS failed, errno = %d\n", 77b92c4f92SJeff Dike -n); 78b92c4f92SJeff Dike } 79f45d9fc9SGennady Sharapov 8016dd07bcSJeff Dike err = ptrace(PTRACE_CONT, pid, 0, 0); 8116dd07bcSJeff Dike if (err) 8216dd07bcSJeff Dike panic("Failed to continue stub, pid = %d, errno = %d\n", pid, 8316dd07bcSJeff Dike errno); 8416dd07bcSJeff Dike 8516dd07bcSJeff Dike wait_stub_done(pid); 86f45d9fc9SGennady Sharapov 87*ba180fd4SJeff Dike /* 88*ba180fd4SJeff Dike * When the stub stops, we find the following values on the 89f45d9fc9SGennady Sharapov * beginning of the stack: 90f45d9fc9SGennady Sharapov * (long )return_value 91f45d9fc9SGennady Sharapov * (long )offset to failed sycall-data (0, if no error) 92f45d9fc9SGennady Sharapov */ 93f45d9fc9SGennady Sharapov ret = *((unsigned long *) mm_idp->stack); 94f45d9fc9SGennady Sharapov offset = *((unsigned long *) mm_idp->stack + 1); 95f45d9fc9SGennady Sharapov if (offset) { 96f45d9fc9SGennady Sharapov data = (unsigned long *)(mm_idp->stack + 97f45d9fc9SGennady Sharapov offset - UML_CONFIG_STUB_DATA); 98*ba180fd4SJeff Dike printk(UM_KERN_ERR "do_syscall_stub : ret = %ld, offset = %ld, " 99802e3077SPaolo 'Blaisorblade' Giarrusso "data = %p\n", ret, offset, data); 100f45d9fc9SGennady Sharapov syscall = (unsigned long *)((unsigned long)data + data[0]); 101*ba180fd4SJeff Dike printk(UM_KERN_ERR "do_syscall_stub: syscall %ld failed, " 102*ba180fd4SJeff Dike "return value = 0x%lx, expected return value = 0x%lx\n", 103f45d9fc9SGennady Sharapov syscall[0], ret, syscall[7]); 104*ba180fd4SJeff Dike printk(UM_KERN_ERR " syscall parameters: " 105f45d9fc9SGennady Sharapov "0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n", 106f45d9fc9SGennady Sharapov syscall[1], syscall[2], syscall[3], 107f45d9fc9SGennady Sharapov syscall[4], syscall[5], syscall[6]); 108f45d9fc9SGennady Sharapov for (n = 1; n < data[0]/sizeof(long); n++) { 109f45d9fc9SGennady Sharapov if (n == 1) 110*ba180fd4SJeff Dike printk(UM_KERN_ERR " additional syscall " 111*ba180fd4SJeff Dike "data:"); 112f45d9fc9SGennady Sharapov if (n % 4 == 1) 113*ba180fd4SJeff Dike printk("\n" UM_KERN_ERR " "); 114f45d9fc9SGennady Sharapov printk(" 0x%lx", data[n]); 115f45d9fc9SGennady Sharapov } 116f45d9fc9SGennady Sharapov if (n > 1) 117f45d9fc9SGennady Sharapov printk("\n"); 118f45d9fc9SGennady Sharapov } 119f45d9fc9SGennady Sharapov else ret = 0; 120f45d9fc9SGennady Sharapov 121f45d9fc9SGennady Sharapov *addr = check_init_stack(mm_idp, NULL); 122f45d9fc9SGennady Sharapov 123f45d9fc9SGennady Sharapov return ret; 124f45d9fc9SGennady Sharapov } 125f45d9fc9SGennady Sharapov 126f45d9fc9SGennady Sharapov long run_syscall_stub(struct mm_id * mm_idp, int syscall, 127f45d9fc9SGennady Sharapov unsigned long *args, long expected, void **addr, 128f45d9fc9SGennady Sharapov int done) 129f45d9fc9SGennady Sharapov { 130f45d9fc9SGennady Sharapov unsigned long *stack = check_init_stack(mm_idp, *addr); 131f45d9fc9SGennady Sharapov 132f45d9fc9SGennady Sharapov if (done && *addr == NULL) 133f45d9fc9SGennady Sharapov single_count++; 134f45d9fc9SGennady Sharapov 135f45d9fc9SGennady Sharapov *stack += sizeof(long); 136f45d9fc9SGennady Sharapov stack += *stack / sizeof(long); 137f45d9fc9SGennady Sharapov 138f45d9fc9SGennady Sharapov *stack++ = syscall; 139f45d9fc9SGennady Sharapov *stack++ = args[0]; 140f45d9fc9SGennady Sharapov *stack++ = args[1]; 141f45d9fc9SGennady Sharapov *stack++ = args[2]; 142f45d9fc9SGennady Sharapov *stack++ = args[3]; 143f45d9fc9SGennady Sharapov *stack++ = args[4]; 144f45d9fc9SGennady Sharapov *stack++ = args[5]; 145f45d9fc9SGennady Sharapov *stack++ = expected; 146f45d9fc9SGennady Sharapov *stack = 0; 147f45d9fc9SGennady Sharapov multi_op_count++; 148f45d9fc9SGennady Sharapov 149c539ab73SJeff Dike if (!done && ((((unsigned long) stack) & ~UM_KERN_PAGE_MASK) < 150c539ab73SJeff Dike UM_KERN_PAGE_SIZE - 10 * sizeof(long))) { 151f45d9fc9SGennady Sharapov *addr = stack; 152f45d9fc9SGennady Sharapov return 0; 153f45d9fc9SGennady Sharapov } 154f45d9fc9SGennady Sharapov 155f45d9fc9SGennady Sharapov return do_syscall_stub(mm_idp, addr); 156f45d9fc9SGennady Sharapov } 157f45d9fc9SGennady Sharapov 158f45d9fc9SGennady Sharapov long syscall_stub_data(struct mm_id * mm_idp, 159f45d9fc9SGennady Sharapov unsigned long *data, int data_count, 160f45d9fc9SGennady Sharapov void **addr, void **stub_addr) 161f45d9fc9SGennady Sharapov { 162f45d9fc9SGennady Sharapov unsigned long *stack; 163f45d9fc9SGennady Sharapov int ret = 0; 164f45d9fc9SGennady Sharapov 165*ba180fd4SJeff Dike /* 166*ba180fd4SJeff Dike * If *addr still is uninitialized, it *must* contain NULL. 167f45d9fc9SGennady Sharapov * Thus in this case do_syscall_stub correctly won't be called. 168f45d9fc9SGennady Sharapov */ 169c539ab73SJeff Dike if ((((unsigned long) *addr) & ~UM_KERN_PAGE_MASK) >= 170c539ab73SJeff Dike UM_KERN_PAGE_SIZE - (10 + data_count) * sizeof(long)) { 171f45d9fc9SGennady Sharapov ret = do_syscall_stub(mm_idp, addr); 172f45d9fc9SGennady Sharapov /* in case of error, don't overwrite data on stack */ 173f45d9fc9SGennady Sharapov if (ret) 174f45d9fc9SGennady Sharapov return ret; 175f45d9fc9SGennady Sharapov } 176f45d9fc9SGennady Sharapov 177f45d9fc9SGennady Sharapov stack = check_init_stack(mm_idp, *addr); 178f45d9fc9SGennady Sharapov *addr = stack; 179f45d9fc9SGennady Sharapov 180f45d9fc9SGennady Sharapov *stack = data_count * sizeof(long); 181f45d9fc9SGennady Sharapov 182f45d9fc9SGennady Sharapov memcpy(stack + 1, data, data_count * sizeof(long)); 183f45d9fc9SGennady Sharapov 184c539ab73SJeff Dike *stub_addr = (void *)(((unsigned long)(stack + 1) & 185c539ab73SJeff Dike ~UM_KERN_PAGE_MASK) + UML_CONFIG_STUB_DATA); 186f45d9fc9SGennady Sharapov 187f45d9fc9SGennady Sharapov return 0; 188f45d9fc9SGennady Sharapov } 189f45d9fc9SGennady Sharapov 19016dd07bcSJeff Dike int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len, int prot, 19116dd07bcSJeff Dike int phys_fd, unsigned long long offset, int done, void **data) 192f45d9fc9SGennady Sharapov { 19316dd07bcSJeff Dike int ret; 194f45d9fc9SGennady Sharapov 195f45d9fc9SGennady Sharapov if (proc_mm) { 196f45d9fc9SGennady Sharapov struct proc_mm_op map; 197f45d9fc9SGennady Sharapov int fd = mm_idp->u.mm_fd; 198f45d9fc9SGennady Sharapov 199f45d9fc9SGennady Sharapov map = ((struct proc_mm_op) { .op = MM_MMAP, 200f45d9fc9SGennady Sharapov .u = 201f45d9fc9SGennady Sharapov { .mmap = 202f45d9fc9SGennady Sharapov { .addr = virt, 203f45d9fc9SGennady Sharapov .len = len, 204f45d9fc9SGennady Sharapov .prot = prot, 205f45d9fc9SGennady Sharapov .flags = MAP_SHARED | 206f45d9fc9SGennady Sharapov MAP_FIXED, 207f45d9fc9SGennady Sharapov .fd = phys_fd, 208f45d9fc9SGennady Sharapov .offset= offset 209f45d9fc9SGennady Sharapov } } } ); 210a61f334fSJeff Dike CATCH_EINTR(ret = write(fd, &map, sizeof(map))); 211a61f334fSJeff Dike if (ret != sizeof(map)) { 212a61f334fSJeff Dike ret = -errno; 213*ba180fd4SJeff Dike printk(UM_KERN_ERR "map : /proc/mm map failed, " 214*ba180fd4SJeff Dike "err = %d\n", -ret); 215a61f334fSJeff Dike } 216f45d9fc9SGennady Sharapov else ret = 0; 217f45d9fc9SGennady Sharapov } 218f45d9fc9SGennady Sharapov else { 219f45d9fc9SGennady Sharapov unsigned long args[] = { virt, len, prot, 220f45d9fc9SGennady Sharapov MAP_SHARED | MAP_FIXED, phys_fd, 221f45d9fc9SGennady Sharapov MMAP_OFFSET(offset) }; 222f45d9fc9SGennady Sharapov 223f45d9fc9SGennady Sharapov ret = run_syscall_stub(mm_idp, STUB_MMAP_NR, args, virt, 224f45d9fc9SGennady Sharapov data, done); 225f45d9fc9SGennady Sharapov } 226f45d9fc9SGennady Sharapov 227f45d9fc9SGennady Sharapov return ret; 228f45d9fc9SGennady Sharapov } 229f45d9fc9SGennady Sharapov 23064f60841SJeff Dike int unmap(struct mm_id * mm_idp, unsigned long addr, unsigned long len, 23164f60841SJeff Dike int done, void **data) 232f45d9fc9SGennady Sharapov { 233f45d9fc9SGennady Sharapov int ret; 234f45d9fc9SGennady Sharapov 235f45d9fc9SGennady Sharapov if (proc_mm) { 236f45d9fc9SGennady Sharapov struct proc_mm_op unmap; 237f45d9fc9SGennady Sharapov int fd = mm_idp->u.mm_fd; 238f45d9fc9SGennady Sharapov 239f45d9fc9SGennady Sharapov unmap = ((struct proc_mm_op) { .op = MM_MUNMAP, 240f45d9fc9SGennady Sharapov .u = 241f45d9fc9SGennady Sharapov { .munmap = 242f45d9fc9SGennady Sharapov { .addr = 243f45d9fc9SGennady Sharapov (unsigned long) addr, 244f45d9fc9SGennady Sharapov .len = len } } } ); 245a61f334fSJeff Dike CATCH_EINTR(ret = write(fd, &unmap, sizeof(unmap))); 246a61f334fSJeff Dike if (ret != sizeof(unmap)) { 247a61f334fSJeff Dike ret = -errno; 248*ba180fd4SJeff Dike printk(UM_KERN_ERR "unmap - proc_mm write returned " 249*ba180fd4SJeff Dike "%d\n", ret); 250a61f334fSJeff Dike } 251f45d9fc9SGennady Sharapov else ret = 0; 252f45d9fc9SGennady Sharapov } 253f45d9fc9SGennady Sharapov else { 254f45d9fc9SGennady Sharapov unsigned long args[] = { (unsigned long) addr, len, 0, 0, 0, 255f45d9fc9SGennady Sharapov 0 }; 256f45d9fc9SGennady Sharapov 257f45d9fc9SGennady Sharapov ret = run_syscall_stub(mm_idp, __NR_munmap, args, 0, 258f45d9fc9SGennady Sharapov data, done); 259f45d9fc9SGennady Sharapov } 260f45d9fc9SGennady Sharapov 261f45d9fc9SGennady Sharapov return ret; 262f45d9fc9SGennady Sharapov } 263f45d9fc9SGennady Sharapov 264f45d9fc9SGennady Sharapov int protect(struct mm_id * mm_idp, unsigned long addr, unsigned long len, 26516dd07bcSJeff Dike unsigned int prot, int done, void **data) 266f45d9fc9SGennady Sharapov { 267f45d9fc9SGennady Sharapov struct proc_mm_op protect; 26816dd07bcSJeff Dike int ret; 269f45d9fc9SGennady Sharapov 270f45d9fc9SGennady Sharapov if (proc_mm) { 271f45d9fc9SGennady Sharapov int fd = mm_idp->u.mm_fd; 272f45d9fc9SGennady Sharapov 273f45d9fc9SGennady Sharapov protect = ((struct proc_mm_op) { .op = MM_MPROTECT, 274f45d9fc9SGennady Sharapov .u = 275f45d9fc9SGennady Sharapov { .mprotect = 276f45d9fc9SGennady Sharapov { .addr = 277f45d9fc9SGennady Sharapov (unsigned long) addr, 278f45d9fc9SGennady Sharapov .len = len, 279f45d9fc9SGennady Sharapov .prot = prot } } } ); 280f45d9fc9SGennady Sharapov 281a61f334fSJeff Dike CATCH_EINTR(ret = write(fd, &protect, sizeof(protect))); 282a61f334fSJeff Dike if (ret != sizeof(protect)) { 283a61f334fSJeff Dike ret = -errno; 284*ba180fd4SJeff Dike printk(UM_KERN_ERR "protect failed, err = %d", -ret); 285a61f334fSJeff Dike } 286f45d9fc9SGennady Sharapov else ret = 0; 287f45d9fc9SGennady Sharapov } 288f45d9fc9SGennady Sharapov else { 289f45d9fc9SGennady Sharapov unsigned long args[] = { addr, len, prot, 0, 0, 0 }; 290f45d9fc9SGennady Sharapov 291f45d9fc9SGennady Sharapov ret = run_syscall_stub(mm_idp, __NR_mprotect, args, 0, 292f45d9fc9SGennady Sharapov data, done); 293f45d9fc9SGennady Sharapov } 294f45d9fc9SGennady Sharapov 295f45d9fc9SGennady Sharapov return ret; 296f45d9fc9SGennady Sharapov } 297