📄 main.c
字号:
/* * qemu user main * * Copyright (c) 2003 Fabrice Bellard * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include <stdlib.h>#include <stdio.h>#include <stdarg.h>#include <string.h>#include <errno.h>#include <unistd.h>#include "qemu.h"#define DEBUG_LOGFILE "/tmp/qemu.log"#ifdef __APPLE__#include <crt_externs.h># define environ (*_NSGetEnviron())#endifstatic const char *interp_prefix = CONFIG_QEMU_PREFIX;#if defined(__i386__) && !defined(CONFIG_STATIC)/* Force usage of an ELF interpreter even if it is an ELF shared object ! */const char interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2";#endif/* for recent libc, we add these dummy symbols which are not declared when generating a linked object (bug in ld ?) */#if (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)) && !defined(CONFIG_STATIC)long __preinit_array_start[0];long __preinit_array_end[0];long __init_array_start[0];long __init_array_end[0];long __fini_array_start[0];long __fini_array_end[0];#endif/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so we allocate a bigger stack. Need a better solution, for example by remapping the process stack directly at the right place */unsigned long x86_stack_size = 512 * 1024;void gemu_log(const char *fmt, ...){ va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap);}void cpu_outb(CPUState *env, int addr, int val){ fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val);}void cpu_outw(CPUState *env, int addr, int val){ fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val);}void cpu_outl(CPUState *env, int addr, int val){ fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val);}int cpu_inb(CPUState *env, int addr){ fprintf(stderr, "inb: port=0x%04x\n", addr); return 0;}int cpu_inw(CPUState *env, int addr){ fprintf(stderr, "inw: port=0x%04x\n", addr); return 0;}int cpu_inl(CPUState *env, int addr){ fprintf(stderr, "inl: port=0x%04x\n", addr); return 0;}int cpu_get_pic_interrupt(CPUState *env){ return -1;}/* timers for rdtsc */#if defined(__i386__)int64_t cpu_get_real_ticks(void){ int64_t val; asm volatile ("rdtsc" : "=A" (val)); return val;}#elif defined(__x86_64__)int64_t cpu_get_real_ticks(void){ uint32_t low,high; int64_t val; asm volatile("rdtsc" : "=a" (low), "=d" (high)); val = high; val <<= 32; val |= low; return val;}#elsestatic uint64_t emu_time;int64_t cpu_get_real_ticks(void){ return emu_time++;}#endif#ifdef TARGET_I386/***********************************************************//* CPUX86 core interface */uint64_t cpu_get_tsc(CPUX86State *env){ return cpu_get_real_ticks();}static void write_dt(void *ptr, unsigned long addr, unsigned long limit, int flags){ unsigned int e1, e2; uint32_t *p; e1 = (addr << 16) | (limit & 0xffff); e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000); e2 |= flags; p = ptr; p[0] = tswapl(e1); p[1] = tswapl(e2);}static void set_gate(void *ptr, unsigned int type, unsigned int dpl, unsigned long addr, unsigned int sel){ unsigned int e1, e2; uint32_t *p; e1 = (addr & 0xffff) | (sel << 16); e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8); p = ptr; p[0] = tswapl(e1); p[1] = tswapl(e2);}uint64_t gdt_table[6];uint64_t idt_table[256];/* only dpl matters as we do only user space emulation */static void set_idt(int n, unsigned int dpl){ set_gate(idt_table + n, 0, dpl, 0, 0);}void cpu_loop(CPUX86State *env){ int trapnr; target_ulong pc; target_siginfo_t info; for(;;) { trapnr = cpu_x86_exec(env); switch(trapnr) { case 0x80: /* linux syscall */ env->regs[R_EAX] = do_syscall(env, env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP]); break; case EXCP0B_NOSEG: case EXCP0C_STACK: info.si_signo = SIGBUS; info.si_errno = 0; info.si_code = TARGET_SI_KERNEL; info._sifields._sigfault._addr = 0; queue_signal(info.si_signo, &info); break; case EXCP0D_GPF: if (env->eflags & VM_MASK) { handle_vm86_fault(env); } else { info.si_signo = SIGSEGV; info.si_errno = 0; info.si_code = TARGET_SI_KERNEL; info._sifields._sigfault._addr = 0; queue_signal(info.si_signo, &info); } break; case EXCP0E_PAGE: info.si_signo = SIGSEGV; info.si_errno = 0; if (!(env->error_code & 1)) info.si_code = TARGET_SEGV_MAPERR; else info.si_code = TARGET_SEGV_ACCERR; info._sifields._sigfault._addr = env->cr[2]; queue_signal(info.si_signo, &info); break; case EXCP00_DIVZ: if (env->eflags & VM_MASK) { handle_vm86_trap(env, trapnr); } else { /* division by zero */ info.si_signo = SIGFPE; info.si_errno = 0; info.si_code = TARGET_FPE_INTDIV; info._sifields._sigfault._addr = env->eip; queue_signal(info.si_signo, &info); } break; case EXCP01_SSTP: case EXCP03_INT3: if (env->eflags & VM_MASK) { handle_vm86_trap(env, trapnr); } else { info.si_signo = SIGTRAP; info.si_errno = 0; if (trapnr == EXCP01_SSTP) { info.si_code = TARGET_TRAP_BRKPT; info._sifields._sigfault._addr = env->eip; } else { info.si_code = TARGET_SI_KERNEL; info._sifields._sigfault._addr = 0; } queue_signal(info.si_signo, &info); } break; case EXCP04_INTO: case EXCP05_BOUND: if (env->eflags & VM_MASK) { handle_vm86_trap(env, trapnr); } else { info.si_signo = SIGSEGV; info.si_errno = 0; info.si_code = TARGET_SI_KERNEL; info._sifields._sigfault._addr = 0; queue_signal(info.si_signo, &info); } break; case EXCP06_ILLOP: info.si_signo = SIGILL; info.si_errno = 0; info.si_code = TARGET_ILL_ILLOPN; info._sifields._sigfault._addr = env->eip; queue_signal(info.si_signo, &info); break; case EXCP_INTERRUPT: /* just indicate that signals should be handled asap */ break; case EXCP_DEBUG: { int sig; sig = gdb_handlesig (env, TARGET_SIGTRAP); if (sig) { info.si_signo = sig; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; queue_signal(info.si_signo, &info); } } break; default: pc = env->segs[R_CS].base + env->eip; fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n", (long)pc, trapnr); abort(); } process_pending_signals(env); }}#endif#ifdef TARGET_ARM/* XXX: find a better solution */extern void tb_invalidate_page_range(target_ulong start, target_ulong end);static void arm_cache_flush(target_ulong start, target_ulong last){ target_ulong addr, last1; if (last < start) return; addr = start; for(;;) { last1 = ((addr + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK) - 1; if (last1 > last) last1 = last; tb_invalidate_page_range(addr, last1 + 1); if (last1 == last) break; addr = last1 + 1; }}void cpu_loop(CPUARMState *env){ int trapnr; unsigned int n, insn; target_siginfo_t info; uint32_t addr; for(;;) { trapnr = cpu_arm_exec(env); switch(trapnr) { case EXCP_UDEF: { TaskState *ts = env->opaque; uint32_t opcode; /* we handle the FPU emulation here, as Linux */ /* we get the opcode */ opcode = tget32(env->regs[15]); if (EmulateAll(opcode, &ts->fpa, env) == 0) { info.si_signo = SIGILL; info.si_errno = 0; info.si_code = TARGET_ILL_ILLOPN; info._sifields._sigfault._addr = env->regs[15]; queue_signal(info.si_signo, &info); } else { /* increment PC */ env->regs[15] += 4; } } break; case EXCP_SWI: case EXCP_BKPT: { env->eabi = 1; /* system call */ if (trapnr == EXCP_BKPT) { if (env->thumb) { insn = tget16(env->regs[15]); n = insn & 0xff; env->regs[15] += 2; } else { insn = tget32(env->regs[15]); n = (insn & 0xf) | ((insn >> 4) & 0xff0); env->regs[15] += 4; } } else { if (env->thumb) { insn = tget16(env->regs[15] - 2); n = insn & 0xff; } else { insn = tget32(env->regs[15] - 4); n = insn & 0xffffff; } } if (n == ARM_NR_cacheflush) { arm_cache_flush(env->regs[0], env->regs[1]); } else if (n == ARM_NR_semihosting || n == ARM_NR_thumb_semihosting) { env->regs[0] = do_arm_semihosting (env); } else if (n == 0 || n >= ARM_SYSCALL_BASE || (env->thumb && n == ARM_THUMB_SYSCALL)) { /* linux syscall */ if (env->thumb || n == 0) { n = env->regs[7]; } else { n -= ARM_SYSCALL_BASE; env->eabi = 0; } env->regs[0] = do_syscall(env, n, env->regs[0], env->regs[1], env->regs[2], env->regs[3], env->regs[4], env->regs[5]); } else { goto error; } } break; case EXCP_INTERRUPT: /* just indicate that signals should be handled asap */ break; case EXCP_PREFETCH_ABORT: addr = env->cp15.c6_data; goto do_segv; case EXCP_DATA_ABORT: addr = env->cp15.c6_insn; goto do_segv; do_segv: { info.si_signo = SIGSEGV; info.si_errno = 0; /* XXX: check env->error_code */ info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = addr;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -