blob: c12ef0f1805d02d38c1e54b05c3cc17447f68f3a [file] [log] [blame]
bellard31e31b82003-02-18 22:55:36 +00001/*
bellard3ef693a2003-03-23 20:17:16 +00002 * qemu main
bellard31e31b82003-02-18 22:55:36 +00003 *
4 * Copyright (c) 2003 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., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20#include <stdlib.h>
21#include <stdio.h>
22#include <stdarg.h>
bellard04369ff2003-03-20 22:33:23 +000023#include <string.h>
bellard31e31b82003-02-18 22:55:36 +000024#include <errno.h>
bellard0ecfa992003-03-03 14:32:43 +000025#include <unistd.h>
bellard31e31b82003-02-18 22:55:36 +000026
bellard3ef693a2003-03-23 20:17:16 +000027#include "qemu.h"
bellard31e31b82003-02-18 22:55:36 +000028
bellard0ecfa992003-03-03 14:32:43 +000029#include "cpu-i386.h"
bellard31e31b82003-02-18 22:55:36 +000030
bellard3ef693a2003-03-23 20:17:16 +000031#define DEBUG_LOGFILE "/tmp/qemu.log"
bellard586314f2003-03-03 15:02:29 +000032
33FILE *logfile = NULL;
34int loglevel;
bellardd691f662003-03-24 21:58:34 +000035const char *interp_prefix = CONFIG_QEMU_PREFIX "/qemu-i386";
bellard586314f2003-03-03 15:02:29 +000036
bellard9de5e442003-03-23 16:49:39 +000037/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
38 we allocate a bigger stack. Need a better solution, for example
39 by remapping the process stack directly at the right place */
40unsigned long x86_stack_size = 512 * 1024;
bellard31e31b82003-02-18 22:55:36 +000041unsigned long stktop;
42
43void gemu_log(const char *fmt, ...)
44{
45 va_list ap;
46
47 va_start(ap, fmt);
48 vfprintf(stderr, fmt, ap);
49 va_end(ap);
50}
51
bellard31e31b82003-02-18 22:55:36 +000052/***********************************************************/
bellard0ecfa992003-03-03 14:32:43 +000053/* CPUX86 core interface */
bellard367e86e2003-03-01 17:13:26 +000054
bellardba1c6e32003-03-03 11:58:28 +000055void cpu_x86_outb(int addr, int val)
bellard367e86e2003-03-01 17:13:26 +000056{
57 fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val);
58}
59
bellardba1c6e32003-03-03 11:58:28 +000060void cpu_x86_outw(int addr, int val)
bellard367e86e2003-03-01 17:13:26 +000061{
62 fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val);
63}
64
bellardba1c6e32003-03-03 11:58:28 +000065void cpu_x86_outl(int addr, int val)
bellard367e86e2003-03-01 17:13:26 +000066{
67 fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val);
68}
69
bellardba1c6e32003-03-03 11:58:28 +000070int cpu_x86_inb(int addr)
bellard367e86e2003-03-01 17:13:26 +000071{
72 fprintf(stderr, "inb: port=0x%04x\n", addr);
73 return 0;
74}
75
bellardba1c6e32003-03-03 11:58:28 +000076int cpu_x86_inw(int addr)
bellard367e86e2003-03-01 17:13:26 +000077{
78 fprintf(stderr, "inw: port=0x%04x\n", addr);
79 return 0;
80}
81
bellardba1c6e32003-03-03 11:58:28 +000082int cpu_x86_inl(int addr)
bellard367e86e2003-03-01 17:13:26 +000083{
84 fprintf(stderr, "inl: port=0x%04x\n", addr);
85 return 0;
86}
87
bellard6dbad632003-03-16 18:05:05 +000088void write_dt(void *ptr, unsigned long addr, unsigned long limit,
89 int seg32_bit)
90{
91 unsigned int e1, e2, limit_in_pages;
92 limit_in_pages = 0;
93 if (limit > 0xffff) {
94 limit = limit >> 12;
95 limit_in_pages = 1;
96 }
97 e1 = (addr << 16) | (limit & 0xffff);
98 e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
99 e2 |= limit_in_pages << 23; /* byte granularity */
100 e2 |= seg32_bit << 22; /* 32 bit segment */
101 stl((uint8_t *)ptr, e1);
102 stl((uint8_t *)ptr + 4, e2);
103}
104
105uint64_t gdt_table[6];
bellard31e31b82003-02-18 22:55:36 +0000106
bellard851e67a2003-03-29 16:53:14 +0000107//#define DEBUG_VM86
108
bellard1b6b0292003-03-22 17:31:38 +0000109void cpu_loop(struct CPUX86State *env)
110{
bellard9de5e442003-03-23 16:49:39 +0000111 int err;
112 uint8_t *pc;
113 target_siginfo_t info;
bellard851e67a2003-03-29 16:53:14 +0000114
bellard1b6b0292003-03-22 17:31:38 +0000115 for(;;) {
bellard1b6b0292003-03-22 17:31:38 +0000116 err = cpu_x86_exec(env);
117 pc = env->seg_cache[R_CS].base + env->eip;
118 switch(err) {
119 case EXCP0D_GPF:
bellard851e67a2003-03-29 16:53:14 +0000120 if (env->eflags & VM_MASK) {
121 TaskState *ts;
122 int ret;
123#ifdef DEBUG_VM86
124 printf("VM86 exception %04x:%08x %02x\n",
125 env->segs[R_CS], env->eip, pc[0]);
126#endif
127 /* VM86 mode */
128 ts = env->opaque;
129
130 /* XXX: add all cases */
131 switch(pc[0]) {
132 case 0xcd: /* int */
133 env->eip += 2;
134 ret = TARGET_VM86_INTx | (pc[1] << 8);
135 break;
136 default:
137 /* real VM86 GPF exception */
138 ret = TARGET_VM86_UNKNOWN;
139 break;
140 }
141#ifdef DEBUG_VM86
142 printf("ret=0x%x\n", ret);
143#endif
144 /* put the VM86 registers in the userspace register structure */
145 ts->target_v86->regs.eax = tswap32(env->regs[R_EAX]);
146 ts->target_v86->regs.ebx = tswap32(env->regs[R_EBX]);
147 ts->target_v86->regs.ecx = tswap32(env->regs[R_ECX]);
148 ts->target_v86->regs.edx = tswap32(env->regs[R_EDX]);
149 ts->target_v86->regs.esi = tswap32(env->regs[R_ESI]);
150 ts->target_v86->regs.edi = tswap32(env->regs[R_EDI]);
151 ts->target_v86->regs.ebp = tswap32(env->regs[R_EBP]);
152 ts->target_v86->regs.esp = tswap32(env->regs[R_ESP]);
153 ts->target_v86->regs.eip = tswap32(env->eip);
154 ts->target_v86->regs.cs = tswap16(env->segs[R_CS]);
155 ts->target_v86->regs.ss = tswap16(env->segs[R_SS]);
156 ts->target_v86->regs.ds = tswap16(env->segs[R_DS]);
157 ts->target_v86->regs.es = tswap16(env->segs[R_ES]);
158 ts->target_v86->regs.fs = tswap16(env->segs[R_FS]);
159 ts->target_v86->regs.gs = tswap16(env->segs[R_GS]);
160
161 /* restore 32 bit registers */
162 env->regs[R_EBX] = ts->vm86_saved_regs.ebx;
163 env->regs[R_ECX] = ts->vm86_saved_regs.ecx;
164 env->regs[R_EDX] = ts->vm86_saved_regs.edx;
165 env->regs[R_ESI] = ts->vm86_saved_regs.esi;
166 env->regs[R_EDI] = ts->vm86_saved_regs.edi;
167 env->regs[R_EBP] = ts->vm86_saved_regs.ebp;
168 env->regs[R_ESP] = ts->vm86_saved_regs.esp;
169 env->eflags = ts->vm86_saved_regs.eflags;
170 env->eip = ts->vm86_saved_regs.eip;
171
172 cpu_x86_load_seg(env, R_CS, ts->vm86_saved_regs.cs);
173 cpu_x86_load_seg(env, R_SS, ts->vm86_saved_regs.ss);
174 cpu_x86_load_seg(env, R_DS, ts->vm86_saved_regs.ds);
175 cpu_x86_load_seg(env, R_ES, ts->vm86_saved_regs.es);
176 cpu_x86_load_seg(env, R_FS, ts->vm86_saved_regs.fs);
177 cpu_x86_load_seg(env, R_GS, ts->vm86_saved_regs.gs);
178
179 env->regs[R_EAX] = ret;
bellard1b6b0292003-03-22 17:31:38 +0000180 } else {
bellard851e67a2003-03-29 16:53:14 +0000181 if (pc[0] == 0xcd && pc[1] == 0x80) {
182 /* syscall */
183 env->eip += 2;
184 env->regs[R_EAX] = do_syscall(env,
185 env->regs[R_EAX],
186 env->regs[R_EBX],
187 env->regs[R_ECX],
188 env->regs[R_EDX],
189 env->regs[R_ESI],
190 env->regs[R_EDI],
191 env->regs[R_EBP]);
192 } else {
193 /* XXX: more precise info */
194 info.si_signo = SIGSEGV;
195 info.si_errno = 0;
196 info.si_code = 0;
197 info._sifields._sigfault._addr = 0;
198 queue_signal(info.si_signo, &info);
199 }
bellard1b6b0292003-03-22 17:31:38 +0000200 }
201 break;
bellard9de5e442003-03-23 16:49:39 +0000202 case EXCP00_DIVZ:
203 /* division by zero */
204 info.si_signo = SIGFPE;
205 info.si_errno = 0;
206 info.si_code = TARGET_FPE_INTDIV;
207 info._sifields._sigfault._addr = env->eip;
208 queue_signal(info.si_signo, &info);
209 break;
210 case EXCP04_INTO:
211 case EXCP05_BOUND:
212 info.si_signo = SIGSEGV;
213 info.si_errno = 0;
214 info.si_code = 0;
215 info._sifields._sigfault._addr = 0;
216 queue_signal(info.si_signo, &info);
217 break;
218 case EXCP06_ILLOP:
219 info.si_signo = SIGILL;
220 info.si_errno = 0;
221 info.si_code = TARGET_ILL_ILLOPN;
222 info._sifields._sigfault._addr = env->eip;
223 queue_signal(info.si_signo, &info);
224 break;
225 case EXCP_INTERRUPT:
226 /* just indicate that signals should be handled asap */
227 break;
bellard1b6b0292003-03-22 17:31:38 +0000228 default:
bellard9de5e442003-03-23 16:49:39 +0000229 fprintf(stderr, "0x%08lx: Unknown exception CPU %d, aborting\n",
bellard1b6b0292003-03-22 17:31:38 +0000230 (long)pc, err);
231 abort();
232 }
bellard66fb9762003-03-23 01:06:05 +0000233 process_pending_signals(env);
bellard1b6b0292003-03-22 17:31:38 +0000234 }
235}
236
bellard31e31b82003-02-18 22:55:36 +0000237void usage(void)
238{
bellard3ef693a2003-03-23 20:17:16 +0000239 printf("qemu version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
bellardd691f662003-03-24 21:58:34 +0000240 "usage: qemu [-h] [-d] [-L path] [-s size] program [arguments...]\n"
bellard31e31b82003-02-18 22:55:36 +0000241 "Linux x86 emulator\n"
bellardd691f662003-03-24 21:58:34 +0000242 "\n"
243 "-h print this help\n"
244 "-d activate log (logfile=%s)\n"
245 "-L path set the x86 elf interpreter prefix (default=%s)\n"
246 "-s size set the x86 stack size in bytes (default=%ld)\n",
247 DEBUG_LOGFILE,
248 interp_prefix,
249 x86_stack_size);
bellard31e31b82003-02-18 22:55:36 +0000250 exit(1);
251}
252
bellard9de5e442003-03-23 16:49:39 +0000253/* XXX: currently only used for async signals (see signal.c) */
254CPUX86State *global_env;
bellard851e67a2003-03-29 16:53:14 +0000255/* used to free thread contexts */
256TaskState *first_task_state;
bellard9de5e442003-03-23 16:49:39 +0000257
bellard31e31b82003-02-18 22:55:36 +0000258int main(int argc, char **argv)
259{
260 const char *filename;
bellard01ffc752003-02-18 23:00:51 +0000261 struct target_pt_regs regs1, *regs = &regs1;
bellard31e31b82003-02-18 22:55:36 +0000262 struct image_info info1, *info = &info1;
bellard851e67a2003-03-29 16:53:14 +0000263 TaskState ts1, *ts = &ts1;
bellard0ecfa992003-03-03 14:32:43 +0000264 CPUX86State *env;
bellard586314f2003-03-03 15:02:29 +0000265 int optind;
bellardd691f662003-03-24 21:58:34 +0000266 const char *r;
267
bellard31e31b82003-02-18 22:55:36 +0000268 if (argc <= 1)
269 usage();
bellard586314f2003-03-03 15:02:29 +0000270 loglevel = 0;
271 optind = 1;
bellardd691f662003-03-24 21:58:34 +0000272 for(;;) {
273 if (optind >= argc)
274 break;
275 r = argv[optind];
276 if (r[0] != '-')
277 break;
bellard586314f2003-03-03 15:02:29 +0000278 optind++;
bellardd691f662003-03-24 21:58:34 +0000279 r++;
280 if (!strcmp(r, "-")) {
281 break;
282 } else if (!strcmp(r, "d")) {
283 loglevel = 1;
284 } else if (!strcmp(r, "s")) {
285 r = argv[optind++];
286 x86_stack_size = strtol(r, (char **)&r, 0);
287 if (x86_stack_size <= 0)
288 usage();
289 if (*r == 'M')
290 x86_stack_size *= 1024 * 1024;
291 else if (*r == 'k' || *r == 'K')
292 x86_stack_size *= 1024;
293 } else if (!strcmp(r, "L")) {
294 interp_prefix = argv[optind++];
295 } else {
296 usage();
297 }
bellard586314f2003-03-03 15:02:29 +0000298 }
bellardd691f662003-03-24 21:58:34 +0000299 if (optind >= argc)
300 usage();
bellard586314f2003-03-03 15:02:29 +0000301 filename = argv[optind];
302
303 /* init debug */
304 if (loglevel) {
305 logfile = fopen(DEBUG_LOGFILE, "w");
306 if (!logfile) {
307 perror(DEBUG_LOGFILE);
308 exit(1);
309 }
310 setvbuf(logfile, NULL, _IOLBF, 0);
311 }
bellard31e31b82003-02-18 22:55:36 +0000312
313 /* Zero out regs */
bellard01ffc752003-02-18 23:00:51 +0000314 memset(regs, 0, sizeof(struct target_pt_regs));
bellard31e31b82003-02-18 22:55:36 +0000315
316 /* Zero out image_info */
317 memset(info, 0, sizeof(struct image_info));
318
bellardd691f662003-03-24 21:58:34 +0000319 if(elf_exec(interp_prefix, filename, argv+optind, environ, regs, info) != 0) {
bellard31e31b82003-02-18 22:55:36 +0000320 printf("Error loading %s\n", filename);
321 exit(1);
322 }
323
bellard4b74fe12003-03-03 23:23:09 +0000324 if (loglevel) {
325 fprintf(logfile, "start_brk 0x%08lx\n" , info->start_brk);
326 fprintf(logfile, "end_code 0x%08lx\n" , info->end_code);
327 fprintf(logfile, "start_code 0x%08lx\n" , info->start_code);
328 fprintf(logfile, "end_data 0x%08lx\n" , info->end_data);
329 fprintf(logfile, "start_stack 0x%08lx\n" , info->start_stack);
330 fprintf(logfile, "brk 0x%08lx\n" , info->brk);
331 fprintf(logfile, "esp 0x%08lx\n" , regs->esp);
332 fprintf(logfile, "eip 0x%08lx\n" , regs->eip);
333 }
bellard31e31b82003-02-18 22:55:36 +0000334
335 target_set_brk((char *)info->brk);
336 syscall_init();
bellard66fb9762003-03-23 01:06:05 +0000337 signal_init();
bellard31e31b82003-02-18 22:55:36 +0000338
bellard0ecfa992003-03-03 14:32:43 +0000339 env = cpu_x86_init();
bellard9de5e442003-03-23 16:49:39 +0000340 global_env = env;
bellard31e31b82003-02-18 22:55:36 +0000341
bellard851e67a2003-03-29 16:53:14 +0000342 /* build Task State */
343 memset(ts, 0, sizeof(TaskState));
344 env->opaque = ts;
345 ts->used = 1;
346
bellard6dbad632003-03-16 18:05:05 +0000347 /* linux register setup */
bellard0ecfa992003-03-03 14:32:43 +0000348 env->regs[R_EAX] = regs->eax;
349 env->regs[R_EBX] = regs->ebx;
350 env->regs[R_ECX] = regs->ecx;
351 env->regs[R_EDX] = regs->edx;
352 env->regs[R_ESI] = regs->esi;
353 env->regs[R_EDI] = regs->edi;
354 env->regs[R_EBP] = regs->ebp;
355 env->regs[R_ESP] = regs->esp;
bellarddab2ed92003-03-22 15:23:14 +0000356 env->eip = regs->eip;
bellard31e31b82003-02-18 22:55:36 +0000357
bellard6dbad632003-03-16 18:05:05 +0000358 /* linux segment setup */
359 env->gdt.base = (void *)gdt_table;
360 env->gdt.limit = sizeof(gdt_table) - 1;
361 write_dt(&gdt_table[__USER_CS >> 3], 0, 0xffffffff, 1);
362 write_dt(&gdt_table[__USER_DS >> 3], 0, 0xffffffff, 1);
363 cpu_x86_load_seg(env, R_CS, __USER_CS);
364 cpu_x86_load_seg(env, R_DS, __USER_DS);
365 cpu_x86_load_seg(env, R_ES, __USER_DS);
366 cpu_x86_load_seg(env, R_SS, __USER_DS);
367 cpu_x86_load_seg(env, R_FS, __USER_DS);
368 cpu_x86_load_seg(env, R_GS, __USER_DS);
bellard31e31b82003-02-18 22:55:36 +0000369
bellard1b6b0292003-03-22 17:31:38 +0000370 cpu_loop(env);
371 /* never exits */
bellard31e31b82003-02-18 22:55:36 +0000372 return 0;
373}