main.c 14.5 KB
Newer Older
1
/*
bellard's avatar
bellard committed
2
 *  qemu main
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 * 
 *  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>
bellard's avatar
bellard committed
23
#include <string.h>
24
#include <errno.h>
bellard's avatar
bellard committed
25
#include <unistd.h>
26

bellard's avatar
bellard committed
27
#include "qemu.h"
28

bellard's avatar
bellard committed
29
#include "cpu-i386.h"
30

bellard's avatar
bellard committed
31
#define DEBUG_LOGFILE "/tmp/qemu.log"
bellard's avatar
bellard committed
32
33
34

FILE *logfile = NULL;
int loglevel;
bellard's avatar
bellard committed
35
static const char *interp_prefix = CONFIG_QEMU_PREFIX;
bellard's avatar
bellard committed
36

37
38
39
40
#ifdef __i386__
/* 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";
bellard's avatar
bellard committed
41
#endif
bellard's avatar
bellard committed
42
43
44
45
46
47
48
49
50
51

/* for recent libc, we add these dummies symbol which are not declared
   when generating a linked object (bug in ld ?) */
#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)
long __init_array_start[0];
long __init_array_end[0];
long __fini_array_start[0];
long __fini_array_end[0];
#endif

bellard's avatar
bellard committed
52
53
54
55
/* 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;
56
57
58
59
60
61
62
63
64
65

void gemu_log(const char *fmt, ...)
{
    va_list ap;

    va_start(ap, fmt);
    vfprintf(stderr, fmt, ap);
    va_end(ap);
}

bellard's avatar
bellard committed
66
#ifdef TARGET_I386
67
/***********************************************************/
bellard's avatar
bellard committed
68
/* CPUX86 core interface */
bellard's avatar
bellard committed
69

bellard's avatar
bellard committed
70
void cpu_x86_outb(CPUX86State *env, int addr, int val)
bellard's avatar
bellard committed
71
72
73
74
{
    fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val);
}

bellard's avatar
bellard committed
75
void cpu_x86_outw(CPUX86State *env, int addr, int val)
bellard's avatar
bellard committed
76
77
78
79
{
    fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val);
}

bellard's avatar
bellard committed
80
void cpu_x86_outl(CPUX86State *env, int addr, int val)
bellard's avatar
bellard committed
81
82
83
84
{
    fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val);
}

bellard's avatar
bellard committed
85
int cpu_x86_inb(CPUX86State *env, int addr)
bellard's avatar
bellard committed
86
87
88
89
90
{
    fprintf(stderr, "inb: port=0x%04x\n", addr);
    return 0;
}

bellard's avatar
bellard committed
91
int cpu_x86_inw(CPUX86State *env, int addr)
bellard's avatar
bellard committed
92
93
94
95
96
{
    fprintf(stderr, "inw: port=0x%04x\n", addr);
    return 0;
}

bellard's avatar
bellard committed
97
int cpu_x86_inl(CPUX86State *env, int addr)
bellard's avatar
bellard committed
98
99
100
101
102
{
    fprintf(stderr, "inl: port=0x%04x\n", addr);
    return 0;
}

103
104
static void write_dt(void *ptr, unsigned long addr, unsigned long limit, 
                     int flags)
bellard's avatar
bellard committed
105
{
106
    unsigned int e1, e2;
bellard's avatar
bellard committed
107
108
    e1 = (addr << 16) | (limit & 0xffff);
    e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
109
110
111
112
113
114
115
116
117
118
119
    e2 |= flags;
    stl((uint8_t *)ptr, e1);
    stl((uint8_t *)ptr + 4, e2);
}

static void set_gate(void *ptr, unsigned int type, unsigned int dpl, 
                     unsigned long addr, unsigned int sel)
{
    unsigned int e1, e2;
    e1 = (addr & 0xffff) | (sel << 16);
    e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
bellard's avatar
bellard committed
120
121
122
123
124
    stl((uint8_t *)ptr, e1);
    stl((uint8_t *)ptr + 4, e2);
}

uint64_t gdt_table[6];
125
126
127
128
129
130
131
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);
}
132

