131e31b8aSbellard /* 23ef693a0Sbellard * qemu main 331e31b8aSbellard * 431e31b8aSbellard * Copyright (c) 2003 Fabrice Bellard 531e31b8aSbellard * 631e31b8aSbellard * This program is free software; you can redistribute it and/or modify 731e31b8aSbellard * it under the terms of the GNU General Public License as published by 831e31b8aSbellard * the Free Software Foundation; either version 2 of the License, or 931e31b8aSbellard * (at your option) any later version. 1031e31b8aSbellard * 1131e31b8aSbellard * This program is distributed in the hope that it will be useful, 1231e31b8aSbellard * but WITHOUT ANY WARRANTY; without even the implied warranty of 1331e31b8aSbellard * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1431e31b8aSbellard * GNU General Public License for more details. 1531e31b8aSbellard * 1631e31b8aSbellard * You should have received a copy of the GNU General Public License 1731e31b8aSbellard * along with this program; if not, write to the Free Software 1831e31b8aSbellard * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 1931e31b8aSbellard */ 2031e31b8aSbellard #include <stdlib.h> 2131e31b8aSbellard #include <stdio.h> 2231e31b8aSbellard #include <stdarg.h> 2304369ff2Sbellard #include <string.h> 2431e31b8aSbellard #include <errno.h> 250ecfa993Sbellard #include <unistd.h> 2631e31b8aSbellard 273ef693a0Sbellard #include "qemu.h" 2831e31b8aSbellard 293ef693a0Sbellard #define DEBUG_LOGFILE "/tmp/qemu.log" 30586314f2Sbellard 31586314f2Sbellard FILE *logfile = NULL; 32586314f2Sbellard int loglevel; 3374cd30b8Sbellard static const char *interp_prefix = CONFIG_QEMU_PREFIX; 34586314f2Sbellard 35f801f97eSbellard #ifdef __i386__ 36f801f97eSbellard /* Force usage of an ELF interpreter even if it is an ELF shared 37f801f97eSbellard object ! */ 38f801f97eSbellard const char interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2"; 394304763bSbellard #endif 4074cd30b8Sbellard 4174cd30b8Sbellard /* for recent libc, we add these dummies symbol which are not declared 4274cd30b8Sbellard when generating a linked object (bug in ld ?) */ 4374cd30b8Sbellard #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3) 4474cd30b8Sbellard long __init_array_start[0]; 4574cd30b8Sbellard long __init_array_end[0]; 4674cd30b8Sbellard long __fini_array_start[0]; 4774cd30b8Sbellard long __fini_array_end[0]; 4874cd30b8Sbellard #endif 4974cd30b8Sbellard 509de5e440Sbellard /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so 519de5e440Sbellard we allocate a bigger stack. Need a better solution, for example 529de5e440Sbellard by remapping the process stack directly at the right place */ 539de5e440Sbellard unsigned long x86_stack_size = 512 * 1024; 5431e31b8aSbellard 5531e31b8aSbellard void gemu_log(const char *fmt, ...) 5631e31b8aSbellard { 5731e31b8aSbellard va_list ap; 5831e31b8aSbellard 5931e31b8aSbellard va_start(ap, fmt); 6031e31b8aSbellard vfprintf(stderr, fmt, ap); 6131e31b8aSbellard va_end(ap); 6231e31b8aSbellard } 6331e31b8aSbellard 64b346ff46Sbellard #ifdef TARGET_I386 6531e31b8aSbellard /***********************************************************/ 660ecfa993Sbellard /* CPUX86 core interface */ 67367e86e8Sbellard 68b689bc57Sbellard void cpu_x86_outb(CPUX86State *env, int addr, int val) 69367e86e8Sbellard { 70367e86e8Sbellard fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val); 71367e86e8Sbellard } 72367e86e8Sbellard 73b689bc57Sbellard void cpu_x86_outw(CPUX86State *env, int addr, int val) 74367e86e8Sbellard { 75367e86e8Sbellard fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val); 76367e86e8Sbellard } 77367e86e8Sbellard 78b689bc57Sbellard void cpu_x86_outl(CPUX86State *env, int addr, int val) 79367e86e8Sbellard { 80367e86e8Sbellard fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val); 81367e86e8Sbellard } 82367e86e8Sbellard 83b689bc57Sbellard int cpu_x86_inb(CPUX86State *env, int addr) 84367e86e8Sbellard { 85367e86e8Sbellard fprintf(stderr, "inb: port=0x%04x\n", addr); 86367e86e8Sbellard return 0; 87367e86e8Sbellard } 88367e86e8Sbellard 89b689bc57Sbellard int cpu_x86_inw(CPUX86State *env, int addr) 90367e86e8Sbellard { 91367e86e8Sbellard fprintf(stderr, "inw: port=0x%04x\n", addr); 92367e86e8Sbellard return 0; 93367e86e8Sbellard } 94367e86e8Sbellard 95b689bc57Sbellard int cpu_x86_inl(CPUX86State *env, int addr) 96367e86e8Sbellard { 97367e86e8Sbellard fprintf(stderr, "inl: port=0x%04x\n", addr); 98367e86e8Sbellard return 0; 99367e86e8Sbellard } 100367e86e8Sbellard 10192ccca6aSbellard int cpu_x86_get_pic_interrupt(CPUX86State *env) 10292ccca6aSbellard { 10392ccca6aSbellard return -1; 10492ccca6aSbellard } 10592ccca6aSbellard 106f4beb510Sbellard static void write_dt(void *ptr, unsigned long addr, unsigned long limit, 107f4beb510Sbellard int flags) 1086dbad63eSbellard { 109f4beb510Sbellard unsigned int e1, e2; 1106dbad63eSbellard e1 = (addr << 16) | (limit & 0xffff); 1116dbad63eSbellard e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000); 112f4beb510Sbellard e2 |= flags; 113f4beb510Sbellard stl((uint8_t *)ptr, e1); 114f4beb510Sbellard stl((uint8_t *)ptr + 4, e2); 115f4beb510Sbellard } 116f4beb510Sbellard 117f4beb510Sbellard static void set_gate(void *ptr, unsigned int type, unsigned int dpl, 118f4beb510Sbellard unsigned long addr, unsigned int sel) 119f4beb510Sbellard { 120f4beb510Sbellard unsigned int e1, e2; 121f4beb510Sbellard e1 = (addr & 0xffff) | (sel << 16); 122f4beb510Sbellard e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8); 1236dbad63eSbellard stl((uint8_t *)ptr, e1); 1246dbad63eSbellard stl((uint8_t *)ptr + 4, e2); 1256dbad63eSbellard } 1266dbad63eSbellard 1276dbad63eSbellard uint64_t gdt_table[6]; 128f4beb510Sbellard uint64_t idt_table[256]; 129f4beb510Sbellard 130f4beb510Sbellard /* only dpl matters as we do only user space emulation */ 131f4beb510Sbellard static void set_idt(int n, unsigned int dpl) 132f4beb510Sbellard { 133f4beb510Sbellard set_gate(idt_table + n, 0, dpl, 0, 0); 134f4beb510Sbellard } 13531e31b8aSbellard 13689e957e7Sbellard void cpu_loop(CPUX86State *env) 137bc8a22ccSbellard { 138bc8a22ccSbellard int trapnr; 139bc8a22ccSbellard uint8_t *pc; 140bc8a22ccSbellard target_siginfo_t info; 141bc8a22ccSbellard 142bc8a22ccSbellard for(;;) { 143bc8a22ccSbellard trapnr = cpu_x86_exec(env); 144bc8a22ccSbellard switch(trapnr) { 145f4beb510Sbellard case 0x80: 146f4beb510Sbellard /* linux syscall */ 1471b6b029eSbellard env->regs[R_EAX] = do_syscall(env, 1481b6b029eSbellard env->regs[R_EAX], 1491b6b029eSbellard env->regs[R_EBX], 1501b6b029eSbellard env->regs[R_ECX], 1511b6b029eSbellard env->regs[R_EDX], 1521b6b029eSbellard env->regs[R_ESI], 1531b6b029eSbellard env->regs[R_EDI], 1541b6b029eSbellard env->regs[R_EBP]); 155f4beb510Sbellard break; 156f4beb510Sbellard case EXCP0B_NOSEG: 157f4beb510Sbellard case EXCP0C_STACK: 158f4beb510Sbellard info.si_signo = SIGBUS; 159f4beb510Sbellard info.si_errno = 0; 160f4beb510Sbellard info.si_code = TARGET_SI_KERNEL; 161f4beb510Sbellard info._sifields._sigfault._addr = 0; 162f4beb510Sbellard queue_signal(info.si_signo, &info); 163f4beb510Sbellard break; 164f4beb510Sbellard case EXCP0D_GPF: 165f4beb510Sbellard if (env->eflags & VM_MASK) { 166f4beb510Sbellard handle_vm86_fault(env); 1671b6b029eSbellard } else { 1689de5e440Sbellard info.si_signo = SIGSEGV; 1699de5e440Sbellard info.si_errno = 0; 170b689bc57Sbellard info.si_code = TARGET_SI_KERNEL; 1719de5e440Sbellard info._sifields._sigfault._addr = 0; 1729de5e440Sbellard queue_signal(info.si_signo, &info); 1731b6b029eSbellard } 1741b6b029eSbellard break; 175b689bc57Sbellard case EXCP0E_PAGE: 176b689bc57Sbellard info.si_signo = SIGSEGV; 177b689bc57Sbellard info.si_errno = 0; 178b689bc57Sbellard if (!(env->error_code & 1)) 179b689bc57Sbellard info.si_code = TARGET_SEGV_MAPERR; 180b689bc57Sbellard else 181b689bc57Sbellard info.si_code = TARGET_SEGV_ACCERR; 182970a87a6Sbellard info._sifields._sigfault._addr = env->cr[2]; 183b689bc57Sbellard queue_signal(info.si_signo, &info); 184b689bc57Sbellard break; 1859de5e440Sbellard case EXCP00_DIVZ: 186bc8a22ccSbellard if (env->eflags & VM_MASK) { 187447db213Sbellard handle_vm86_trap(env, trapnr); 188bc8a22ccSbellard } else { 1899de5e440Sbellard /* division by zero */ 1909de5e440Sbellard info.si_signo = SIGFPE; 1919de5e440Sbellard info.si_errno = 0; 1929de5e440Sbellard info.si_code = TARGET_FPE_INTDIV; 1939de5e440Sbellard info._sifields._sigfault._addr = env->eip; 1949de5e440Sbellard queue_signal(info.si_signo, &info); 195bc8a22ccSbellard } 1969de5e440Sbellard break; 197447db213Sbellard case EXCP01_SSTP: 198447db213Sbellard case EXCP03_INT3: 199447db213Sbellard if (env->eflags & VM_MASK) { 200447db213Sbellard handle_vm86_trap(env, trapnr); 201447db213Sbellard } else { 202447db213Sbellard info.si_signo = SIGTRAP; 203447db213Sbellard info.si_errno = 0; 204447db213Sbellard if (trapnr == EXCP01_SSTP) { 205447db213Sbellard info.si_code = TARGET_TRAP_BRKPT; 206447db213Sbellard info._sifields._sigfault._addr = env->eip; 207447db213Sbellard } else { 208447db213Sbellard info.si_code = TARGET_SI_KERNEL; 209447db213Sbellard info._sifields._sigfault._addr = 0; 210447db213Sbellard } 211447db213Sbellard queue_signal(info.si_signo, &info); 212447db213Sbellard } 213447db213Sbellard break; 2149de5e440Sbellard case EXCP04_INTO: 2159de5e440Sbellard case EXCP05_BOUND: 216bc8a22ccSbellard if (env->eflags & VM_MASK) { 217447db213Sbellard handle_vm86_trap(env, trapnr); 218bc8a22ccSbellard } else { 2199de5e440Sbellard info.si_signo = SIGSEGV; 2209de5e440Sbellard info.si_errno = 0; 221b689bc57Sbellard info.si_code = TARGET_SI_KERNEL; 2229de5e440Sbellard info._sifields._sigfault._addr = 0; 2239de5e440Sbellard queue_signal(info.si_signo, &info); 224bc8a22ccSbellard } 2259de5e440Sbellard break; 2269de5e440Sbellard case EXCP06_ILLOP: 2279de5e440Sbellard info.si_signo = SIGILL; 2289de5e440Sbellard info.si_errno = 0; 2299de5e440Sbellard info.si_code = TARGET_ILL_ILLOPN; 2309de5e440Sbellard info._sifields._sigfault._addr = env->eip; 2319de5e440Sbellard queue_signal(info.si_signo, &info); 2329de5e440Sbellard break; 2339de5e440Sbellard case EXCP_INTERRUPT: 2349de5e440Sbellard /* just indicate that signals should be handled asap */ 2359de5e440Sbellard break; 2361b6b029eSbellard default: 237970a87a6Sbellard pc = env->segs[R_CS].base + env->eip; 238bc8a22ccSbellard fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n", 239bc8a22ccSbellard (long)pc, trapnr); 2401b6b029eSbellard abort(); 2411b6b029eSbellard } 24266fb9763Sbellard process_pending_signals(env); 2431b6b029eSbellard } 2441b6b029eSbellard } 245b346ff46Sbellard #endif 246b346ff46Sbellard 247b346ff46Sbellard #ifdef TARGET_ARM 248b346ff46Sbellard 249b346ff46Sbellard #define ARM_SYSCALL_BASE 0x900000 250b346ff46Sbellard 251b346ff46Sbellard void cpu_loop(CPUARMState *env) 252b346ff46Sbellard { 253b346ff46Sbellard int trapnr; 254b346ff46Sbellard unsigned int n, insn; 255b346ff46Sbellard target_siginfo_t info; 256b346ff46Sbellard 257b346ff46Sbellard for(;;) { 258b346ff46Sbellard trapnr = cpu_arm_exec(env); 259b346ff46Sbellard switch(trapnr) { 260b346ff46Sbellard case EXCP_UDEF: 261b346ff46Sbellard info.si_signo = SIGILL; 262b346ff46Sbellard info.si_errno = 0; 263b346ff46Sbellard info.si_code = TARGET_ILL_ILLOPN; 264b346ff46Sbellard info._sifields._sigfault._addr = env->regs[15]; 265b346ff46Sbellard queue_signal(info.si_signo, &info); 266b346ff46Sbellard break; 267b346ff46Sbellard case EXCP_SWI: 268b346ff46Sbellard { 269b346ff46Sbellard /* system call */ 270b346ff46Sbellard insn = ldl((void *)(env->regs[15] - 4)); 271b346ff46Sbellard n = insn & 0xffffff; 272b346ff46Sbellard if (n >= ARM_SYSCALL_BASE) { 273b346ff46Sbellard /* linux syscall */ 274b346ff46Sbellard n -= ARM_SYSCALL_BASE; 275b346ff46Sbellard env->regs[0] = do_syscall(env, 276b346ff46Sbellard n, 277b346ff46Sbellard env->regs[0], 278b346ff46Sbellard env->regs[1], 279b346ff46Sbellard env->regs[2], 280b346ff46Sbellard env->regs[3], 281b346ff46Sbellard env->regs[4], 282b346ff46Sbellard 0); 283b346ff46Sbellard } else { 284b346ff46Sbellard goto error; 285b346ff46Sbellard } 286b346ff46Sbellard } 287b346ff46Sbellard break; 288b346ff46Sbellard default: 289b346ff46Sbellard error: 290b346ff46Sbellard fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", 291b346ff46Sbellard trapnr); 292b346ff46Sbellard cpu_arm_dump_state(env, stderr, 0); 293b346ff46Sbellard abort(); 294b346ff46Sbellard } 295b346ff46Sbellard process_pending_signals(env); 296b346ff46Sbellard } 297b346ff46Sbellard } 298b346ff46Sbellard 299b346ff46Sbellard #endif 3001b6b029eSbellard 30131e31b8aSbellard void usage(void) 30231e31b8aSbellard { 3033ef693a0Sbellard printf("qemu version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n" 304d691f669Sbellard "usage: qemu [-h] [-d] [-L path] [-s size] program [arguments...]\n" 305b346ff46Sbellard "Linux CPU emulator (compiled for %s emulation)\n" 306d691f669Sbellard "\n" 307d691f669Sbellard "-h print this help\n" 308b346ff46Sbellard "-L path set the elf interpreter prefix (default=%s)\n" 309b346ff46Sbellard "-s size set the stack size in bytes (default=%ld)\n" 31054936004Sbellard "\n" 31154936004Sbellard "debug options:\n" 31254936004Sbellard "-d activate log (logfile=%s)\n" 31354936004Sbellard "-p pagesize set the host page size to 'pagesize'\n", 314b346ff46Sbellard TARGET_ARCH, 315d691f669Sbellard interp_prefix, 31654936004Sbellard x86_stack_size, 31754936004Sbellard DEBUG_LOGFILE); 31874cd30b8Sbellard _exit(1); 31931e31b8aSbellard } 32031e31b8aSbellard 3219de5e440Sbellard /* XXX: currently only used for async signals (see signal.c) */ 322b346ff46Sbellard CPUState *global_env; 323*59faf6d6Sbellard /* used only if single thread */ 324*59faf6d6Sbellard CPUState *cpu_single_env = NULL; 325*59faf6d6Sbellard 326851e67a1Sbellard /* used to free thread contexts */ 327851e67a1Sbellard TaskState *first_task_state; 3289de5e440Sbellard 32931e31b8aSbellard int main(int argc, char **argv) 33031e31b8aSbellard { 33131e31b8aSbellard const char *filename; 33201ffc75bSbellard struct target_pt_regs regs1, *regs = ®s1; 33331e31b8aSbellard struct image_info info1, *info = &info1; 334851e67a1Sbellard TaskState ts1, *ts = &ts1; 335b346ff46Sbellard CPUState *env; 336586314f2Sbellard int optind; 337d691f669Sbellard const char *r; 33831e31b8aSbellard 33931e31b8aSbellard if (argc <= 1) 34031e31b8aSbellard usage(); 341f801f97eSbellard 342586314f2Sbellard loglevel = 0; 343586314f2Sbellard optind = 1; 344d691f669Sbellard for(;;) { 345d691f669Sbellard if (optind >= argc) 346d691f669Sbellard break; 347d691f669Sbellard r = argv[optind]; 348d691f669Sbellard if (r[0] != '-') 349d691f669Sbellard break; 350586314f2Sbellard optind++; 351d691f669Sbellard r++; 352d691f669Sbellard if (!strcmp(r, "-")) { 353d691f669Sbellard break; 354d691f669Sbellard } else if (!strcmp(r, "d")) { 355d691f669Sbellard loglevel = 1; 356d691f669Sbellard } else if (!strcmp(r, "s")) { 357d691f669Sbellard r = argv[optind++]; 358d691f669Sbellard x86_stack_size = strtol(r, (char **)&r, 0); 359d691f669Sbellard if (x86_stack_size <= 0) 360d691f669Sbellard usage(); 361d691f669Sbellard if (*r == 'M') 362d691f669Sbellard x86_stack_size *= 1024 * 1024; 363d691f669Sbellard else if (*r == 'k' || *r == 'K') 364d691f669Sbellard x86_stack_size *= 1024; 365d691f669Sbellard } else if (!strcmp(r, "L")) { 366d691f669Sbellard interp_prefix = argv[optind++]; 36754936004Sbellard } else if (!strcmp(r, "p")) { 36854936004Sbellard host_page_size = atoi(argv[optind++]); 36954936004Sbellard if (host_page_size == 0 || 37054936004Sbellard (host_page_size & (host_page_size - 1)) != 0) { 37154936004Sbellard fprintf(stderr, "page size must be a power of two\n"); 37254936004Sbellard exit(1); 37354936004Sbellard } 374d691f669Sbellard } else { 375d691f669Sbellard usage(); 376586314f2Sbellard } 377d691f669Sbellard } 378d691f669Sbellard if (optind >= argc) 379d691f669Sbellard usage(); 380586314f2Sbellard filename = argv[optind]; 38131e31b8aSbellard 382586314f2Sbellard /* init debug */ 383586314f2Sbellard if (loglevel) { 384586314f2Sbellard logfile = fopen(DEBUG_LOGFILE, "w"); 385586314f2Sbellard if (!logfile) { 386586314f2Sbellard perror(DEBUG_LOGFILE); 38774cd30b8Sbellard _exit(1); 388586314f2Sbellard } 389586314f2Sbellard setvbuf(logfile, NULL, _IOLBF, 0); 390586314f2Sbellard } 39131e31b8aSbellard 39231e31b8aSbellard /* Zero out regs */ 39301ffc75bSbellard memset(regs, 0, sizeof(struct target_pt_regs)); 39431e31b8aSbellard 39531e31b8aSbellard /* Zero out image_info */ 39631e31b8aSbellard memset(info, 0, sizeof(struct image_info)); 39731e31b8aSbellard 39874cd30b8Sbellard /* Scan interp_prefix dir for replacement files. */ 39974cd30b8Sbellard init_paths(interp_prefix); 40074cd30b8Sbellard 40154936004Sbellard /* NOTE: we need to init the CPU at this stage to get the 40254936004Sbellard host_page_size */ 403b346ff46Sbellard env = cpu_init(); 40454936004Sbellard 40574cd30b8Sbellard if (elf_exec(filename, argv+optind, environ, regs, info) != 0) { 40631e31b8aSbellard printf("Error loading %s\n", filename); 40774cd30b8Sbellard _exit(1); 40831e31b8aSbellard } 40931e31b8aSbellard 4104b74fe1fSbellard if (loglevel) { 41154936004Sbellard page_dump(logfile); 41254936004Sbellard 4134b74fe1fSbellard fprintf(logfile, "start_brk 0x%08lx\n" , info->start_brk); 4144b74fe1fSbellard fprintf(logfile, "end_code 0x%08lx\n" , info->end_code); 4154b74fe1fSbellard fprintf(logfile, "start_code 0x%08lx\n" , info->start_code); 4164b74fe1fSbellard fprintf(logfile, "end_data 0x%08lx\n" , info->end_data); 4174b74fe1fSbellard fprintf(logfile, "start_stack 0x%08lx\n" , info->start_stack); 4184b74fe1fSbellard fprintf(logfile, "brk 0x%08lx\n" , info->brk); 419b346ff46Sbellard fprintf(logfile, "entry 0x%08lx\n" , info->entry); 4204b74fe1fSbellard } 42131e31b8aSbellard 42231e31b8aSbellard target_set_brk((char *)info->brk); 42331e31b8aSbellard syscall_init(); 42466fb9763Sbellard signal_init(); 42531e31b8aSbellard 4269de5e440Sbellard global_env = env; 42731e31b8aSbellard 428851e67a1Sbellard /* build Task State */ 429851e67a1Sbellard memset(ts, 0, sizeof(TaskState)); 430851e67a1Sbellard env->opaque = ts; 431851e67a1Sbellard ts->used = 1; 432*59faf6d6Sbellard env->user_mode_only = 1; 433851e67a1Sbellard 434b346ff46Sbellard #if defined(TARGET_I386) 4356dbad63eSbellard /* linux register setup */ 4360ecfa993Sbellard env->regs[R_EAX] = regs->eax; 4370ecfa993Sbellard env->regs[R_EBX] = regs->ebx; 4380ecfa993Sbellard env->regs[R_ECX] = regs->ecx; 4390ecfa993Sbellard env->regs[R_EDX] = regs->edx; 4400ecfa993Sbellard env->regs[R_ESI] = regs->esi; 4410ecfa993Sbellard env->regs[R_EDI] = regs->edi; 4420ecfa993Sbellard env->regs[R_EBP] = regs->ebp; 4430ecfa993Sbellard env->regs[R_ESP] = regs->esp; 444dab2ed99Sbellard env->eip = regs->eip; 44531e31b8aSbellard 446f4beb510Sbellard /* linux interrupt setup */ 447f4beb510Sbellard env->idt.base = (void *)idt_table; 448f4beb510Sbellard env->idt.limit = sizeof(idt_table) - 1; 449f4beb510Sbellard set_idt(0, 0); 450f4beb510Sbellard set_idt(1, 0); 451f4beb510Sbellard set_idt(2, 0); 452f4beb510Sbellard set_idt(3, 3); 453f4beb510Sbellard set_idt(4, 3); 454f4beb510Sbellard set_idt(5, 3); 455f4beb510Sbellard set_idt(6, 0); 456f4beb510Sbellard set_idt(7, 0); 457f4beb510Sbellard set_idt(8, 0); 458f4beb510Sbellard set_idt(9, 0); 459f4beb510Sbellard set_idt(10, 0); 460f4beb510Sbellard set_idt(11, 0); 461f4beb510Sbellard set_idt(12, 0); 462f4beb510Sbellard set_idt(13, 0); 463f4beb510Sbellard set_idt(14, 0); 464f4beb510Sbellard set_idt(15, 0); 465f4beb510Sbellard set_idt(16, 0); 466f4beb510Sbellard set_idt(17, 0); 467f4beb510Sbellard set_idt(18, 0); 468f4beb510Sbellard set_idt(19, 0); 469f4beb510Sbellard set_idt(0x80, 3); 470f4beb510Sbellard 4716dbad63eSbellard /* linux segment setup */ 4726dbad63eSbellard env->gdt.base = (void *)gdt_table; 4736dbad63eSbellard env->gdt.limit = sizeof(gdt_table) - 1; 474f4beb510Sbellard write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff, 475f4beb510Sbellard DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | 476f4beb510Sbellard (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT)); 477f4beb510Sbellard write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff, 478f4beb510Sbellard DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | 479f4beb510Sbellard (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT)); 4806dbad63eSbellard cpu_x86_load_seg(env, R_CS, __USER_CS); 4816dbad63eSbellard cpu_x86_load_seg(env, R_DS, __USER_DS); 4826dbad63eSbellard cpu_x86_load_seg(env, R_ES, __USER_DS); 4836dbad63eSbellard cpu_x86_load_seg(env, R_SS, __USER_DS); 4846dbad63eSbellard cpu_x86_load_seg(env, R_FS, __USER_DS); 4856dbad63eSbellard cpu_x86_load_seg(env, R_GS, __USER_DS); 48692ccca6aSbellard 487b346ff46Sbellard #elif defined(TARGET_ARM) 488b346ff46Sbellard { 489b346ff46Sbellard int i; 490b346ff46Sbellard for(i = 0; i < 16; i++) { 491b346ff46Sbellard env->regs[i] = regs->uregs[i]; 492b346ff46Sbellard } 493b346ff46Sbellard env->cpsr = regs->uregs[16]; 494b346ff46Sbellard } 495b346ff46Sbellard #else 496b346ff46Sbellard #error unsupported target CPU 497b346ff46Sbellard #endif 49831e31b8aSbellard 4991b6b029eSbellard cpu_loop(env); 5001b6b029eSbellard /* never exits */ 50131e31b8aSbellard return 0; 50231e31b8aSbellard } 503