vl.c 33.1 KB
Newer Older
1
/*
bellard's avatar
bellard committed
2
 * QEMU System Emulator
3
 * 
bellard's avatar
bellard committed
4
 * Copyright (c) 2003-2004 Fabrice Bellard
5
 * 
bellard's avatar
bellard committed
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
23
24
25
 */
#include <stdlib.h>
#include <stdio.h>
bellard's avatar
bellard committed
26
#include <stdarg.h>
27
#include <string.h>
28
#include <ctype.h>
29
30
31
32
33
34
35
36
37
38
39
40
#include <getopt.h>
#include <inttypes.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
#include <malloc.h>
#include <termios.h>
#include <sys/poll.h>
#include <errno.h>
bellard's avatar
bellard committed
41
42
43
44
45
46
#include <sys/wait.h>

#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/if.h>
#include <linux/if_tun.h>
47
48

#include "disas.h"
bellard's avatar
bellard committed
49
50
51
#include "thunk.h"

#include "vl.h"
52

53
#define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup"
bellard's avatar
bellard committed
54

55
//#define DEBUG_UNUSED_IOPORT
56

57
#if !defined(CONFIG_SOFTMMU)
bellard's avatar
bellard committed
58
#define PHYS_RAM_MAX_SIZE (256 * 1024 * 1024)
59
60
61
#else
#define PHYS_RAM_MAX_SIZE (2047 * 1024 * 1024)
#endif
bellard's avatar
bellard committed
62

63
64
65
#if defined (TARGET_I386)
#elif defined (TARGET_PPC)
//#define USE_OPEN_FIRMWARE
bellard's avatar
bellard committed
66
#if !defined (USE_OPEN_FIRMWARE)
67
68
69
70
71
72
73
#define KERNEL_LOAD_ADDR    0x01000000
#define KERNEL_STACK_ADDR   0x01200000
#else
#define KERNEL_LOAD_ADDR    0x00000000
#define KERNEL_STACK_ADDR   0x00400000
#endif
#endif
74

75
76
#define GUI_REFRESH_INTERVAL 30 

77
78
/* XXX: use a two level table to limit memory usage */
#define MAX_IOPORTS 65536
79

bellard's avatar
bellard committed
80
const char *bios_dir = CONFIG_QEMU_SHAREDIR;
81
char phys_ram_file[1024];
82
83
CPUState *global_env;
CPUState *cpu_single_env;
bellard's avatar
bellard committed
84
85
IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS];
IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS];
86
BlockDriverState *bs_table[MAX_DISKS], *fd_table[MAX_FD];
87
88
int vga_ram_size;
static DisplayState display_state;
89
int nographic;
90
91
int term_inited;
int64_t ticks_per_sec;
92
int boot_device = 'c';
93
static int ram_size;
bellard's avatar
bellard committed
94
95
static char network_script[1024];
int pit_min_timer_count = 0;
96
97
98
99

/***********************************************************/
/* x86 io ports */

100
uint32_t default_ioport_readb(CPUState *env, uint32_t address)
101
102
103
104
{
#ifdef DEBUG_UNUSED_IOPORT
    fprintf(stderr, "inb: port=0x%04x\n", address);
#endif
bellard's avatar
bellard committed
105
    return 0xff;
106
107
}

108
void default_ioport_writeb(CPUState *env, uint32_t address, uint32_t data)
109
110
111
112
113
114
115
{
#ifdef DEBUG_UNUSED_IOPORT
    fprintf(stderr, "outb: port=0x%04x data=0x%02x\n", address, data);
#endif
}

/* default is to make two byte accesses */
116
uint32_t default_ioport_readw(CPUState *env, uint32_t address)
117
118
{
    uint32_t data;
119
120
    data = ioport_read_table[0][address & (MAX_IOPORTS - 1)](env, address);
    data |= ioport_read_table[0][(address + 1) & (MAX_IOPORTS - 1)](env, address + 1) << 8;
121
122
123
    return data;
}

124
void default_ioport_writew(CPUState *env, uint32_t address, uint32_t data)
125
{
126
127
    ioport_write_table[0][address & (MAX_IOPORTS - 1)](env, address, data & 0xff);
    ioport_write_table[0][(address + 1) & (MAX_IOPORTS - 1)](env, address + 1, (data >> 8) & 0xff);
128
129
}

130
uint32_t default_ioport_readl(CPUState *env, uint32_t address)
131
{
bellard's avatar
bellard committed
132
133
134
135
#ifdef DEBUG_UNUSED_IOPORT
    fprintf(stderr, "inl: port=0x%04x\n", address);
#endif
    return 0xffffffff;
136
137
}

138
void default_ioport_writel(CPUState *env, uint32_t address, uint32_t data)
139
{
bellard's avatar
bellard committed
140
141
142
#ifdef DEBUG_UNUSED_IOPORT
    fprintf(stderr, "outl: port=0x%04x data=0x%02x\n", address, data);
#endif
143
144
}

bellard's avatar
bellard committed
145
void init_ioports(void)
146
147
148
{
    int i;

bellard's avatar
bellard committed
149
150
151
152
153
154
155
156
    for(i = 0; i < MAX_IOPORTS; i++) {
        ioport_read_table[0][i] = default_ioport_readb;
        ioport_write_table[0][i] = default_ioport_writeb;
        ioport_read_table[1][i] = default_ioport_readw;
        ioport_write_table[1][i] = default_ioport_writew;
        ioport_read_table[2][i] = default_ioport_readl;
        ioport_write_table[2][i] = default_ioport_writel;
    }
157
158
}