bellard's avatar
bellard committed
133
void cpu_loop(CPUX86State *env)
bellard's avatar
bellard committed
134
{
bellard's avatar
bellard committed
135
    int trapnr;
bellard's avatar
bellard committed
136
137
    uint8_t *pc;
    target_siginfo_t info;
bellard's avatar
bellard committed
138

bellard's avatar
bellard committed
139
    for(;;) {
bellard's avatar
bellard committed
140
141
        trapnr = cpu_x86_exec(env);
        switch(trapnr) {
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
        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;
bellard's avatar
bellard committed
161
        case EXCP0D_GPF:
bellard's avatar
bellard committed
162
            if (env->eflags & VM_MASK) {
bellard's avatar
bellard committed
163
                handle_vm86_fault(env);
bellard's avatar
bellard committed
164
            } else {
165
166
167
168
169
                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);
bellard's avatar
bellard committed
170
171
            }
            break;
bellard's avatar
bellard committed
172
173
174
175
176
177
178
        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;
bellard's avatar
bellard committed
179
            info._sifields._sigfault._addr = env->cr[2];
bellard's avatar
bellard committed
180
181
            queue_signal(info.si_signo, &info);
            break;
bellard's avatar
bellard committed
182
        case EXCP00_DIVZ:
bellard's avatar
bellard committed
183
            if (env->eflags & VM_MASK) {
bellard's avatar
bellard committed
184
                handle_vm86_trap(env, trapnr);
bellard's avatar
bellard committed
185
186
187
188
189
190
191
192
            } 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);
            }
bellard's avatar
bellard committed
193
            break;
bellard's avatar
bellard committed
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
        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;
bellard's avatar
bellard committed
211
212
        case EXCP04_INTO:
        case EXCP05_BOUND:
bellard's avatar
bellard committed
213
            if (env->eflags & VM_MASK) {
bellard's avatar
bellard committed
214
                handle_vm86_trap(env, trapnr);
bellard's avatar
bellard committed
215
216
217
            } else {
                info.si_signo = SIGSEGV;
                info.si_errno = 0;
bellard's avatar
bellard committed
218
                info.si_code = TARGET_SI_KERNEL;
bellard's avatar
bellard committed
219
220
221
                info._sifields._sigfault._addr = 0;
                queue_signal(info.si_signo, &info);
            }
bellard's avatar
bellard committed
222
223
224
225
226
227
228
229
230
231
232
            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;
bellard's avatar
bellard committed
233
        default:
bellard's avatar
bellard committed
234
            pc = env->segs[R_CS].base + env->eip;
bellard's avatar
bellard committed
235
236
            fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n", 
                    (long)pc, trapnr);
bellard's avatar
bellard committed
237
238
            abort();
        }
bellard's avatar
bellard committed
239
        process_pending_signals(env);
bellard's avatar
bellard committed
240
241
    }
}
bellard's avatar
bellard committed
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
#endif

#ifdef TARGET_ARM

#define ARM_SYSCALL_BASE	0x900000

void cpu_loop(CPUARMState *env)
{
    int trapnr;
    unsigned int n, insn;
    target_siginfo_t info;
    
    for(;;) {
        trapnr = cpu_arm_exec(env);
        switch(trapnr) {
        case EXCP_UDEF:
            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);
            break;
        case EXCP_SWI:
            {
                /* system call */
                insn = ldl((void *)(env->regs[15] - 4));
                n = insn & 0xffffff;
                if (n >= ARM_SYSCALL_BASE) {
                    /* linux syscall */
                    n -= ARM_SYSCALL_BASE;
                    env->regs[0] = do_syscall(env, 
                                              n, 
                                              env->regs[0],
                                              env->regs[1],
                                              env->regs[2],
                                              env->regs[3],
                                              env->regs[4],
                                              0);
                } else {
                    goto error;
                }
            }
            break;
        default:
        error:
            fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", 
                    trapnr);
            cpu_arm_dump_state(env, stderr, 0);
            abort();
        }
        process_pending_signals(env);
    }
}

#endif
bellard's avatar
bellard committed
297

