|
|
1.1 ! root 1: /* ! 2: * qemu user main ! 3: * ! 4: * Copyright (c) 2003 Fabrice Bellard ! 5: * Copyright (c) 2006 Pierre d'Herbemont ! 6: * ! 7: * This program is free software; you can redistribute it and/or modify ! 8: * it under the terms of the GNU General Public License as published by ! 9: * the Free Software Foundation; either version 2 of the License, or ! 10: * (at your option) any later version. ! 11: * ! 12: * This program is distributed in the hope that it will be useful, ! 13: * but WITHOUT ANY WARRANTY; without even the implied warranty of ! 14: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 15: * GNU General Public License for more details. ! 16: * ! 17: * You should have received a copy of the GNU General Public License ! 18: * along with this program; if not, write to the Free Software ! 19: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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: ! 28: #include <sys/syscall.h> ! 29: #include <sys/mman.h> ! 30: ! 31: #include "qemu.h" ! 32: ! 33: #define DEBUG_LOGFILE "/tmp/qemu.log" ! 34: ! 35: #ifdef __APPLE__ ! 36: #include <crt_externs.h> ! 37: # define environ (*_NSGetEnviron()) ! 38: #endif ! 39: ! 40: #include <mach/mach_init.h> ! 41: #include <mach/vm_map.h> ! 42: ! 43: const char *interp_prefix = ""; ! 44: ! 45: asm(".zerofill __STD_PROG_ZONE, __STD_PROG_ZONE, __std_prog_zone, 0x0dfff000"); ! 46: ! 47: /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so ! 48: we allocate a bigger stack. Need a better solution, for example ! 49: by remapping the process stack directly at the right place */ ! 50: unsigned long stack_size = 512 * 1024; ! 51: ! 52: void qerror(const char *fmt, ...) ! 53: { ! 54: va_list ap; ! 55: ! 56: va_start(ap, fmt); ! 57: vfprintf(stderr, fmt, ap); ! 58: va_end(ap); ! 59: fprintf(stderr, "\n"); ! 60: exit(1); ! 61: } ! 62: ! 63: void gemu_log(const char *fmt, ...) ! 64: { ! 65: va_list ap; ! 66: ! 67: va_start(ap, fmt); ! 68: vfprintf(stderr, fmt, ap); ! 69: va_end(ap); ! 70: } ! 71: ! 72: void cpu_outb(CPUState *env, int addr, int val) ! 73: { ! 74: fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val); ! 75: } ! 76: ! 77: void cpu_outw(CPUState *env, int addr, int val) ! 78: { ! 79: fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val); ! 80: } ! 81: ! 82: void cpu_outl(CPUState *env, int addr, int val) ! 83: { ! 84: fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val); ! 85: } ! 86: ! 87: int cpu_inb(CPUState *env, int addr) ! 88: { ! 89: fprintf(stderr, "inb: port=0x%04x\n", addr); ! 90: return 0; ! 91: } ! 92: ! 93: int cpu_inw(CPUState *env, int addr) ! 94: { ! 95: fprintf(stderr, "inw: port=0x%04x\n", addr); ! 96: return 0; ! 97: } ! 98: ! 99: int cpu_inl(CPUState *env, int addr) ! 100: { ! 101: fprintf(stderr, "inl: port=0x%04x\n", addr); ! 102: return 0; ! 103: } ! 104: ! 105: int cpu_get_pic_interrupt(CPUState *env) ! 106: { ! 107: return -1; ! 108: } ! 109: #ifdef TARGET_PPC ! 110: ! 111: static inline uint64_t cpu_ppc_get_tb (CPUState *env) ! 112: { ! 113: /* TO FIX */ ! 114: return 0; ! 115: } ! 116: ! 117: uint32_t cpu_ppc_load_tbl (CPUState *env) ! 118: { ! 119: return cpu_ppc_get_tb(env) & 0xFFFFFFFF; ! 120: } ! 121: ! 122: uint32_t cpu_ppc_load_tbu (CPUState *env) ! 123: { ! 124: return cpu_ppc_get_tb(env) >> 32; ! 125: } ! 126: ! 127: static void cpu_ppc_store_tb (CPUState *env, uint64_t value) ! 128: { ! 129: /* TO FIX */ ! 130: } ! 131: ! 132: void cpu_ppc_store_tbu (CPUState *env, uint32_t value) ! 133: { ! 134: cpu_ppc_store_tb(env, ((uint64_t)value << 32) | cpu_ppc_load_tbl(env)); ! 135: } ! 136: ! 137: void cpu_ppc_store_tbl (CPUState *env, uint32_t value) ! 138: { ! 139: cpu_ppc_store_tb(env, ((uint64_t)cpu_ppc_load_tbl(env) << 32) | value); ! 140: } ! 141: ! 142: uint32_t cpu_ppc_load_decr (CPUState *env) ! 143: { ! 144: /* TO FIX */ ! 145: return -1; ! 146: } ! 147: ! 148: void cpu_ppc_store_decr (CPUState *env, uint32_t value) ! 149: { ! 150: /* TO FIX */ ! 151: } ! 152: ! 153: void cpu_loop(CPUPPCState *env) ! 154: { ! 155: int trapnr; ! 156: uint32_t ret; ! 157: target_siginfo_t info; ! 158: ! 159: for(;;) { ! 160: trapnr = cpu_ppc_exec(env); ! 161: if (trapnr != EXCP_SYSCALL_USER && trapnr != EXCP_BRANCH && ! 162: trapnr != EXCP_TRACE) { ! 163: if (loglevel > 0) { ! 164: cpu_dump_state(env, logfile, fprintf, 0); ! 165: } ! 166: } ! 167: switch(trapnr) { ! 168: case EXCP_NONE: ! 169: break; ! 170: case EXCP_SYSCALL_USER: ! 171: /* system call */ ! 172: if(((int)env->gpr[0]) <= SYS_MAXSYSCALL && ((int)env->gpr[0])>0) ! 173: ret = do_unix_syscall(env, env->gpr[0]/*, env->gpr[3], env->gpr[4], ! 174: env->gpr[5], env->gpr[6], env->gpr[7], ! 175: env->gpr[8], env->gpr[9], env->gpr[10]*/); ! 176: else if(((int)env->gpr[0])<0) ! 177: ret = do_mach_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4], ! 178: env->gpr[5], env->gpr[6], env->gpr[7], ! 179: env->gpr[8], env->gpr[9], env->gpr[10]); ! 180: else ! 181: ret = do_thread_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4], ! 182: env->gpr[5], env->gpr[6], env->gpr[7], ! 183: env->gpr[8], env->gpr[9], env->gpr[10]); ! 184: ! 185: /* Unix syscall error signaling */ ! 186: if(((int)env->gpr[0]) <= SYS_MAXSYSCALL && ((int)env->gpr[0])>0) ! 187: { ! 188: if( (int)ret < 0 ) ! 189: env->nip += 0; ! 190: else ! 191: env->nip += 4; ! 192: } ! 193: ! 194: /* Return value */ ! 195: env->gpr[3] = ret; ! 196: break; ! 197: case EXCP_RESET: ! 198: /* Should not happen ! */ ! 199: fprintf(stderr, "RESET asked... Stop emulation\n"); ! 200: if (loglevel) ! 201: fprintf(logfile, "RESET asked... Stop emulation\n"); ! 202: abort(); ! 203: case EXCP_MACHINE_CHECK: ! 204: fprintf(stderr, "Machine check exeption... Stop emulation\n"); ! 205: if (loglevel) ! 206: fprintf(logfile, "RESET asked... Stop emulation\n"); ! 207: info.si_signo = SIGBUS; ! 208: info.si_errno = 0; ! 209: info.si_code = BUS_OBJERR; ! 210: info.si_addr = (void*)(env->nip - 4); ! 211: queue_signal(info.si_signo, &info); ! 212: case EXCP_DSI: ! 213: #ifndef DAR ! 214: /* To deal with multiple qemu header version as host for the darwin-user code */ ! 215: # define DAR SPR_DAR ! 216: #endif ! 217: fprintf(stderr, "Invalid data memory access: 0x%08x\n", env->spr[DAR]); ! 218: if (loglevel) { ! 219: fprintf(logfile, "Invalid data memory access: 0x%08x\n", ! 220: env->spr[DAR]); ! 221: } ! 222: /* Handle this via the gdb */ ! 223: gdb_handlesig (env, SIGSEGV); ! 224: ! 225: info.si_addr = (void*)env->nip; ! 226: queue_signal(info.si_signo, &info); ! 227: break; ! 228: case EXCP_ISI: ! 229: fprintf(stderr, "Invalid instruction fetch\n"); ! 230: if (loglevel) ! 231: fprintf(logfile, "Invalid instruction fetch\n"); ! 232: /* Handle this via the gdb */ ! 233: gdb_handlesig (env, SIGSEGV); ! 234: ! 235: info.si_addr = (void*)(env->nip - 4); ! 236: queue_signal(info.si_signo, &info); ! 237: break; ! 238: case EXCP_EXTERNAL: ! 239: /* Should not happen ! */ ! 240: fprintf(stderr, "External interruption... Stop emulation\n"); ! 241: if (loglevel) ! 242: fprintf(logfile, "External interruption... Stop emulation\n"); ! 243: abort(); ! 244: case EXCP_ALIGN: ! 245: fprintf(stderr, "Invalid unaligned memory access\n"); ! 246: if (loglevel) ! 247: fprintf(logfile, "Invalid unaligned memory access\n"); ! 248: info.si_signo = SIGBUS; ! 249: info.si_errno = 0; ! 250: info.si_code = BUS_ADRALN; ! 251: info.si_addr = (void*)(env->nip - 4); ! 252: queue_signal(info.si_signo, &info); ! 253: break; ! 254: case EXCP_PROGRAM: ! 255: switch (env->error_code & ~0xF) { ! 256: case EXCP_FP: ! 257: fprintf(stderr, "Program exception\n"); ! 258: if (loglevel) ! 259: fprintf(logfile, "Program exception\n"); ! 260: /* Set FX */ ! 261: env->fpscr[7] |= 0x8; ! 262: /* Finally, update FEX */ ! 263: if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) & ! 264: ((env->fpscr[1] << 1) | (env->fpscr[0] >> 3))) ! 265: env->fpscr[7] |= 0x4; ! 266: info.si_signo = SIGFPE; ! 267: info.si_errno = 0; ! 268: switch (env->error_code & 0xF) { ! 269: case EXCP_FP_OX: ! 270: info.si_code = FPE_FLTOVF; ! 271: break; ! 272: case EXCP_FP_UX: ! 273: info.si_code = FPE_FLTUND; ! 274: break; ! 275: case EXCP_FP_ZX: ! 276: case EXCP_FP_VXZDZ: ! 277: info.si_code = FPE_FLTDIV; ! 278: break; ! 279: case EXCP_FP_XX: ! 280: info.si_code = FPE_FLTRES; ! 281: break; ! 282: case EXCP_FP_VXSOFT: ! 283: info.si_code = FPE_FLTINV; ! 284: break; ! 285: case EXCP_FP_VXNAN: ! 286: case EXCP_FP_VXISI: ! 287: case EXCP_FP_VXIDI: ! 288: case EXCP_FP_VXIMZ: ! 289: case EXCP_FP_VXVC: ! 290: case EXCP_FP_VXSQRT: ! 291: case EXCP_FP_VXCVI: ! 292: info.si_code = FPE_FLTSUB; ! 293: break; ! 294: default: ! 295: fprintf(stderr, "Unknown floating point exception " ! 296: "(%02x)\n", env->error_code); ! 297: if (loglevel) { ! 298: fprintf(logfile, "Unknown floating point exception " ! 299: "(%02x)\n", env->error_code & 0xF); ! 300: } ! 301: } ! 302: break; ! 303: case EXCP_INVAL: ! 304: fprintf(stderr, "Invalid instruction\n"); ! 305: if (loglevel) ! 306: fprintf(logfile, "Invalid instruction\n"); ! 307: info.si_signo = SIGILL; ! 308: info.si_errno = 0; ! 309: switch (env->error_code & 0xF) { ! 310: case EXCP_INVAL_INVAL: ! 311: info.si_code = ILL_ILLOPC; ! 312: break; ! 313: case EXCP_INVAL_LSWX: ! 314: info.si_code = ILL_ILLOPN; ! 315: break; ! 316: case EXCP_INVAL_SPR: ! 317: info.si_code = ILL_PRVREG; ! 318: break; ! 319: case EXCP_INVAL_FP: ! 320: info.si_code = ILL_COPROC; ! 321: break; ! 322: default: ! 323: fprintf(stderr, "Unknown invalid operation (%02x)\n", ! 324: env->error_code & 0xF); ! 325: if (loglevel) { ! 326: fprintf(logfile, "Unknown invalid operation (%02x)\n", ! 327: env->error_code & 0xF); ! 328: } ! 329: info.si_code = ILL_ILLADR; ! 330: break; ! 331: } ! 332: /* Handle this via the gdb */ ! 333: gdb_handlesig (env, SIGSEGV); ! 334: break; ! 335: case EXCP_PRIV: ! 336: fprintf(stderr, "Privilege violation\n"); ! 337: if (loglevel) ! 338: fprintf(logfile, "Privilege violation\n"); ! 339: info.si_signo = SIGILL; ! 340: info.si_errno = 0; ! 341: switch (env->error_code & 0xF) { ! 342: case EXCP_PRIV_OPC: ! 343: info.si_code = ILL_PRVOPC; ! 344: break; ! 345: case EXCP_PRIV_REG: ! 346: info.si_code = ILL_PRVREG; ! 347: break; ! 348: default: ! 349: fprintf(stderr, "Unknown privilege violation (%02x)\n", ! 350: env->error_code & 0xF); ! 351: info.si_code = ILL_PRVOPC; ! 352: break; ! 353: } ! 354: break; ! 355: case EXCP_TRAP: ! 356: fprintf(stderr, "Tried to call a TRAP\n"); ! 357: if (loglevel) ! 358: fprintf(logfile, "Tried to call a TRAP\n"); ! 359: abort(); ! 360: default: ! 361: /* Should not happen ! */ ! 362: fprintf(stderr, "Unknown program exception (%02x)\n", ! 363: env->error_code); ! 364: if (loglevel) { ! 365: fprintf(logfile, "Unknwon program exception (%02x)\n", ! 366: env->error_code); ! 367: } ! 368: abort(); ! 369: } ! 370: info.si_addr = (void*)(env->nip - 4); ! 371: queue_signal(info.si_signo, &info); ! 372: break; ! 373: case EXCP_NO_FP: ! 374: fprintf(stderr, "No floating point allowed\n"); ! 375: if (loglevel) ! 376: fprintf(logfile, "No floating point allowed\n"); ! 377: info.si_signo = SIGILL; ! 378: info.si_errno = 0; ! 379: info.si_code = ILL_COPROC; ! 380: info.si_addr = (void*)(env->nip - 4); ! 381: queue_signal(info.si_signo, &info); ! 382: break; ! 383: case EXCP_DECR: ! 384: /* Should not happen ! */ ! 385: fprintf(stderr, "Decrementer exception\n"); ! 386: if (loglevel) ! 387: fprintf(logfile, "Decrementer exception\n"); ! 388: abort(); ! 389: case EXCP_TRACE: ! 390: /* Pass to gdb: we use this to trace execution */ ! 391: gdb_handlesig (env, SIGTRAP); ! 392: break; ! 393: case EXCP_FP_ASSIST: ! 394: /* Should not happen ! */ ! 395: fprintf(stderr, "Floating point assist exception\n"); ! 396: if (loglevel) ! 397: fprintf(logfile, "Floating point assist exception\n"); ! 398: abort(); ! 399: case EXCP_MTMSR: ! 400: /* We reloaded the msr, just go on */ ! 401: if (msr_pr == 0) { ! 402: fprintf(stderr, "Tried to go into supervisor mode !\n"); ! 403: if (loglevel) ! 404: fprintf(logfile, "Tried to go into supervisor mode !\n"); ! 405: abort(); ! 406: } ! 407: break; ! 408: case EXCP_BRANCH: ! 409: /* We stopped because of a jump... */ ! 410: break; ! 411: case EXCP_INTERRUPT: ! 412: /* Don't know why this should ever happen... */ ! 413: fprintf(stderr, "EXCP_INTERRUPT\n"); ! 414: break; ! 415: case EXCP_DEBUG: ! 416: gdb_handlesig (env, SIGTRAP); ! 417: break; ! 418: default: ! 419: fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", ! 420: trapnr); ! 421: if (loglevel) { ! 422: fprintf(logfile, "qemu: unhandled CPU exception 0x%02x - " ! 423: "0x%02x - aborting\n", trapnr, env->error_code); ! 424: } ! 425: abort(); ! 426: } ! 427: process_pending_signals(env); ! 428: } ! 429: } ! 430: #endif ! 431: ! 432: ! 433: #ifdef TARGET_I386 ! 434: ! 435: /***********************************************************/ ! 436: /* CPUX86 core interface */ ! 437: ! 438: uint64_t cpu_get_tsc(CPUX86State *env) ! 439: { ! 440: return cpu_get_real_ticks(); ! 441: } ! 442: ! 443: void ! 444: write_dt(void *ptr, unsigned long addr, unsigned long limit, ! 445: int flags) ! 446: { ! 447: unsigned int e1, e2; ! 448: e1 = (addr << 16) | (limit & 0xffff); ! 449: e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000); ! 450: e2 |= flags; ! 451: stl((uint8_t *)ptr, e1); ! 452: stl((uint8_t *)ptr + 4, e2); ! 453: } ! 454: ! 455: static void set_gate(void *ptr, unsigned int type, unsigned int dpl, ! 456: unsigned long addr, unsigned int sel) ! 457: { ! 458: unsigned int e1, e2; ! 459: e1 = (addr & 0xffff) | (sel << 16); ! 460: e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8); ! 461: stl((uint8_t *)ptr, e1); ! 462: stl((uint8_t *)ptr + 4, e2); ! 463: } ! 464: ! 465: #define GDT_TABLE_SIZE 14 ! 466: #define LDT_TABLE_SIZE 15 ! 467: #define IDT_TABLE_SIZE 256 ! 468: #define TSS_SIZE 104 ! 469: uint64_t gdt_table[GDT_TABLE_SIZE]; ! 470: uint64_t ldt_table[LDT_TABLE_SIZE]; ! 471: uint64_t idt_table[IDT_TABLE_SIZE]; ! 472: uint32_t tss[TSS_SIZE]; ! 473: ! 474: /* only dpl matters as we do only user space emulation */ ! 475: static void set_idt(int n, unsigned int dpl) ! 476: { ! 477: set_gate(idt_table + n, 0, dpl, 0, 0); ! 478: } ! 479: ! 480: /* ABI convention: after a syscall if there was an error the CF flag is set */ ! 481: static inline void set_error(CPUX86State *env, int ret) ! 482: { ! 483: if(ret<0) ! 484: env->eflags = env->eflags | 0x1; ! 485: else ! 486: env->eflags &= ~0x1; ! 487: env->regs[R_EAX] = ret; ! 488: } ! 489: ! 490: void cpu_loop(CPUX86State *env) ! 491: { ! 492: int trapnr; ! 493: int ret; ! 494: uint8_t *pc; ! 495: target_siginfo_t info; ! 496: ! 497: for(;;) { ! 498: trapnr = cpu_x86_exec(env); ! 499: uint32_t *params = (uint32_t *)env->regs[R_ESP]; ! 500: switch(trapnr) { ! 501: case 0x79: /* Our commpage hack back door exit is here */ ! 502: do_commpage(env, env->eip, *(params + 1), *(params + 2), ! 503: *(params + 3), *(params + 4), ! 504: *(params + 5), *(params + 6), ! 505: *(params + 7), *(params + 8)); ! 506: break; ! 507: case 0x81: /* mach syscall */ ! 508: { ! 509: ret = do_mach_syscall(env, env->regs[R_EAX], ! 510: *(params + 1), *(params + 2), ! 511: *(params + 3), *(params + 4), ! 512: *(params + 5), *(params + 6), ! 513: *(params + 7), *(params + 8)); ! 514: set_error(env, ret); ! 515: break; ! 516: } ! 517: case 0x90: /* unix backdoor */ ! 518: { ! 519: /* after sysenter, stack is in R_ECX, new eip in R_EDX (sysexit will flip them back)*/ ! 520: int saved_stack = env->regs[R_ESP]; ! 521: env->regs[R_ESP] = env->regs[R_ECX]; ! 522: ! 523: ret = do_unix_syscall(env, env->regs[R_EAX]); ! 524: ! 525: env->regs[R_ECX] = env->regs[R_ESP]; ! 526: env->regs[R_ESP] = saved_stack; ! 527: ! 528: set_error(env, ret); ! 529: break; ! 530: } ! 531: case 0x80: /* unix syscall */ ! 532: { ! 533: ret = do_unix_syscall(env, env->regs[R_EAX]/*, ! 534: *(params + 1), *(params + 2), ! 535: *(params + 3), *(params + 4), ! 536: *(params + 5), *(params + 6), ! 537: *(params + 7), *(params + 8)*/); ! 538: set_error(env, ret); ! 539: break; ! 540: } ! 541: case 0x82: /* thread syscall */ ! 542: { ! 543: ret = do_thread_syscall(env, env->regs[R_EAX], ! 544: *(params + 1), *(params + 2), ! 545: *(params + 3), *(params + 4), ! 546: *(params + 5), *(params + 6), ! 547: *(params + 7), *(params + 8)); ! 548: set_error(env, ret); ! 549: break; ! 550: } ! 551: case EXCP0B_NOSEG: ! 552: case EXCP0C_STACK: ! 553: info.si_signo = SIGBUS; ! 554: info.si_errno = 0; ! 555: info.si_code = BUS_NOOP; ! 556: info.si_addr = 0; ! 557: gdb_handlesig (env, SIGBUS); ! 558: queue_signal(info.si_signo, &info); ! 559: break; ! 560: case EXCP0D_GPF: ! 561: info.si_signo = SIGSEGV; ! 562: info.si_errno = 0; ! 563: info.si_code = SEGV_NOOP; ! 564: info.si_addr = 0; ! 565: gdb_handlesig (env, SIGSEGV); ! 566: queue_signal(info.si_signo, &info); ! 567: break; ! 568: case EXCP0E_PAGE: ! 569: info.si_signo = SIGSEGV; ! 570: info.si_errno = 0; ! 571: if (!(env->error_code & 1)) ! 572: info.si_code = SEGV_MAPERR; ! 573: else ! 574: info.si_code = SEGV_ACCERR; ! 575: info.si_addr = (void*)env->cr[2]; ! 576: gdb_handlesig (env, SIGSEGV); ! 577: queue_signal(info.si_signo, &info); ! 578: break; ! 579: case EXCP00_DIVZ: ! 580: /* division by zero */ ! 581: info.si_signo = SIGFPE; ! 582: info.si_errno = 0; ! 583: info.si_code = FPE_INTDIV; ! 584: info.si_addr = (void*)env->eip; ! 585: gdb_handlesig (env, SIGFPE); ! 586: queue_signal(info.si_signo, &info); ! 587: break; ! 588: case EXCP01_SSTP: ! 589: case EXCP03_INT3: ! 590: info.si_signo = SIGTRAP; ! 591: info.si_errno = 0; ! 592: info.si_code = TRAP_BRKPT; ! 593: info.si_addr = (void*)env->eip; ! 594: gdb_handlesig (env, SIGTRAP); ! 595: queue_signal(info.si_signo, &info); ! 596: break; ! 597: case EXCP04_INTO: ! 598: case EXCP05_BOUND: ! 599: info.si_signo = SIGSEGV; ! 600: info.si_errno = 0; ! 601: info.si_code = SEGV_NOOP; ! 602: info.si_addr = 0; ! 603: gdb_handlesig (env, SIGSEGV); ! 604: queue_signal(info.si_signo, &info); ! 605: break; ! 606: case EXCP06_ILLOP: ! 607: info.si_signo = SIGILL; ! 608: info.si_errno = 0; ! 609: info.si_code = ILL_ILLOPN; ! 610: info.si_addr = (void*)env->eip; ! 611: gdb_handlesig (env, SIGILL); ! 612: queue_signal(info.si_signo, &info); ! 613: break; ! 614: case EXCP_INTERRUPT: ! 615: /* just indicate that signals should be handled asap */ ! 616: break; ! 617: case EXCP_DEBUG: ! 618: { ! 619: int sig; ! 620: ! 621: sig = gdb_handlesig (env, SIGTRAP); ! 622: if (sig) ! 623: { ! 624: info.si_signo = sig; ! 625: info.si_errno = 0; ! 626: info.si_code = TRAP_BRKPT; ! 627: queue_signal(info.si_signo, &info); ! 628: } ! 629: } ! 630: break; ! 631: default: ! 632: pc = (void*)(env->segs[R_CS].base + env->eip); ! 633: fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n", ! 634: (long)pc, trapnr); ! 635: abort(); ! 636: } ! 637: process_pending_signals(env); ! 638: } ! 639: } ! 640: #endif ! 641: ! 642: void usage(void) ! 643: { ! 644: printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2004 Fabrice Bellard\n" ! 645: "usage: qemu-" TARGET_ARCH " [-h] [-d opts] [-L path] [-s size] program [arguments...]\n" ! 646: "Darwin CPU emulator (compiled for %s emulation)\n" ! 647: "\n" ! 648: "-h print this help\n" ! 649: "-L path set the %s library path (default='%s')\n" ! 650: "-s size set the stack size in bytes (default=%ld)\n" ! 651: "\n" ! 652: "debug options:\n" ! 653: #ifdef USE_CODE_COPY ! 654: "-no-code-copy disable code copy acceleration\n" ! 655: #endif ! 656: "-d options activate log (logfile='%s')\n" ! 657: "-g wait for gdb on port 1234\n" ! 658: "-p pagesize set the host page size to 'pagesize'\n", ! 659: TARGET_ARCH, ! 660: TARGET_ARCH, ! 661: interp_prefix, ! 662: stack_size, ! 663: DEBUG_LOGFILE); ! 664: _exit(1); ! 665: } ! 666: ! 667: /* XXX: currently only used for async signals (see signal.c) */ ! 668: CPUState *global_env; ! 669: /* used only if single thread */ ! 670: CPUState *cpu_single_env = NULL; ! 671: ! 672: /* used to free thread contexts */ ! 673: TaskState *first_task_state; ! 674: ! 675: int main(int argc, char **argv) ! 676: { ! 677: const char *filename; ! 678: struct target_pt_regs regs1, *regs = ®s1; ! 679: TaskState ts1, *ts = &ts1; ! 680: CPUState *env; ! 681: int optind; ! 682: short use_gdbstub = 0; ! 683: const char *r; ! 684: ! 685: if (argc <= 1) ! 686: usage(); ! 687: ! 688: /* init debug */ ! 689: cpu_set_log_filename(DEBUG_LOGFILE); ! 690: ! 691: optind = 1; ! 692: for(;;) { ! 693: if (optind >= argc) ! 694: break; ! 695: r = argv[optind]; ! 696: if (r[0] != '-') ! 697: break; ! 698: optind++; ! 699: r++; ! 700: if (!strcmp(r, "-")) { ! 701: break; ! 702: } else if (!strcmp(r, "d")) { ! 703: int mask; ! 704: CPULogItem *item; ! 705: ! 706: if (optind >= argc) ! 707: break; ! 708: ! 709: r = argv[optind++]; ! 710: mask = cpu_str_to_log_mask(r); ! 711: if (!mask) { ! 712: printf("Log items (comma separated):\n"); ! 713: for(item = cpu_log_items; item->mask != 0; item++) { ! 714: printf("%-10s %s\n", item->name, item->help); ! 715: } ! 716: exit(1); ! 717: } ! 718: cpu_set_log(mask); ! 719: } else if (!strcmp(r, "s")) { ! 720: r = argv[optind++]; ! 721: stack_size = strtol(r, (char **)&r, 0); ! 722: if (stack_size <= 0) ! 723: usage(); ! 724: if (*r == 'M') ! 725: stack_size *= 1024 * 1024; ! 726: else if (*r == 'k' || *r == 'K') ! 727: stack_size *= 1024; ! 728: } else if (!strcmp(r, "L")) { ! 729: interp_prefix = argv[optind++]; ! 730: } else if (!strcmp(r, "p")) { ! 731: qemu_host_page_size = atoi(argv[optind++]); ! 732: if (qemu_host_page_size == 0 || ! 733: (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) { ! 734: fprintf(stderr, "page size must be a power of two\n"); ! 735: exit(1); ! 736: } ! 737: } else ! 738: if (!strcmp(r, "g")) { ! 739: use_gdbstub = 1; ! 740: } else ! 741: #ifdef USE_CODE_COPY ! 742: if (!strcmp(r, "no-code-copy")) { ! 743: code_copy_enabled = 0; ! 744: } else ! 745: #endif ! 746: { ! 747: usage(); ! 748: } ! 749: } ! 750: if (optind >= argc) ! 751: usage(); ! 752: filename = argv[optind]; ! 753: ! 754: /* Zero out regs */ ! 755: memset(regs, 0, sizeof(struct target_pt_regs)); ! 756: ! 757: /* NOTE: we need to init the CPU at this stage to get ! 758: qemu_host_page_size */ ! 759: env = cpu_init(); ! 760: ! 761: printf("Starting %s with qemu\n----------------\n", filename); ! 762: ! 763: commpage_init(); ! 764: ! 765: if (mach_exec(filename, argv+optind, environ, regs) != 0) { ! 766: printf("Error loading %s\n", filename); ! 767: _exit(1); ! 768: } ! 769: ! 770: syscall_init(); ! 771: signal_init(); ! 772: global_env = env; ! 773: ! 774: /* build Task State */ ! 775: memset(ts, 0, sizeof(TaskState)); ! 776: env->opaque = ts; ! 777: ts->used = 1; ! 778: env->user_mode_only = 1; ! 779: ! 780: #if defined(TARGET_I386) ! 781: cpu_x86_set_cpl(env, 3); ! 782: ! 783: env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK; ! 784: env->hflags |= HF_PE_MASK; ! 785: ! 786: if (env->cpuid_features & CPUID_SSE) { ! 787: env->cr[4] |= CR4_OSFXSR_MASK; ! 788: env->hflags |= HF_OSFXSR_MASK; ! 789: } ! 790: ! 791: /* flags setup : we activate the IRQs by default as in user mode */ ! 792: env->eflags |= IF_MASK; ! 793: ! 794: /* darwin register setup */ ! 795: env->regs[R_EAX] = regs->eax; ! 796: env->regs[R_EBX] = regs->ebx; ! 797: env->regs[R_ECX] = regs->ecx; ! 798: env->regs[R_EDX] = regs->edx; ! 799: env->regs[R_ESI] = regs->esi; ! 800: env->regs[R_EDI] = regs->edi; ! 801: env->regs[R_EBP] = regs->ebp; ! 802: env->regs[R_ESP] = regs->esp; ! 803: env->eip = regs->eip; ! 804: ! 805: /* Darwin LDT setup */ ! 806: /* 2 - User code segment ! 807: 3 - User data segment ! 808: 4 - User cthread */ ! 809: bzero(ldt_table, LDT_TABLE_SIZE * sizeof(ldt_table[0])); ! 810: env->ldt.base = (uint32_t) ldt_table; ! 811: env->ldt.limit = sizeof(ldt_table) - 1; ! 812: ! 813: write_dt(ldt_table + 2, 0, 0xfffff, ! 814: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | ! 815: (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT)); ! 816: write_dt(ldt_table + 3, 0, 0xfffff, ! 817: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | ! 818: (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT)); ! 819: write_dt(ldt_table + 4, 0, 0xfffff, ! 820: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | ! 821: (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT)); ! 822: ! 823: /* Darwin GDT setup. ! 824: * has changed a lot between old Darwin/x86 (pre-Mac Intel) and Mac OS X/x86, ! 825: now everything is done via int 0x81(mach) int 0x82 (thread) and sysenter/sysexit(unix) */ ! 826: bzero(gdt_table, sizeof(gdt_table)); ! 827: env->gdt.base = (uint32_t)gdt_table; ! 828: env->gdt.limit = sizeof(gdt_table) - 1; ! 829: ! 830: /* Set up a back door to handle sysenter syscalls (unix) */ ! 831: char * syscallbackdoor = malloc(64); ! 832: page_set_flags((int)syscallbackdoor, (int)syscallbackdoor + 64, PROT_EXEC | PROT_READ | PAGE_VALID); ! 833: ! 834: int i = 0; ! 835: syscallbackdoor[i++] = 0xcd; ! 836: syscallbackdoor[i++] = 0x90; /* int 0x90 */ ! 837: syscallbackdoor[i++] = 0x0F; ! 838: syscallbackdoor[i++] = 0x35; /* sysexit */ ! 839: ! 840: /* Darwin sysenter/sysexit setup */ ! 841: env->sysenter_cs = 0x1; //XXX ! 842: env->sysenter_eip = (int)syscallbackdoor; ! 843: env->sysenter_esp = (int)malloc(64); ! 844: ! 845: /* Darwin TSS setup ! 846: This must match up with GDT[4] */ ! 847: env->tr.base = (uint32_t) tss; ! 848: env->tr.limit = sizeof(tss) - 1; ! 849: env->tr.flags = DESC_P_MASK | (0x9 << DESC_TYPE_SHIFT); ! 850: stw(tss + 2, 0x10); // ss0 = 0x10 = GDT[2] = Kernel Data Segment ! 851: ! 852: /* Darwin interrupt setup */ ! 853: bzero(idt_table, sizeof(idt_table)); ! 854: env->idt.base = (uint32_t) idt_table; ! 855: env->idt.limit = sizeof(idt_table) - 1; ! 856: set_idt(0, 0); ! 857: set_idt(1, 0); ! 858: set_idt(2, 0); ! 859: set_idt(3, 3); ! 860: set_idt(4, 3); ! 861: set_idt(5, 3); ! 862: set_idt(6, 0); ! 863: set_idt(7, 0); ! 864: set_idt(8, 0); ! 865: set_idt(9, 0); ! 866: set_idt(10, 0); ! 867: set_idt(11, 0); ! 868: set_idt(12, 0); ! 869: set_idt(13, 0); ! 870: set_idt(14, 0); ! 871: set_idt(15, 0); ! 872: set_idt(16, 0); ! 873: set_idt(17, 0); ! 874: set_idt(18, 0); ! 875: set_idt(19, 0); ! 876: /* Syscalls are done via ! 877: int 0x80 (unix) (rarely used) ! 878: int 0x81 (mach) ! 879: int 0x82 (thread) ! 880: int 0x83 (diag) (not handled here) ! 881: sysenter/sysexit (unix) -> we redirect that to int 0x90 */ ! 882: set_idt(0x79, 3); /* Commpage hack, here is our backdoor interrupt */ ! 883: set_idt(0x80, 3); /* Unix Syscall */ ! 884: set_idt(0x81, 3); /* Mach Syscalls */ ! 885: set_idt(0x82, 3); /* thread Syscalls */ ! 886: ! 887: set_idt(0x90, 3); /* qemu-darwin-user's Unix syscalls backdoor */ ! 888: ! 889: ! 890: cpu_x86_load_seg(env, R_CS, __USER_CS); ! 891: cpu_x86_load_seg(env, R_DS, __USER_DS); ! 892: cpu_x86_load_seg(env, R_ES, __USER_DS); ! 893: cpu_x86_load_seg(env, R_SS, __USER_DS); ! 894: cpu_x86_load_seg(env, R_FS, __USER_DS); ! 895: cpu_x86_load_seg(env, R_GS, __USER_DS); ! 896: ! 897: #elif defined(TARGET_PPC) ! 898: { ! 899: int i; ! 900: env->nip = regs->nip; ! 901: for(i = 0; i < 32; i++) { ! 902: env->gpr[i] = regs->gpr[i]; ! 903: } ! 904: } ! 905: #else ! 906: #error unsupported target CPU ! 907: #endif ! 908: ! 909: if (use_gdbstub) { ! 910: printf("Waiting for gdb Connection on port 1234...\n"); ! 911: gdbserver_start (1234); ! 912: gdb_handlesig(env, 0); ! 913: } ! 914: ! 915: cpu_loop(env); ! 916: /* never exits */ ! 917: return 0; ! 918: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.