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