298
299
void usage(void)
{
bellard's avatar
bellard committed
300
    printf("qemu version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
301
           "usage: qemu [-h] [-d] [-L path] [-s size] program [arguments...]\n"
bellard's avatar
bellard committed
302
           "Linux CPU emulator (compiled for %s emulation)\n"
303
           "\n"
bellard's avatar
bellard committed
304
           "-h           print this help\n"
bellard's avatar
bellard committed
305
306
           "-L path      set the elf interpreter prefix (default=%s)\n"
           "-s size      set the stack size in bytes (default=%ld)\n"
bellard's avatar
bellard committed
307
308
309
310
           "\n"
           "debug options:\n"
           "-d           activate log (logfile=%s)\n"
           "-p pagesize  set the host page size to 'pagesize'\n",
bellard's avatar
bellard committed
311
           TARGET_ARCH,
312
           interp_prefix, 
bellard's avatar
bellard committed
313
314
           x86_stack_size,
           DEBUG_LOGFILE);
bellard's avatar
bellard committed
315
    _exit(1);
316
317
}

bellard's avatar
bellard committed
318
/* XXX: currently only used for async signals (see signal.c) */
bellard's avatar
bellard committed
319
CPUState *global_env;
bellard's avatar
bellard committed
320
321
/* used to free thread contexts */
TaskState *first_task_state;
bellard's avatar
bellard committed
322

323
324
325
int main(int argc, char **argv)
{
    const char *filename;
bellard's avatar
bellard committed
326
    struct target_pt_regs regs1, *regs = &regs1;
327
    struct image_info info1, *info = &info1;
bellard's avatar
bellard committed
328
    TaskState ts1, *ts = &ts1;
bellard's avatar
bellard committed
329
    CPUState *env;
bellard's avatar
bellard committed
330
    int optind;
331
332
    const char *r;
    
333
334
    if (argc <= 1)
        usage();
335

bellard's avatar
bellard committed
336
337
    loglevel = 0;
    optind = 1;
338
339
340
341
342
343
    for(;;) {
        if (optind >= argc)
            break;
        r = argv[optind];
        if (r[0] != '-')
            break;
bellard's avatar
bellard committed
344
        optind++;
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
        r++;
        if (!strcmp(r, "-")) {
            break;
        } else if (!strcmp(r, "d")) {
            loglevel = 1;
        } 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++];
bellard's avatar
bellard committed
361
362
363
364
365
366
367
        } else if (!strcmp(r, "p")) {
            host_page_size = atoi(argv[optind++]);
            if (host_page_size == 0 ||
                (host_page_size & (host_page_size - 1)) != 0) {
                fprintf(stderr, "page size must be a power of two\n");
                exit(1);
            }
368
369
370
        } else {
            usage();
        }
bellard's avatar
bellard committed
371
    }
372
373
    if (optind >= argc)
        usage();
bellard's avatar
bellard committed
374
375
376
377
378
379
380
    filename = argv[optind];

    /* init debug */
    if (loglevel) {
        logfile = fopen(DEBUG_LOGFILE, "w");
        if (!logfile) {
            perror(DEBUG_LOGFILE);
bellard's avatar
bellard committed
381
            _exit(1);
bellard's avatar
bellard committed
382
383
384
        }
        setvbuf(logfile, NULL, _IOLBF, 0);
    }
385
386

    /* Zero out regs */
bellard's avatar
bellard committed
387
    memset(regs, 0, sizeof(struct target_pt_regs));
388
389
390
391

    /* Zero out image_info */
    memset(info, 0, sizeof(struct image_info));

bellard's avatar
bellard committed
392
393
394
    /* Scan interp_prefix dir for replacement files. */
    init_paths(interp_prefix);

bellard's avatar
bellard committed
395
396
    /* NOTE: we need to init the CPU at this stage to get the
       host_page_size */
bellard's avatar
bellard committed
397
    env = cpu_init();
bellard's avatar
bellard committed
398

bellard's avatar
bellard committed
399
    if (elf_exec(filename, argv+optind, environ, regs, info) != 0) {
400
	printf("Error loading %s\n", filename);
bellard's avatar
bellard committed
401
	_exit(1);
402
403
    }
    
