1f45d9fc9SGennady Sharapov /* 2ba180fd4SJeff Dike * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 3f45d9fc9SGennady Sharapov * Licensed under the GPL 4f45d9fc9SGennady Sharapov */ 5f45d9fc9SGennady Sharapov 6ba180fd4SJeff Dike #include <stddef.h> 7ba180fd4SJeff Dike #include <unistd.h> 8f45d9fc9SGennady Sharapov #include <errno.h> 9f45d9fc9SGennady Sharapov #include <string.h> 10f45d9fc9SGennady Sharapov #include <sys/mman.h> 1137185b33SAl Viro #include <init.h> 1237185b33SAl Viro #include <as-layout.h> 1337185b33SAl Viro #include <mm_id.h> 1437185b33SAl Viro #include <os.h> 1537185b33SAl Viro #include <ptrace_user.h> 1637185b33SAl Viro #include <registers.h> 1737185b33SAl Viro #include <skas.h> 1837185b33SAl Viro #include <sysdep/ptrace.h> 1937185b33SAl Viro #include <sysdep/stub.h> 20f45d9fc9SGennady Sharapov 21*5f32943bSNicolas Iooss extern char batch_syscall_stub[], __syscall_stub_start[]; 22f45d9fc9SGennady Sharapov 2316dd07bcSJeff Dike extern void wait_stub_done(int pid); 24f45d9fc9SGennady Sharapov 25f45d9fc9SGennady Sharapov static inline unsigned long *check_init_stack(struct mm_id * mm_idp, 26f45d9fc9SGennady Sharapov unsigned long *stack) 27f45d9fc9SGennady Sharapov { 28f45d9fc9SGennady Sharapov if (stack == NULL) { 29f45d9fc9SGennady Sharapov stack = (unsigned long *) mm_idp->stack + 2; 30f45d9fc9SGennady Sharapov *stack = 0; 31f45d9fc9SGennady Sharapov } 32f45d9fc9SGennady Sharapov return stack; 33f45d9fc9SGennady Sharapov } 34f45d9fc9SGennady Sharapov 3516dd07bcSJeff Dike static unsigned long syscall_regs[MAX_REG_NR]; 3616dd07bcSJeff Dike 3716dd07bcSJeff Dike static int __init init_syscall_regs(void) 3816dd07bcSJeff Dike { 39fbfe9c84SIngo van Lil get_safe_registers(syscall_regs, NULL); 4054ae36f2SJeff Dike syscall_regs[REGS_IP_INDEX] = STUB_CODE + 41*5f32943bSNicolas Iooss ((unsigned long) batch_syscall_stub - 42*5f32943bSNicolas Iooss (unsigned long) __syscall_stub_start); 4316dd07bcSJeff Dike return 0; 4416dd07bcSJeff Dike } 4516dd07bcSJeff Dike 4616dd07bcSJeff Dike __initcall(init_syscall_regs); 4716dd07bcSJeff Dike 48f45d9fc9SGennady Sharapov static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr) 49f45d9fc9SGennady Sharapov { 50b92c4f92SJeff Dike int n, i; 51f45d9fc9SGennady Sharapov long ret, offset; 52f45d9fc9SGennady Sharapov unsigned long * data; 53f45d9fc9SGennady Sharapov unsigned long * syscall; 5416dd07bcSJeff Dike int err, pid = mm_idp->u.pid; 55f45d9fc9SGennady Sharapov 5616dd07bcSJeff Dike n = ptrace_setregs(pid, syscall_regs); 57b92c4f92SJeff Dike if (n < 0) { 58ba180fd4SJeff Dike printk(UM_KERN_ERR "Registers - \n"); 59b92c4f92SJeff Dike for (i = 0; i < MAX_REG_NR; i++) 60ba180fd4SJeff Dike printk(UM_KERN_ERR "\t%d\t0x%lx\n", i, syscall_regs[i]); 61f45d9fc9SGennady Sharapov panic("do_syscall_stub : PTRACE_SETREGS failed, errno = %d\n", 62b92c4f92SJeff Dike -n); 63b92c4f92SJeff Dike } 64f45d9fc9SGennady Sharapov 6516dd07bcSJeff Dike err = ptrace(PTRACE_CONT, pid, 0, 0); 6616dd07bcSJeff Dike if (err) 6716dd07bcSJeff Dike panic("Failed to continue stub, pid = %d, errno = %d\n", pid, 6816dd07bcSJeff Dike errno); 6916dd07bcSJeff Dike 7016dd07bcSJeff Dike wait_stub_done(pid); 71f45d9fc9SGennady Sharapov 72ba180fd4SJeff Dike /* 73ba180fd4SJeff Dike * When the stub stops, we find the following values on the 74f45d9fc9SGennady Sharapov * beginning of the stack: 75f45d9fc9SGennady Sharapov * (long )return_value 76f45d9fc9SGennady Sharapov * (long )offset to failed sycall-data (0, if no error) 77f45d9fc9SGennady Sharapov */ 78f45d9fc9SGennady Sharapov ret = *((unsigned long *) mm_idp->stack); 79f45d9fc9SGennady Sharapov offset = *((unsigned long *) mm_idp->stack + 1); 80f45d9fc9SGennady Sharapov if (offset) { 8154ae36f2SJeff Dike data = (unsigned long *)(mm_idp->stack + offset - STUB_DATA); 82ba180fd4SJeff Dike printk(UM_KERN_ERR "do_syscall_stub : ret = %ld, offset = %ld, " 83802e3077SPaolo 'Blaisorblade' Giarrusso "data = %p\n", ret, offset, data); 84f45d9fc9SGennady Sharapov syscall = (unsigned long *)((unsigned long)data + data[0]); 85ba180fd4SJeff Dike printk(UM_KERN_ERR "do_syscall_stub: syscall %ld failed, " 86ba180fd4SJeff Dike "return value = 0x%lx, expected return value = 0x%lx\n", 87f45d9fc9SGennady Sharapov syscall[0], ret, syscall[7]); 88ba180fd4SJeff Dike printk(UM_KERN_ERR " syscall parameters: " 89f45d9fc9SGennady Sharapov "0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n", 90f45d9fc9SGennady Sharapov syscall[1], syscall[2], syscall[3], 91f45d9fc9SGennady Sharapov syscall[4], syscall[5], syscall[6]); 92f45d9fc9SGennady Sharapov for (n = 1; n < data[0]/sizeof(long); n++) { 93f45d9fc9SGennady Sharapov if (n == 1) 94ba180fd4SJeff Dike printk(UM_KERN_ERR " additional syscall " 95ba180fd4SJeff Dike "data:"); 96f45d9fc9SGennady Sharapov if (n % 4 == 1) 97ba180fd4SJeff Dike printk("\n" UM_KERN_ERR " "); 98f45d9fc9SGennady Sharapov printk(" 0x%lx", data[n]); 99f45d9fc9SGennady Sharapov } 100f45d9fc9SGennady Sharapov if (n > 1) 101f45d9fc9SGennady Sharapov printk("\n"); 102f45d9fc9SGennady Sharapov } 103f45d9fc9SGennady Sharapov else ret = 0; 104f45d9fc9SGennady Sharapov 105f45d9fc9SGennady Sharapov *addr = check_init_stack(mm_idp, NULL); 106f45d9fc9SGennady Sharapov 107f45d9fc9SGennady Sharapov return ret; 108f45d9fc9SGennady Sharapov } 109f45d9fc9SGennady Sharapov 110f45d9fc9SGennady Sharapov long run_syscall_stub(struct mm_id * mm_idp, int syscall, 111f45d9fc9SGennady Sharapov unsigned long *args, long expected, void **addr, 112f45d9fc9SGennady Sharapov int done) 113f45d9fc9SGennady Sharapov { 114f45d9fc9SGennady Sharapov unsigned long *stack = check_init_stack(mm_idp, *addr); 115f45d9fc9SGennady Sharapov 116f45d9fc9SGennady Sharapov *stack += sizeof(long); 117f45d9fc9SGennady Sharapov stack += *stack / sizeof(long); 118f45d9fc9SGennady Sharapov 119f45d9fc9SGennady Sharapov *stack++ = syscall; 120f45d9fc9SGennady Sharapov *stack++ = args[0]; 121f45d9fc9SGennady Sharapov *stack++ = args[1]; 122f45d9fc9SGennady Sharapov *stack++ = args[2]; 123f45d9fc9SGennady Sharapov *stack++ = args[3]; 124f45d9fc9SGennady Sharapov *stack++ = args[4]; 125f45d9fc9SGennady Sharapov *stack++ = args[5]; 126f45d9fc9SGennady Sharapov *stack++ = expected; 127f45d9fc9SGennady Sharapov *stack = 0; 128f45d9fc9SGennady Sharapov 129c539ab73SJeff Dike if (!done && ((((unsigned long) stack) & ~UM_KERN_PAGE_MASK) < 130c539ab73SJeff Dike UM_KERN_PAGE_SIZE - 10 * sizeof(long))) { 131f45d9fc9SGennady Sharapov *addr = stack; 132f45d9fc9SGennady Sharapov return 0; 133f45d9fc9SGennady Sharapov } 134f45d9fc9SGennady Sharapov 135f45d9fc9SGennady Sharapov return do_syscall_stub(mm_idp, addr); 136f45d9fc9SGennady Sharapov } 137f45d9fc9SGennady Sharapov 138f45d9fc9SGennady Sharapov long syscall_stub_data(struct mm_id * mm_idp, 139f45d9fc9SGennady Sharapov unsigned long *data, int data_count, 140f45d9fc9SGennady Sharapov void **addr, void **stub_addr) 141f45d9fc9SGennady Sharapov { 142f45d9fc9SGennady Sharapov unsigned long *stack; 143f45d9fc9SGennady Sharapov int ret = 0; 144f45d9fc9SGennady Sharapov 145ba180fd4SJeff Dike /* 146ba180fd4SJeff Dike * If *addr still is uninitialized, it *must* contain NULL. 147f45d9fc9SGennady Sharapov * Thus in this case do_syscall_stub correctly won't be called. 148f45d9fc9SGennady Sharapov */ 149c539ab73SJeff Dike if ((((unsigned long) *addr) & ~UM_KERN_PAGE_MASK) >= 150c539ab73SJeff Dike UM_KERN_PAGE_SIZE - (10 + data_count) * sizeof(long)) { 151f45d9fc9SGennady Sharapov ret = do_syscall_stub(mm_idp, addr); 152f45d9fc9SGennady Sharapov /* in case of error, don't overwrite data on stack */ 153f45d9fc9SGennady Sharapov if (ret) 154f45d9fc9SGennady Sharapov return ret; 155f45d9fc9SGennady Sharapov } 156f45d9fc9SGennady Sharapov 157f45d9fc9SGennady Sharapov stack = check_init_stack(mm_idp, *addr); 158f45d9fc9SGennady Sharapov *addr = stack; 159f45d9fc9SGennady Sharapov 160f45d9fc9SGennady Sharapov *stack = data_count * sizeof(long); 161f45d9fc9SGennady Sharapov 162f45d9fc9SGennady Sharapov memcpy(stack + 1, data, data_count * sizeof(long)); 163f45d9fc9SGennady Sharapov 164c539ab73SJeff Dike *stub_addr = (void *)(((unsigned long)(stack + 1) & 16554ae36f2SJeff Dike ~UM_KERN_PAGE_MASK) + STUB_DATA); 166f45d9fc9SGennady Sharapov 167f45d9fc9SGennady Sharapov return 0; 168f45d9fc9SGennady Sharapov } 169f45d9fc9SGennady Sharapov 17016dd07bcSJeff Dike int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len, int prot, 17116dd07bcSJeff Dike int phys_fd, unsigned long long offset, int done, void **data) 172f45d9fc9SGennady Sharapov { 17316dd07bcSJeff Dike int ret; 174f45d9fc9SGennady Sharapov unsigned long args[] = { virt, len, prot, 175f45d9fc9SGennady Sharapov MAP_SHARED | MAP_FIXED, phys_fd, 176f45d9fc9SGennady Sharapov MMAP_OFFSET(offset) }; 177f45d9fc9SGennady Sharapov 178f45d9fc9SGennady Sharapov ret = run_syscall_stub(mm_idp, STUB_MMAP_NR, args, virt, 179f45d9fc9SGennady Sharapov data, done); 180f45d9fc9SGennady Sharapov 181f45d9fc9SGennady Sharapov return ret; 182f45d9fc9SGennady Sharapov } 183f45d9fc9SGennady Sharapov 18464f60841SJeff Dike int unmap(struct mm_id * mm_idp, unsigned long addr, unsigned long len, 18564f60841SJeff Dike int done, void **data) 186f45d9fc9SGennady Sharapov { 187f45d9fc9SGennady Sharapov int ret; 188f45d9fc9SGennady Sharapov unsigned long args[] = { (unsigned long) addr, len, 0, 0, 0, 189f45d9fc9SGennady Sharapov 0 }; 190f45d9fc9SGennady Sharapov 191f45d9fc9SGennady Sharapov ret = run_syscall_stub(mm_idp, __NR_munmap, args, 0, 192f45d9fc9SGennady Sharapov data, done); 193f45d9fc9SGennady Sharapov 194f45d9fc9SGennady Sharapov return ret; 195f45d9fc9SGennady Sharapov } 196f45d9fc9SGennady Sharapov 197f45d9fc9SGennady Sharapov int protect(struct mm_id * mm_idp, unsigned long addr, unsigned long len, 19816dd07bcSJeff Dike unsigned int prot, int done, void **data) 199f45d9fc9SGennady Sharapov { 20016dd07bcSJeff Dike int ret; 201f45d9fc9SGennady Sharapov unsigned long args[] = { addr, len, prot, 0, 0, 0 }; 202f45d9fc9SGennady Sharapov 203f45d9fc9SGennady Sharapov ret = run_syscall_stub(mm_idp, __NR_mprotect, args, 0, 204f45d9fc9SGennady Sharapov data, done); 205f45d9fc9SGennady Sharapov 206f45d9fc9SGennady Sharapov return ret; 207f45d9fc9SGennady Sharapov } 208