This is very much work in progress, it does not compile yet. However, the only target dependencies remaining are QEMU_OPTION_xxx enums and the target specific option handling in the option parsing loop. I haven't got a good plan for that, except maybe QEMUOption structure could have a field that specifies for which targets the option is valid. Any ideas?
There also are some pieces (set_cpu_log, debug_requested, gdbstub.h and kvm.h cleanup, allow balloon options to all targets) that deserve separate patches. RAM handling could go to a new file, perhaps in hw/ram.c instead of arch_init.c. Comments? This depends on the various previous patches I sent. I set up a public git tree: http://repo.or.cz/w/qemu/blueswirl.git git://repo.or.cz/qemu/blueswirl.git Not-quite-signed-off-by-yet: Blue Swirl <blauwir...@gmail.com> --- Makefile.objs | 2 +- Makefile.target | 2 +- arch_init.c | 461 +++++++++++++++++++++++++++++++++++++++++++++++++++++ arch_init.h | 20 +++ balloon.h | 2 - cpu-all.h | 1 - cpus.c | 18 ++- cpus.h | 1 + gdbstub.h | 11 +- hw/smbios.c | 1 + kvm.h | 4 +- qemu-common.h | 2 + qemu-options.hx | 2 - vl.c | 475 ++++--------------------------------------------------- 14 files changed, 543 insertions(+), 459 deletions(-) create mode 100644 arch_init.c create mode 100644 arch_init.h diff --git a/Makefile.objs b/Makefile.objs index 1c360a6..4ff3214 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -127,7 +127,7 @@ user-obj-y += cutils.o cache-utils.o # libhw hw-obj-y = -hw-obj-y += loader.o +hw-obj-y += vl.o loader.o hw-obj-y += virtio.o virtio-console.o hw-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o hw-obj-y += fw_cfg.o pci.o pci_host.o pcie_host.o diff --git a/Makefile.target b/Makefile.target index 156b4bd..98cf52c 100644 --- a/Makefile.target +++ b/Makefile.target @@ -161,7 +161,7 @@ endif #CONFIG_BSD_USER # System emulator target ifdef CONFIG_SOFTMMU -obj-y = vl.o cpus.o monitor.o machine.o gdbstub.o +obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o obj-y += qemu-timer.o # virtio has to be here due to weird dependency between PCI and virtio-net. # need to fix this properly diff --git a/arch_init.c b/arch_init.c new file mode 100644 index 0000000..eb4dc07 --- /dev/null +++ b/arch_init.c @@ -0,0 +1,461 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * 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. + */ +#include <stdint.h> +#include <stdarg.h> +#include <sys/mman.h> +#include "config.h" +#include "monitor.h" +#include "sysemu.h" +#include "arch_init.h" +#include "audio/audio.h" +#include "hw/pc.h" +#include "hw/pci.h" +#include "hw/audiodev.h" +#include "kvm.h" +#include "migration.h" +#include "net.h" +#include "gdbstub.h" + +#ifdef TARGET_SPARC +int graphic_width = 1024; +int graphic_height = 768; +int graphic_depth = 8; +#else +int graphic_width = 800; +int graphic_height = 600; +int graphic_depth = 15; +#endif + +#ifdef TARGET_I386 +int rtc_td_hack = 0; +#endif + +#ifdef TARGET_ARM +int old_param = 0; +#endif + +#if defined(TARGET_SPARC) || defined(TARGET_PPC) +unsigned int nb_prom_envs = 0; +const char *prom_envs[MAX_PROM_ENVS]; +#endif + +const char arch_config_name[] = CONFIG_QEMU_CONFDIR "/target-" TARGET_ARCH ".conf"; + +/***********************************************************/ +/* ram save/restore */ + +#define RAM_SAVE_FLAG_FULL 0x01 /* Obsolete, not used anymore */ +#define RAM_SAVE_FLAG_COMPRESS 0x02 +#define RAM_SAVE_FLAG_MEM_SIZE 0x04 +#define RAM_SAVE_FLAG_PAGE 0x08 +#define RAM_SAVE_FLAG_EOS 0x10 + +static int is_dup_page(uint8_t *page, uint8_t ch) +{ + uint32_t val = ch << 24 | ch << 16 | ch << 8 | ch; + uint32_t *array = (uint32_t *)page; + int i; + + for (i = 0; i < (TARGET_PAGE_SIZE / 4); i++) { + if (array[i] != val) + return 0; + } + + return 1; +} + +static int ram_save_block(QEMUFile *f) +{ + static ram_addr_t current_addr = 0; + ram_addr_t saved_addr = current_addr; + ram_addr_t addr = 0; + int found = 0; + + while (addr < last_ram_offset) { + if (cpu_physical_memory_get_dirty(current_addr, MIGRATION_DIRTY_FLAG)) { + uint8_t *p; + + cpu_physical_memory_reset_dirty(current_addr, + current_addr + TARGET_PAGE_SIZE, + MIGRATION_DIRTY_FLAG); + + p = qemu_get_ram_ptr(current_addr); + + if (is_dup_page(p, *p)) { + qemu_put_be64(f, current_addr | RAM_SAVE_FLAG_COMPRESS); + qemu_put_byte(f, *p); + } else { + qemu_put_be64(f, current_addr | RAM_SAVE_FLAG_PAGE); + qemu_put_buffer(f, p, TARGET_PAGE_SIZE); + } + + found = 1; + break; + } + addr += TARGET_PAGE_SIZE; + current_addr = (saved_addr + addr) % last_ram_offset; + } + + return found; +} + +static uint64_t bytes_transferred; + +static ram_addr_t ram_save_remaining(void) +{ + ram_addr_t addr; + ram_addr_t count = 0; + + for (addr = 0; addr < last_ram_offset; addr += TARGET_PAGE_SIZE) { + if (cpu_physical_memory_get_dirty(addr, MIGRATION_DIRTY_FLAG)) + count++; + } + + return count; +} + +uint64_t ram_bytes_remaining(void) +{ + return ram_save_remaining() * TARGET_PAGE_SIZE; +} + +uint64_t ram_bytes_transferred(void) +{ + return bytes_transferred; +} + +uint64_t ram_bytes_total(void) +{ + return last_ram_offset; +} + +int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque) +{ + ram_addr_t addr; + uint64_t bytes_transferred_last; + double bwidth = 0; + uint64_t expected_time = 0; + + if (stage < 0) { + cpu_physical_memory_set_dirty_tracking(0); + return 0; + } + + if (cpu_physical_sync_dirty_bitmap(0, TARGET_PHYS_ADDR_MAX) != 0) { + qemu_file_set_error(f); + return 0; + } + + if (stage == 1) { + bytes_transferred = 0; + + /* Make sure all dirty bits are set */ + for (addr = 0; addr < last_ram_offset; addr += TARGET_PAGE_SIZE) { + if (!cpu_physical_memory_get_dirty(addr, MIGRATION_DIRTY_FLAG)) { + cpu_physical_memory_set_dirty(addr); + } + } + + /* Enable dirty memory tracking */ + cpu_physical_memory_set_dirty_tracking(1); + + qemu_put_be64(f, last_ram_offset | RAM_SAVE_FLAG_MEM_SIZE); + } + + bytes_transferred_last = bytes_transferred; + bwidth = qemu_get_clock_ns(rt_clock); + + while (!qemu_file_rate_limit(f)) { + int ret; + + ret = ram_save_block(f); + bytes_transferred += ret * TARGET_PAGE_SIZE; + if (ret == 0) { /* no more blocks */ + break; + } + } + + bwidth = qemu_get_clock_ns(rt_clock) - bwidth; + bwidth = (bytes_transferred - bytes_transferred_last) / bwidth; + + /* if we haven't transferred anything this round, force expected_time to a + * a very high value, but without crashing */ + if (bwidth == 0) + bwidth = 0.000001; + + /* try transferring iterative blocks of memory */ + if (stage == 3) { + /* flush all remaining blocks regardless of rate limiting */ + while (ram_save_block(f) != 0) { + bytes_transferred += TARGET_PAGE_SIZE; + } + cpu_physical_memory_set_dirty_tracking(0); + } + + qemu_put_be64(f, RAM_SAVE_FLAG_EOS); + + expected_time = ram_save_remaining() * TARGET_PAGE_SIZE / bwidth; + + return (stage == 2) && (expected_time <= migrate_max_downtime()); +} + +int ram_load(QEMUFile *f, void *opaque, int version_id) +{ + ram_addr_t addr; + int flags; + + if (version_id != 3) { + return -EINVAL; + } + + do { + addr = qemu_get_be64(f); + + flags = addr & ~TARGET_PAGE_MASK; + addr &= TARGET_PAGE_MASK; + + if (flags & RAM_SAVE_FLAG_MEM_SIZE) { + if (addr != last_ram_offset) + return -EINVAL; + } + + if (flags & RAM_SAVE_FLAG_COMPRESS) { + uint8_t ch = qemu_get_byte(f); + memset(qemu_get_ram_ptr(addr), ch, TARGET_PAGE_SIZE); +#ifndef _WIN32 + if (ch == 0 && + (!kvm_enabled() || kvm_has_sync_mmu())) { + madvise(qemu_get_ram_ptr(addr), TARGET_PAGE_SIZE, MADV_DONTNEED); + } +#endif + } else if (flags & RAM_SAVE_FLAG_PAGE) { + qemu_get_buffer(f, qemu_get_ram_ptr(addr), TARGET_PAGE_SIZE); + } + if (qemu_file_has_error(f)) { + return -EIO; + } + } while (!(flags & RAM_SAVE_FLAG_EOS)); + + return 0; +} + +void qemu_service_io(void) +{ + qemu_notify_event(); +} + +#ifdef HAS_AUDIO +struct soundhw soundhw[] = { +#ifdef HAS_AUDIO_CHOICE +#if defined(TARGET_I386) || defined(TARGET_MIPS) + { + "pcspk", + "PC speaker", + 0, + 1, + { .init_isa = pcspk_audio_init } + }, +#endif + +#ifdef CONFIG_SB16 + { + "sb16", + "Creative Sound Blaster 16", + 0, + 1, + { .init_isa = SB16_init } + }, +#endif + +#ifdef CONFIG_CS4231A + { + "cs4231a", + "CS4231A", + 0, + 1, + { .init_isa = cs4231a_init } + }, +#endif + +#ifdef CONFIG_ADLIB + { + "adlib", +#ifdef HAS_YMF262 + "Yamaha YMF262 (OPL3)", +#else + "Yamaha YM3812 (OPL2)", +#endif + 0, + 1, + { .init_isa = Adlib_init } + }, +#endif + +#ifdef CONFIG_GUS + { + "gus", + "Gravis Ultrasound GF1", + 0, + 1, + { .init_isa = GUS_init } + }, +#endif + +#ifdef CONFIG_AC97 + { + "ac97", + "Intel 82801AA AC97 Audio", + 0, + 0, + { .init_pci = ac97_init } + }, +#endif + +#ifdef CONFIG_ES1370 + { + "es1370", + "ENSONIQ AudioPCI ES1370", + 0, + 0, + { .init_pci = es1370_init } + }, +#endif + +#endif /* HAS_AUDIO_CHOICE */ + + { NULL, NULL, 0, 0, { NULL } } +}; + +void select_soundhw(const char *optarg) +{ + struct soundhw *c; + + if (*optarg == '?') { + show_valid_cards: + + printf("Valid sound card names (comma separated):\n"); + for (c = soundhw; c->name; ++c) { + printf ("%-11s %s\n", c->name, c->descr); + } + printf("\n-soundhw all will enable all of the above\n"); + exit(*optarg != '?'); + } + else { + size_t l; + const char *p; + char *e; + int bad_card = 0; + + if (!strcmp(optarg, "all")) { + for (c = soundhw; c->name; ++c) { + c->enabled = 1; + } + return; + } + + p = optarg; + while (*p) { + e = strchr(p, ','); + l = !e ? strlen(p) : (size_t) (e - p); + + for (c = soundhw; c->name; ++c) { + if (!strncmp(c->name, p, l) && !c->name[l]) { + c->enabled = 1; + break; + } + } + + if (!c->name) { + if (l > 80) { + fprintf(stderr, + "Unknown sound card name (too big to show)\n"); + } + else { + fprintf(stderr, "Unknown sound card name `%.*s'\n", + (int) l, p); + } + bad_card = 1; + } + p += l + (e != NULL); + } + + if (bad_card) { + goto show_valid_cards; + } + } +} +#endif + +void help(int exitcode) +{ + const char *options_help = +#define DEF(option, opt_arg, opt_enum, opt_help) \ + opt_help +#define DEFHEADING(text) stringify(text) "\n" +#include "qemu-options.h" +#undef DEF +#undef DEFHEADING +#undef GEN_DOCS + ; + version(); + printf("usage: %s [options] [disk_image]\n" + "\n" + "'disk_image' is a raw hard image image for IDE hard disk 0\n" + "\n" + "%s\n" + "During emulation, the following keys are useful:\n" + "ctrl-alt-f toggle full screen\n" + "ctrl-alt-n switch to virtual console 'n'\n" + "ctrl-alt toggle mouse and keyboard grab\n" + "\n" + "When using -nographic, press 'ctrl-a h' to get some help.\n", + "qemu", + options_help); + exit(exitcode); +} + +#define HAS_ARG 0x0001 + +enum { +#define DEF(option, opt_arg, opt_enum, opt_help) \ + opt_enum, +#define DEFHEADING(text) +#include "qemu-options.h" +#undef DEF +#undef DEFHEADING +#undef GEN_DOCS +}; + +const QEMUOption qemu_options[] = { + { "h", 0, QEMU_OPTION_h }, +#define DEF(option, opt_arg, opt_enum, opt_help) \ + { option, opt_arg, opt_enum }, +#define DEFHEADING(text) +#include "qemu-options.h" +#undef DEF +#undef DEFHEADING +#undef GEN_DOCS + { NULL }, +}; + diff --git a/arch_init.h b/arch_init.h new file mode 100644 index 0000000..67d504b --- /dev/null +++ b/arch_init.h @@ -0,0 +1,20 @@ +#ifndef QEMU_ARCH_INIT_H +#define QEMU_ARCH_INIT_H + +extern const char arch_config_name[]; + +typedef struct QEMUOption { + const char *name; + int flags; + int index; +} QEMUOption; + +extern const QEMUOption qemu_options[]; + +void select_soundhw(const char *optarg); +int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque); +int ram_load(QEMUFile *f, void *opaque, int version_id); +void help(int exitcode); +void version(void); + +#endif diff --git a/balloon.h b/balloon.h index c3a1ad3..8c019eb 100644 --- a/balloon.h +++ b/balloon.h @@ -14,8 +14,6 @@ #ifndef _QEMU_BALLOON_H #define _QEMU_BALLOON_H -#include "cpu-defs.h" - typedef void (QEMUBalloonEvent)(void *opaque, ram_addr_t target, MonitorCompletion cb, void *cb_data); diff --git a/cpu-all.h b/cpu-all.h index f281a91..9942d49 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -756,7 +756,6 @@ void page_set_flags(target_ulong start, target_ulong end, int flags); int page_check_range(target_ulong start, target_ulong len, int flags); #endif -void cpu_exec_init_all(unsigned long tb_size); CPUState *cpu_copy(CPUState *env); CPUState *qemu_get_cpu(int cpu); diff --git a/cpus.c b/cpus.c index c7b0520..9a8c2f7 100644 --- a/cpus.c +++ b/cpus.c @@ -735,7 +735,7 @@ bool tcg_cpu_exec(void) if (ret == EXCP_DEBUG) { gdb_set_stop_cpu(env); - debug_requested = 1; + debug_requested = EXCP_DEBUG; break; } } @@ -755,3 +755,19 @@ void set_numa_modes(void) } } } + +void set_cpu_log(const char *optarg) +{ + int mask; + const 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); +} diff --git a/cpus.h b/cpus.h index e543b30..67c9a3b 100644 --- a/cpus.h +++ b/cpus.h @@ -13,5 +13,6 @@ extern int debug_requested; void vm_state_notify(int running, int reason); bool tcg_cpu_exec(void); void set_numa_modes(void); +void set_cpu_log(const char *optarg); #endif diff --git a/gdbstub.h b/gdbstub.h index 5740041..08fbe9c 100644 --- a/gdbstub.h +++ b/gdbstub.h @@ -10,6 +10,7 @@ #define GDB_WATCHPOINT_READ 3 #define GDB_WATCHPOINT_ACCESS 4 +#ifdef NEED_CPU_H typedef void (*gdb_syscall_complete_cb)(CPUState *env, target_ulong ret, target_ulong err); @@ -21,15 +22,19 @@ int gdb_queuesig (void); int gdb_handlesig (CPUState *, int); void gdb_exit(CPUState *, int); void gdb_signalled(CPUState *, int); -int gdbserver_start(int); void gdbserver_fork(CPUState *); -#else -int gdbserver_start(const char *port); #endif /* Get or set a register. Returns the size of the register. */ typedef int (*gdb_reg_cb)(CPUState *env, uint8_t *buf, int reg); void gdb_register_coprocessor(CPUState *env, gdb_reg_cb get_reg, gdb_reg_cb set_reg, int num_regs, const char *xml, int g_pos); +#endif + +#ifdef CONFIG_USER_ONLY +int gdbserver_start(int); +#else +int gdbserver_start(const char *port); +#endif #endif diff --git a/hw/smbios.c b/hw/smbios.c index a3ae1de..9f2fe1b 100644 --- a/hw/smbios.c +++ b/hw/smbios.c @@ -167,6 +167,7 @@ static void smbios_build_type_1_fields(const char *t) fprintf(stderr, "Invalid SMBIOS UUID string\n"); exit(1); } + smbios_add_field(1, offsetof(struct smbios_type_1, uuid), 16, buf); } if (get_param_value(buf, sizeof(buf), "sku", t)) smbios_add_field(1, offsetof(struct smbios_type_1, sku_number_str), diff --git a/kvm.h b/kvm.h index fd8d0c1..3bee843 100644 --- a/kvm.h +++ b/kvm.h @@ -14,7 +14,7 @@ #ifndef QEMU_KVM_H #define QEMU_KVM_H -#include "config.h" +#include "config-host.h" #include "qemu-queue.h" #ifdef CONFIG_KVM @@ -31,6 +31,7 @@ struct kvm_run; int kvm_init(int smp_cpus); +#ifdef NEED_CPU_H int kvm_init_vcpu(CPUState *env); int kvm_cpu_exec(CPUState *env); @@ -162,3 +163,4 @@ static inline void cpu_synchronize_post_init(CPUState *env) } #endif +#endif diff --git a/qemu-common.h b/qemu-common.h index 087c034..d881a39 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -231,6 +231,8 @@ typedef struct SSIBus SSIBus; typedef uint64_t pcibus_t; +void cpu_exec_init_all(unsigned long tb_size); + /* CPU save/load. */ void cpu_save(QEMUFile *f, void *opaque); int cpu_load(QEMUFile *f, void *opaque, int version_id); diff --git a/qemu-options.hx b/qemu-options.hx index 8450b45..c972984 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -807,12 +807,10 @@ STEXI Disable HPET support. ETEXI -#ifdef TARGET_I386 DEF("balloon", HAS_ARG, QEMU_OPTION_balloon, "-balloon none disable balloon device\n" "-balloon virtio[,addr=str]\n" " enable virtio balloon device (default)\n") -#endif STEXI @item -balloon none @findex -balloon diff --git a/vl.c b/vl.c index 2eef69e..50d419f 100644 --- a/vl.c +++ b/vl.c @@ -120,7 +120,6 @@ int main(int argc, char **argv) #include "hw/usb.h" #include "hw/pcmcia.h" #include "hw/pc.h" -#include "hw/audiodev.h" #include "hw/isa.h" #include "hw/baum.h" #include "hw/bt.h" @@ -153,14 +152,13 @@ int main(int argc, char **argv) #include "disas.h" -#include "exec-all.h" - #include "qemu_socket.h" #include "slirp/libslirp.h" #include "qemu-queue.h" #include "cpus.h" +#include "arch_init.h" //#define DEBUG_NET //#define DEBUG_SLIRP @@ -191,15 +189,6 @@ static int rtc_utc = 1; static int rtc_date_offset = -1; /* -1 means no change */ QEMUClock *rtc_clock; int vga_interface_type = VGA_NONE; -#ifdef TARGET_SPARC -int graphic_width = 1024; -int graphic_height = 768; -int graphic_depth = 8; -#else -int graphic_width = 800; -int graphic_height = 600; -int graphic_depth = 15; -#endif static int full_screen = 0; #ifdef CONFIG_SDL static int no_frame = 0; @@ -209,9 +198,6 @@ CharDriverState *serial_hds[MAX_SERIAL_PORTS]; CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; CharDriverState *virtcon_hds[MAX_VIRTIO_CONSOLES]; int win2k_install_hack = 0; -#ifdef TARGET_I386 -int rtc_td_hack = 0; -#endif int usb_enabled = 0; int singlestep = 0; int smp_cpus = 1; @@ -234,16 +220,9 @@ const char *watchdog; const char *option_rom[MAX_OPTION_ROMS]; int nb_option_roms; int semihosting_enabled = 0; -#ifdef TARGET_ARM -int old_param = 0; -#endif const char *qemu_name; int alt_grab = 0; int ctrl_grab = 0; -#if defined(TARGET_SPARC) || defined(TARGET_PPC) -unsigned int nb_prom_envs = 0; -const char *prom_envs[MAX_PROM_ENVS]; -#endif int boot_menu; int nb_numa_nodes; @@ -468,7 +447,7 @@ static void configure_rtc_date_offset(const char *startdate, int legacy) } } -static void configure_rtc(QemuOpts *opts) +static void configure_rtc(QemuOpts *opts, int driftfix) { const char *value; @@ -493,19 +472,19 @@ static void configure_rtc(QemuOpts *opts) exit(1); } } -#ifdef CONFIG_TARGET_I386 - value = qemu_opt_get(opts, "driftfix"); - if (value) { - if (!strcmp(buf, "slew")) { - rtc_td_hack = 1; - } else if (!strcmp(buf, "none")) { - rtc_td_hack = 0; - } else { - fprintf(stderr, "qemu: invalid option value '%s'\n", value); - exit(1); + if (driftfix) { + value = qemu_opt_get(opts, "driftfix"); + if (value) { + if (!strcmp(value, "slew")) { + rtc_td_hack = 1; + } else if (!strcmp(value, "none")) { + rtc_td_hack = 0; + } else { + fprintf(stderr, "qemu: invalid option value '%s'\n", value); + exit(1); + } } } -#endif } #ifdef _WIN32 @@ -1665,206 +1644,6 @@ void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque) #endif /***********************************************************/ -/* ram save/restore */ - -#define RAM_SAVE_FLAG_FULL 0x01 /* Obsolete, not used anymore */ -#define RAM_SAVE_FLAG_COMPRESS 0x02 -#define RAM_SAVE_FLAG_MEM_SIZE 0x04 -#define RAM_SAVE_FLAG_PAGE 0x08 -#define RAM_SAVE_FLAG_EOS 0x10 - -static int is_dup_page(uint8_t *page, uint8_t ch) -{ - uint32_t val = ch << 24 | ch << 16 | ch << 8 | ch; - uint32_t *array = (uint32_t *)page; - int i; - - for (i = 0; i < (TARGET_PAGE_SIZE / 4); i++) { - if (array[i] != val) - return 0; - } - - return 1; -} - -static int ram_save_block(QEMUFile *f) -{ - static ram_addr_t current_addr = 0; - ram_addr_t saved_addr = current_addr; - ram_addr_t addr = 0; - int found = 0; - - while (addr < last_ram_offset) { - if (cpu_physical_memory_get_dirty(current_addr, MIGRATION_DIRTY_FLAG)) { - uint8_t *p; - - cpu_physical_memory_reset_dirty(current_addr, - current_addr + TARGET_PAGE_SIZE, - MIGRATION_DIRTY_FLAG); - - p = qemu_get_ram_ptr(current_addr); - - if (is_dup_page(p, *p)) { - qemu_put_be64(f, current_addr | RAM_SAVE_FLAG_COMPRESS); - qemu_put_byte(f, *p); - } else { - qemu_put_be64(f, current_addr | RAM_SAVE_FLAG_PAGE); - qemu_put_buffer(f, p, TARGET_PAGE_SIZE); - } - - found = 1; - break; - } - addr += TARGET_PAGE_SIZE; - current_addr = (saved_addr + addr) % last_ram_offset; - } - - return found; -} - -static uint64_t bytes_transferred; - -static ram_addr_t ram_save_remaining(void) -{ - ram_addr_t addr; - ram_addr_t count = 0; - - for (addr = 0; addr < last_ram_offset; addr += TARGET_PAGE_SIZE) { - if (cpu_physical_memory_get_dirty(addr, MIGRATION_DIRTY_FLAG)) - count++; - } - - return count; -} - -uint64_t ram_bytes_remaining(void) -{ - return ram_save_remaining() * TARGET_PAGE_SIZE; -} - -uint64_t ram_bytes_transferred(void) -{ - return bytes_transferred; -} - -uint64_t ram_bytes_total(void) -{ - return last_ram_offset; -} - -static int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque) -{ - ram_addr_t addr; - uint64_t bytes_transferred_last; - double bwidth = 0; - uint64_t expected_time = 0; - - if (stage < 0) { - cpu_physical_memory_set_dirty_tracking(0); - return 0; - } - - if (cpu_physical_sync_dirty_bitmap(0, TARGET_PHYS_ADDR_MAX) != 0) { - qemu_file_set_error(f); - return 0; - } - - if (stage == 1) { - bytes_transferred = 0; - - /* Make sure all dirty bits are set */ - for (addr = 0; addr < last_ram_offset; addr += TARGET_PAGE_SIZE) { - if (!cpu_physical_memory_get_dirty(addr, MIGRATION_DIRTY_FLAG)) - cpu_physical_memory_set_dirty(addr); - } - - /* Enable dirty memory tracking */ - cpu_physical_memory_set_dirty_tracking(1); - - qemu_put_be64(f, last_ram_offset | RAM_SAVE_FLAG_MEM_SIZE); - } - - bytes_transferred_last = bytes_transferred; - bwidth = qemu_get_clock_ns(rt_clock); - - while (!qemu_file_rate_limit(f)) { - int ret; - - ret = ram_save_block(f); - bytes_transferred += ret * TARGET_PAGE_SIZE; - if (ret == 0) /* no more blocks */ - break; - } - - bwidth = qemu_get_clock_ns(rt_clock) - bwidth; - bwidth = (bytes_transferred - bytes_transferred_last) / bwidth; - - /* if we haven't transferred anything this round, force expected_time to a - * a very high value, but without crashing */ - if (bwidth == 0) - bwidth = 0.000001; - - /* try transferring iterative blocks of memory */ - if (stage == 3) { - /* flush all remaining blocks regardless of rate limiting */ - while (ram_save_block(f) != 0) { - bytes_transferred += TARGET_PAGE_SIZE; - } - cpu_physical_memory_set_dirty_tracking(0); - } - - qemu_put_be64(f, RAM_SAVE_FLAG_EOS); - - expected_time = ram_save_remaining() * TARGET_PAGE_SIZE / bwidth; - - return (stage == 2) && (expected_time <= migrate_max_downtime()); -} - -static int ram_load(QEMUFile *f, void *opaque, int version_id) -{ - ram_addr_t addr; - int flags; - - if (version_id != 3) - return -EINVAL; - - do { - addr = qemu_get_be64(f); - - flags = addr & ~TARGET_PAGE_MASK; - addr &= TARGET_PAGE_MASK; - - if (flags & RAM_SAVE_FLAG_MEM_SIZE) { - if (addr != last_ram_offset) - return -EINVAL; - } - - if (flags & RAM_SAVE_FLAG_COMPRESS) { - uint8_t ch = qemu_get_byte(f); - memset(qemu_get_ram_ptr(addr), ch, TARGET_PAGE_SIZE); -#ifndef _WIN32 - if (ch == 0 && - (!kvm_enabled() || kvm_has_sync_mmu())) { - madvise(qemu_get_ram_ptr(addr), TARGET_PAGE_SIZE, MADV_DONTNEED); - } -#endif - } else if (flags & RAM_SAVE_FLAG_PAGE) { - qemu_get_buffer(f, qemu_get_ram_ptr(addr), TARGET_PAGE_SIZE); - } - if (qemu_file_has_error(f)) { - return -EIO; - } - } while (!(flags & RAM_SAVE_FLAG_EOS)); - - return 0; -} - -void qemu_service_io(void) -{ - qemu_notify_event(); -} - -/***********************************************************/ /* machine registration */ static QEMUMachine *first_machine = NULL; @@ -2256,8 +2035,8 @@ static void main_loop(void) #endif } while (vm_can_run()); - if (qemu_debug_requested()) { - vm_stop(EXCP_DEBUG); + if ((r = qemu_debug_requested())) { + vm_stop(r); } if (qemu_shutdown_requested()) { monitor_protocol_event(QEVENT_SHUTDOWN, NULL); @@ -2283,39 +2062,11 @@ static void main_loop(void) pause_all_vcpus(); } -static void version(void) +void version(void) { printf("QEMU PC emulator version " QEMU_VERSION QEMU_PKGVERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n"); } -static void help(int exitcode) -{ - const char *options_help = -#define DEF(option, opt_arg, opt_enum, opt_help) \ - opt_help -#define DEFHEADING(text) stringify(text) "\n" -#include "qemu-options.h" -#undef DEF -#undef DEFHEADING -#undef GEN_DOCS - ; - version(); - printf("usage: %s [options] [disk_image]\n" - "\n" - "'disk_image' is a raw hard image image for IDE hard disk 0\n" - "\n" - "%s\n" - "During emulation, the following keys are useful:\n" - "ctrl-alt-f toggle full screen\n" - "ctrl-alt-n switch to virtual console 'n'\n" - "ctrl-alt toggle mouse and keyboard grab\n" - "\n" - "When using -nographic, press 'ctrl-a h' to get some help.\n", - "qemu", - options_help); - exit(exitcode); -} - #define HAS_ARG 0x0001 enum { @@ -2328,165 +2079,6 @@ enum { #undef GEN_DOCS }; -typedef struct QEMUOption { - const char *name; - int flags; - int index; -} QEMUOption; - -static const QEMUOption qemu_options[] = { - { "h", 0, QEMU_OPTION_h }, -#define DEF(option, opt_arg, opt_enum, opt_help) \ - { option, opt_arg, opt_enum }, -#define DEFHEADING(text) -#include "qemu-options.h" -#undef DEF -#undef DEFHEADING -#undef GEN_DOCS - { NULL }, -}; - -#ifdef HAS_AUDIO -struct soundhw soundhw[] = { -#ifdef HAS_AUDIO_CHOICE -#if defined(TARGET_I386) || defined(TARGET_MIPS) - { - "pcspk", - "PC speaker", - 0, - 1, - { .init_isa = pcspk_audio_init } - }, -#endif - -#ifdef CONFIG_SB16 - { - "sb16", - "Creative Sound Blaster 16", - 0, - 1, - { .init_isa = SB16_init } - }, -#endif - -#ifdef CONFIG_CS4231A - { - "cs4231a", - "CS4231A", - 0, - 1, - { .init_isa = cs4231a_init } - }, -#endif - -#ifdef CONFIG_ADLIB - { - "adlib", -#ifdef HAS_YMF262 - "Yamaha YMF262 (OPL3)", -#else - "Yamaha YM3812 (OPL2)", -#endif - 0, - 1, - { .init_isa = Adlib_init } - }, -#endif - -#ifdef CONFIG_GUS - { - "gus", - "Gravis Ultrasound GF1", - 0, - 1, - { .init_isa = GUS_init } - }, -#endif - -#ifdef CONFIG_AC97 - { - "ac97", - "Intel 82801AA AC97 Audio", - 0, - 0, - { .init_pci = ac97_init } - }, -#endif - -#ifdef CONFIG_ES1370 - { - "es1370", - "ENSONIQ AudioPCI ES1370", - 0, - 0, - { .init_pci = es1370_init } - }, -#endif - -#endif /* HAS_AUDIO_CHOICE */ - - { NULL, NULL, 0, 0, { NULL } } -}; - -static void select_soundhw (const char *optarg) -{ - struct soundhw *c; - - if (*optarg == '?') { - show_valid_cards: - - printf ("Valid sound card names (comma separated):\n"); - for (c = soundhw; c->name; ++c) { - printf ("%-11s %s\n", c->name, c->descr); - } - printf ("\n-soundhw all will enable all of the above\n"); - exit (*optarg != '?'); - } - else { - size_t l; - const char *p; - char *e; - int bad_card = 0; - - if (!strcmp (optarg, "all")) { - for (c = soundhw; c->name; ++c) { - c->enabled = 1; - } - return; - } - - p = optarg; - while (*p) { - e = strchr (p, ','); - l = !e ? strlen (p) : (size_t) (e - p); - - for (c = soundhw; c->name; ++c) { - if (!strncmp (c->name, p, l) && !c->name[l]) { - c->enabled = 1; - break; - } - } - - if (!c->name) { - if (l > 80) { - fprintf (stderr, - "Unknown sound card name (too big to show)\n"); - } - else { - fprintf (stderr, "Unknown sound card name `%.*s'\n", - (int) l, p); - } - bad_card = 1; - } - p += l + (e != NULL); - } - - if (bad_card) - goto show_valid_cards; - } -} -#endif - static void select_vgahw (const char *p) { const char *opts; @@ -2521,7 +2113,6 @@ static void select_vgahw (const char *p) } } -#ifdef TARGET_I386 static int balloon_parse(const char *arg) { QemuOpts *opts; @@ -2546,7 +2137,6 @@ static int balloon_parse(const char *arg) return -1; } -#endif #ifdef _WIN32 static BOOL WINAPI qemu_ctrl_handler(DWORD type) @@ -2570,10 +2160,6 @@ int qemu_uuid_parse(const char *str, uint8_t *uuid) if(ret != 16) return -1; -#ifdef TARGET_I386 - smbios_add_field(1, offsetof(struct smbios_type_1, uuid), 16, uuid); -#endif - return 0; } @@ -3116,7 +2702,7 @@ int main(int argc, char **argv, char **envp) fclose(fp); } - fname = CONFIG_QEMU_CONFDIR "/target-" TARGET_ARCH ".conf"; + fname = arch_config_name; fp = fopen(fname, "r"); if (fp) { if (qemu_config_parse(fp, fname) != 0) { @@ -3433,20 +3019,7 @@ int main(int argc, char **argv, char **envp) break; #endif case QEMU_OPTION_d: - { - int mask; - const 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); - } + set_cpu_log(optarg); break; case QEMU_OPTION_s: gdbstub_dev = "tcp::" DEFAULT_GDBSTUB_PORT; @@ -3670,13 +3243,13 @@ int main(int argc, char **argv, char **envp) case QEMU_OPTION_no_hpet: no_hpet = 1; break; +#endif case QEMU_OPTION_balloon: if (balloon_parse(optarg) < 0) { fprintf(stderr, "Unknown -balloon argument %s\n", optarg); exit(1); } break; -#endif case QEMU_OPTION_no_reboot: no_reboot = 1; break; @@ -3692,6 +3265,10 @@ int main(int argc, char **argv, char **envp) " Wrong format.\n"); exit(1); } +#ifdef TARGET_I386 + smbios_add_field(1, offsetof(struct smbios_type_1, uuid), 16, + qemu_uuid); +#endif break; #ifndef _WIN32 case QEMU_OPTION_daemonize: @@ -3753,7 +3330,11 @@ int main(int argc, char **argv, char **envp) fprintf(stderr, "parse error: %s\n", optarg); exit(1); } - configure_rtc(opts); +#ifdef TARGET_I386 + configure_rtc(opts, 1); +#else + configure_rtc(opts, 0); +#endif break; case QEMU_OPTION_tb_size: tb_size = strtol(optarg, NULL, 0); -- 1.6.2.4