bellard's avatar
bellard committed
159
160
/* size is the word size in byte */
int register_ioport_read(int start, int length, IOPortReadFunc *func, int size)
bellard's avatar
bellard committed
161
{
bellard's avatar
bellard committed
162
    int i, bsize;
bellard's avatar
bellard committed
163

bellard's avatar
bellard committed
164
165
166
167
168
169
170
171
172
173
    if (size == 1)
        bsize = 0;
    else if (size == 2)
        bsize = 1;
    else if (size == 4)
        bsize = 2;
    else
        return -1;
    for(i = start; i < start + length; i += size)
        ioport_read_table[bsize][i] = func;
bellard's avatar
bellard committed
174
175
176
    return 0;
}

bellard's avatar
bellard committed
177
178
/* size is the word size in byte */
int register_ioport_write(int start, int length, IOPortWriteFunc *func, int size)
bellard's avatar
bellard committed
179
{
bellard's avatar
bellard committed
180
    int i, bsize;
bellard's avatar
bellard committed
181

bellard's avatar
bellard committed
182
183
184
185
186
187
188
189
190
191
    if (size == 1)
        bsize = 0;
    else if (size == 2)
        bsize = 1;
    else if (size == 4)
        bsize = 2;
    else
        return -1;
    for(i = start; i < start + length; i += size)
        ioport_write_table[bsize][i] = func;
bellard's avatar
bellard committed
192
193
194
    return 0;
}

195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
void pstrcpy(char *buf, int buf_size, const char *str)
{
    int c;
    char *q = buf;

    if (buf_size <= 0)
        return;

    for(;;) {
        c = *str++;
        if (c == 0 || q >= buf + buf_size - 1)
            break;
        *q++ = c;
    }
    *q = '\0';
}

/* strcat and truncate. */
char *pstrcat(char *buf, int buf_size, const char *s)
{
    int len;
    len = strlen(buf);
    if (len < buf_size) 
        pstrcpy(buf + len, buf_size - len, s);
    return buf;
}

/* return the size or -1 if error */
int load_image(const char *filename, uint8_t *addr)
{
    int fd, size;
    fd = open(filename, O_RDONLY);
    if (fd < 0)
        return -1;
    size = lseek(fd, 0, SEEK_END);
    lseek(fd, 0, SEEK_SET);
    if (read(fd, addr, size) != size) {
        close(fd);
        return -1;
    }
    close(fd);
    return size;
}

239
void cpu_outb(CPUState *env, int addr, int val)
240
{
bellard's avatar
bellard committed
241
    ioport_write_table[0][addr & (MAX_IOPORTS - 1)](env, addr, val);
242
243
}

244
void cpu_outw(CPUState *env, int addr, int val)
245
{
bellard's avatar
bellard committed
246
    ioport_write_table[1][addr & (MAX_IOPORTS - 1)](env, addr, val);
247
248
}

249
void cpu_outl(CPUState *env, int addr, int val)
250
{
bellard's avatar
bellard committed
251
    ioport_write_table[2][addr & (MAX_IOPORTS - 1)](env, addr, val);
252
253
}

254
int cpu_inb(CPUState *env, int addr)
255
{
bellard's avatar
bellard committed
256
    return ioport_read_table[0][addr & (MAX_IOPORTS - 1)](env, addr);
257
258
}

259
int cpu_inw(CPUState *env, int addr)
260
{
bellard's avatar
bellard committed
261
    return ioport_read_table[1][addr & (MAX_IOPORTS - 1)](env, addr);
262
263
}

264
int cpu_inl(CPUState *env, int addr)
265
{
bellard's avatar
bellard committed
266
    return ioport_read_table[2][addr & (MAX_IOPORTS - 1)](env, addr);
267
268
269
270
271
272
273
274
275
276
277
278
279
}

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

    va_start(ap, fmt);
    fprintf(stderr, "qemu: hardware error: ");
    vfprintf(stderr, fmt, ap);
    fprintf(stderr, "\n");
#ifdef TARGET_I386
    cpu_x86_dump_state(global_env, stderr, X86_DUMP_FPU | X86_DUMP_CCOP);
280
281
#else
    cpu_dump_state(global_env, stderr, 0);
282
283
284
285
286
#endif
    va_end(ap);
    abort();
}

287
288
289
#if defined(__powerpc__)

static inline uint32_t get_tbl(void) 
290
{
291
292
293
    uint32_t tbl;
    asm volatile("mftb %0" : "=r" (tbl));
    return tbl;
294
295
}

296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
static inline uint32_t get_tbu(void) 
{
	uint32_t tbl;
	asm volatile("mftbu %0" : "=r" (tbl));
	return tbl;
}

int64_t cpu_get_real_ticks(void)
{
    uint32_t l, h, h1;
    /* NOTE: we test if wrapping has occurred */
    do {
        h = get_tbu();
        l = get_tbl();
        h1 = get_tbu();
    } while (h != h1);
    return ((int64_t)h << 32) | l;
}

#elif defined(__i386__)

int64_t cpu_get_real_ticks(void)
318
319
320
321
322
323
{
    int64_t val;
    asm("rdtsc" : "=A" (val));
    return val;
}

324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
#else
#error unsupported CPU
#endif

static int64_t cpu_ticks_offset;
static int64_t cpu_ticks_last;

