|
|
1.1 ! root 1: /* ! 2: * qemu user main ! 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, write to the Free Software ! 18: * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, ! 19: * MA 02110-1301, USA. ! 20: */ ! 21: #include <stdlib.h> ! 22: #include <stdio.h> ! 23: #include <stdarg.h> ! 24: #include <string.h> ! 25: #include <errno.h> ! 26: #include <unistd.h> ! 27: #include <machine/trap.h> ! 28: ! 29: #include "qemu.h" ! 30: #include "qemu-common.h" ! 31: /* For tb_lock */ ! 32: #include "exec-all.h" ! 33: ! 34: #define DEBUG_LOGFILE "/tmp/qemu.log" ! 35: ! 36: static const char *interp_prefix = CONFIG_QEMU_PREFIX; ! 37: const char *qemu_uname_release = CONFIG_UNAME_RELEASE; ! 38: extern char **environ; ! 39: ! 40: /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so ! 41: we allocate a bigger stack. Need a better solution, for example ! 42: by remapping the process stack directly at the right place */ ! 43: unsigned long x86_stack_size = 512 * 1024; ! 44: ! 45: void gemu_log(const char *fmt, ...) ! 46: { ! 47: va_list ap; ! 48: ! 49: va_start(ap, fmt); ! 50: vfprintf(stderr, fmt, ap); ! 51: va_end(ap); ! 52: } ! 53: #ifdef TARGET_SPARC ! 54: #define SPARC64_STACK_BIAS 2047 ! 55: ! 56: //#define DEBUG_WIN ! 57: /* WARNING: dealing with register windows _is_ complicated. More info ! 58: can be found at http://www.sics.se/~psm/sparcstack.html */ ! 59: static inline int get_reg_index(CPUSPARCState *env, int cwp, int index) ! 60: { ! 61: index = (index + cwp * 16) % (16 * env->nwindows); ! 62: /* wrap handling : if cwp is on the last window, then we use the ! 63: registers 'after' the end */ ! 64: if (index < 8 && env->cwp == env->nwindows - 1) ! 65: index += 16 * env->nwindows; ! 66: return index; ! 67: } ! 68: ! 69: /* save the register window 'cwp1' */ ! 70: static inline void save_window_offset(CPUSPARCState *env, int cwp1) ! 71: { ! 72: unsigned int i; ! 73: abi_ulong sp_ptr; ! 74: ! 75: sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)]; ! 76: #ifdef TARGET_SPARC64 ! 77: if (sp_ptr & 3) ! 78: sp_ptr += SPARC64_STACK_BIAS; ! 79: #endif ! 80: #if defined(DEBUG_WIN) ! 81: printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n", ! 82: sp_ptr, cwp1); ! 83: #endif ! 84: for(i = 0; i < 16; i++) { ! 85: /* FIXME - what to do if put_user() fails? */ ! 86: put_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr); ! 87: sp_ptr += sizeof(abi_ulong); ! 88: } ! 89: } ! 90: ! 91: static void save_window(CPUSPARCState *env) ! 92: { ! 93: #ifndef TARGET_SPARC64 ! 94: unsigned int new_wim; ! 95: new_wim = ((env->wim >> 1) | (env->wim << (env->nwindows - 1))) & ! 96: ((1LL << env->nwindows) - 1); ! 97: save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2)); ! 98: env->wim = new_wim; ! 99: #else ! 100: save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2)); ! 101: env->cansave++; ! 102: env->canrestore--; ! 103: #endif ! 104: } ! 105: ! 106: static void restore_window(CPUSPARCState *env) ! 107: { ! 108: #ifndef TARGET_SPARC64 ! 109: unsigned int new_wim; ! 110: #endif ! 111: unsigned int i, cwp1; ! 112: abi_ulong sp_ptr; ! 113: ! 114: #ifndef TARGET_SPARC64 ! 115: new_wim = ((env->wim << 1) | (env->wim >> (env->nwindows - 1))) & ! 116: ((1LL << env->nwindows) - 1); ! 117: #endif ! 118: ! 119: /* restore the invalid window */ ! 120: cwp1 = cpu_cwp_inc(env, env->cwp + 1); ! 121: sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)]; ! 122: #ifdef TARGET_SPARC64 ! 123: if (sp_ptr & 3) ! 124: sp_ptr += SPARC64_STACK_BIAS; ! 125: #endif ! 126: #if defined(DEBUG_WIN) ! 127: printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n", ! 128: sp_ptr, cwp1); ! 129: #endif ! 130: for(i = 0; i < 16; i++) { ! 131: /* FIXME - what to do if get_user() fails? */ ! 132: get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr); ! 133: sp_ptr += sizeof(abi_ulong); ! 134: } ! 135: #ifdef TARGET_SPARC64 ! 136: env->canrestore++; ! 137: if (env->cleanwin < env->nwindows - 1) ! 138: env->cleanwin++; ! 139: env->cansave--; ! 140: #else ! 141: env->wim = new_wim; ! 142: #endif ! 143: } ! 144: ! 145: static void flush_windows(CPUSPARCState *env) ! 146: { ! 147: int offset, cwp1; ! 148: ! 149: offset = 1; ! 150: for(;;) { ! 151: /* if restore would invoke restore_window(), then we can stop */ ! 152: cwp1 = cpu_cwp_inc(env, env->cwp + offset); ! 153: #ifndef TARGET_SPARC64 ! 154: if (env->wim & (1 << cwp1)) ! 155: break; ! 156: #else ! 157: if (env->canrestore == 0) ! 158: break; ! 159: env->cansave++; ! 160: env->canrestore--; ! 161: #endif ! 162: save_window_offset(env, cwp1); ! 163: offset++; ! 164: } ! 165: cwp1 = cpu_cwp_inc(env, env->cwp + 1); ! 166: #ifndef TARGET_SPARC64 ! 167: /* set wim so that restore will reload the registers */ ! 168: env->wim = 1 << cwp1; ! 169: #endif ! 170: #if defined(DEBUG_WIN) ! 171: printf("flush_windows: nb=%d\n", offset - 1); ! 172: #endif ! 173: } ! 174: ! 175: void cpu_loop(CPUSPARCState *env, enum BSDType bsd_type) ! 176: { ! 177: int trapnr, ret, syscall_nr; ! 178: //target_siginfo_t info; ! 179: ! 180: while (1) { ! 181: trapnr = cpu_sparc_exec (env); ! 182: ! 183: switch (trapnr) { ! 184: #ifndef TARGET_SPARC64 ! 185: case 0x80: ! 186: #else ! 187: case 0x100: ! 188: #endif ! 189: syscall_nr = env->gregs[1]; ! 190: if (bsd_type == target_freebsd) ! 191: ret = do_freebsd_syscall(env, syscall_nr, ! 192: env->regwptr[0], env->regwptr[1], ! 193: env->regwptr[2], env->regwptr[3], ! 194: env->regwptr[4], env->regwptr[5]); ! 195: else if (bsd_type == target_netbsd) ! 196: ret = do_netbsd_syscall(env, syscall_nr, ! 197: env->regwptr[0], env->regwptr[1], ! 198: env->regwptr[2], env->regwptr[3], ! 199: env->regwptr[4], env->regwptr[5]); ! 200: else { //if (bsd_type == target_openbsd) ! 201: #if defined(TARGET_SPARC64) ! 202: syscall_nr &= ~(TARGET_OPENBSD_SYSCALL_G7RFLAG | ! 203: TARGET_OPENBSD_SYSCALL_G2RFLAG); ! 204: #endif ! 205: ret = do_openbsd_syscall(env, syscall_nr, ! 206: env->regwptr[0], env->regwptr[1], ! 207: env->regwptr[2], env->regwptr[3], ! 208: env->regwptr[4], env->regwptr[5]); ! 209: } ! 210: if ((unsigned int)ret >= (unsigned int)(-515)) { ! 211: #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) ! 212: env->xcc |= PSR_CARRY; ! 213: #else ! 214: env->psr |= PSR_CARRY; ! 215: #endif ! 216: } else { ! 217: #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) ! 218: env->xcc &= ~PSR_CARRY; ! 219: #else ! 220: env->psr &= ~PSR_CARRY; ! 221: #endif ! 222: } ! 223: env->regwptr[0] = ret; ! 224: /* next instruction */ ! 225: #if defined(TARGET_SPARC64) ! 226: if (bsd_type == target_openbsd && ! 227: env->gregs[1] & TARGET_OPENBSD_SYSCALL_G2RFLAG) { ! 228: env->pc = env->gregs[2]; ! 229: env->npc = env->pc + 4; ! 230: } else if (bsd_type == target_openbsd && ! 231: env->gregs[1] & TARGET_OPENBSD_SYSCALL_G7RFLAG) { ! 232: env->pc = env->gregs[7]; ! 233: env->npc = env->pc + 4; ! 234: } else { ! 235: env->pc = env->npc; ! 236: env->npc = env->npc + 4; ! 237: } ! 238: #else ! 239: env->pc = env->npc; ! 240: env->npc = env->npc + 4; ! 241: #endif ! 242: break; ! 243: case 0x83: /* flush windows */ ! 244: #ifdef TARGET_ABI32 ! 245: case 0x103: ! 246: #endif ! 247: flush_windows(env); ! 248: /* next instruction */ ! 249: env->pc = env->npc; ! 250: env->npc = env->npc + 4; ! 251: break; ! 252: #ifndef TARGET_SPARC64 ! 253: case TT_WIN_OVF: /* window overflow */ ! 254: save_window(env); ! 255: break; ! 256: case TT_WIN_UNF: /* window underflow */ ! 257: restore_window(env); ! 258: break; ! 259: case TT_TFAULT: ! 260: case TT_DFAULT: ! 261: #if 0 ! 262: { ! 263: info.si_signo = SIGSEGV; ! 264: info.si_errno = 0; ! 265: /* XXX: check env->error_code */ ! 266: info.si_code = TARGET_SEGV_MAPERR; ! 267: info._sifields._sigfault._addr = env->mmuregs[4]; ! 268: queue_signal(env, info.si_signo, &info); ! 269: } ! 270: #endif ! 271: break; ! 272: #else ! 273: case TT_SPILL: /* window overflow */ ! 274: save_window(env); ! 275: break; ! 276: case TT_FILL: /* window underflow */ ! 277: restore_window(env); ! 278: break; ! 279: case TT_TFAULT: ! 280: case TT_DFAULT: ! 281: #if 0 ! 282: { ! 283: info.si_signo = SIGSEGV; ! 284: info.si_errno = 0; ! 285: /* XXX: check env->error_code */ ! 286: info.si_code = TARGET_SEGV_MAPERR; ! 287: if (trapnr == TT_DFAULT) ! 288: info._sifields._sigfault._addr = env->dmmuregs[4]; ! 289: else ! 290: info._sifields._sigfault._addr = env->tsptr->tpc; ! 291: //queue_signal(env, info.si_signo, &info); ! 292: } ! 293: #endif ! 294: break; ! 295: #endif ! 296: case EXCP_INTERRUPT: ! 297: /* just indicate that signals should be handled asap */ ! 298: break; ! 299: case EXCP_DEBUG: ! 300: { ! 301: int sig; ! 302: ! 303: sig = gdb_handlesig (env, TARGET_SIGTRAP); ! 304: #if 0 ! 305: if (sig) ! 306: { ! 307: info.si_signo = sig; ! 308: info.si_errno = 0; ! 309: info.si_code = TARGET_TRAP_BRKPT; ! 310: //queue_signal(env, info.si_signo, &info); ! 311: } ! 312: #endif ! 313: } ! 314: break; ! 315: default: ! 316: printf ("Unhandled trap: 0x%x\n", trapnr); ! 317: cpu_dump_state(env, stderr, fprintf, 0); ! 318: exit (1); ! 319: } ! 320: process_pending_signals (env); ! 321: } ! 322: } ! 323: ! 324: #endif ! 325: ! 326: static void usage(void) ! 327: { ! 328: printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n" ! 329: "usage: qemu-" TARGET_ARCH " [options] program [arguments...]\n" ! 330: "BSD CPU emulator (compiled for %s emulation)\n" ! 331: "\n" ! 332: "Standard options:\n" ! 333: "-h print this help\n" ! 334: "-g port wait gdb connection to port\n" ! 335: "-L path set the elf interpreter prefix (default=%s)\n" ! 336: "-s size set the stack size in bytes (default=%ld)\n" ! 337: "-cpu model select CPU (-cpu ? for list)\n" ! 338: "-drop-ld-preload drop LD_PRELOAD for target process\n" ! 339: "-bsd type select emulated BSD type FreeBSD/NetBSD/OpenBSD (default)\n" ! 340: "\n" ! 341: "Debug options:\n" ! 342: "-d options activate log (logfile=%s)\n" ! 343: "-p pagesize set the host page size to 'pagesize'\n" ! 344: "-strace log system calls\n" ! 345: "\n" ! 346: "Environment variables:\n" ! 347: "QEMU_STRACE Print system calls and arguments similar to the\n" ! 348: " 'strace' program. Enable by setting to any value.\n" ! 349: , ! 350: TARGET_ARCH, ! 351: interp_prefix, ! 352: x86_stack_size, ! 353: DEBUG_LOGFILE); ! 354: exit(1); ! 355: } ! 356: ! 357: THREAD CPUState *thread_env; ! 358: ! 359: /* Assumes contents are already zeroed. */ ! 360: void init_task_state(TaskState *ts) ! 361: { ! 362: int i; ! 363: ! 364: ts->used = 1; ! 365: ts->first_free = ts->sigqueue_table; ! 366: for (i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++) { ! 367: ts->sigqueue_table[i].next = &ts->sigqueue_table[i + 1]; ! 368: } ! 369: ts->sigqueue_table[i].next = NULL; ! 370: } ! 371: ! 372: int main(int argc, char **argv) ! 373: { ! 374: const char *filename; ! 375: const char *cpu_model; ! 376: struct target_pt_regs regs1, *regs = ®s1; ! 377: struct image_info info1, *info = &info1; ! 378: TaskState ts1, *ts = &ts1; ! 379: CPUState *env; ! 380: int optind; ! 381: const char *r; ! 382: int gdbstub_port = 0; ! 383: int drop_ld_preload = 0, environ_count = 0; ! 384: char **target_environ, **wrk, **dst; ! 385: enum BSDType bsd_type = target_openbsd; ! 386: ! 387: if (argc <= 1) ! 388: usage(); ! 389: ! 390: /* init debug */ ! 391: cpu_set_log_filename(DEBUG_LOGFILE); ! 392: ! 393: cpu_model = NULL; ! 394: optind = 1; ! 395: for(;;) { ! 396: if (optind >= argc) ! 397: break; ! 398: r = argv[optind]; ! 399: if (r[0] != '-') ! 400: break; ! 401: optind++; ! 402: r++; ! 403: if (!strcmp(r, "-")) { ! 404: break; ! 405: } else if (!strcmp(r, "d")) { ! 406: int mask; ! 407: const CPULogItem *item; ! 408: ! 409: if (optind >= argc) ! 410: break; ! 411: ! 412: r = argv[optind++]; ! 413: mask = cpu_str_to_log_mask(r); ! 414: if (!mask) { ! 415: printf("Log items (comma separated):\n"); ! 416: for(item = cpu_log_items; item->mask != 0; item++) { ! 417: printf("%-10s %s\n", item->name, item->help); ! 418: } ! 419: exit(1); ! 420: } ! 421: cpu_set_log(mask); ! 422: } else if (!strcmp(r, "s")) { ! 423: r = argv[optind++]; ! 424: x86_stack_size = strtol(r, (char **)&r, 0); ! 425: if (x86_stack_size <= 0) ! 426: usage(); ! 427: if (*r == 'M') ! 428: x86_stack_size *= 1024 * 1024; ! 429: else if (*r == 'k' || *r == 'K') ! 430: x86_stack_size *= 1024; ! 431: } else if (!strcmp(r, "L")) { ! 432: interp_prefix = argv[optind++]; ! 433: } else if (!strcmp(r, "p")) { ! 434: qemu_host_page_size = atoi(argv[optind++]); ! 435: if (qemu_host_page_size == 0 || ! 436: (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) { ! 437: fprintf(stderr, "page size must be a power of two\n"); ! 438: exit(1); ! 439: } ! 440: } else if (!strcmp(r, "g")) { ! 441: gdbstub_port = atoi(argv[optind++]); ! 442: } else if (!strcmp(r, "r")) { ! 443: qemu_uname_release = argv[optind++]; ! 444: } else if (!strcmp(r, "cpu")) { ! 445: cpu_model = argv[optind++]; ! 446: if (strcmp(cpu_model, "?") == 0) { ! 447: /* XXX: implement xxx_cpu_list for targets that still miss it */ ! 448: #if defined(cpu_list) ! 449: cpu_list(stdout, &fprintf); ! 450: #endif ! 451: exit(1); ! 452: } ! 453: } else if (!strcmp(r, "drop-ld-preload")) { ! 454: drop_ld_preload = 1; ! 455: } else if (!strcmp(r, "bsd")) { ! 456: if (!strcasecmp(argv[optind], "freebsd")) { ! 457: bsd_type = target_freebsd; ! 458: } else if (!strcasecmp(argv[optind], "netbsd")) { ! 459: bsd_type = target_netbsd; ! 460: } else if (!strcasecmp(argv[optind], "openbsd")) { ! 461: bsd_type = target_openbsd; ! 462: } else { ! 463: usage(); ! 464: } ! 465: optind++; ! 466: } else if (!strcmp(r, "strace")) { ! 467: do_strace = 1; ! 468: } else ! 469: { ! 470: usage(); ! 471: } ! 472: } ! 473: if (optind >= argc) ! 474: usage(); ! 475: filename = argv[optind]; ! 476: ! 477: /* Zero out regs */ ! 478: memset(regs, 0, sizeof(struct target_pt_regs)); ! 479: ! 480: /* Zero out image_info */ ! 481: memset(info, 0, sizeof(struct image_info)); ! 482: ! 483: /* Scan interp_prefix dir for replacement files. */ ! 484: init_paths(interp_prefix); ! 485: ! 486: if (cpu_model == NULL) { ! 487: #if defined(TARGET_SPARC) ! 488: #ifdef TARGET_SPARC64 ! 489: cpu_model = "TI UltraSparc II"; ! 490: #else ! 491: cpu_model = "Fujitsu MB86904"; ! 492: #endif ! 493: #else ! 494: cpu_model = "any"; ! 495: #endif ! 496: } ! 497: cpu_exec_init_all(0); ! 498: /* NOTE: we need to init the CPU at this stage to get ! 499: qemu_host_page_size */ ! 500: env = cpu_init(cpu_model); ! 501: if (!env) { ! 502: fprintf(stderr, "Unable to find CPU definition\n"); ! 503: exit(1); ! 504: } ! 505: thread_env = env; ! 506: ! 507: if (getenv("QEMU_STRACE")) { ! 508: do_strace = 1; ! 509: } ! 510: ! 511: wrk = environ; ! 512: while (*(wrk++)) ! 513: environ_count++; ! 514: ! 515: target_environ = malloc((environ_count + 1) * sizeof(char *)); ! 516: if (!target_environ) ! 517: abort(); ! 518: for (wrk = environ, dst = target_environ; *wrk; wrk++) { ! 519: if (drop_ld_preload && !strncmp(*wrk, "LD_PRELOAD=", 11)) ! 520: continue; ! 521: *(dst++) = strdup(*wrk); ! 522: } ! 523: *dst = NULL; /* NULL terminate target_environ */ ! 524: ! 525: if (loader_exec(filename, argv+optind, target_environ, regs, info) != 0) { ! 526: printf("Error loading %s\n", filename); ! 527: _exit(1); ! 528: } ! 529: ! 530: for (wrk = target_environ; *wrk; wrk++) { ! 531: free(*wrk); ! 532: } ! 533: ! 534: free(target_environ); ! 535: ! 536: if (qemu_log_enabled()) { ! 537: log_page_dump(); ! 538: ! 539: qemu_log("start_brk 0x" TARGET_ABI_FMT_lx "\n", info->start_brk); ! 540: qemu_log("end_code 0x" TARGET_ABI_FMT_lx "\n", info->end_code); ! 541: qemu_log("start_code 0x" TARGET_ABI_FMT_lx "\n", ! 542: info->start_code); ! 543: qemu_log("start_data 0x" TARGET_ABI_FMT_lx "\n", ! 544: info->start_data); ! 545: qemu_log("end_data 0x" TARGET_ABI_FMT_lx "\n", info->end_data); ! 546: qemu_log("start_stack 0x" TARGET_ABI_FMT_lx "\n", ! 547: info->start_stack); ! 548: qemu_log("brk 0x" TARGET_ABI_FMT_lx "\n", info->brk); ! 549: qemu_log("entry 0x" TARGET_ABI_FMT_lx "\n", info->entry); ! 550: } ! 551: ! 552: target_set_brk(info->brk); ! 553: syscall_init(); ! 554: signal_init(); ! 555: ! 556: /* build Task State */ ! 557: memset(ts, 0, sizeof(TaskState)); ! 558: init_task_state(ts); ! 559: ts->info = info; ! 560: env->opaque = ts; ! 561: ! 562: #if defined(TARGET_SPARC) ! 563: { ! 564: int i; ! 565: env->pc = regs->pc; ! 566: env->npc = regs->npc; ! 567: env->y = regs->y; ! 568: for(i = 0; i < 8; i++) ! 569: env->gregs[i] = regs->u_regs[i]; ! 570: for(i = 0; i < 8; i++) ! 571: env->regwptr[i] = regs->u_regs[i + 8]; ! 572: } ! 573: #else ! 574: #error unsupported target CPU ! 575: #endif ! 576: ! 577: if (gdbstub_port) { ! 578: gdbserver_start (gdbstub_port); ! 579: gdb_handlesig(env, 0); ! 580: } ! 581: cpu_loop(env, bsd_type); ! 582: /* never exits */ ! 583: return 0; ! 584: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.