qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio
at master 576 lines 17 kB view raw
1/* 2 * BSD syscalls 3 * 4 * Copyright (c) 2003 - 2008 Fabrice Bellard 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, see <http://www.gnu.org/licenses/>. 18 */ 19#include "qemu/osdep.h" 20#include "qemu/cutils.h" 21#include "qemu/path.h" 22#include <sys/syscall.h> 23#include <sys/param.h> 24#include <sys/sysctl.h> 25#include <utime.h> 26 27#include "qemu.h" 28#include "qemu-common.h" 29#include "user/syscall-trace.h" 30 31//#define DEBUG 32 33static abi_ulong target_brk; 34static abi_ulong target_original_brk; 35 36static inline abi_long get_errno(abi_long ret) 37{ 38 if (ret == -1) 39 /* XXX need to translate host -> target errnos here */ 40 return -(errno); 41 else 42 return ret; 43} 44 45#define target_to_host_bitmask(x, tbl) (x) 46 47static inline int is_error(abi_long ret) 48{ 49 return (abi_ulong)ret >= (abi_ulong)(-4096); 50} 51 52void target_set_brk(abi_ulong new_brk) 53{ 54 target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk); 55} 56 57/* do_obreak() must return target errnos. */ 58static abi_long do_obreak(abi_ulong new_brk) 59{ 60 abi_ulong brk_page; 61 abi_long mapped_addr; 62 int new_alloc_size; 63 64 if (!new_brk) 65 return 0; 66 if (new_brk < target_original_brk) 67 return -TARGET_EINVAL; 68 69 brk_page = HOST_PAGE_ALIGN(target_brk); 70 71 /* If the new brk is less than this, set it and we're done... */ 72 if (new_brk < brk_page) { 73 target_brk = new_brk; 74 return 0; 75 } 76 77 /* We need to allocate more memory after the brk... */ 78 new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page + 1); 79 mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size, 80 PROT_READ|PROT_WRITE, 81 MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0)); 82 83 if (!is_error(mapped_addr)) 84 target_brk = new_brk; 85 else 86 return mapped_addr; 87 88 return 0; 89} 90 91#if defined(TARGET_I386) 92static abi_long do_freebsd_sysarch(CPUX86State *env, int op, abi_ulong parms) 93{ 94 abi_long ret = 0; 95 abi_ulong val; 96 int idx; 97 98 switch(op) { 99#ifdef TARGET_ABI32 100 case TARGET_FREEBSD_I386_SET_GSBASE: 101 case TARGET_FREEBSD_I386_SET_FSBASE: 102 if (op == TARGET_FREEBSD_I386_SET_GSBASE) 103#else 104 case TARGET_FREEBSD_AMD64_SET_GSBASE: 105 case TARGET_FREEBSD_AMD64_SET_FSBASE: 106 if (op == TARGET_FREEBSD_AMD64_SET_GSBASE) 107#endif 108 idx = R_GS; 109 else 110 idx = R_FS; 111 if (get_user(val, parms, abi_ulong)) 112 return -TARGET_EFAULT; 113 cpu_x86_load_seg(env, idx, 0); 114 env->segs[idx].base = val; 115 break; 116#ifdef TARGET_ABI32 117 case TARGET_FREEBSD_I386_GET_GSBASE: 118 case TARGET_FREEBSD_I386_GET_FSBASE: 119 if (op == TARGET_FREEBSD_I386_GET_GSBASE) 120#else 121 case TARGET_FREEBSD_AMD64_GET_GSBASE: 122 case TARGET_FREEBSD_AMD64_GET_FSBASE: 123 if (op == TARGET_FREEBSD_AMD64_GET_GSBASE) 124#endif 125 idx = R_GS; 126 else 127 idx = R_FS; 128 val = env->segs[idx].base; 129 if (put_user(val, parms, abi_ulong)) 130 return -TARGET_EFAULT; 131 break; 132 /* XXX handle the others... */ 133 default: 134 ret = -TARGET_EINVAL; 135 break; 136 } 137 return ret; 138} 139#endif 140 141#ifdef TARGET_SPARC 142static abi_long do_freebsd_sysarch(void *env, int op, abi_ulong parms) 143{ 144 /* XXX handle 145 * TARGET_FREEBSD_SPARC_UTRAP_INSTALL, 146 * TARGET_FREEBSD_SPARC_SIGTRAMP_INSTALL 147 */ 148 return -TARGET_EINVAL; 149} 150#endif 151 152#ifdef __FreeBSD__ 153/* 154 * XXX this uses the undocumented oidfmt interface to find the kind of 155 * a requested sysctl, see /sys/kern/kern_sysctl.c:sysctl_sysctl_oidfmt() 156 * (this is mostly copied from src/sbin/sysctl/sysctl.c) 157 */ 158static int 159oidfmt(int *oid, int len, char *fmt, uint32_t *kind) 160{ 161 int qoid[CTL_MAXNAME+2]; 162 uint8_t buf[BUFSIZ]; 163 int i; 164 size_t j; 165 166 qoid[0] = 0; 167 qoid[1] = 4; 168 memcpy(qoid + 2, oid, len * sizeof(int)); 169 170 j = sizeof(buf); 171 i = sysctl(qoid, len + 2, buf, &j, 0, 0); 172 if (i) 173 return i; 174 175 if (kind) 176 *kind = *(uint32_t *)buf; 177 178 if (fmt) 179 strcpy(fmt, (char *)(buf + sizeof(uint32_t))); 180 return (0); 181} 182 183/* 184 * try and convert sysctl return data for the target. 185 * XXX doesn't handle CTLTYPE_OPAQUE and CTLTYPE_STRUCT. 186 */ 187static int sysctl_oldcvt(void *holdp, size_t holdlen, uint32_t kind) 188{ 189 switch (kind & CTLTYPE) { 190 case CTLTYPE_INT: 191 case CTLTYPE_UINT: 192 *(uint32_t *)holdp = tswap32(*(uint32_t *)holdp); 193 break; 194#ifdef TARGET_ABI32 195 case CTLTYPE_LONG: 196 case CTLTYPE_ULONG: 197 *(uint32_t *)holdp = tswap32(*(long *)holdp); 198 break; 199#else 200 case CTLTYPE_LONG: 201 *(uint64_t *)holdp = tswap64(*(long *)holdp); 202 case CTLTYPE_ULONG: 203 *(uint64_t *)holdp = tswap64(*(unsigned long *)holdp); 204 break; 205#endif 206#ifdef CTLTYPE_U64 207 case CTLTYPE_S64: 208 case CTLTYPE_U64: 209#else 210 case CTLTYPE_QUAD: 211#endif 212 *(uint64_t *)holdp = tswap64(*(uint64_t *)holdp); 213 break; 214 case CTLTYPE_STRING: 215 break; 216 default: 217 /* XXX unhandled */ 218 return -1; 219 } 220 return 0; 221} 222 223/* XXX this needs to be emulated on non-FreeBSD hosts... */ 224static abi_long do_freebsd_sysctl(abi_ulong namep, int32_t namelen, abi_ulong oldp, 225 abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen) 226{ 227 abi_long ret; 228 void *hnamep, *holdp, *hnewp = NULL; 229 size_t holdlen; 230 abi_ulong oldlen = 0; 231 int32_t *snamep = g_malloc(sizeof(int32_t) * namelen), *p, *q, i; 232 uint32_t kind = 0; 233 234 if (oldlenp) 235 get_user_ual(oldlen, oldlenp); 236 if (!(hnamep = lock_user(VERIFY_READ, namep, namelen, 1))) 237 return -TARGET_EFAULT; 238 if (newp && !(hnewp = lock_user(VERIFY_READ, newp, newlen, 1))) 239 return -TARGET_EFAULT; 240 if (!(holdp = lock_user(VERIFY_WRITE, oldp, oldlen, 0))) 241 return -TARGET_EFAULT; 242 holdlen = oldlen; 243 for (p = hnamep, q = snamep, i = 0; i < namelen; p++, i++) 244 *q++ = tswap32(*p); 245 oidfmt(snamep, namelen, NULL, &kind); 246 /* XXX swap hnewp */ 247 ret = get_errno(sysctl(snamep, namelen, holdp, &holdlen, hnewp, newlen)); 248 if (!ret) 249 sysctl_oldcvt(holdp, holdlen, kind); 250 put_user_ual(holdlen, oldlenp); 251 unlock_user(hnamep, namep, 0); 252 unlock_user(holdp, oldp, holdlen); 253 if (hnewp) 254 unlock_user(hnewp, newp, 0); 255 g_free(snamep); 256 return ret; 257} 258#endif 259 260/* FIXME 261 * lock_iovec()/unlock_iovec() have a return code of 0 for success where 262 * other lock functions have a return code of 0 for failure. 263 */ 264static abi_long lock_iovec(int type, struct iovec *vec, abi_ulong target_addr, 265 int count, int copy) 266{ 267 struct target_iovec *target_vec; 268 abi_ulong base; 269 int i; 270 271 target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1); 272 if (!target_vec) 273 return -TARGET_EFAULT; 274 for(i = 0;i < count; i++) { 275 base = tswapl(target_vec[i].iov_base); 276 vec[i].iov_len = tswapl(target_vec[i].iov_len); 277 if (vec[i].iov_len != 0) { 278 vec[i].iov_base = lock_user(type, base, vec[i].iov_len, copy); 279 /* Don't check lock_user return value. We must call writev even 280 if a element has invalid base address. */ 281 } else { 282 /* zero length pointer is ignored */ 283 vec[i].iov_base = NULL; 284 } 285 } 286 unlock_user (target_vec, target_addr, 0); 287 return 0; 288} 289 290static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr, 291 int count, int copy) 292{ 293 struct target_iovec *target_vec; 294 abi_ulong base; 295 int i; 296 297 target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1); 298 if (!target_vec) 299 return -TARGET_EFAULT; 300 for(i = 0;i < count; i++) { 301 if (target_vec[i].iov_base) { 302 base = tswapl(target_vec[i].iov_base); 303 unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0); 304 } 305 } 306 unlock_user (target_vec, target_addr, 0); 307 308 return 0; 309} 310 311/* do_syscall() should always have a single exit point at the end so 312 that actions, such as logging of syscall results, can be performed. 313 All errnos that do_syscall() returns must be -TARGET_<errcode>. */ 314abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, 315 abi_long arg2, abi_long arg3, abi_long arg4, 316 abi_long arg5, abi_long arg6, abi_long arg7, 317 abi_long arg8) 318{ 319 CPUState *cpu = env_cpu(cpu_env); 320 abi_long ret; 321 void *p; 322 323#ifdef DEBUG 324 gemu_log("freebsd syscall %d\n", num); 325#endif 326 record_syscall_start(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, 0, 0); 327 328 if(do_strace) 329 print_freebsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6); 330 331 switch(num) { 332 case TARGET_FREEBSD_NR_exit: 333#ifdef CONFIG_GPROF 334 _mcleanup(); 335#endif 336 gdb_exit(cpu_env, arg1); 337 qemu_plugin_atexit_cb(); 338 /* XXX: should free thread stack and CPU env */ 339 _exit(arg1); 340 ret = 0; /* avoid warning */ 341 break; 342 case TARGET_FREEBSD_NR_read: 343 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) 344 goto efault; 345 ret = get_errno(read(arg1, p, arg3)); 346 unlock_user(p, arg2, ret); 347 break; 348 case TARGET_FREEBSD_NR_write: 349 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1))) 350 goto efault; 351 ret = get_errno(write(arg1, p, arg3)); 352 unlock_user(p, arg2, 0); 353 break; 354 case TARGET_FREEBSD_NR_writev: 355 { 356 int count = arg3; 357 struct iovec *vec; 358 359 vec = alloca(count * sizeof(struct iovec)); 360 if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0) 361 goto efault; 362 ret = get_errno(writev(arg1, vec, count)); 363 unlock_iovec(vec, arg2, count, 0); 364 } 365 break; 366 case TARGET_FREEBSD_NR_open: 367 if (!(p = lock_user_string(arg1))) 368 goto efault; 369 ret = get_errno(open(path(p), 370 target_to_host_bitmask(arg2, fcntl_flags_tbl), 371 arg3)); 372 unlock_user(p, arg1, 0); 373 break; 374 case TARGET_FREEBSD_NR_mmap: 375 ret = get_errno(target_mmap(arg1, arg2, arg3, 376 target_to_host_bitmask(arg4, mmap_flags_tbl), 377 arg5, 378 arg6)); 379 break; 380 case TARGET_FREEBSD_NR_mprotect: 381 ret = get_errno(target_mprotect(arg1, arg2, arg3)); 382 break; 383 case TARGET_FREEBSD_NR_break: 384 ret = do_obreak(arg1); 385 break; 386#ifdef __FreeBSD__ 387 case TARGET_FREEBSD_NR___sysctl: 388 ret = do_freebsd_sysctl(arg1, arg2, arg3, arg4, arg5, arg6); 389 break; 390#endif 391 case TARGET_FREEBSD_NR_sysarch: 392 ret = do_freebsd_sysarch(cpu_env, arg1, arg2); 393 break; 394 case TARGET_FREEBSD_NR_syscall: 395 case TARGET_FREEBSD_NR___syscall: 396 ret = do_freebsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,arg7,arg8,0); 397 break; 398 default: 399 ret = get_errno(syscall(num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)); 400 break; 401 } 402 fail: 403#ifdef DEBUG 404 gemu_log(" = %ld\n", ret); 405#endif 406 if (do_strace) 407 print_freebsd_syscall_ret(num, ret); 408 409 record_syscall_return(cpu, num, ret); 410 return ret; 411 efault: 412 ret = -TARGET_EFAULT; 413 goto fail; 414} 415 416abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1, 417 abi_long arg2, abi_long arg3, abi_long arg4, 418 abi_long arg5, abi_long arg6) 419{ 420 CPUState *cpu = env_cpu(cpu_env); 421 abi_long ret; 422 void *p; 423 424#ifdef DEBUG 425 gemu_log("netbsd syscall %d\n", num); 426#endif 427 428 record_syscall_start(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, 0, 0); 429 430 if(do_strace) 431 print_netbsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6); 432 433 switch(num) { 434 case TARGET_NETBSD_NR_exit: 435#ifdef CONFIG_GPROF 436 _mcleanup(); 437#endif 438 gdb_exit(cpu_env, arg1); 439 qemu_plugin_atexit_cb(); 440 /* XXX: should free thread stack and CPU env */ 441 _exit(arg1); 442 ret = 0; /* avoid warning */ 443 break; 444 case TARGET_NETBSD_NR_read: 445 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) 446 goto efault; 447 ret = get_errno(read(arg1, p, arg3)); 448 unlock_user(p, arg2, ret); 449 break; 450 case TARGET_NETBSD_NR_write: 451 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1))) 452 goto efault; 453 ret = get_errno(write(arg1, p, arg3)); 454 unlock_user(p, arg2, 0); 455 break; 456 case TARGET_NETBSD_NR_open: 457 if (!(p = lock_user_string(arg1))) 458 goto efault; 459 ret = get_errno(open(path(p), 460 target_to_host_bitmask(arg2, fcntl_flags_tbl), 461 arg3)); 462 unlock_user(p, arg1, 0); 463 break; 464 case TARGET_NETBSD_NR_mmap: 465 ret = get_errno(target_mmap(arg1, arg2, arg3, 466 target_to_host_bitmask(arg4, mmap_flags_tbl), 467 arg5, 468 arg6)); 469 break; 470 case TARGET_NETBSD_NR_mprotect: 471 ret = get_errno(target_mprotect(arg1, arg2, arg3)); 472 break; 473 case TARGET_NETBSD_NR_syscall: 474 case TARGET_NETBSD_NR___syscall: 475 ret = do_netbsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0); 476 break; 477 default: 478 ret = syscall(num, arg1, arg2, arg3, arg4, arg5, arg6); 479 break; 480 } 481 fail: 482#ifdef DEBUG 483 gemu_log(" = %ld\n", ret); 484#endif 485 if (do_strace) 486 print_netbsd_syscall_ret(num, ret); 487 488 record_syscall_return(cpu, num, ret); 489 return ret; 490 efault: 491 ret = -TARGET_EFAULT; 492 goto fail; 493} 494 495abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1, 496 abi_long arg2, abi_long arg3, abi_long arg4, 497 abi_long arg5, abi_long arg6) 498{ 499 CPUState *cpu = env_cpu(cpu_env); 500 abi_long ret; 501 void *p; 502 503#ifdef DEBUG 504 gemu_log("openbsd syscall %d\n", num); 505#endif 506 507 record_syscall_start(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, 0, 0); 508 509 if(do_strace) 510 print_openbsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6); 511 512 switch(num) { 513 case TARGET_OPENBSD_NR_exit: 514#ifdef CONFIG_GPROF 515 _mcleanup(); 516#endif 517 gdb_exit(cpu_env, arg1); 518 qemu_plugin_atexit_cb(); 519 /* XXX: should free thread stack and CPU env */ 520 _exit(arg1); 521 ret = 0; /* avoid warning */ 522 break; 523 case TARGET_OPENBSD_NR_read: 524 if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) 525 goto efault; 526 ret = get_errno(read(arg1, p, arg3)); 527 unlock_user(p, arg2, ret); 528 break; 529 case TARGET_OPENBSD_NR_write: 530 if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1))) 531 goto efault; 532 ret = get_errno(write(arg1, p, arg3)); 533 unlock_user(p, arg2, 0); 534 break; 535 case TARGET_OPENBSD_NR_open: 536 if (!(p = lock_user_string(arg1))) 537 goto efault; 538 ret = get_errno(open(path(p), 539 target_to_host_bitmask(arg2, fcntl_flags_tbl), 540 arg3)); 541 unlock_user(p, arg1, 0); 542 break; 543 case TARGET_OPENBSD_NR_mmap: 544 ret = get_errno(target_mmap(arg1, arg2, arg3, 545 target_to_host_bitmask(arg4, mmap_flags_tbl), 546 arg5, 547 arg6)); 548 break; 549 case TARGET_OPENBSD_NR_mprotect: 550 ret = get_errno(target_mprotect(arg1, arg2, arg3)); 551 break; 552 case TARGET_OPENBSD_NR_syscall: 553 case TARGET_OPENBSD_NR___syscall: 554 ret = do_openbsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0); 555 break; 556 default: 557 ret = syscall(num, arg1, arg2, arg3, arg4, arg5, arg6); 558 break; 559 } 560 fail: 561#ifdef DEBUG 562 gemu_log(" = %ld\n", ret); 563#endif 564 if (do_strace) 565 print_openbsd_syscall_ret(num, ret); 566 567 record_syscall_return(cpu, num, ret); 568 return ret; 569 efault: 570 ret = -TARGET_EFAULT; 571 goto fail; 572} 573 574void syscall_init(void) 575{ 576}