int64_t cpu_get_ticks(void)
{
    return cpu_get_real_ticks() + cpu_ticks_offset;
}

/* enable cpu_get_ticks() */
void cpu_enable_ticks(void)
{
    cpu_ticks_offset = cpu_ticks_last - cpu_get_real_ticks();
}

/* disable cpu_get_ticks() : the clock is stopped. You must not call
   cpu_get_ticks() after that.  */
void cpu_disable_ticks(void)
{
    cpu_ticks_last = cpu_get_ticks();
}

int64_t get_clock(void)
{
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return tv.tv_sec * 1000000LL + tv.tv_usec;
}

356
357
358
359
360
361
362
363
364
365
366
367
void cpu_calibrate_ticks(void)
{
    int64_t usec, ticks;

    usec = get_clock();
    ticks = cpu_get_ticks();
    usleep(50 * 1000);
    usec = get_clock() - usec;
    ticks = cpu_get_ticks() - ticks;
    ticks_per_sec = (ticks * 1000000LL + (usec >> 1)) / usec;
}

368
/* compute with 96 bit intermediate result: (a*b)/c */
bellard's avatar
bellard committed
369
uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
{
    union {
        uint64_t ll;
        struct {
#ifdef WORDS_BIGENDIAN
            uint32_t high, low;
#else
            uint32_t low, high;
#endif            
        } l;
    } u, res;
    uint64_t rl, rh;

    u.ll = a;
    rl = (uint64_t)u.l.low * (uint64_t)b;
    rh = (uint64_t)u.l.high * (uint64_t)b;
    rh += (rl >> 32);
    res.l.high = rh / c;
    res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c;
    return res.ll;
}

bellard's avatar
bellard committed
392
393
394
#define TERM_ESCAPE 0x01 /* ctrl-a is used for escape */
static int term_got_escape, term_command;
static unsigned char term_cmd_buf[128];
395

bellard's avatar
bellard committed
396
397
398
399
typedef struct term_cmd_t {
    const unsigned char *name;
    void (*handler)(unsigned char *params);
} term_cmd_t;
400

bellard's avatar
bellard committed
401
402
403
static void do_change_cdrom (unsigned char *params);
static void do_change_fd0 (unsigned char *params);
static void do_change_fd1 (unsigned char *params);
404
405
406
407
408

static term_cmd_t term_cmds[] = {
    { "changecd", &do_change_cdrom, },
    { "changefd0", &do_change_fd0, },
    { "changefd1", &do_change_fd1, },
bellard's avatar
bellard committed
409
410
    { NULL, NULL, },
};
411

bellard's avatar
bellard committed
412
void term_print_help(void)
413
{
bellard's avatar
bellard committed
414
415
416
417
418
419
420
421
422
    printf("\n"
           "C-a h    print this help\n"
           "C-a x    exit emulatior\n"
           "C-a d    switch on/off debug log\n"
	   "C-a s    save disk data back to file (if -snapshot)\n"
           "C-a b    send break (magic sysrq)\n"
           "C-a c    send qemu internal command\n"
           "C-a C-a  send C-a\n"
           );
423
424
}

bellard's avatar
bellard committed
425
static void do_change_cdrom (unsigned char *params)
426
{
bellard's avatar
bellard committed
427
    /* Dunno how to do it... */
428
429
}

bellard's avatar
bellard committed
430
static void do_change_fd (int fd, unsigned char *params)
431
{
bellard's avatar
bellard committed
432
433
    unsigned char *name_start, *name_end, *ros;
    int ro;
434

bellard's avatar
bellard committed
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
    for (name_start = params;
         isspace(*name_start); name_start++)
        continue;
    if (*name_start == '\0')
        return;
    for (name_end = name_start;
         !isspace(*name_end) && *name_end != '\0'; name_end++)
        continue;
    for (ros = name_end + 1; isspace(*ros); ros++)
        continue;
    if (ros[0] == 'r' && ros[1] == 'o')
        ro = 1;
    else
        ro = 0;
    *name_end = '\0';
    printf("Change fd %d to %s (%s)\n", fd, name_start, params);
    fdctrl_disk_change(fd, name_start, ro);
452
453
}

bellard's avatar
bellard committed
454
static void do_change_fd0 (unsigned char *params)
455
{
bellard's avatar
bellard committed
456
    do_change_fd(0, params);
457
458
}

bellard's avatar
bellard committed
459
static void do_change_fd1 (unsigned char *params)
460
{
bellard's avatar
bellard committed
461
    do_change_fd(1, params);
462
463
}

bellard's avatar
bellard committed
464
static void term_treat_command(void)
465
{
bellard's avatar
bellard committed
466
467
    unsigned char *cmd_start, *cmd_end;
    int i;
468

bellard's avatar
bellard committed
469
470
471
472
473
474
475
476
477
478
    for (cmd_start = term_cmd_buf; isspace(*cmd_start); cmd_start++)
        continue;
    for (cmd_end = cmd_start;
         !isspace(*cmd_end) && *cmd_end != '\0'; cmd_end++)
        continue;
    for (i = 0; term_cmds[i].name != NULL; i++) {
        if (strlen(term_cmds[i].name) == (cmd_end - cmd_start) &&
            memcmp(term_cmds[i].name, cmd_start, cmd_end - cmd_start) == 0) {
            (*term_cmds[i].handler)(cmd_end + 1);
            return;
479
480
        }
    }
bellard's avatar
bellard committed
481
482
    *cmd_end = '\0';
    printf("Unknown term command: %s\n", cmd_start);
483
484
}