bellard's avatar
bellard committed
404
    if (loglevel) {
bellard's avatar
bellard committed
405
406
        page_dump(logfile);
    
bellard's avatar
bellard committed
407
408
409
410
411
412
        fprintf(logfile, "start_brk   0x%08lx\n" , info->start_brk);
        fprintf(logfile, "end_code    0x%08lx\n" , info->end_code);
        fprintf(logfile, "start_code  0x%08lx\n" , info->start_code);
        fprintf(logfile, "end_data    0x%08lx\n" , info->end_data);
        fprintf(logfile, "start_stack 0x%08lx\n" , info->start_stack);
        fprintf(logfile, "brk         0x%08lx\n" , info->brk);
bellard's avatar
bellard committed
413
        fprintf(logfile, "entry       0x%08lx\n" , info->entry);
bellard's avatar
bellard committed
414
    }
415
416
417

    target_set_brk((char *)info->brk);
    syscall_init();
bellard's avatar
bellard committed
418
    signal_init();
419

bellard's avatar
bellard committed
420
    global_env = env;
bellard's avatar
bellard committed
421

bellard's avatar
bellard committed
422
423
424
425
426
    /* build Task State */
    memset(ts, 0, sizeof(TaskState));
    env->opaque = ts;
    ts->used = 1;
    
bellard's avatar
bellard committed
427
#if defined(TARGET_I386)
bellard's avatar
bellard committed
428
    /* linux register setup */
bellard's avatar
bellard committed
429
430
431
432
433
434
435
436
    env->regs[R_EAX] = regs->eax;
    env->regs[R_EBX] = regs->ebx;
    env->regs[R_ECX] = regs->ecx;
    env->regs[R_EDX] = regs->edx;
    env->regs[R_ESI] = regs->esi;
    env->regs[R_EDI] = regs->edi;
    env->regs[R_EBP] = regs->ebp;
    env->regs[R_ESP] = regs->esp;
bellard's avatar
bellard committed
437
    env->eip = regs->eip;
438

439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
    /* linux interrupt setup */
    env->idt.base = (void *)idt_table;
    env->idt.limit = sizeof(idt_table) - 1;
    set_idt(0, 0);
    set_idt(1, 0);
    set_idt(2, 0);
    set_idt(3, 3);
    set_idt(4, 3);
    set_idt(5, 3);
    set_idt(6, 0);
    set_idt(7, 0);
    set_idt(8, 0);
    set_idt(9, 0);
    set_idt(10, 0);
    set_idt(11, 0);
    set_idt(12, 0);
    set_idt(13, 0);
    set_idt(14, 0);
    set_idt(15, 0);
    set_idt(16, 0);
    set_idt(17, 0);
    set_idt(18, 0);
    set_idt(19, 0);
    set_idt(0x80, 3);

bellard's avatar
bellard committed
464
465
466
    /* linux segment setup */
    env->gdt.base = (void *)gdt_table;
    env->gdt.limit = sizeof(gdt_table) - 1;
467
468
469
470
471
472
    write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
             DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | 
             (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
    write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff,
             DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | 
             (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
bellard's avatar
bellard committed
473
474
475
476
477
478
    cpu_x86_load_seg(env, R_CS, __USER_CS);
    cpu_x86_load_seg(env, R_DS, __USER_DS);
    cpu_x86_load_seg(env, R_ES, __USER_DS);
    cpu_x86_load_seg(env, R_SS, __USER_DS);
    cpu_x86_load_seg(env, R_FS, __USER_DS);
    cpu_x86_load_seg(env, R_GS, __USER_DS);
bellard's avatar
bellard committed
479
480
481
482
483
484
485
486
487
488
489
#elif defined(TARGET_ARM)
    {
        int i;
        for(i = 0; i < 16; i++) {
            env->regs[i] = regs->uregs[i];
        }
        env->cpsr = regs->uregs[16];
    }
#else
#error unsupported target CPU
#endif
490

bellard's avatar
bellard committed
491
492
    cpu_loop(env);
    /* never exits */
493
494
    return 0;
}