123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584 |
- /*
- * qemu user main
- *
- * Copyright (c) 2003-2008 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., 51 Franklin Street - Fifth Floor, Boston,
- * MA 02110-1301, USA.
- */
- #include <stdlib.h>
- #include <stdio.h>
- #include <stdarg.h>
- #include <string.h>
- #include <errno.h>
- #include <unistd.h>
- #include <machine/trap.h>
- #include "qemu.h"
- #include "qemu-common.h"
- /* For tb_lock */
- #include "exec-all.h"
- #define DEBUG_LOGFILE "/tmp/qemu.log"
- static const char *interp_prefix = CONFIG_QEMU_PREFIX;
- const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
- extern char **environ;
- /* 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);
- }
- #ifdef TARGET_SPARC
- #define SPARC64_STACK_BIAS 2047
- //#define DEBUG_WIN
- /* WARNING: dealing with register windows _is_ complicated. More info
- can be found at http://www.sics.se/~psm/sparcstack.html */
- static inline int get_reg_index(CPUSPARCState *env, int cwp, int index)
- {
- index = (index + cwp * 16) % (16 * env->nwindows);
- /* wrap handling : if cwp is on the last window, then we use the
- registers 'after' the end */
- if (index < 8 && env->cwp == env->nwindows - 1)
- index += 16 * env->nwindows;
- return index;
- }
- /* save the register window 'cwp1' */
- static inline void save_window_offset(CPUSPARCState *env, int cwp1)
- {
- unsigned int i;
- abi_ulong sp_ptr;
- sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
- #ifdef TARGET_SPARC64
- if (sp_ptr & 3)
- sp_ptr += SPARC64_STACK_BIAS;
- #endif
- #if defined(DEBUG_WIN)
- printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n",
- sp_ptr, cwp1);
- #endif
- for(i = 0; i < 16; i++) {
- /* FIXME - what to do if put_user() fails? */
- put_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
- sp_ptr += sizeof(abi_ulong);
- }
- }
- static void save_window(CPUSPARCState *env)
- {
- #ifndef TARGET_SPARC64
- unsigned int new_wim;
- new_wim = ((env->wim >> 1) | (env->wim << (env->nwindows - 1))) &
- ((1LL << env->nwindows) - 1);
- save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
- env->wim = new_wim;
- #else
- save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
- env->cansave++;
- env->canrestore--;
- #endif
- }
- static void restore_window(CPUSPARCState *env)
- {
- #ifndef TARGET_SPARC64
- unsigned int new_wim;
- #endif
- unsigned int i, cwp1;
- abi_ulong sp_ptr;
- #ifndef TARGET_SPARC64
- new_wim = ((env->wim << 1) | (env->wim >> (env->nwindows - 1))) &
- ((1LL << env->nwindows) - 1);
- #endif
- /* restore the invalid window */
- cwp1 = cpu_cwp_inc(env, env->cwp + 1);
- sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
- #ifdef TARGET_SPARC64
- if (sp_ptr & 3)
- sp_ptr += SPARC64_STACK_BIAS;
- #endif
- #if defined(DEBUG_WIN)
- printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n",
- sp_ptr, cwp1);
- #endif
- for(i = 0; i < 16; i++) {
- /* FIXME - what to do if get_user() fails? */
- get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
- sp_ptr += sizeof(abi_ulong);
- }
- #ifdef TARGET_SPARC64
- env->canrestore++;
- if (env->cleanwin < env->nwindows - 1)
- env->cleanwin++;
- env->cansave--;
- #else
- env->wim = new_wim;
- #endif
- }
- static void flush_windows(CPUSPARCState *env)
- {
- int offset, cwp1;
- offset = 1;
- for(;;) {
- /* if restore would invoke restore_window(), then we can stop */
- cwp1 = cpu_cwp_inc(env, env->cwp + offset);
- #ifndef TARGET_SPARC64
- if (env->wim & (1 << cwp1))
- break;
- #else
- if (env->canrestore == 0)
- break;
- env->cansave++;
- env->canrestore--;
- #endif
- save_window_offset(env, cwp1);
- offset++;
- }
- cwp1 = cpu_cwp_inc(env, env->cwp + 1);
- #ifndef TARGET_SPARC64
- /* set wim so that restore will reload the registers */
- env->wim = 1 << cwp1;
- #endif
- #if defined(DEBUG_WIN)
- printf("flush_windows: nb=%d\n", offset - 1);
- #endif
- }
- void cpu_loop(CPUSPARCState *env, enum BSDType bsd_type)
- {
- int trapnr, ret, syscall_nr;
- //target_siginfo_t info;
- while (1) {
- trapnr = cpu_sparc_exec (env);
- switch (trapnr) {
- #ifndef TARGET_SPARC64
- case 0x80:
- #else
- case 0x100:
- #endif
- syscall_nr = env->gregs[1];
- if (bsd_type == target_freebsd)
- ret = do_freebsd_syscall(env, syscall_nr,
- env->regwptr[0], env->regwptr[1],
- env->regwptr[2], env->regwptr[3],
- env->regwptr[4], env->regwptr[5]);
- else if (bsd_type == target_netbsd)
- ret = do_netbsd_syscall(env, syscall_nr,
- env->regwptr[0], env->regwptr[1],
- env->regwptr[2], env->regwptr[3],
- env->regwptr[4], env->regwptr[5]);
- else { //if (bsd_type == target_openbsd)
- #if defined(TARGET_SPARC64)
- syscall_nr &= ~(TARGET_OPENBSD_SYSCALL_G7RFLAG |
- TARGET_OPENBSD_SYSCALL_G2RFLAG);
- #endif
- ret = do_openbsd_syscall(env, syscall_nr,
- env->regwptr[0], env->regwptr[1],
- env->regwptr[2], env->regwptr[3],
- env->regwptr[4], env->regwptr[5]);
- }
- if ((unsigned int)ret >= (unsigned int)(-515)) {
- #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
- env->xcc |= PSR_CARRY;
- #else
- env->psr |= PSR_CARRY;
- #endif
- } else {
- #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
- env->xcc &= ~PSR_CARRY;
- #else
- env->psr &= ~PSR_CARRY;
- #endif
- }
- env->regwptr[0] = ret;
- /* next instruction */
- #if defined(TARGET_SPARC64)
- if (bsd_type == target_openbsd &&
- env->gregs[1] & TARGET_OPENBSD_SYSCALL_G2RFLAG) {
- env->pc = env->gregs[2];
- env->npc = env->pc + 4;
- } else if (bsd_type == target_openbsd &&
- env->gregs[1] & TARGET_OPENBSD_SYSCALL_G7RFLAG) {
- env->pc = env->gregs[7];
- env->npc = env->pc + 4;
- } else {
- env->pc = env->npc;
- env->npc = env->npc + 4;
- }
- #else
- env->pc = env->npc;
- env->npc = env->npc + 4;
- #endif
- break;
- case 0x83: /* flush windows */
- #ifdef TARGET_ABI32
- case 0x103:
- #endif
- flush_windows(env);
- /* next instruction */
- env->pc = env->npc;
- env->npc = env->npc + 4;
- break;
- #ifndef TARGET_SPARC64
- case TT_WIN_OVF: /* window overflow */
- save_window(env);
- break;
- case TT_WIN_UNF: /* window underflow */
- restore_window(env);
- break;
- case TT_TFAULT:
- case TT_DFAULT:
- #if 0
- {
- info.si_signo = SIGSEGV;
- info.si_errno = 0;
- /* XXX: check env->error_code */
- info.si_code = TARGET_SEGV_MAPERR;
- info._sifields._sigfault._addr = env->mmuregs[4];
- queue_signal(env, info.si_signo, &info);
- }
- #endif
- break;
- #else
- case TT_SPILL: /* window overflow */
- save_window(env);
- break;
- case TT_FILL: /* window underflow */
- restore_window(env);
- break;
- case TT_TFAULT:
- case TT_DFAULT:
- #if 0
- {
- info.si_signo = SIGSEGV;
- info.si_errno = 0;
- /* XXX: check env->error_code */
- info.si_code = TARGET_SEGV_MAPERR;
- if (trapnr == TT_DFAULT)
- info._sifields._sigfault._addr = env->dmmuregs[4];
- else
- info._sifields._sigfault._addr = env->tsptr->tpc;
- //queue_signal(env, info.si_signo, &info);
- }
- #endif
- break;
- #endif
- case EXCP_INTERRUPT:
- /* just indicate that signals should be handled asap */
- break;
- case EXCP_DEBUG:
- {
- int sig;
- sig = gdb_handlesig (env, TARGET_SIGTRAP);
- #if 0
- if (sig)
- {
- info.si_signo = sig;
- info.si_errno = 0;
- info.si_code = TARGET_TRAP_BRKPT;
- //queue_signal(env, info.si_signo, &info);
- }
- #endif
- }
- break;
- default:
- printf ("Unhandled trap: 0x%x\n", trapnr);
- cpu_dump_state(env, stderr, fprintf, 0);
- exit (1);
- }
- process_pending_signals (env);
- }
- }
- #endif
- static void usage(void)
- {
- printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n"
- "usage: qemu-" TARGET_ARCH " [options] program [arguments...]\n"
- "BSD CPU emulator (compiled for %s emulation)\n"
- "\n"
- "Standard options:\n"
- "-h print this help\n"
- "-g port wait gdb connection to port\n"
- "-L path set the elf interpreter prefix (default=%s)\n"
- "-s size set the stack size in bytes (default=%ld)\n"
- "-cpu model select CPU (-cpu ? for list)\n"
- "-drop-ld-preload drop LD_PRELOAD for target process\n"
- "-bsd type select emulated BSD type FreeBSD/NetBSD/OpenBSD (default)\n"
- "\n"
- "Debug options:\n"
- "-d options activate log (logfile=%s)\n"
- "-p pagesize set the host page size to 'pagesize'\n"
- "-strace log system calls\n"
- "\n"
- "Environment variables:\n"
- "QEMU_STRACE Print system calls and arguments similar to the\n"
- " 'strace' program. Enable by setting to any value.\n"
- ,
- TARGET_ARCH,
- interp_prefix,
- x86_stack_size,
- DEBUG_LOGFILE);
- exit(1);
- }
- THREAD CPUState *thread_env;
- /* Assumes contents are already zeroed. */
- void init_task_state(TaskState *ts)
- {
- int i;
- ts->used = 1;
- ts->first_free = ts->sigqueue_table;
- for (i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++) {
- ts->sigqueue_table[i].next = &ts->sigqueue_table[i + 1];
- }
- ts->sigqueue_table[i].next = NULL;
- }
- int main(int argc, char **argv)
- {
- const char *filename;
- const char *cpu_model;
- struct target_pt_regs regs1, *regs = ®s1;
- struct image_info info1, *info = &info1;
- TaskState ts1, *ts = &ts1;
- CPUState *env;
- int optind;
- const char *r;
- int gdbstub_port = 0;
- int drop_ld_preload = 0, environ_count = 0;
- char **target_environ, **wrk, **dst;
- enum BSDType bsd_type = target_openbsd;
- if (argc <= 1)
- usage();
- /* init debug */
- cpu_set_log_filename(DEBUG_LOGFILE);
- cpu_model = NULL;
- optind = 1;
- for(;;) {
- if (optind >= argc)
- break;
- r = argv[optind];
- if (r[0] != '-')
- break;
- optind++;
- r++;
- if (!strcmp(r, "-")) {
- break;
- } else if (!strcmp(r, "d")) {
- int mask;
- const CPULogItem *item;
- if (optind >= argc)
- break;
- r = argv[optind++];
- mask = cpu_str_to_log_mask(r);
- if (!mask) {
- printf("Log items (comma separated):\n");
- for(item = cpu_log_items; item->mask != 0; item++) {
- printf("%-10s %s\n", item->name, item->help);
- }
- exit(1);
- }
- cpu_set_log(mask);
- } else if (!strcmp(r, "s")) {
- r = argv[optind++];
- x86_stack_size = strtol(r, (char **)&r, 0);
- if (x86_stack_size <= 0)
- usage();
- if (*r == 'M')
- x86_stack_size *= 1024 * 1024;
- else if (*r == 'k' || *r == 'K')
- x86_stack_size *= 1024;
- } else if (!strcmp(r, "L")) {
- interp_prefix = argv[optind++];
- } else if (!strcmp(r, "p")) {
- qemu_host_page_size = atoi(argv[optind++]);
- if (qemu_host_page_size == 0 ||
- (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
- fprintf(stderr, "page size must be a power of two\n");
- exit(1);
- }
- } else if (!strcmp(r, "g")) {
- gdbstub_port = atoi(argv[optind++]);
- } else if (!strcmp(r, "r")) {
- qemu_uname_release = argv[optind++];
- } else if (!strcmp(r, "cpu")) {
- cpu_model = argv[optind++];
- if (strcmp(cpu_model, "?") == 0) {
- /* XXX: implement xxx_cpu_list for targets that still miss it */
- #if defined(cpu_list)
- cpu_list(stdout, &fprintf);
- #endif
- exit(1);
- }
- } else if (!strcmp(r, "drop-ld-preload")) {
- drop_ld_preload = 1;
- } else if (!strcmp(r, "bsd")) {
- if (!strcasecmp(argv[optind], "freebsd")) {
- bsd_type = target_freebsd;
- } else if (!strcasecmp(argv[optind], "netbsd")) {
- bsd_type = target_netbsd;
- } else if (!strcasecmp(argv[optind], "openbsd")) {
- bsd_type = target_openbsd;
- } else {
- usage();
- }
- optind++;
- } else if (!strcmp(r, "strace")) {
- do_strace = 1;
- } else
- {
- usage();
- }
- }
- if (optind >= argc)
- usage();
- filename = argv[optind];
- /* Zero out regs */
- memset(regs, 0, sizeof(struct target_pt_regs));
- /* Zero out image_info */
- memset(info, 0, sizeof(struct image_info));
- /* Scan interp_prefix dir for replacement files. */
- init_paths(interp_prefix);
- if (cpu_model == NULL) {
- #if defined(TARGET_SPARC)
- #ifdef TARGET_SPARC64
- cpu_model = "TI UltraSparc II";
- #else
- cpu_model = "Fujitsu MB86904";
- #endif
- #else
- cpu_model = "any";
- #endif
- }
- cpu_exec_init_all(0);
- /* NOTE: we need to init the CPU at this stage to get
- qemu_host_page_size */
- env = cpu_init(cpu_model);
- if (!env) {
- fprintf(stderr, "Unable to find CPU definition\n");
- exit(1);
- }
- thread_env = env;
- if (getenv("QEMU_STRACE")) {
- do_strace = 1;
- }
- wrk = environ;
- while (*(wrk++))
- environ_count++;
- target_environ = malloc((environ_count + 1) * sizeof(char *));
- if (!target_environ)
- abort();
- for (wrk = environ, dst = target_environ; *wrk; wrk++) {
- if (drop_ld_preload && !strncmp(*wrk, "LD_PRELOAD=", 11))
- continue;
- *(dst++) = strdup(*wrk);
- }
- *dst = NULL; /* NULL terminate target_environ */
- if (loader_exec(filename, argv+optind, target_environ, regs, info) != 0) {
- printf("Error loading %s\n", filename);
- _exit(1);
- }
- for (wrk = target_environ; *wrk; wrk++) {
- free(*wrk);
- }
- free(target_environ);
- if (qemu_log_enabled()) {
- log_page_dump();
- qemu_log("start_brk 0x" TARGET_ABI_FMT_lx "\n", info->start_brk);
- qemu_log("end_code 0x" TARGET_ABI_FMT_lx "\n", info->end_code);
- qemu_log("start_code 0x" TARGET_ABI_FMT_lx "\n",
- info->start_code);
- qemu_log("start_data 0x" TARGET_ABI_FMT_lx "\n",
- info->start_data);
- qemu_log("end_data 0x" TARGET_ABI_FMT_lx "\n", info->end_data);
- qemu_log("start_stack 0x" TARGET_ABI_FMT_lx "\n",
- info->start_stack);
- qemu_log("brk 0x" TARGET_ABI_FMT_lx "\n", info->brk);
- qemu_log("entry 0x" TARGET_ABI_FMT_lx "\n", info->entry);
- }
- target_set_brk(info->brk);
- syscall_init();
- signal_init();
- /* build Task State */
- memset(ts, 0, sizeof(TaskState));
- init_task_state(ts);
- ts->info = info;
- env->opaque = ts;
- #if defined(TARGET_SPARC)
- {
- int i;
- env->pc = regs->pc;
- env->npc = regs->npc;
- env->y = regs->y;
- for(i = 0; i < 8; i++)
- env->gregs[i] = regs->u_regs[i];
- for(i = 0; i < 8; i++)
- env->regwptr[i] = regs->u_regs[i + 8];
- }
- #else
- #error unsupported target CPU
- #endif
- if (gdbstub_port) {
- gdbserver_start (gdbstub_port);
- gdb_handlesig(env, 0);
- }
- cpu_loop(env, bsd_type);
- /* never exits */
- return 0;
- }
|