bellard's avatar
bellard committed
485
486
487
488
extern FILE *logfile;

/* called when a char is received */
void term_received_byte(int ch)
489
{
bellard's avatar
bellard committed
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
    if (term_command) {
        if (ch == '\n' || ch == '\r' || term_command == 127) {
            printf("\n");
            term_treat_command();
            term_command = 0;
        } else {
            if (ch == 0x7F || ch == 0x08) {
                if (term_command > 1) {
                    term_cmd_buf[--term_command - 1] = '\0';
                    printf("\r                                               "
                           "                               ");
                    printf("\r> %s", term_cmd_buf);
                }
            } else if (ch > 0x1f) {
                term_cmd_buf[term_command++ - 1] = ch;
                term_cmd_buf[term_command - 1] = '\0';
                printf("\r> %s", term_cmd_buf);
507
            }
bellard's avatar
bellard committed
508
            fflush(stdout);
509
        }
bellard's avatar
bellard committed
510
511
512
513
514
    } else if (term_got_escape) {
        term_got_escape = 0;
        switch(ch) {
        case 'h':
            term_print_help();
515
            break;
bellard's avatar
bellard committed
516
517
        case 'x':
            exit(0);
518
            break;
bellard's avatar
bellard committed
519
520
521
522
523
524
525
526
	case 's': 
            {
                int i;
                for (i = 0; i < MAX_DISKS; i++) {
                    if (bs_table[i])
                        bdrv_commit(bs_table[i]);
                }
	    }
527
            break;
bellard's avatar
bellard committed
528
529
        case 'b':
            serial_receive_break();
530
            break;
bellard's avatar
bellard committed
531
532
533
534
        case 'c':
            printf("> ");
            fflush(stdout);
            term_command = 1;
535
            break;
bellard's avatar
bellard committed
536
537
        case 'd':
            cpu_set_log(CPU_LOG_ALL);
538
            break;
bellard's avatar
bellard committed
539
540
        case TERM_ESCAPE:
            goto send_char;
541
        }
bellard's avatar
bellard committed
542
543
544
545
546
    } else if (ch == TERM_ESCAPE) {
        term_got_escape = 1;
    } else {
    send_char:
        serial_receive_byte(ch);
547
548
549
    }
}

bellard's avatar
bellard committed
550
551
/***********************************************************/
/* Linux network device redirector */
552

bellard's avatar
bellard committed
553
int net_init(void)
554
{
bellard's avatar
bellard committed
555
556
557
558
559
560
561
    struct ifreq ifr;
    int fd, ret, pid, status;
    
    fd = open("/dev/net/tun", O_RDWR);
    if (fd < 0) {
        fprintf(stderr, "warning: could not open /dev/net/tun: no virtual network emulation\n");
        return -1;
562
    }
bellard's avatar
bellard committed
563
564
565
566
567
568
569
570
571
572
573
574
    memset(&ifr, 0, sizeof(ifr));
    ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
    pstrcpy(ifr.ifr_name, IFNAMSIZ, "tun%d");
    ret = ioctl(fd, TUNSETIFF, (void *) &ifr);
    if (ret != 0) {
        fprintf(stderr, "warning: could not configure /dev/net/tun: no virtual network emulation\n");
        close(fd);
        return -1;
    }
    printf("Connected to host network interface: %s\n", ifr.ifr_name);
    fcntl(fd, F_SETFL, O_NONBLOCK);
    net_fd = fd;
575

bellard's avatar
bellard committed
576
577
578
579
580
581
582
583
584
585
586
587
588
    /* try to launch network init script */
    pid = fork();
    if (pid >= 0) {
        if (pid == 0) {
            execl(network_script, network_script, ifr.ifr_name, NULL);
            exit(1);
        }
        while (waitpid(pid, &status, 0) != pid);
        if (!WIFEXITED(status) ||
            WEXITSTATUS(status) != 0) {
            fprintf(stderr, "%s: could not launch network script for '%s'\n",
                    network_script, ifr.ifr_name);
        }
589
    }
bellard's avatar
bellard committed
590
    return 0;
591
592
}

bellard's avatar
bellard committed
593
void net_send_packet(int net_fd, const uint8_t *buf, int size)
594
{
bellard's avatar
bellard committed
595
596
#ifdef DEBUG_NE2000
    printf("NE2000: sending packet size=%d\n", size);
597
#endif
bellard's avatar
bellard committed
598
599
    write(net_fd, buf, size);
}
600

601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
/***********************************************************/
/* dumb display */

/* init terminal so that we can grab keys */
static struct termios oldtty;

static void term_exit(void)
{
    tcsetattr (0, TCSANOW, &oldtty);
}

static void term_init(void)
{
    struct termios tty;

    tcgetattr (0, &tty);
    oldtty = tty;

    tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
                          |INLCR|IGNCR|ICRNL|IXON);
    tty.c_oflag |= OPOST;
622
623
624
625
    tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
    /* if graphical mode, we allow Ctrl-C handling */
    if (nographic)
        tty.c_lflag &= ~ISIG;
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
    tty.c_cflag &= ~(CSIZE|PARENB);
    tty.c_cflag |= CS8;
    tty.c_cc[VMIN] = 1;
    tty.c_cc[VTIME] = 0;
    
    tcsetattr (0, TCSANOW, &tty);

    atexit(term_exit);

    fcntl(0, F_SETFL, O_NONBLOCK);
}

