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