|
|
1.1 root 1: /*
2: * qemu user main
3: *
4: * Copyright (c) 2003-2008 Fabrice Bellard
5: *
6: * This program is free software; you can redistribute it and/or modify
7: * it under the terms of the GNU General Public License as published by
8: * the Free Software Foundation; either version 2 of the License, or
9: * (at your option) any later version.
10: *
11: * This program is distributed in the hope that it will be useful,
12: * but WITHOUT ANY WARRANTY; without even the implied warranty of
13: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14: * GNU General Public License for more details.
15: *
16: * You should have received a copy of the GNU General Public License
17: * along with this program; if not, write to the Free Software
18: * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19: * MA 02110-1301, 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: #include <machine/trap.h>
28:
29: #include "qemu.h"
30: #include "qemu-common.h"
31: /* For tb_lock */
32: #include "exec-all.h"
33:
34: #define DEBUG_LOGFILE "/tmp/qemu.log"
35:
36: static const char *interp_prefix = CONFIG_QEMU_PREFIX;
37: const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
38: extern char **environ;
39:
40: /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
41: we allocate a bigger stack. Need a better solution, for example
42: by remapping the process stack directly at the right place */
43: unsigned long x86_stack_size = 512 * 1024;
44:
45: void gemu_log(const char *fmt, ...)
46: {
47: va_list ap;
48:
49: va_start(ap, fmt);
50: vfprintf(stderr, fmt, ap);
51: va_end(ap);
52: }
53: #ifdef TARGET_SPARC
54: #define SPARC64_STACK_BIAS 2047
55:
56: //#define DEBUG_WIN
57: /* WARNING: dealing with register windows _is_ complicated. More info
58: can be found at http://www.sics.se/~psm/sparcstack.html */
59: static inline int get_reg_index(CPUSPARCState *env, int cwp, int index)
60: {
61: index = (index + cwp * 16) % (16 * env->nwindows);
62: /* wrap handling : if cwp is on the last window, then we use the
63: registers 'after' the end */
64: if (index < 8 && env->cwp == env->nwindows - 1)
65: index += 16 * env->nwindows;
66: return index;
67: }
68:
69: /* save the register window 'cwp1' */
70: static inline void save_window_offset(CPUSPARCState *env, int cwp1)
71: {
72: unsigned int i;
73: abi_ulong sp_ptr;
74:
75: sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
76: #ifdef TARGET_SPARC64
77: if (sp_ptr & 3)
78: sp_ptr += SPARC64_STACK_BIAS;
79: #endif
80: #if defined(DEBUG_WIN)
81: printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n",
82: sp_ptr, cwp1);
83: #endif
84: for(i = 0; i < 16; i++) {
85: /* FIXME - what to do if put_user() fails? */
86: put_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
87: sp_ptr += sizeof(abi_ulong);
88: }
89: }
90:
91: static void save_window(CPUSPARCState *env)
92: {
93: #ifndef TARGET_SPARC64
94: unsigned int new_wim;
95: new_wim = ((env->wim >> 1) | (env->wim << (env->nwindows - 1))) &
96: ((1LL << env->nwindows) - 1);
97: save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
98: env->wim = new_wim;
99: #else
100: save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
101: env->cansave++;
102: env->canrestore--;
103: #endif
104: }
105:
106: static void restore_window(CPUSPARCState *env)
107: {
108: #ifndef TARGET_SPARC64
109: unsigned int new_wim;
110: #endif
111: unsigned int i, cwp1;
112: abi_ulong sp_ptr;
113:
114: #ifndef TARGET_SPARC64
115: new_wim = ((env->wim << 1) | (env->wim >> (env->nwindows - 1))) &
116: ((1LL << env->nwindows) - 1);
117: #endif
118:
119: /* restore the invalid window */
120: cwp1 = cpu_cwp_inc(env, env->cwp + 1);
121: sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
122: #ifdef TARGET_SPARC64
123: if (sp_ptr & 3)
124: sp_ptr += SPARC64_STACK_BIAS;
125: #endif
126: #if defined(DEBUG_WIN)
127: printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n",
128: sp_ptr, cwp1);
129: #endif
130: for(i = 0; i < 16; i++) {
131: /* FIXME - what to do if get_user() fails? */
132: get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
133: sp_ptr += sizeof(abi_ulong);
134: }
135: #ifdef TARGET_SPARC64
136: env->canrestore++;
137: if (env->cleanwin < env->nwindows - 1)
138: env->cleanwin++;
139: env->cansave--;
140: #else
141: env->wim = new_wim;
142: #endif
143: }
144:
145: static void flush_windows(CPUSPARCState *env)
146: {
147: int offset, cwp1;
148:
149: offset = 1;
150: for(;;) {
151: /* if restore would invoke restore_window(), then we can stop */
152: cwp1 = cpu_cwp_inc(env, env->cwp + offset);
153: #ifndef TARGET_SPARC64
154: if (env->wim & (1 << cwp1))
155: break;
156: #else
157: if (env->canrestore == 0)
158: break;
159: env->cansave++;
160: env->canrestore--;
161: #endif
162: save_window_offset(env, cwp1);
163: offset++;
164: }
165: cwp1 = cpu_cwp_inc(env, env->cwp + 1);
166: #ifndef TARGET_SPARC64
167: /* set wim so that restore will reload the registers */
168: env->wim = 1 << cwp1;
169: #endif
170: #if defined(DEBUG_WIN)
171: printf("flush_windows: nb=%d\n", offset - 1);
172: #endif
173: }
174:
175: void cpu_loop(CPUSPARCState *env, enum BSDType bsd_type)
176: {
177: int trapnr, ret, syscall_nr;
178: //target_siginfo_t info;
179:
180: while (1) {
181: trapnr = cpu_sparc_exec (env);
182:
183: switch (trapnr) {
184: #ifndef TARGET_SPARC64
185: case 0x80:
186: #else
187: case 0x100:
188: #endif
189: syscall_nr = env->gregs[1];
190: if (bsd_type == target_freebsd)
191: ret = do_freebsd_syscall(env, syscall_nr,
192: env->regwptr[0], env->regwptr[1],
193: env->regwptr[2], env->regwptr[3],
194: env->regwptr[4], env->regwptr[5]);
195: else if (bsd_type == target_netbsd)
196: ret = do_netbsd_syscall(env, syscall_nr,
197: env->regwptr[0], env->regwptr[1],
198: env->regwptr[2], env->regwptr[3],
199: env->regwptr[4], env->regwptr[5]);
200: else { //if (bsd_type == target_openbsd)
201: #if defined(TARGET_SPARC64)
202: syscall_nr &= ~(TARGET_OPENBSD_SYSCALL_G7RFLAG |
203: TARGET_OPENBSD_SYSCALL_G2RFLAG);
204: #endif
205: ret = do_openbsd_syscall(env, syscall_nr,
206: env->regwptr[0], env->regwptr[1],
207: env->regwptr[2], env->regwptr[3],
208: env->regwptr[4], env->regwptr[5]);
209: }
210: if ((unsigned int)ret >= (unsigned int)(-515)) {
211: #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
212: env->xcc |= PSR_CARRY;
213: #else
214: env->psr |= PSR_CARRY;
215: #endif
216: } else {
217: #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
218: env->xcc &= ~PSR_CARRY;
219: #else
220: env->psr &= ~PSR_CARRY;
221: #endif
222: }
223: env->regwptr[0] = ret;
224: /* next instruction */
225: #if defined(TARGET_SPARC64)
226: if (bsd_type == target_openbsd &&
227: env->gregs[1] & TARGET_OPENBSD_SYSCALL_G2RFLAG) {
228: env->pc = env->gregs[2];
229: env->npc = env->pc + 4;
230: } else if (bsd_type == target_openbsd &&
231: env->gregs[1] & TARGET_OPENBSD_SYSCALL_G7RFLAG) {
232: env->pc = env->gregs[7];
233: env->npc = env->pc + 4;
234: } else {
235: env->pc = env->npc;
236: env->npc = env->npc + 4;
237: }
238: #else
239: env->pc = env->npc;
240: env->npc = env->npc + 4;
241: #endif
242: break;
243: case 0x83: /* flush windows */
244: #ifdef TARGET_ABI32
245: case 0x103:
246: #endif
247: flush_windows(env);
248: /* next instruction */
249: env->pc = env->npc;
250: env->npc = env->npc + 4;
251: break;
252: #ifndef TARGET_SPARC64
253: case TT_WIN_OVF: /* window overflow */
254: save_window(env);
255: break;
256: case TT_WIN_UNF: /* window underflow */
257: restore_window(env);
258: break;
259: case TT_TFAULT:
260: case TT_DFAULT:
261: #if 0
262: {
263: info.si_signo = SIGSEGV;
264: info.si_errno = 0;
265: /* XXX: check env->error_code */
266: info.si_code = TARGET_SEGV_MAPERR;
267: info._sifields._sigfault._addr = env->mmuregs[4];
268: queue_signal(env, info.si_signo, &info);
269: }
270: #endif
271: break;
272: #else
273: case TT_SPILL: /* window overflow */
274: save_window(env);
275: break;
276: case TT_FILL: /* window underflow */
277: restore_window(env);
278: break;
279: case TT_TFAULT:
280: case TT_DFAULT:
281: #if 0
282: {
283: info.si_signo = SIGSEGV;
284: info.si_errno = 0;
285: /* XXX: check env->error_code */
286: info.si_code = TARGET_SEGV_MAPERR;
287: if (trapnr == TT_DFAULT)
288: info._sifields._sigfault._addr = env->dmmuregs[4];
289: else
290: info._sifields._sigfault._addr = env->tsptr->tpc;
291: //queue_signal(env, info.si_signo, &info);
292: }
293: #endif
294: break;
295: #endif
296: case EXCP_INTERRUPT:
297: /* just indicate that signals should be handled asap */
298: break;
299: case EXCP_DEBUG:
300: {
301: int sig;
302:
303: sig = gdb_handlesig (env, TARGET_SIGTRAP);
304: #if 0
305: if (sig)
306: {
307: info.si_signo = sig;
308: info.si_errno = 0;
309: info.si_code = TARGET_TRAP_BRKPT;
310: //queue_signal(env, info.si_signo, &info);
311: }
312: #endif
313: }
314: break;
315: default:
316: printf ("Unhandled trap: 0x%x\n", trapnr);
317: cpu_dump_state(env, stderr, fprintf, 0);
318: exit (1);
319: }
320: process_pending_signals (env);
321: }
322: }
323:
324: #endif
325:
326: static void usage(void)
327: {
328: printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n"
329: "usage: qemu-" TARGET_ARCH " [options] program [arguments...]\n"
330: "BSD CPU emulator (compiled for %s emulation)\n"
331: "\n"
332: "Standard options:\n"
333: "-h print this help\n"
334: "-g port wait gdb connection to port\n"
335: "-L path set the elf interpreter prefix (default=%s)\n"
336: "-s size set the stack size in bytes (default=%ld)\n"
337: "-cpu model select CPU (-cpu ? for list)\n"
338: "-drop-ld-preload drop LD_PRELOAD for target process\n"
339: "-bsd type select emulated BSD type FreeBSD/NetBSD/OpenBSD (default)\n"
340: "\n"
341: "Debug options:\n"
342: "-d options activate log (logfile=%s)\n"
343: "-p pagesize set the host page size to 'pagesize'\n"
344: "-strace log system calls\n"
345: "\n"
346: "Environment variables:\n"
347: "QEMU_STRACE Print system calls and arguments similar to the\n"
348: " 'strace' program. Enable by setting to any value.\n"
349: ,
350: TARGET_ARCH,
351: interp_prefix,
352: x86_stack_size,
353: DEBUG_LOGFILE);
354: exit(1);
355: }
356:
357: THREAD CPUState *thread_env;
358:
359: /* Assumes contents are already zeroed. */
360: void init_task_state(TaskState *ts)
361: {
362: int i;
363:
364: ts->used = 1;
365: ts->first_free = ts->sigqueue_table;
366: for (i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++) {
367: ts->sigqueue_table[i].next = &ts->sigqueue_table[i + 1];
368: }
369: ts->sigqueue_table[i].next = NULL;
370: }
371:
372: int main(int argc, char **argv)
373: {
374: const char *filename;
375: const char *cpu_model;
376: struct target_pt_regs regs1, *regs = ®s1;
377: struct image_info info1, *info = &info1;
378: TaskState ts1, *ts = &ts1;
379: CPUState *env;
380: int optind;
381: const char *r;
382: int gdbstub_port = 0;
383: int drop_ld_preload = 0, environ_count = 0;
384: char **target_environ, **wrk, **dst;
385: enum BSDType bsd_type = target_openbsd;
386:
387: if (argc <= 1)
388: usage();
389:
390: /* init debug */
391: cpu_set_log_filename(DEBUG_LOGFILE);
392:
393: cpu_model = NULL;
394: optind = 1;
395: for(;;) {
396: if (optind >= argc)
397: break;
398: r = argv[optind];
399: if (r[0] != '-')
400: break;
401: optind++;
402: r++;
403: if (!strcmp(r, "-")) {
404: break;
405: } else if (!strcmp(r, "d")) {
406: int mask;
407: const CPULogItem *item;
408:
409: if (optind >= argc)
410: break;
411:
412: r = argv[optind++];
413: mask = cpu_str_to_log_mask(r);
414: if (!mask) {
415: printf("Log items (comma separated):\n");
416: for(item = cpu_log_items; item->mask != 0; item++) {
417: printf("%-10s %s\n", item->name, item->help);
418: }
419: exit(1);
420: }
421: cpu_set_log(mask);
422: } else if (!strcmp(r, "s")) {
423: r = argv[optind++];
424: x86_stack_size = strtol(r, (char **)&r, 0);
425: if (x86_stack_size <= 0)
426: usage();
427: if (*r == 'M')
428: x86_stack_size *= 1024 * 1024;
429: else if (*r == 'k' || *r == 'K')
430: x86_stack_size *= 1024;
431: } else if (!strcmp(r, "L")) {
432: interp_prefix = argv[optind++];
433: } else if (!strcmp(r, "p")) {
434: qemu_host_page_size = atoi(argv[optind++]);
435: if (qemu_host_page_size == 0 ||
436: (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
437: fprintf(stderr, "page size must be a power of two\n");
438: exit(1);
439: }
440: } else if (!strcmp(r, "g")) {
441: gdbstub_port = atoi(argv[optind++]);
442: } else if (!strcmp(r, "r")) {
443: qemu_uname_release = argv[optind++];
444: } else if (!strcmp(r, "cpu")) {
445: cpu_model = argv[optind++];
446: if (strcmp(cpu_model, "?") == 0) {
447: /* XXX: implement xxx_cpu_list for targets that still miss it */
448: #if defined(cpu_list)
449: cpu_list(stdout, &fprintf);
450: #endif
451: exit(1);
452: }
453: } else if (!strcmp(r, "drop-ld-preload")) {
454: drop_ld_preload = 1;
455: } else if (!strcmp(r, "bsd")) {
456: if (!strcasecmp(argv[optind], "freebsd")) {
457: bsd_type = target_freebsd;
458: } else if (!strcasecmp(argv[optind], "netbsd")) {
459: bsd_type = target_netbsd;
460: } else if (!strcasecmp(argv[optind], "openbsd")) {
461: bsd_type = target_openbsd;
462: } else {
463: usage();
464: }
465: optind++;
466: } else if (!strcmp(r, "strace")) {
467: do_strace = 1;
468: } else
469: {
470: usage();
471: }
472: }
473: if (optind >= argc)
474: usage();
475: filename = argv[optind];
476:
477: /* Zero out regs */
478: memset(regs, 0, sizeof(struct target_pt_regs));
479:
480: /* Zero out image_info */
481: memset(info, 0, sizeof(struct image_info));
482:
483: /* Scan interp_prefix dir for replacement files. */
484: init_paths(interp_prefix);
485:
486: if (cpu_model == NULL) {
487: #if defined(TARGET_SPARC)
488: #ifdef TARGET_SPARC64
489: cpu_model = "TI UltraSparc II";
490: #else
491: cpu_model = "Fujitsu MB86904";
492: #endif
493: #else
494: cpu_model = "any";
495: #endif
496: }
497: cpu_exec_init_all(0);
498: /* NOTE: we need to init the CPU at this stage to get
499: qemu_host_page_size */
500: env = cpu_init(cpu_model);
501: if (!env) {
502: fprintf(stderr, "Unable to find CPU definition\n");
503: exit(1);
504: }
505: thread_env = env;
506:
507: if (getenv("QEMU_STRACE")) {
508: do_strace = 1;
509: }
510:
511: wrk = environ;
512: while (*(wrk++))
513: environ_count++;
514:
515: target_environ = malloc((environ_count + 1) * sizeof(char *));
516: if (!target_environ)
517: abort();
518: for (wrk = environ, dst = target_environ; *wrk; wrk++) {
519: if (drop_ld_preload && !strncmp(*wrk, "LD_PRELOAD=", 11))
520: continue;
521: *(dst++) = strdup(*wrk);
522: }
523: *dst = NULL; /* NULL terminate target_environ */
524:
525: if (loader_exec(filename, argv+optind, target_environ, regs, info) != 0) {
526: printf("Error loading %s\n", filename);
527: _exit(1);
528: }
529:
530: for (wrk = target_environ; *wrk; wrk++) {
531: free(*wrk);
532: }
533:
534: free(target_environ);
535:
536: if (qemu_log_enabled()) {
537: log_page_dump();
538:
539: qemu_log("start_brk 0x" TARGET_ABI_FMT_lx "\n", info->start_brk);
540: qemu_log("end_code 0x" TARGET_ABI_FMT_lx "\n", info->end_code);
541: qemu_log("start_code 0x" TARGET_ABI_FMT_lx "\n",
542: info->start_code);
543: qemu_log("start_data 0x" TARGET_ABI_FMT_lx "\n",
544: info->start_data);
545: qemu_log("end_data 0x" TARGET_ABI_FMT_lx "\n", info->end_data);
546: qemu_log("start_stack 0x" TARGET_ABI_FMT_lx "\n",
547: info->start_stack);
548: qemu_log("brk 0x" TARGET_ABI_FMT_lx "\n", info->brk);
549: qemu_log("entry 0x" TARGET_ABI_FMT_lx "\n", info->entry);
550: }
551:
552: target_set_brk(info->brk);
553: syscall_init();
554: signal_init();
555:
556: /* build Task State */
557: memset(ts, 0, sizeof(TaskState));
558: init_task_state(ts);
559: ts->info = info;
560: env->opaque = ts;
561:
562: #if defined(TARGET_SPARC)
563: {
564: int i;
565: env->pc = regs->pc;
566: env->npc = regs->npc;
567: env->y = regs->y;
568: for(i = 0; i < 8; i++)
569: env->gregs[i] = regs->u_regs[i];
570: for(i = 0; i < 8; i++)
571: env->regwptr[i] = regs->u_regs[i + 8];
572: }
573: #else
574: #error unsupported target CPU
575: #endif
576:
577: if (gdbstub_port) {
578: gdbserver_start (gdbstub_port);
579: gdb_handlesig(env, 0);
580: }
581: cpu_loop(env, bsd_type);
582: /* never exits */
583: return 0;
584: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.