static void dumb_update(DisplayState *ds, int x, int y, int w, int h)
{
}

static void dumb_resize(DisplayState *ds, int w, int h)
{
}

static void dumb_refresh(DisplayState *ds)
{
    vga_update_display();
}

void dumb_display_init(DisplayState *ds)
{
    ds->data = NULL;
    ds->linesize = 0;
    ds->depth = 0;
    ds->dpy_update = dumb_update;
    ds->dpy_resize = dumb_resize;
    ds->dpy_refresh = dumb_refresh;
}

661
#if !defined(CONFIG_SOFTMMU)
bellard's avatar
bellard committed
662
/***********************************************************/
663
664
665
666
667
668
669
670
671
/* cpu signal handler */
static void host_segv_handler(int host_signum, siginfo_t *info, 
                              void *puc)
{
    if (cpu_signal_handler(host_signum, info, puc))
        return;
    term_exit();
    abort();
}
672
#endif
673
674

static int timer_irq_pending;
675
static int timer_irq_count;
676

677
678
679
static int timer_ms;
static int gui_refresh_pending, gui_refresh_count;

680
681
682
static void host_alarm_handler(int host_signum, siginfo_t *info, 
                               void *puc)
{
683
684
685
686
687
688
689
690
    /* NOTE: since usually the OS asks a 100 Hz clock, there can be
       some drift between cpu_get_ticks() and the interrupt time. So
       we queue some interrupts to avoid missing some */
    timer_irq_count += pit_get_out_edges(&pit_channels[0]);
    if (timer_irq_count) {
        if (timer_irq_count > 2)
            timer_irq_count = 2;
        timer_irq_count--;
691
692
693
694
695
696
697
698
699
        timer_irq_pending = 1;
    }
    gui_refresh_count += timer_ms;
    if (gui_refresh_count >= GUI_REFRESH_INTERVAL) {
        gui_refresh_count = 0;
        gui_refresh_pending = 1;
    }

    if (gui_refresh_pending || timer_irq_pending) {
700
        /* just exit from the cpu to have a chance to handle timers */
701
        cpu_interrupt(global_env, CPU_INTERRUPT_EXIT);
702
    }
703
704
}

bellard's avatar
bellard committed
705
706
707
708
709
710
711
/* main execution loop */

CPUState *cpu_gdbstub_get_env(void *opaque)
{
    return global_env;
}

bellard's avatar
bellard committed
712
int main_loop(void *opaque)
bellard's avatar
bellard committed
713
{
714
715
716
717
    struct pollfd ufds[3], *pf, *serial_ufd, *gdb_ufd;
#if defined (TARGET_I386)
    struct pollfd *net_ufd;
#endif
718
    int ret, n, timeout, serial_ok;
bellard's avatar
bellard committed
719
720
721
    uint8_t ch;
    CPUState *env = global_env;

722
    if (!term_inited) {
723
724
725
726
727
728
729
        /* initialize terminal only there so that the user has a
           chance to stop QEMU with Ctrl-C before the gdb connection
           is launched */
        term_inited = 1;
        term_init();
    }

730
    serial_ok = 1;
731
    cpu_enable_ticks();
bellard's avatar
bellard committed
732
    for(;;) {
733
734
735
736
#if defined (DO_TB_FLUSH)
        tb_flush();
#endif
        ret = cpu_exec(env);
737
738
        if (reset_requested) {
            ret = EXCP_INTERRUPT; 
739
            break;
740
741
742
743
744
        }
        if (ret == EXCP_DEBUG) {
            ret = EXCP_DEBUG;
            break;
        }
bellard's avatar
bellard committed
745
746
747
748
749
750
751
752
        /* if hlt instruction, we wait until the next IRQ */
        if (ret == EXCP_HLT) 
            timeout = 10;
        else
            timeout = 0;
        /* poll any events */
        serial_ufd = NULL;
        pf = ufds;
bellard's avatar
bellard committed
753
        if (serial_ok && serial_can_receive()) {
bellard's avatar
bellard committed
754
755
756
757
758
            serial_ufd = pf;
            pf->fd = 0;
            pf->events = POLLIN;
            pf++;
        }
759
#if defined (TARGET_I386)
bellard's avatar
bellard committed
760
        net_ufd = NULL;
bellard's avatar
bellard committed
761
        if (net_fd > 0 && ne2000_can_receive()) {
bellard's avatar
bellard committed
762
763
764
765
766
            net_ufd = pf;
            pf->fd = net_fd;
            pf->events = POLLIN;
            pf++;
        }
767
#endif
bellard's avatar
bellard committed
768
769
770
771
772
773
774
775
776
777
778
779
780
        gdb_ufd = NULL;
        if (gdbstub_fd > 0) {
            gdb_ufd = pf;
            pf->fd = gdbstub_fd;
            pf->events = POLLIN;
            pf++;
        }

        ret = poll(ufds, pf - ufds, timeout);
        if (ret > 0) {
            if (serial_ufd && (serial_ufd->revents & POLLIN)) {
                n = read(0, &ch, 1);
                if (n == 1) {
bellard's avatar
bellard committed
781
                    term_received_byte(ch);
782
783
784
                } else {
		    /* Closed, stop polling. */
                    serial_ok = 0;
bellard's avatar
bellard committed
785
786
                }
            }
787
#if defined (TARGET_I386)
bellard's avatar
bellard committed
788
789
790
791
792
793
794
795
796
            if (net_ufd && (net_ufd->revents & POLLIN)) {
                uint8_t buf[MAX_ETH_FRAME_SIZE];

                n = read(net_fd, buf, MAX_ETH_FRAME_SIZE);
                if (n > 0) {
                    if (n < 60) {
                        memset(buf + n, 0, 60 - n);
                        n = 60;
                    }
bellard's avatar
bellard committed
797
                    ne2000_receive(buf, n);
bellard's avatar
bellard committed
798
799
                }
            }
800
#endif
bellard's avatar
bellard committed
801
802
803
804
            if (gdb_ufd && (gdb_ufd->revents & POLLIN)) {
                uint8_t buf[1];
                /* stop emulation if requested by gdb */
                n = read(gdbstub_fd, buf, 1);
805
806
                if (n == 1) {
                    ret = EXCP_INTERRUPT; 
bellard's avatar
bellard committed
807
                    break;
808
                }
bellard's avatar
bellard committed
809
810
811
812
813
            }
        }

        /* timer IRQ */
        if (timer_irq_pending) {
814
#if defined (TARGET_I386)
bellard's avatar
bellard committed
815
816
817
            pic_set_irq(0, 1);
            pic_set_irq(0, 0);
            timer_irq_pending = 0;
bellard's avatar
bellard committed
818
            rtc_timer();
819
#endif
bellard's avatar
bellard committed
820
        }
821
822
823
824
825
        /* XXX: add explicit timer */
        SB16_run();

        /* run dma transfers, if any */
        DMA_run();
826
827
828
829
830
831

        /* VGA */
        if (gui_refresh_pending) {
            display_state.dpy_refresh(&display_state);
            gui_refresh_pending = 0;
        }
bellard's avatar
bellard committed
832
    }
833
834
    cpu_disable_ticks();
    return ret;
bellard's avatar
bellard committed
835
836
}

