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