X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/3a1bc175ea78fed181fae643fef47de06ce9a412..91d848ebf3bc7fd73fb1a4fc11bdb04225b3f37d:/vl.c diff --git a/vl.c b/vl.c index 18f957dccf..3dee9d32c8 100644 --- a/vl.c +++ b/vl.c @@ -23,7 +23,6 @@ */ #include "vl.h" -#include #include #include #include @@ -94,6 +93,11 @@ extern void __sigaction(); #define PHYS_RAM_MAX_SIZE (2047 * 1024 * 1024) #endif +#ifdef TARGET_PPC +#define DEFAULT_RAM_SIZE 144 +#else +#define DEFAULT_RAM_SIZE 32 +#endif /* in ms */ #define GUI_REFRESH_INTERVAL 30 @@ -109,11 +113,12 @@ IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS]; IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS]; BlockDriverState *bs_table[MAX_DISKS], *fd_table[MAX_FD]; int vga_ram_size; +int bios_size; static DisplayState display_state; int nographic; int64_t ticks_per_sec; int boot_device = 'c'; -static int ram_size; +int ram_size; static char network_script[1024]; int pit_min_timer_count = 0; int nb_nics; @@ -122,6 +127,13 @@ SerialState *serial_console; QEMUTimer *gui_timer; int vm_running; int audio_enabled = 0; +int pci_enabled = 1; +int prep_enabled = 0; +int rtc_utc = 1; +int cirrus_vga_enabled = 0; +int graphic_width = 640; +int graphic_height = 480; +int graphic_depth = 15; /***********************************************************/ /* x86 ISA bus support */ @@ -239,6 +251,21 @@ int register_ioport_write(int start, int length, int size, return 0; } +void isa_unassign_ioport(int start, int length) +{ + int i; + + for(i = start; i < start + length; i++) { + ioport_read_table[0][i] = default_ioport_readb; + ioport_read_table[1][i] = default_ioport_readw; + ioport_read_table[2][i] = default_ioport_readl; + + ioport_write_table[0][i] = default_ioport_writeb; + ioport_write_table[1][i] = default_ioport_writew; + ioport_write_table[2][i] = default_ioport_writel; + } +} + void pstrcpy(char *buf, int buf_size, const char *str) { int c; @@ -266,6 +293,18 @@ char *pstrcat(char *buf, int buf_size, const char *s) return buf; } +/* return the size or -1 if error */ +int get_image_size(const char *filename) +{ + int fd, size; + fd = open(filename, O_RDONLY | O_BINARY); + if (fd < 0) + return -1; + size = lseek(fd, 0, SEEK_END); + close(fd); + return size; +} + /* return the size or -1 if error */ int load_image(const char *filename, uint8_t *addr) { @@ -361,6 +400,41 @@ void hw_error(const char *fmt, ...) abort(); } +/***********************************************************/ +/* keyboard/mouse */ + +static QEMUPutKBDEvent *qemu_put_kbd_event; +static void *qemu_put_kbd_event_opaque; +static QEMUPutMouseEvent *qemu_put_mouse_event; +static void *qemu_put_mouse_event_opaque; + +void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque) +{ + qemu_put_kbd_event_opaque = opaque; + qemu_put_kbd_event = func; +} + +void qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, void *opaque) +{ + qemu_put_mouse_event_opaque = opaque; + qemu_put_mouse_event = func; +} + +void kbd_put_keycode(int keycode) +{ + if (qemu_put_kbd_event) { + qemu_put_kbd_event(qemu_put_kbd_event_opaque, keycode); + } +} + +void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) +{ + if (qemu_put_mouse_event) { + qemu_put_mouse_event(qemu_put_mouse_event_opaque, + dx, dy, dz, buttons_state); + } +} + /***********************************************************/ /* timers */ @@ -724,10 +798,12 @@ static void host_alarm_handler(int host_signum) #ifndef _WIN32 +#if defined(__linux__) + #define RTC_FREQ 1024 static int rtc_fd; - + static int start_rtc_timer(void) { rtc_fd = open("/dev/rtc", O_RDONLY); @@ -748,7 +824,16 @@ static int start_rtc_timer(void) return 0; } -#endif +#else + +static int start_rtc_timer(void) +{ + return -1; +} + +#endif /* !defined(__linux__) */ + +#endif /* !defined(_WIN32) */ static void init_timers(void) { @@ -847,12 +932,17 @@ int serial_open_device(void) /* use console for serial port */ return 0; } else { +#if 0 + /* Not satisfying */ if (openpty(&master_fd, &slave_fd, slave_name, NULL, NULL) < 0) { fprintf(stderr, "warning: could not create pseudo terminal for serial port\n"); return -1; } fprintf(stderr, "Serial port redirected to %s\n", slave_name); return master_fd; +#else + return -1; +#endif } } @@ -1744,6 +1834,62 @@ void vm_stop(int reason) } } +/* reset/shutdown handler */ + +typedef struct QEMUResetEntry { + QEMUResetHandler *func; + void *opaque; + struct QEMUResetEntry *next; +} QEMUResetEntry; + +static QEMUResetEntry *first_reset_entry; +static int reset_requested; +static int shutdown_requested; + +void qemu_register_reset(QEMUResetHandler *func, void *opaque) +{ + QEMUResetEntry **pre, *re; + + pre = &first_reset_entry; + while (*pre != NULL) + pre = &(*pre)->next; + re = qemu_mallocz(sizeof(QEMUResetEntry)); + re->func = func; + re->opaque = opaque; + re->next = NULL; + *pre = re; +} + +void qemu_system_reset(void) +{ + QEMUResetEntry *re; + + /* reset all devices */ + for(re = first_reset_entry; re != NULL; re = re->next) { + re->func(re->opaque); + } +} + +void qemu_system_reset_request(void) +{ + reset_requested = 1; + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); +} + +void qemu_system_shutdown_request(void) +{ + shutdown_requested = 1; + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); +} + +static void main_cpu_reset(void *opaque) +{ +#ifdef TARGET_I386 + CPUState *env = opaque; + cpu_reset(env); +#endif +} + int main_loop(void) { #ifndef _WIN32 @@ -1758,10 +1904,15 @@ int main_loop(void) for(;;) { if (vm_running) { ret = cpu_exec(env); - if (reset_requested) { + if (shutdown_requested) { ret = EXCP_INTERRUPT; break; } + if (reset_requested) { + reset_requested = 0; + qemu_system_reset(); + ret = EXCP_INTERRUPT; + } if (ret == EXCP_DEBUG) { vm_stop(EXCP_DEBUG); } @@ -1821,7 +1972,7 @@ int main_loop(void) n = read(ioh->fd, buf, ioh->max_size); if (n >= 0) { ioh->fd_read(ioh->opaque, buf, n); - } else if (errno != -EAGAIN) { + } else if (errno != EAGAIN) { ioh->fd_read(ioh->opaque, NULL, -errno); } } @@ -1888,9 +2039,14 @@ void help(void) "-cdrom file use 'file' as IDE cdrom image (cdrom is ide1 master)\n" "-boot [a|b|c|d] boot on floppy (a, b), hard disk (c) or CD-ROM (d)\n" "-snapshot write to temporary files instead of disk image files\n" - "-m megs set virtual RAM size to megs MB\n" + "-m megs set virtual RAM size to megs MB [default=%d]\n" "-nographic disable graphical output and redirect serial I/Os to console\n" "-enable-audio enable audio support\n" + "-localtime set the real time clock to local time [default=utc]\n" +#ifdef TARGET_PPC + "-prep Simulate a PREP system (default is PowerMAC)\n" + "-g WxH[xDEPTH] Set the initial VGA graphic mode\n" +#endif "\n" "Network options:\n" "-nics n simulate 'n' network cards [default=1]\n" @@ -1908,6 +2064,7 @@ void help(void) "-initrd file use 'file' as initial ram disk\n" "\n" "Debug/Expert options:\n" + "-S freeze CPU at startup (use 'c' to start execution)\n" "-s wait gdb connection to port %d\n" "-p port change gdb connection port\n" "-d item1,... output log to %s (use -d ? for a list of log items)\n" @@ -1916,7 +2073,9 @@ void help(void) #ifdef USE_CODE_COPY "-no-code-copy disable code copy acceleration\n" #endif - +#ifdef TARGET_I386 + "-isa simulate an ISA-only system (default is PCI system)\n" +#endif "\n" "During emulation, use C-a h to get terminal commands:\n", #ifdef CONFIG_SOFTMMU @@ -1924,7 +2083,8 @@ void help(void) #else "qemu-fast", #endif - DEFAULT_NETWORK_SCRIPT, + DEFAULT_RAM_SIZE, + DEFAULT_NETWORK_SCRIPT, DEFAULT_GDBSTUB_PORT, "/tmp/qemu.log"); term_print_help(); @@ -1937,29 +2097,103 @@ void help(void) exit(1); } -struct option long_options[] = { - { "initrd", 1, NULL, 0, }, - { "hda", 1, NULL, 0, }, - { "hdb", 1, NULL, 0, }, - { "snapshot", 0, NULL, 0, }, - { "hdachs", 1, NULL, 0, }, - { "nographic", 0, NULL, 0, }, - { "kernel", 1, NULL, 0, }, - { "append", 1, NULL, 0, }, - { "tun-fd", 1, NULL, 0, }, - { "hdc", 1, NULL, 0, }, - { "hdd", 1, NULL, 0, }, - { "cdrom", 1, NULL, 0, }, - { "boot", 1, NULL, 0, }, - { "fda", 1, NULL, 0, }, - { "fdb", 1, NULL, 0, }, - { "no-code-copy", 0, NULL, 0 }, - { "nics", 1, NULL, 0 }, - { "macaddr", 1, NULL, 0 }, - { "user-net", 0, NULL, 0 }, - { "dummy-net", 0, NULL, 0 }, - { "enable-audio", 0, NULL, 0 }, - { NULL, 0, NULL, 0 }, +#define HAS_ARG 0x0001 + +enum { + QEMU_OPTION_h, + + QEMU_OPTION_fda, + QEMU_OPTION_fdb, + QEMU_OPTION_hda, + QEMU_OPTION_hdb, + QEMU_OPTION_hdc, + QEMU_OPTION_hdd, + QEMU_OPTION_cdrom, + QEMU_OPTION_boot, + QEMU_OPTION_snapshot, + QEMU_OPTION_m, + QEMU_OPTION_nographic, + QEMU_OPTION_enable_audio, + + QEMU_OPTION_nics, + QEMU_OPTION_macaddr, + QEMU_OPTION_n, + QEMU_OPTION_tun_fd, + QEMU_OPTION_user_net, + QEMU_OPTION_dummy_net, + + QEMU_OPTION_kernel, + QEMU_OPTION_append, + QEMU_OPTION_initrd, + + QEMU_OPTION_S, + QEMU_OPTION_s, + QEMU_OPTION_p, + QEMU_OPTION_d, + QEMU_OPTION_hdachs, + QEMU_OPTION_L, + QEMU_OPTION_no_code_copy, + QEMU_OPTION_pci, + QEMU_OPTION_isa, + QEMU_OPTION_prep, + QEMU_OPTION_localtime, + QEMU_OPTION_cirrusvga, + QEMU_OPTION_g, +}; + +typedef struct QEMUOption { + const char *name; + int flags; + int index; +} QEMUOption; + +const QEMUOption qemu_options[] = { + { "h", 0, QEMU_OPTION_h }, + + { "fda", HAS_ARG, QEMU_OPTION_fda }, + { "fdb", HAS_ARG, QEMU_OPTION_fdb }, + { "hda", HAS_ARG, QEMU_OPTION_hda }, + { "hdb", HAS_ARG, QEMU_OPTION_hdb }, + { "hdc", HAS_ARG, QEMU_OPTION_hdc }, + { "hdd", HAS_ARG, QEMU_OPTION_hdd }, + { "cdrom", HAS_ARG, QEMU_OPTION_cdrom }, + { "boot", HAS_ARG, QEMU_OPTION_boot }, + { "snapshot", 0, QEMU_OPTION_snapshot }, + { "m", HAS_ARG, QEMU_OPTION_m }, + { "nographic", 0, QEMU_OPTION_nographic }, + { "enable-audio", 0, QEMU_OPTION_enable_audio }, + + { "nics", HAS_ARG, QEMU_OPTION_nics}, + { "macaddr", HAS_ARG, QEMU_OPTION_macaddr}, + { "n", HAS_ARG, QEMU_OPTION_n }, + { "tun-fd", HAS_ARG, QEMU_OPTION_tun_fd }, +#ifdef CONFIG_SLIRP + { "user-net", 0, QEMU_OPTION_user_net }, +#endif + { "dummy-net", 0, QEMU_OPTION_dummy_net }, + + { "kernel", HAS_ARG, QEMU_OPTION_kernel }, + { "append", HAS_ARG, QEMU_OPTION_append }, + { "initrd", HAS_ARG, QEMU_OPTION_initrd }, + + { "S", 0, QEMU_OPTION_S }, + { "s", 0, QEMU_OPTION_s }, + { "p", HAS_ARG, QEMU_OPTION_p }, + { "d", HAS_ARG, QEMU_OPTION_d }, + { "hdachs", HAS_ARG, QEMU_OPTION_hdachs }, + { "L", HAS_ARG, QEMU_OPTION_L }, + { "no-code-copy", 0, QEMU_OPTION_no_code_copy }, +#ifdef TARGET_PPC + { "prep", 0, QEMU_OPTION_prep }, + { "g", 1, QEMU_OPTION_g }, +#endif + { "localtime", 0, QEMU_OPTION_localtime }, + { "isa", 0, QEMU_OPTION_isa }, + + /* temporary options */ + { "pci", 0, QEMU_OPTION_pci }, + { "cirrusvga", 0, QEMU_OPTION_cirrusvga }, + { NULL }, }; #if defined (TARGET_I386) && defined(USE_CODE_COPY) @@ -1980,7 +2214,7 @@ int main(int argc, char **argv) #ifdef CONFIG_GDBSTUB int use_gdbstub, gdbstub_port; #endif - int c, i, long_index, has_cdrom; + int i, has_cdrom; int snapshot, linux_boot; CPUState *env; const char *initrd_filename; @@ -1991,7 +2225,9 @@ int main(int argc, char **argv) int start_emulation = 1; uint8_t macaddr[6]; int net_if_type, nb_tun_fds, tun_fds[MAX_NICS]; - + int optind; + const char *r, *optarg; + #if !defined(CONFIG_SOFTMMU) /* we never want that malloc() uses mmap() */ mallopt(M_MMAP_THRESHOLD, 4096 * 1024); @@ -2001,8 +2237,9 @@ int main(int argc, char **argv) fd_filename[i] = NULL; for(i = 0; i < MAX_DISKS; i++) hd_filename[i] = NULL; - ram_size = 32 * 1024 * 1024; + ram_size = DEFAULT_RAM_SIZE * 1024 * 1024; vga_ram_size = VGA_RAM_SIZE; + bios_size = BIOS_SIZE; pstrcpy(network_script, sizeof(network_script), DEFAULT_NETWORK_SCRIPT); #ifdef CONFIG_GDBSTUB use_gdbstub = 0; @@ -2026,27 +2263,53 @@ int main(int argc, char **argv) macaddr[4] = 0x34; macaddr[5] = 0x56; - + optind = 1; for(;;) { - c = getopt_long_only(argc, argv, "hm:d:n:sp:L:S", long_options, &long_index); - if (c == -1) + if (optind >= argc) break; - switch(c) { - case 0: - switch(long_index) { - case 0: + r = argv[optind]; + if (r[0] != '-') { + hd_filename[0] = argv[optind++]; + } else { + const QEMUOption *popt; + + optind++; + popt = qemu_options; + for(;;) { + if (!popt->name) { + fprintf(stderr, "%s: invalid option -- '%s'\n", + argv[0], r); + exit(1); + } + if (!strcmp(popt->name, r + 1)) + break; + popt++; + } + if (popt->flags & HAS_ARG) { + if (optind >= argc) { + fprintf(stderr, "%s: option '%s' requires an argument\n", + argv[0], r); + exit(1); + } + optarg = argv[optind++]; + } else { + optarg = NULL; + } + + switch(popt->index) { + case QEMU_OPTION_initrd: initrd_filename = optarg; break; - case 1: + case QEMU_OPTION_hda: hd_filename[0] = optarg; break; - case 2: + case QEMU_OPTION_hdb: hd_filename[1] = optarg; break; - case 3: + case QEMU_OPTION_snapshot: snapshot = 1; break; - case 4: + case QEMU_OPTION_hdachs: { const char *p; p = optarg; @@ -2065,19 +2328,20 @@ int main(int argc, char **argv) } } break; - case 5: + case QEMU_OPTION_nographic: nographic = 1; break; - case 6: + case QEMU_OPTION_kernel: kernel_filename = optarg; break; - case 7: + case QEMU_OPTION_append: kernel_cmdline = optarg; break; - case 8: + case QEMU_OPTION_tun_fd: { const char *p; int fd; + net_if_type = NET_IF_TUN; if (nb_tun_fds < MAX_NICS) { fd = strtol(optarg, (char **)&p, 0); if (*p != '\0') { @@ -2088,18 +2352,18 @@ int main(int argc, char **argv) } } break; - case 9: + case QEMU_OPTION_hdc: hd_filename[2] = optarg; has_cdrom = 0; break; - case 10: + case QEMU_OPTION_hdd: hd_filename[3] = optarg; break; - case 11: + case QEMU_OPTION_cdrom: hd_filename[2] = optarg; has_cdrom = 1; break; - case 12: + case QEMU_OPTION_boot: boot_device = optarg[0]; if (boot_device != 'a' && boot_device != 'b' && boot_device != 'c' && boot_device != 'd') { @@ -2107,23 +2371,23 @@ int main(int argc, char **argv) exit(1); } break; - case 13: + case QEMU_OPTION_fda: fd_filename[0] = optarg; break; - case 14: + case QEMU_OPTION_fdb: fd_filename[1] = optarg; break; - case 15: + case QEMU_OPTION_no_code_copy: code_copy_enabled = 0; break; - case 16: + case QEMU_OPTION_nics: nb_nics = atoi(optarg); if (nb_nics < 0 || nb_nics > MAX_NICS) { fprintf(stderr, "qemu: invalid number of network interfaces\n"); exit(1); } break; - case 17: + case QEMU_OPTION_macaddr: { const char *p; int i; @@ -2144,70 +2408,114 @@ int main(int argc, char **argv) } } break; - case 18: + case QEMU_OPTION_user_net: net_if_type = NET_IF_USER; break; - case 19: + case QEMU_OPTION_dummy_net: net_if_type = NET_IF_DUMMY; break; - case 20: + case QEMU_OPTION_enable_audio: audio_enabled = 1; break; - } - break; - case 'h': - help(); - break; - case 'm': - ram_size = atoi(optarg) * 1024 * 1024; - if (ram_size <= 0) + case QEMU_OPTION_h: help(); - if (ram_size > PHYS_RAM_MAX_SIZE) { - fprintf(stderr, "qemu: at most %d MB RAM can be simulated\n", - PHYS_RAM_MAX_SIZE / (1024 * 1024)); - exit(1); - } - break; - case 'd': - { - int mask; - CPULogItem *item; - - mask = cpu_str_to_log_mask(optarg); - if (!mask) { - printf("Log items (comma separated):\n"); + break; + case QEMU_OPTION_m: + ram_size = atoi(optarg) * 1024 * 1024; + if (ram_size <= 0) + help(); + if (ram_size > PHYS_RAM_MAX_SIZE) { + fprintf(stderr, "qemu: at most %d MB RAM can be simulated\n", + PHYS_RAM_MAX_SIZE / (1024 * 1024)); + exit(1); + } + break; + case QEMU_OPTION_d: + { + int mask; + CPULogItem *item; + + mask = cpu_str_to_log_mask(optarg); + if (!mask) { + printf("Log items (comma separated):\n"); for(item = cpu_log_items; item->mask != 0; item++) { printf("%-10s %s\n", item->name, item->help); } exit(1); + } + cpu_set_log(mask); } - cpu_set_log(mask); - } - break; - case 'n': - pstrcpy(network_script, sizeof(network_script), optarg); - break; + break; + case QEMU_OPTION_n: + pstrcpy(network_script, sizeof(network_script), optarg); + break; #ifdef CONFIG_GDBSTUB - case 's': - use_gdbstub = 1; - break; - case 'p': - gdbstub_port = atoi(optarg); - break; + case QEMU_OPTION_s: + use_gdbstub = 1; + break; + case QEMU_OPTION_p: + gdbstub_port = atoi(optarg); + break; #endif - case 'L': - bios_dir = optarg; - break; - case 'S': - start_emulation = 0; - break; + case QEMU_OPTION_L: + bios_dir = optarg; + break; + case QEMU_OPTION_S: + start_emulation = 0; + break; + case QEMU_OPTION_pci: + pci_enabled = 1; + break; + case QEMU_OPTION_isa: + pci_enabled = 0; + break; + case QEMU_OPTION_prep: + prep_enabled = 1; + break; + case QEMU_OPTION_localtime: + rtc_utc = 0; + break; + case QEMU_OPTION_cirrusvga: + cirrus_vga_enabled = 1; + break; + case QEMU_OPTION_g: + { + const char *p; + int w, h, depth; + p = optarg; + w = strtol(p, (char **)&p, 10); + if (w <= 0) { + graphic_error: + fprintf(stderr, "qemu: invalid resolution or depth\n"); + exit(1); + } + if (*p != 'x') + goto graphic_error; + p++; + h = strtol(p, (char **)&p, 10); + if (h <= 0) + goto graphic_error; + if (*p == 'x') { + p++; + depth = strtol(p, (char **)&p, 10); + if (depth != 8 && depth != 15 && depth != 16 && + depth != 24 && depth != 32) + goto graphic_error; + } else if (*p == '\0') { + depth = graphic_depth; + } else { + goto graphic_error; + } + + graphic_width = w; + graphic_height = h; + graphic_depth = depth; + } + break; + } } } - if (optind < argc) { - hd_filename[0] = argv[optind++]; - } - linux_boot = (kernel_filename != NULL); if (!linux_boot && hd_filename[0] == '\0' && hd_filename[2] == '\0' && @@ -2276,7 +2584,7 @@ int main(int argc, char **argv) } /* init the memory */ - phys_ram_size = ram_size + vga_ram_size; + phys_ram_size = ram_size + vga_ram_size + bios_size; #ifdef CONFIG_SOFTMMU #ifdef _BSD @@ -2377,6 +2685,7 @@ int main(int argc, char **argv) register_savevm("timer", 0, 1, timer_save, timer_load, env); register_savevm("cpu", 0, 1, cpu_save, cpu_load, env); register_savevm("ram", 0, 1, ram_save, ram_load, NULL); + qemu_register_reset(main_cpu_reset, global_env); init_ioports(); cpu_calibrate_ticks();