837
838
void help(void)
{
839
    printf("QEMU PC emulator version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
840
           "usage: %s [options] [disk_image]\n"
841
           "\n"
842
           "'disk_image' is a raw hard image image for IDE hard disk 0\n"
bellard's avatar
bellard committed
843
           "\n"
844
           "Standard options:\n"
845
           "-fda/-fdb file  use 'file' as floppy disk 0/1 image\n"
846
847
848
           "-hda/-hdb file  use 'file' as IDE hard disk 0/1 image\n"
           "-hdc/-hdd file  use 'file' as IDE hard disk 2/3 image\n"
           "-cdrom file     use 'file' as IDE cdrom 2 image\n"
849
           "-boot [a|b|c|d] boot on floppy (a, b), hard disk (c) or CD-ROM (d)\n"
850
851
852
	   "-snapshot       write to temporary files instead of disk image files\n"
           "-m megs         set virtual RAM size to megs MB\n"
           "-n script       set network init script [default=%s]\n"
853
           "-tun-fd fd      this fd talks to tap/tun, use it.\n"
854
855
856
857
858
859
           "-nographic      disable graphical output\n"
           "\n"
           "Linux boot specific (does not require PC BIOS):\n"
           "-kernel bzImage use 'bzImage' as kernel image\n"
           "-append cmdline use 'cmdline' as kernel command line\n"
           "-initrd file    use 'file' as initial ram disk\n"
bellard's avatar
bellard committed
860
           "\n"
861
           "Debug/Expert options:\n"
862
863
           "-s              wait gdb connection to port %d\n"
           "-p port         change gdb connection port\n"
864
           "-d              output log to %s\n"
865
866
           "-hdachs c,h,s   force hard disk 0 geometry (usually qemu can guess it)\n"
           "-L path         set the directory for the BIOS and VGA BIOS\n"
867
868
869
870
#ifdef USE_CODE_COPY
           "-no-code-copy   disable code copy acceleration\n"
#endif

871
           "\n"
bellard's avatar
bellard committed
872
           "During emulation, use C-a h to get terminal commands:\n",
873
874
875
876
877
878
#ifdef CONFIG_SOFTMMU
           "qemu",
#else
           "qemu-fast",
#endif
           DEFAULT_NETWORK_SCRIPT, 
879
880
           DEFAULT_GDBSTUB_PORT,
           "/tmp/qemu.log");
881
    term_print_help();
882
883
884
885
886
887
#ifndef CONFIG_SOFTMMU
    printf("\n"
           "NOTE: this version of QEMU is faster but it needs slightly patched OSes to\n"
           "work. Please use the 'qemu' executable to have a more accurate (but slower)\n"
           "PC emulation.\n");
#endif
888
889
890
    exit(1);
}

bellard's avatar
bellard committed
891
892
893
894
struct option long_options[] = {
    { "initrd", 1, NULL, 0, },
    { "hda", 1, NULL, 0, },
    { "hdb", 1, NULL, 0, },
895
    { "snapshot", 0, NULL, 0, },
896
    { "hdachs", 1, NULL, 0, },
897
898
899
    { "nographic", 0, NULL, 0, },
    { "kernel", 1, NULL, 0, },
    { "append", 1, NULL, 0, },
900
    { "tun-fd", 1, NULL, 0, },
901
902
903
904
    { "hdc", 1, NULL, 0, },
    { "hdd", 1, NULL, 0, },
    { "cdrom", 1, NULL, 0, },
    { "boot", 1, NULL, 0, },
905
906
    { "fda", 1, NULL, 0, },
    { "fdb", 1, NULL, 0, },
907
    { "no-code-copy", 0, NULL, 0},
bellard's avatar
bellard committed
908
909
910
    { NULL, 0, NULL, 0 },
};

