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 30extern unsigned long batch_syscall_stub, __syscall_stub_start; 31 32extern void wait_stub_done(int pid); 33 34static 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 44static unsigned long syscall_regs[MAX_REG_NR]; 45 46static 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 57extern int proc_mm; 58 59int single_count = 0; 60int multi_count = 0; 61int multi_op_count = 0; 62 63static 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 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 129long 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 161long 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 192int 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 231int 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 264int 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 298void before_mem_skas(unsigned long unused) 299{ 300} 301