|
|
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:
1.1.1.2 ! root 127: uint32_t cpu_ppc_load_atbl (CPUState *env)
1.1 root 128: {
1.1.1.2 ! root 129: return cpu_ppc_get_tb(env) & 0xFFFFFFFF;
1.1 root 130: }
131:
1.1.1.2 ! root 132: uint32_t cpu_ppc_load_atbu (CPUState *env)
1.1 root 133: {
1.1.1.2 ! root 134: return cpu_ppc_get_tb(env) >> 32;
1.1 root 135: }
136:
1.1.1.2 ! root 137: uint32_t cpu_ppc601_load_rtcu (CPUState *env)
1.1 root 138: {
1.1.1.2 ! root 139: cpu_ppc_load_tbu(env);
1.1 root 140: }
141:
1.1.1.2 ! root 142: uint32_t cpu_ppc601_load_rtcl (CPUState *env)
! 143: {
! 144: return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
! 145: }
! 146:
! 147: /* XXX: to be fixed */
! 148: int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, target_ulong *valp)
1.1 root 149: {
150: return -1;
151: }
152:
1.1.1.2 ! root 153: int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val)
1.1 root 154: {
1.1.1.2 ! root 155: return -1;
1.1 root 156: }
157:
1.1.1.2 ! root 158: #define EXCP_DUMP(env, fmt, args...) \
! 159: do { \
! 160: fprintf(stderr, fmt , ##args); \
! 161: cpu_dump_state(env, stderr, fprintf, 0); \
! 162: if (loglevel != 0) { \
! 163: fprintf(logfile, fmt , ##args); \
! 164: cpu_dump_state(env, logfile, fprintf, 0); \
! 165: } \
! 166: } while (0)
! 167:
1.1 root 168: void cpu_loop(CPUPPCState *env)
169: {
170: int trapnr;
171: uint32_t ret;
172: target_siginfo_t info;
173:
174: for(;;) {
175: trapnr = cpu_ppc_exec(env);
176: switch(trapnr) {
1.1.1.2 ! root 177: case POWERPC_EXCP_NONE:
! 178: /* Just go on */
1.1 root 179: break;
1.1.1.2 ! root 180: case POWERPC_EXCP_CRITICAL: /* Critical input */
! 181: cpu_abort(env, "Critical interrupt while in user mode. "
! 182: "Aborting\n");
! 183: break;
! 184: case POWERPC_EXCP_MCHECK: /* Machine check exception */
! 185: cpu_abort(env, "Machine check exception while in user mode. "
! 186: "Aborting\n");
1.1 root 187: break;
1.1.1.2 ! root 188: case POWERPC_EXCP_DSI: /* Data storage exception */
1.1 root 189: #ifndef DAR
190: /* To deal with multiple qemu header version as host for the darwin-user code */
191: # define DAR SPR_DAR
192: #endif
1.1.1.2 ! root 193: EXCP_DUMP(env, "Invalid data memory access: 0x" ADDRX "\n",
! 194: env->spr[SPR_DAR]);
1.1 root 195: /* Handle this via the gdb */
196: gdb_handlesig (env, SIGSEGV);
197:
198: info.si_addr = (void*)env->nip;
199: queue_signal(info.si_signo, &info);
200: break;
1.1.1.2 ! root 201: case POWERPC_EXCP_ISI: /* Instruction storage exception */
! 202: EXCP_DUMP(env, "Invalid instruction fetch: 0x\n" ADDRX "\n",
! 203: env->spr[SPR_DAR]);
1.1 root 204: /* Handle this via the gdb */
205: gdb_handlesig (env, SIGSEGV);
206:
207: info.si_addr = (void*)(env->nip - 4);
208: queue_signal(info.si_signo, &info);
209: break;
1.1.1.2 ! root 210: case POWERPC_EXCP_EXTERNAL: /* External input */
! 211: cpu_abort(env, "External interrupt while in user mode. "
! 212: "Aborting\n");
! 213: break;
! 214: case POWERPC_EXCP_ALIGN: /* Alignment exception */
! 215: EXCP_DUMP(env, "Unaligned memory access\n");
1.1 root 216: info.si_errno = 0;
217: info.si_code = BUS_ADRALN;
218: info.si_addr = (void*)(env->nip - 4);
219: queue_signal(info.si_signo, &info);
220: break;
1.1.1.2 ! root 221: case POWERPC_EXCP_PROGRAM: /* Program exception */
! 222: /* XXX: check this */
1.1 root 223: switch (env->error_code & ~0xF) {
1.1.1.2 ! root 224: case POWERPC_EXCP_FP:
! 225: EXCP_DUMP(env, "Floating point program exception\n");
! 226: /* Set FX */
! 227: info.si_signo = SIGFPE;
! 228: info.si_errno = 0;
! 229: switch (env->error_code & 0xF) {
! 230: case POWERPC_EXCP_FP_OX:
! 231: info.si_code = FPE_FLTOVF;
! 232: break;
! 233: case POWERPC_EXCP_FP_UX:
! 234: info.si_code = FPE_FLTUND;
! 235: break;
! 236: case POWERPC_EXCP_FP_ZX:
! 237: case POWERPC_EXCP_FP_VXZDZ:
! 238: info.si_code = FPE_FLTDIV;
! 239: break;
! 240: case POWERPC_EXCP_FP_XX:
! 241: info.si_code = FPE_FLTRES;
! 242: break;
! 243: case POWERPC_EXCP_FP_VXSOFT:
! 244: info.si_code = FPE_FLTINV;
! 245: break;
! 246: case POWERPC_EXCP_FP_VXSNAN:
! 247: case POWERPC_EXCP_FP_VXISI:
! 248: case POWERPC_EXCP_FP_VXIDI:
! 249: case POWERPC_EXCP_FP_VXIMZ:
! 250: case POWERPC_EXCP_FP_VXVC:
! 251: case POWERPC_EXCP_FP_VXSQRT:
! 252: case POWERPC_EXCP_FP_VXCVI:
! 253: info.si_code = FPE_FLTSUB;
! 254: break;
! 255: default:
! 256: EXCP_DUMP(env, "Unknown floating point exception (%02x)\n",
! 257: env->error_code);
! 258: break;
! 259: }
! 260: break;
! 261: case POWERPC_EXCP_INVAL:
! 262: EXCP_DUMP(env, "Invalid instruction\n");
! 263: info.si_signo = SIGILL;
! 264: info.si_errno = 0;
! 265: switch (env->error_code & 0xF) {
! 266: case POWERPC_EXCP_INVAL_INVAL:
! 267: info.si_code = ILL_ILLOPC;
! 268: break;
! 269: case POWERPC_EXCP_INVAL_LSWX:
! 270: info.si_code = ILL_ILLOPN;
! 271: break;
! 272: case POWERPC_EXCP_INVAL_SPR:
! 273: info.si_code = ILL_PRVREG;
! 274: break;
! 275: case POWERPC_EXCP_INVAL_FP:
! 276: info.si_code = ILL_COPROC;
! 277: break;
1.1 root 278: default:
1.1.1.2 ! root 279: EXCP_DUMP(env, "Unknown invalid operation (%02x)\n",
! 280: env->error_code & 0xF);
! 281: info.si_code = ILL_ILLADR;
! 282: break;
! 283: }
! 284: /* Handle this via the gdb */
! 285: gdb_handlesig (env, SIGSEGV);
! 286: break;
! 287: case POWERPC_EXCP_PRIV:
! 288: EXCP_DUMP(env, "Privilege violation\n");
! 289: info.si_signo = SIGILL;
! 290: info.si_errno = 0;
! 291: switch (env->error_code & 0xF) {
! 292: case POWERPC_EXCP_PRIV_OPC:
! 293: info.si_code = ILL_PRVOPC;
! 294: break;
! 295: case POWERPC_EXCP_PRIV_REG:
! 296: info.si_code = ILL_PRVREG;
! 297: break;
! 298: default:
! 299: EXCP_DUMP(env, "Unknown privilege violation (%02x)\n",
! 300: env->error_code & 0xF);
! 301: info.si_code = ILL_PRVOPC;
! 302: break;
! 303: }
! 304: break;
! 305: case POWERPC_EXCP_TRAP:
! 306: cpu_abort(env, "Tried to call a TRAP\n");
! 307: break;
! 308: default:
! 309: /* Should not happen ! */
! 310: cpu_abort(env, "Unknown program exception (%02x)\n",
! 311: env->error_code);
! 312: break;
1.1 root 313: }
314: info.si_addr = (void*)(env->nip - 4);
315: queue_signal(info.si_signo, &info);
316: break;
1.1.1.2 ! root 317: case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
! 318: EXCP_DUMP(env, "No floating point allowed\n");
! 319: info.si_signo = SIGILL;
1.1 root 320: info.si_errno = 0;
321: info.si_code = ILL_COPROC;
322: info.si_addr = (void*)(env->nip - 4);
323: queue_signal(info.si_signo, &info);
324: break;
1.1.1.2 ! root 325: case POWERPC_EXCP_SYSCALL: /* System call exception */
! 326: cpu_abort(env, "Syscall exception while in user mode. "
! 327: "Aborting\n");
! 328: break;
! 329: case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */
! 330: EXCP_DUMP(env, "No APU instruction allowed\n");
! 331: info.si_signo = SIGILL;
! 332: info.si_errno = 0;
! 333: info.si_code = ILL_COPROC;
! 334: info.si_addr = (void*)(env->nip - 4);
! 335: queue_signal(info.si_signo, &info);
! 336: break;
! 337: case POWERPC_EXCP_DECR: /* Decrementer exception */
! 338: cpu_abort(env, "Decrementer interrupt while in user mode. "
! 339: "Aborting\n");
! 340: break;
! 341: case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */
! 342: cpu_abort(env, "Fix interval timer interrupt while in user mode. "
! 343: "Aborting\n");
! 344: break;
! 345: case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */
! 346: cpu_abort(env, "Watchdog timer interrupt while in user mode. "
! 347: "Aborting\n");
! 348: break;
! 349: case POWERPC_EXCP_DTLB: /* Data TLB error */
! 350: cpu_abort(env, "Data TLB exception while in user mode. "
! 351: "Aborting\n");
! 352: break;
! 353: case POWERPC_EXCP_ITLB: /* Instruction TLB error */
! 354: cpu_abort(env, "Instruction TLB exception while in user mode. "
! 355: "Aborting\n");
! 356: break;
! 357: case POWERPC_EXCP_DEBUG: /* Debug interrupt */
1.1 root 358: gdb_handlesig (env, SIGTRAP);
359: break;
1.1.1.2 ! root 360: case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavail. */
! 361: EXCP_DUMP(env, "No SPE/floating-point instruction allowed\n");
! 362: info.si_signo = SIGILL;
! 363: info.si_errno = 0;
! 364: info.si_code = ILL_COPROC;
! 365: info.si_addr = (void*)(env->nip - 4);
! 366: queue_signal(info.si_signo, &info);
1.1 root 367: break;
1.1.1.2 ! root 368: case POWERPC_EXCP_EFPDI: /* Embedded floating-point data IRQ */
! 369: cpu_abort(env, "Embedded floating-point data IRQ not handled\n");
1.1 root 370: break;
1.1.1.2 ! root 371: case POWERPC_EXCP_EFPRI: /* Embedded floating-point round IRQ */
! 372: cpu_abort(env, "Embedded floating-point round IRQ not handled\n");
1.1 root 373: break;
1.1.1.2 ! root 374: case POWERPC_EXCP_EPERFM: /* Embedded performance monitor IRQ */
! 375: cpu_abort(env, "Performance monitor exception not handled\n");
1.1 root 376: break;
1.1.1.2 ! root 377: case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */
! 378: cpu_abort(env, "Doorbell interrupt while in user mode. "
! 379: "Aborting\n");
! 380: break;
! 381: case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */
! 382: cpu_abort(env, "Doorbell critical interrupt while in user mode. "
! 383: "Aborting\n");
! 384: break;
! 385: case POWERPC_EXCP_RESET: /* System reset exception */
! 386: cpu_abort(env, "Reset interrupt while in user mode. "
! 387: "Aborting\n");
! 388: break;
! 389: case POWERPC_EXCP_DSEG: /* Data segment exception */
! 390: cpu_abort(env, "Data segment exception while in user mode. "
! 391: "Aborting\n");
! 392: break;
! 393: case POWERPC_EXCP_ISEG: /* Instruction segment exception */
! 394: cpu_abort(env, "Instruction segment exception "
! 395: "while in user mode. Aborting\n");
! 396: break;
! 397: case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */
! 398: cpu_abort(env, "Hypervisor decrementer interrupt "
! 399: "while in user mode. Aborting\n");
! 400: break;
! 401: case POWERPC_EXCP_TRACE: /* Trace exception */
! 402: /* Nothing to do:
! 403: * we use this exception to emulate step-by-step execution mode.
! 404: */
! 405: break;
! 406: case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */
! 407: cpu_abort(env, "Hypervisor data storage exception "
! 408: "while in user mode. Aborting\n");
! 409: break;
! 410: case POWERPC_EXCP_HISI: /* Hypervisor instruction storage excp */
! 411: cpu_abort(env, "Hypervisor instruction storage exception "
! 412: "while in user mode. Aborting\n");
! 413: break;
! 414: case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */
! 415: cpu_abort(env, "Hypervisor data segment exception "
! 416: "while in user mode. Aborting\n");
! 417: break;
! 418: case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment excp */
! 419: cpu_abort(env, "Hypervisor instruction segment exception "
! 420: "while in user mode. Aborting\n");
! 421: break;
! 422: case POWERPC_EXCP_VPU: /* Vector unavailable exception */
! 423: EXCP_DUMP(env, "No Altivec instructions allowed\n");
! 424: info.si_signo = SIGILL;
! 425: info.si_errno = 0;
! 426: info.si_code = ILL_COPROC;
! 427: info.si_addr = (void*)(env->nip - 4);
! 428: queue_signal(info.si_signo, &info);
! 429: break;
! 430: case POWERPC_EXCP_PIT: /* Programmable interval timer IRQ */
! 431: cpu_abort(env, "Programable interval timer interrupt "
! 432: "while in user mode. Aborting\n");
! 433: break;
! 434: case POWERPC_EXCP_IO: /* IO error exception */
! 435: cpu_abort(env, "IO error exception while in user mode. "
! 436: "Aborting\n");
! 437: break;
! 438: case POWERPC_EXCP_RUNM: /* Run mode exception */
! 439: cpu_abort(env, "Run mode exception while in user mode. "
! 440: "Aborting\n");
! 441: break;
! 442: case POWERPC_EXCP_EMUL: /* Emulation trap exception */
! 443: cpu_abort(env, "Emulation trap exception not handled\n");
! 444: break;
! 445: case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */
! 446: cpu_abort(env, "Instruction fetch TLB exception "
! 447: "while in user-mode. Aborting");
! 448: break;
! 449: case POWERPC_EXCP_DLTLB: /* Data load TLB miss */
! 450: cpu_abort(env, "Data load TLB exception while in user-mode. "
! 451: "Aborting");
! 452: break;
! 453: case POWERPC_EXCP_DSTLB: /* Data store TLB miss */
! 454: cpu_abort(env, "Data store TLB exception while in user-mode. "
! 455: "Aborting");
! 456: break;
! 457: case POWERPC_EXCP_FPA: /* Floating-point assist exception */
! 458: cpu_abort(env, "Floating-point assist exception not handled\n");
! 459: break;
! 460: case POWERPC_EXCP_IABR: /* Instruction address breakpoint */
! 461: cpu_abort(env, "Instruction address breakpoint exception "
! 462: "not handled\n");
! 463: break;
! 464: case POWERPC_EXCP_SMI: /* System management interrupt */
! 465: cpu_abort(env, "System management interrupt while in user mode. "
! 466: "Aborting\n");
! 467: break;
! 468: case POWERPC_EXCP_THERM: /* Thermal interrupt */
! 469: cpu_abort(env, "Thermal interrupt interrupt while in user mode. "
! 470: "Aborting\n");
! 471: break;
! 472: case POWERPC_EXCP_PERFM: /* Embedded performance monitor IRQ */
! 473: cpu_abort(env, "Performance monitor exception not handled\n");
! 474: break;
! 475: case POWERPC_EXCP_VPUA: /* Vector assist exception */
! 476: cpu_abort(env, "Vector assist exception not handled\n");
! 477: break;
! 478: case POWERPC_EXCP_SOFTP: /* Soft patch exception */
! 479: cpu_abort(env, "Soft patch exception not handled\n");
! 480: break;
! 481: case POWERPC_EXCP_MAINT: /* Maintenance exception */
! 482: cpu_abort(env, "Maintenance exception while in user mode. "
! 483: "Aborting\n");
! 484: break;
! 485: case POWERPC_EXCP_STOP: /* stop translation */
! 486: /* We did invalidate the instruction cache. Go on */
! 487: break;
! 488: case POWERPC_EXCP_BRANCH: /* branch instruction: */
! 489: /* We just stopped because of a branch. Go on */
! 490: break;
! 491: case POWERPC_EXCP_SYSCALL_USER:
! 492: /* system call in user-mode emulation */
! 493: /* system call */
! 494: if(((int)env->gpr[0]) <= SYS_MAXSYSCALL && ((int)env->gpr[0])>0)
! 495: ret = do_unix_syscall(env, env->gpr[0]/*, env->gpr[3], env->gpr[4],
! 496: env->gpr[5], env->gpr[6], env->gpr[7],
! 497: env->gpr[8], env->gpr[9], env->gpr[10]*/);
! 498: else if(((int)env->gpr[0])<0)
! 499: ret = do_mach_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
! 500: env->gpr[5], env->gpr[6], env->gpr[7],
! 501: env->gpr[8], env->gpr[9], env->gpr[10]);
! 502: else
! 503: ret = do_thread_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
! 504: env->gpr[5], env->gpr[6], env->gpr[7],
! 505: env->gpr[8], env->gpr[9], env->gpr[10]);
! 506:
! 507: /* Unix syscall error signaling */
! 508: if(((int)env->gpr[0]) <= SYS_MAXSYSCALL && ((int)env->gpr[0])>0)
! 509: {
! 510: if( (int)ret < 0 )
! 511: env->nip += 0;
! 512: else
! 513: env->nip += 4;
1.1 root 514: }
1.1.1.2 ! root 515:
! 516: /* Return value */
! 517: env->gpr[3] = ret;
! 518: break;
! 519: case EXCP_INTERRUPT:
! 520: /* just indicate that signals should be handled asap */
! 521: break;
! 522: default:
! 523: cpu_abort(env, "Unknown exception 0x%d. Aborting\n", trapnr);
! 524: break;
1.1 root 525: }
526: process_pending_signals(env);
527: }
528: }
529: #endif
530:
531:
532: #ifdef TARGET_I386
533:
534: /***********************************************************/
535: /* CPUX86 core interface */
536:
537: uint64_t cpu_get_tsc(CPUX86State *env)
538: {
539: return cpu_get_real_ticks();
540: }
541:
542: void
543: write_dt(void *ptr, unsigned long addr, unsigned long limit,
544: int flags)
545: {
546: unsigned int e1, e2;
547: e1 = (addr << 16) | (limit & 0xffff);
548: e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
549: e2 |= flags;
550: stl((uint8_t *)ptr, e1);
551: stl((uint8_t *)ptr + 4, e2);
552: }
553:
554: static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
555: unsigned long addr, unsigned int sel)
556: {
557: unsigned int e1, e2;
558: e1 = (addr & 0xffff) | (sel << 16);
559: e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
560: stl((uint8_t *)ptr, e1);
561: stl((uint8_t *)ptr + 4, e2);
562: }
563:
564: #define GDT_TABLE_SIZE 14
565: #define LDT_TABLE_SIZE 15
566: #define IDT_TABLE_SIZE 256
567: #define TSS_SIZE 104
568: uint64_t gdt_table[GDT_TABLE_SIZE];
569: uint64_t ldt_table[LDT_TABLE_SIZE];
570: uint64_t idt_table[IDT_TABLE_SIZE];
571: uint32_t tss[TSS_SIZE];
572:
573: /* only dpl matters as we do only user space emulation */
574: static void set_idt(int n, unsigned int dpl)
575: {
576: set_gate(idt_table + n, 0, dpl, 0, 0);
577: }
578:
579: /* ABI convention: after a syscall if there was an error the CF flag is set */
580: static inline void set_error(CPUX86State *env, int ret)
581: {
582: if(ret<0)
583: env->eflags = env->eflags | 0x1;
584: else
585: env->eflags &= ~0x1;
586: env->regs[R_EAX] = ret;
587: }
588:
589: void cpu_loop(CPUX86State *env)
590: {
591: int trapnr;
592: int ret;
593: uint8_t *pc;
594: target_siginfo_t info;
595:
596: for(;;) {
597: trapnr = cpu_x86_exec(env);
598: uint32_t *params = (uint32_t *)env->regs[R_ESP];
599: switch(trapnr) {
600: case 0x79: /* Our commpage hack back door exit is here */
601: do_commpage(env, env->eip, *(params + 1), *(params + 2),
602: *(params + 3), *(params + 4),
603: *(params + 5), *(params + 6),
604: *(params + 7), *(params + 8));
605: break;
606: case 0x81: /* mach syscall */
607: {
608: ret = do_mach_syscall(env, env->regs[R_EAX],
609: *(params + 1), *(params + 2),
610: *(params + 3), *(params + 4),
611: *(params + 5), *(params + 6),
612: *(params + 7), *(params + 8));
613: set_error(env, ret);
614: break;
615: }
616: case 0x90: /* unix backdoor */
617: {
618: /* after sysenter, stack is in R_ECX, new eip in R_EDX (sysexit will flip them back)*/
619: int saved_stack = env->regs[R_ESP];
620: env->regs[R_ESP] = env->regs[R_ECX];
621:
622: ret = do_unix_syscall(env, env->regs[R_EAX]);
623:
624: env->regs[R_ECX] = env->regs[R_ESP];
625: env->regs[R_ESP] = saved_stack;
626:
627: set_error(env, ret);
628: break;
629: }
630: case 0x80: /* unix syscall */
631: {
632: ret = do_unix_syscall(env, env->regs[R_EAX]/*,
633: *(params + 1), *(params + 2),
634: *(params + 3), *(params + 4),
635: *(params + 5), *(params + 6),
636: *(params + 7), *(params + 8)*/);
637: set_error(env, ret);
638: break;
639: }
640: case 0x82: /* thread syscall */
641: {
642: ret = do_thread_syscall(env, env->regs[R_EAX],
643: *(params + 1), *(params + 2),
644: *(params + 3), *(params + 4),
645: *(params + 5), *(params + 6),
646: *(params + 7), *(params + 8));
647: set_error(env, ret);
648: break;
649: }
650: case EXCP0B_NOSEG:
651: case EXCP0C_STACK:
652: info.si_signo = SIGBUS;
653: info.si_errno = 0;
654: info.si_code = BUS_NOOP;
655: info.si_addr = 0;
656: gdb_handlesig (env, SIGBUS);
657: queue_signal(info.si_signo, &info);
658: break;
659: case EXCP0D_GPF:
660: info.si_signo = SIGSEGV;
661: info.si_errno = 0;
662: info.si_code = SEGV_NOOP;
663: info.si_addr = 0;
664: gdb_handlesig (env, SIGSEGV);
665: queue_signal(info.si_signo, &info);
666: break;
667: case EXCP0E_PAGE:
668: info.si_signo = SIGSEGV;
669: info.si_errno = 0;
670: if (!(env->error_code & 1))
671: info.si_code = SEGV_MAPERR;
672: else
673: info.si_code = SEGV_ACCERR;
674: info.si_addr = (void*)env->cr[2];
675: gdb_handlesig (env, SIGSEGV);
676: queue_signal(info.si_signo, &info);
677: break;
678: case EXCP00_DIVZ:
679: /* division by zero */
680: info.si_signo = SIGFPE;
681: info.si_errno = 0;
682: info.si_code = FPE_INTDIV;
683: info.si_addr = (void*)env->eip;
684: gdb_handlesig (env, SIGFPE);
685: queue_signal(info.si_signo, &info);
686: break;
687: case EXCP01_SSTP:
688: case EXCP03_INT3:
689: info.si_signo = SIGTRAP;
690: info.si_errno = 0;
691: info.si_code = TRAP_BRKPT;
692: info.si_addr = (void*)env->eip;
693: gdb_handlesig (env, SIGTRAP);
694: queue_signal(info.si_signo, &info);
695: break;
696: case EXCP04_INTO:
697: case EXCP05_BOUND:
698: info.si_signo = SIGSEGV;
699: info.si_errno = 0;
700: info.si_code = SEGV_NOOP;
701: info.si_addr = 0;
702: gdb_handlesig (env, SIGSEGV);
703: queue_signal(info.si_signo, &info);
704: break;
705: case EXCP06_ILLOP:
706: info.si_signo = SIGILL;
707: info.si_errno = 0;
708: info.si_code = ILL_ILLOPN;
709: info.si_addr = (void*)env->eip;
710: gdb_handlesig (env, SIGILL);
711: queue_signal(info.si_signo, &info);
712: break;
713: case EXCP_INTERRUPT:
714: /* just indicate that signals should be handled asap */
715: break;
716: case EXCP_DEBUG:
717: {
718: int sig;
719:
720: sig = gdb_handlesig (env, SIGTRAP);
721: if (sig)
722: {
723: info.si_signo = sig;
724: info.si_errno = 0;
725: info.si_code = TRAP_BRKPT;
726: queue_signal(info.si_signo, &info);
727: }
728: }
729: break;
730: default:
731: pc = (void*)(env->segs[R_CS].base + env->eip);
732: fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
733: (long)pc, trapnr);
734: abort();
735: }
736: process_pending_signals(env);
737: }
738: }
739: #endif
740:
741: void usage(void)
742: {
743: printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2004 Fabrice Bellard\n"
744: "usage: qemu-" TARGET_ARCH " [-h] [-d opts] [-L path] [-s size] program [arguments...]\n"
745: "Darwin CPU emulator (compiled for %s emulation)\n"
746: "\n"
747: "-h print this help\n"
748: "-L path set the %s library path (default='%s')\n"
749: "-s size set the stack size in bytes (default=%ld)\n"
750: "\n"
751: "debug options:\n"
752: "-d options activate log (logfile='%s')\n"
753: "-g wait for gdb on port 1234\n"
754: "-p pagesize set the host page size to 'pagesize'\n",
755: TARGET_ARCH,
756: TARGET_ARCH,
757: interp_prefix,
758: stack_size,
759: DEBUG_LOGFILE);
760: _exit(1);
761: }
762:
763: /* XXX: currently only used for async signals (see signal.c) */
764: CPUState *global_env;
765: /* used only if single thread */
766: CPUState *cpu_single_env = NULL;
767:
768: /* used to free thread contexts */
769: TaskState *first_task_state;
770:
771: int main(int argc, char **argv)
772: {
773: const char *filename;
774: struct target_pt_regs regs1, *regs = ®s1;
775: TaskState ts1, *ts = &ts1;
776: CPUState *env;
777: int optind;
778: short use_gdbstub = 0;
779: const char *r;
1.1.1.2 ! root 780: const char *cpu_model;
1.1 root 781:
782: if (argc <= 1)
783: usage();
784:
785: /* init debug */
786: cpu_set_log_filename(DEBUG_LOGFILE);
787:
788: optind = 1;
789: for(;;) {
790: if (optind >= argc)
791: break;
792: r = argv[optind];
793: if (r[0] != '-')
794: break;
795: optind++;
796: r++;
797: if (!strcmp(r, "-")) {
798: break;
799: } else if (!strcmp(r, "d")) {
800: int mask;
801: CPULogItem *item;
802:
803: if (optind >= argc)
804: break;
805:
806: r = argv[optind++];
807: mask = cpu_str_to_log_mask(r);
808: if (!mask) {
809: printf("Log items (comma separated):\n");
810: for(item = cpu_log_items; item->mask != 0; item++) {
811: printf("%-10s %s\n", item->name, item->help);
812: }
813: exit(1);
814: }
815: cpu_set_log(mask);
816: } else if (!strcmp(r, "s")) {
817: r = argv[optind++];
818: stack_size = strtol(r, (char **)&r, 0);
819: if (stack_size <= 0)
820: usage();
821: if (*r == 'M')
822: stack_size *= 1024 * 1024;
823: else if (*r == 'k' || *r == 'K')
824: stack_size *= 1024;
825: } else if (!strcmp(r, "L")) {
826: interp_prefix = argv[optind++];
827: } else if (!strcmp(r, "p")) {
828: qemu_host_page_size = atoi(argv[optind++]);
829: if (qemu_host_page_size == 0 ||
830: (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
831: fprintf(stderr, "page size must be a power of two\n");
832: exit(1);
833: }
834: } else
835: if (!strcmp(r, "g")) {
836: use_gdbstub = 1;
1.1.1.2 ! root 837: } else if (!strcmp(r, "cpu")) {
! 838: cpu_model = argv[optind++];
! 839: if (strcmp(cpu_model, "?") == 0) {
! 840: /* XXX: implement xxx_cpu_list for targets that still miss it */
! 841: #if defined(cpu_list)
! 842: cpu_list(stdout, &fprintf);
1.1 root 843: #endif
1.1.1.2 ! root 844: _exit(1);
! 845: }
! 846: } else
1.1 root 847: {
848: usage();
849: }
850: }
851: if (optind >= argc)
852: usage();
853: filename = argv[optind];
854:
855: /* Zero out regs */
856: memset(regs, 0, sizeof(struct target_pt_regs));
857:
1.1.1.2 ! root 858: if (cpu_model == NULL) {
! 859: #if defined(TARGET_I386)
! 860: #ifdef TARGET_X86_64
! 861: cpu_model = "qemu64";
! 862: #else
! 863: cpu_model = "qemu32";
! 864: #endif
! 865: #elif defined(TARGET_PPC)
! 866: #ifdef TARGET_PPC64
! 867: cpu_model = "970";
! 868: #else
! 869: cpu_model = "750";
! 870: #endif
! 871: #else
! 872: #error unsupported CPU
! 873: #endif
! 874: }
! 875:
1.1 root 876: /* NOTE: we need to init the CPU at this stage to get
877: qemu_host_page_size */
1.1.1.2 ! root 878: env = cpu_init(cpu_model);
1.1 root 879:
880: printf("Starting %s with qemu\n----------------\n", filename);
881:
882: commpage_init();
883:
884: if (mach_exec(filename, argv+optind, environ, regs) != 0) {
885: printf("Error loading %s\n", filename);
886: _exit(1);
887: }
888:
889: syscall_init();
890: signal_init();
891: global_env = env;
892:
893: /* build Task State */
894: memset(ts, 0, sizeof(TaskState));
895: env->opaque = ts;
896: ts->used = 1;
897: env->user_mode_only = 1;
898:
899: #if defined(TARGET_I386)
900: cpu_x86_set_cpl(env, 3);
901:
902: env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
903: env->hflags |= HF_PE_MASK;
904:
905: if (env->cpuid_features & CPUID_SSE) {
906: env->cr[4] |= CR4_OSFXSR_MASK;
907: env->hflags |= HF_OSFXSR_MASK;
908: }
909:
910: /* flags setup : we activate the IRQs by default as in user mode */
911: env->eflags |= IF_MASK;
912:
913: /* darwin register setup */
914: env->regs[R_EAX] = regs->eax;
915: env->regs[R_EBX] = regs->ebx;
916: env->regs[R_ECX] = regs->ecx;
917: env->regs[R_EDX] = regs->edx;
918: env->regs[R_ESI] = regs->esi;
919: env->regs[R_EDI] = regs->edi;
920: env->regs[R_EBP] = regs->ebp;
921: env->regs[R_ESP] = regs->esp;
922: env->eip = regs->eip;
923:
924: /* Darwin LDT setup */
925: /* 2 - User code segment
926: 3 - User data segment
927: 4 - User cthread */
928: bzero(ldt_table, LDT_TABLE_SIZE * sizeof(ldt_table[0]));
929: env->ldt.base = (uint32_t) ldt_table;
930: env->ldt.limit = sizeof(ldt_table) - 1;
931:
932: write_dt(ldt_table + 2, 0, 0xfffff,
933: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
934: (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
935: write_dt(ldt_table + 3, 0, 0xfffff,
936: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
937: (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
938: write_dt(ldt_table + 4, 0, 0xfffff,
939: DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
940: (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
941:
942: /* Darwin GDT setup.
943: * has changed a lot between old Darwin/x86 (pre-Mac Intel) and Mac OS X/x86,
944: now everything is done via int 0x81(mach) int 0x82 (thread) and sysenter/sysexit(unix) */
945: bzero(gdt_table, sizeof(gdt_table));
946: env->gdt.base = (uint32_t)gdt_table;
947: env->gdt.limit = sizeof(gdt_table) - 1;
948:
949: /* Set up a back door to handle sysenter syscalls (unix) */
950: char * syscallbackdoor = malloc(64);
951: page_set_flags((int)syscallbackdoor, (int)syscallbackdoor + 64, PROT_EXEC | PROT_READ | PAGE_VALID);
952:
953: int i = 0;
954: syscallbackdoor[i++] = 0xcd;
955: syscallbackdoor[i++] = 0x90; /* int 0x90 */
956: syscallbackdoor[i++] = 0x0F;
957: syscallbackdoor[i++] = 0x35; /* sysexit */
958:
959: /* Darwin sysenter/sysexit setup */
960: env->sysenter_cs = 0x1; //XXX
961: env->sysenter_eip = (int)syscallbackdoor;
962: env->sysenter_esp = (int)malloc(64);
963:
964: /* Darwin TSS setup
965: This must match up with GDT[4] */
966: env->tr.base = (uint32_t) tss;
967: env->tr.limit = sizeof(tss) - 1;
968: env->tr.flags = DESC_P_MASK | (0x9 << DESC_TYPE_SHIFT);
969: stw(tss + 2, 0x10); // ss0 = 0x10 = GDT[2] = Kernel Data Segment
970:
971: /* Darwin interrupt setup */
972: bzero(idt_table, sizeof(idt_table));
973: env->idt.base = (uint32_t) idt_table;
974: env->idt.limit = sizeof(idt_table) - 1;
975: set_idt(0, 0);
976: set_idt(1, 0);
977: set_idt(2, 0);
978: set_idt(3, 3);
979: set_idt(4, 3);
980: set_idt(5, 3);
981: set_idt(6, 0);
982: set_idt(7, 0);
983: set_idt(8, 0);
984: set_idt(9, 0);
985: set_idt(10, 0);
986: set_idt(11, 0);
987: set_idt(12, 0);
988: set_idt(13, 0);
989: set_idt(14, 0);
990: set_idt(15, 0);
991: set_idt(16, 0);
992: set_idt(17, 0);
993: set_idt(18, 0);
994: set_idt(19, 0);
995: /* Syscalls are done via
996: int 0x80 (unix) (rarely used)
997: int 0x81 (mach)
998: int 0x82 (thread)
999: int 0x83 (diag) (not handled here)
1000: sysenter/sysexit (unix) -> we redirect that to int 0x90 */
1001: set_idt(0x79, 3); /* Commpage hack, here is our backdoor interrupt */
1002: set_idt(0x80, 3); /* Unix Syscall */
1003: set_idt(0x81, 3); /* Mach Syscalls */
1004: set_idt(0x82, 3); /* thread Syscalls */
1005:
1006: set_idt(0x90, 3); /* qemu-darwin-user's Unix syscalls backdoor */
1007:
1008:
1009: cpu_x86_load_seg(env, R_CS, __USER_CS);
1010: cpu_x86_load_seg(env, R_DS, __USER_DS);
1011: cpu_x86_load_seg(env, R_ES, __USER_DS);
1012: cpu_x86_load_seg(env, R_SS, __USER_DS);
1013: cpu_x86_load_seg(env, R_FS, __USER_DS);
1014: cpu_x86_load_seg(env, R_GS, __USER_DS);
1015:
1016: #elif defined(TARGET_PPC)
1017: {
1018: int i;
1.1.1.2 ! root 1019:
! 1020: #if defined(TARGET_PPC64)
! 1021: #if defined(TARGET_ABI32)
! 1022: env->msr &= ~((target_ulong)1 << MSR_SF);
! 1023: #else
! 1024: env->msr |= (target_ulong)1 << MSR_SF;
! 1025: #endif
! 1026: #endif
1.1 root 1027: env->nip = regs->nip;
1028: for(i = 0; i < 32; i++) {
1029: env->gpr[i] = regs->gpr[i];
1030: }
1031: }
1032: #else
1033: #error unsupported target CPU
1034: #endif
1035:
1036: if (use_gdbstub) {
1037: printf("Waiting for gdb Connection on port 1234...\n");
1038: gdbserver_start (1234);
1039: gdb_handlesig(env, 0);
1040: }
1041:
1042: cpu_loop(env);
1043: /* never exits */
1044: return 0;
1045: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.