911
912
913
#ifdef CONFIG_SDL
/* SDL use the pthreads and they modify sigaction. We don't
   want that. */
914
#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2)
915
916
917
918
919
920
921
922
extern void __libc_sigaction();
#define sigaction(sig, act, oact) __libc_sigaction(sig, act, oact)
#else
extern void __sigaction();
#define sigaction(sig, act, oact) __sigaction(sig, act, oact)
#endif
#endif /* CONFIG_SDL */

923
924
925
926
927
928
929
930
931
#if defined (TARGET_I386) && defined(USE_CODE_COPY)

/* this stack is only used during signal handling */
#define SIGNAL_STACK_SIZE 32768

static uint8_t *signal_stack;

#endif

932
933
int main(int argc, char **argv)
{
bellard's avatar
bellard committed
934
    int c, i, use_gdbstub, gdbstub_port, long_index;
935
    int snapshot, linux_boot;
936
937
    struct sigaction act;
    struct itimerval itv;
938
    CPUState *env;
bellard's avatar
bellard committed
939
    const char *initrd_filename;
940
    const char *hd_filename[MAX_DISKS], *fd_filename[MAX_FD];
941
    const char *kernel_filename, *kernel_cmdline;
942
943
    DisplayState *ds = &display_state;

944
945
    /* we never want that malloc() uses mmap() */
    mallopt(M_MMAP_THRESHOLD, 4096 * 1024);
bellard's avatar
bellard committed
946
    initrd_filename = NULL;
947
948
    for(i = 0; i < MAX_FD; i++)
        fd_filename[i] = NULL;
bellard's avatar
bellard committed
949
950
    for(i = 0; i < MAX_DISKS; i++)
        hd_filename[i] = NULL;
951
    ram_size = 32 * 1024 * 1024;
952
    vga_ram_size = VGA_RAM_SIZE;
953
#if defined (TARGET_I386)
bellard's avatar
bellard committed
954
    pstrcpy(network_script, sizeof(network_script), DEFAULT_NETWORK_SCRIPT);
955
#endif
bellard's avatar
bellard committed
956
957
    use_gdbstub = 0;
    gdbstub_port = DEFAULT_GDBSTUB_PORT;
958
    snapshot = 0;
959
960
961
    nographic = 0;
    kernel_filename = NULL;
    kernel_cmdline = "";
962
    for(;;) {
963
        c = getopt_long_only(argc, argv, "hm:dn:sp:L:", long_options, &long_index);
964
965
966
        if (c == -1)
            break;
        switch(c) {
bellard's avatar
bellard committed
967
968
969
970
971
972
973
974
975
976
977
        case 0:
            switch(long_index) {
            case 0:
                initrd_filename = optarg;
                break;
            case 1:
                hd_filename[0] = optarg;
                break;
            case 2:
                hd_filename[1] = optarg;
                break;
978
979
980
            case 3:
                snapshot = 1;
                break;
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
            case 4:
                {
                    int cyls, heads, secs;
                    const char *p;
                    p = optarg;
                    cyls = strtol(p, (char **)&p, 0);
                    if (*p != ',')
                        goto chs_fail;
                    p++;
                    heads = strtol(p, (char **)&p, 0);
                    if (*p != ',')
                        goto chs_fail;
                    p++;
                    secs = strtol(p, (char **)&p, 0);
                    if (*p != '\0')
                        goto chs_fail;
bellard's avatar
bellard committed
997
                    ide_set_geometry(0, cyls, heads, secs);
998
999
1000
                chs_fail: ;
                }
                break;
1001
            case 5:
1002
1003
1004
1005
1006
1007
1008
                nographic = 1;
                break;
            case 6:
                kernel_filename = optarg;
                break;
            case 7:
                kernel_cmdline = optarg;
1009
                break;
1010
#if defined (TARGET_I386)
1011
1012
1013
	    case 8:
		net_fd = atoi(optarg);
		break;
1014
#endif
1015
1016
1017
1018
1019
1020
1021
1022
            case 9:
                hd_filename[2] = optarg;
                break;
            case 10:
                hd_filename[3] = optarg;
                break;
            case 11:
                hd_filename[2] = optarg;
bellard's avatar
bellard committed
1023
                ide_set_cdrom(2, 1);
1024
1025
1026
                break;
            case 12:
                boot_device = optarg[0];
1027
1028
                if (boot_device != 'a' && boot_device != 'b' &&
                    boot_device != 'c' && boot_device != 'd') {
1029
1030
1031
1032
                    fprintf(stderr, "qemu: invalid boot device '%c'\n", boot_device);
                    exit(1);
                }
                break;
1033
1034
1035
1036
1037
1038
            case 13:
                fd_filename[0] = optarg;
                break;
            case 14:
                fd_filename[1] = optarg;
                break;
1039
1040
1041
            case 15:
                code_copy_enabled = 0;
                break;
bellard's avatar
bellard committed
1042
1043
            }
            break;
1044
1045
1046
1047
        case 'h':
            help();
            break;
        case 'm':
1048
1049
            ram_size = atoi(optarg) * 1024 * 1024;
            if (ram_size <= 0)
1050
                help();
1051
            if (ram_size > PHYS_RAM_MAX_SIZE) {
1052
                fprintf(stderr, "qemu: at most %d MB RAM can be simulated\n",
bellard's avatar
bellard committed
1053
1054
1055
                        PHYS_RAM_MAX_SIZE / (1024 * 1024));
                exit(1);
            }
1056
1057
            break;
        case 'd':
1058
            cpu_set_log(CPU_LOG_ALL);
1059
            break;
1060
#if defined (TARGET_I386)
bellard's avatar
bellard committed
1061
1062
1063
        case 'n':
            pstrcpy(network_script, sizeof(network_script), optarg);
            break;
1064
#endif
bellard's avatar
bellard committed
1065
1066
1067
1068
1069
1070
        case 's':
            use_gdbstub = 1;
            break;
        case 'p':
            gdbstub_port = atoi(optarg);
            break;
1071
        case 'L':
1072
            bios_dir = optarg;
1073
            break;
1074
1075
        }
    }
1076

1077
1078
1079
1080
1081
    if (optind < argc) {
        hd_filename[0] = argv[optind++];
    }

    linux_boot = (kernel_filename != NULL);
1082
        
1083
1084
    if (!linux_boot && hd_filename[0] == '\0' && hd_filename[2] == '\0' &&
        fd_filename[0] == '\0')
1085
        help();
1086
1087
    
    /* boot to cd by default if no hard disk */
bellard's avatar
bellard committed
1088
1089
1090
1091
1092
1093
    if (hd_filename[0] == '\0' && boot_device == 'c') {
        if (fd_filename[0] != '\0')
            boot_device = 'a';
        else
            boot_device = 'd';
    }
1094

1095
1096
1097
1098
1099
1100
1101
#if !defined(CONFIG_SOFTMMU)
    /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
    {
        static uint8_t stdout_buf[4096];
        setvbuf(stdout, stdout_buf, _IOLBF, sizeof(stdout_buf));
    }
#else
bellard's avatar
bellard committed
1102
    setvbuf(stdout, NULL, _IOLBF, 0);
1103
#endif
1104

bellard's avatar
bellard committed
1105
    /* init network tun interface */
1106
#if defined (TARGET_I386)
1107
1108
    if (net_fd < 0)
	net_init();
1109
#endif
bellard's avatar
bellard committed
1110

1111
    /* init the memory */
1112
    phys_ram_size = ram_size + vga_ram_size;
bellard's avatar
bellard committed
1113
1114

#ifdef CONFIG_SOFTMMU
1115
    phys_ram_base = memalign(TARGET_PAGE_SIZE, phys_ram_size);
bellard's avatar
bellard committed
1116
1117
    if (!phys_ram_base) {
        fprintf(stderr, "Could not allocate physical memory\n");
1118
1119
        exit(1);
    }
bellard's avatar
bellard committed
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
#else
    /* as we must map the same page at several addresses, we must use
       a fd */
    {
        const char *tmpdir;

        tmpdir = getenv("QEMU_TMPDIR");
        if (!tmpdir)
            tmpdir = "/tmp";
        snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/vlXXXXXX", tmpdir);
        if (mkstemp(phys_ram_file) < 0) {
            fprintf(stderr, "Could not create temporary memory file '%s'\n", 
                    phys_ram_file);
            exit(1);
        }
        phys_ram_fd = open(phys_ram_file, O_CREAT | O_TRUNC | O_RDWR, 0600);
        if (phys_ram_fd < 0) {
            fprintf(stderr, "Could not open temporary memory file '%s'\n", 
                    phys_ram_file);
            exit(1);
        }
1141
        ftruncate(phys_ram_fd, phys_ram_size);
bellard's avatar
bellard committed
1142
        unlink(phys_ram_file);
1143
1144
        phys_ram_base = mmap(get_mmap_addr(phys_ram_size), 
                             phys_ram_size, 
bellard's avatar
bellard committed
1145
1146
1147
1148
1149
1150
1151
1152
                             PROT_WRITE | PROT_READ, MAP_SHARED | MAP_FIXED, 
                             phys_ram_fd, 0);
        if (phys_ram_base == MAP_FAILED) {
            fprintf(stderr, "Could not map physical memory\n");
            exit(1);
        }
    }
#endif
1153

1154
1155
1156
1157
1158
    /* open the virtual block devices */
    for(i = 0; i < MAX_DISKS; i++) {
        if (hd_filename[i]) {
            bs_table[i] = bdrv_open(hd_filename[i], snapshot);
            if (!bs_table[i]) {
1159
                fprintf(stderr, "qemu: could not open hard disk image '%s\n",
1160
1161
1162
1163
1164
1165
                        hd_filename[i]);
                exit(1);
            }
        }
    }

1166
1167
1168
1169
1170
1171
    /* init CPU state */
    env = cpu_init();
    global_env = env;
    cpu_single_env = env;

    init_ioports();
bellard's avatar
bellard committed
1172
    cpu_calibrate_ticks();
1173

1174
    /* terminal init */
1175
    if (nographic) {
1176
1177
1178
1179
1180
1181
1182
1183
        dumb_display_init(ds);
    } else {
#ifdef CONFIG_SDL
        sdl_display_init(ds);
#else
        dumb_display_init(ds);
#endif
    }
1184

bellard's avatar
bellard committed
1185
1186
1187
1188
1189
1190
#if defined(TARGET_I386)
    pc_init(ram_size, vga_ram_size, boot_device,
            ds, fd_filename, snapshot,
            kernel_filename, kernel_cmdline, initrd_filename);
#elif defined(TARGET_PPC)
    ppc_init