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