diff --git a/WinQemu.vcxproj b/WinQemu.vcxproj index 611c10f5..0a3c3646 100644 --- a/WinQemu.vcxproj +++ b/WinQemu.vcxproj @@ -165,6 +165,7 @@ false + diff --git a/WinQemu.vcxproj.filters b/WinQemu.vcxproj.filters index cd042706..27fa6331 100644 --- a/WinQemu.vcxproj.filters +++ b/WinQemu.vcxproj.filters @@ -1272,6 +1272,9 @@ qemu\src + + Source Files + diff --git a/gettimeofday.c b/gettimeofday.c new file mode 100644 index 00000000..0b18b2a1 --- /dev/null +++ b/gettimeofday.c @@ -0,0 +1,32 @@ +// Source: https://stackoverflow.com/questions/10905892/equivalent-of-gettimeofday-for-windows + +#define WIN32_LEAN_AND_MEAN +#include +#include // portable: uint64_t MSVC: __int64 + +// MSVC defines this in winsock2.h!? +typedef struct timeval { + long tv_sec; + long tv_usec; +} timeval; + +int gettimeofday(struct timeval* tp, struct timezone* tzp) +{ + // Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's + // This magic number is the number of 100 nanosecond intervals since January 1, 1601 (UTC) + // until 00:00:00 January 1, 1970 + static const uint64_t EPOCH = ((uint64_t)116444736000000000ULL); + + SYSTEMTIME system_time; + FILETIME file_time; + uint64_t time; + + GetSystemTime(&system_time); + SystemTimeToFileTime(&system_time, &file_time); + time = ((uint64_t)file_time.dwLowDateTime); + time += ((uint64_t)file_time.dwHighDateTime) << 32; + + tp->tv_sec = (long)((time - EPOCH) / 10000000L); + tp->tv_usec = (long)(system_time.wMilliseconds * 1000); + return 0; +} \ No newline at end of file diff --git a/qemu/arm-dis.c b/qemu/arm-dis.c index dedc8f75..70041e45 100644 --- a/qemu/arm-dis.c +++ b/qemu/arm-dis.c @@ -33,15 +33,12 @@ */ #include "dis-asm.h" -#define FALSE 0 -#define TRUE (!FALSE) #ifndef _MSC_VER #define ATTRIBUTE_UNUSED __attribute__((unused)) #else #define ATTRIBUTE_UNUSED #endif - #define ISSPACE(x) ((x) == ' ' || (x) == '\t' || (x) == '\n') #define ARM_EXT_V1 0 @@ -1547,7 +1544,7 @@ static unsigned int regname_selected = 1; #define NUM_ARM_REGNAMES NUM_ELEM (regnames) #define arm_regnames regnames[regname_selected].reg_names -static bfd_boolean force_thumb = FALSE; +static bfd_boolean force_thumb = false; /* Current IT instruction state. This contains the same state as the IT bits in the CPSR. */ @@ -1644,7 +1641,7 @@ arm_decode_shift (long given, fprintf_ftype func, void *stream, } /* Print one coprocessor instruction on INFO->STREAM. - Return TRUE if the instuction matched, FALSE if this is not a + Return true if the instuction matched, false if this is not a recognised coprocessor instruction. */ static bfd_boolean @@ -2137,10 +2134,10 @@ print_insn_coprocessor (bfd_vma pc, struct disassemble_info *info, long given, else func (stream, "%c", *c); } - return TRUE; + return true; } } - return FALSE; + return false; } static void @@ -2234,7 +2231,7 @@ print_arm_address (bfd_vma pc, struct disassemble_info *info, long given) } /* Print one neon instruction on INFO->STREAM. - Return TRUE if the instuction matched, FALSE if this is not a + Return true if the instuction matched, false if this is not a recognised neon instruction. */ static bfd_boolean @@ -2260,7 +2257,7 @@ print_insn_neon (struct disassemble_info *info, long given, bfd_boolean thumb) else if ((given & 0xff000000) == 0xf9000000) given ^= 0xf9000000 ^ 0xf4000000; else - return FALSE; + return false; } for (insn = neon_opcodes; insn->assembler; insn++) @@ -2350,34 +2347,34 @@ print_insn_neon (struct disassemble_info *info, long given, bfd_boolean thumb) { int amask = (1 << size) - 1; if ((idx_align & (1 << size)) != 0) - return FALSE; + return false; if (size > 0) { if ((idx_align & amask) == amask) align = 8 << size; else if ((idx_align & amask) != 0) - return FALSE; + return false; } } break; case 2: if (size == 2 && (idx_align & 2) != 0) - return FALSE; + return false; align = (idx_align & 1) ? 16 << size : 0; break; case 3: if ((size == 2 && (idx_align & 3) != 0) || (idx_align & 1) != 0) - return FALSE; + return false; break; case 4: if (size == 2) { if ((idx_align & 3) == 3) - return FALSE; + return false; align = (idx_align & 3) * 64; } else @@ -2686,10 +2683,10 @@ print_insn_neon (struct disassemble_info *info, long given, bfd_boolean thumb) else func (stream, "%c", *c); } - return TRUE; + return true; } } - return FALSE; + return false; } /* Print one ARM instruction from PC on INFO->STREAM. */ @@ -2701,10 +2698,10 @@ print_insn_arm_internal (bfd_vma pc, struct disassemble_info *info, long given) void *stream = info->stream; fprintf_ftype func = info->fprintf_func; - if (print_insn_coprocessor (pc, info, given, FALSE)) + if (print_insn_coprocessor (pc, info, given, false)) return; - if (print_insn_neon (info, given, FALSE)) + if (print_insn_neon (info, given, false)) return; for (insn = arm_opcodes; insn->assembler; insn++) @@ -3337,10 +3334,10 @@ print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given) void *stream = info->stream; fprintf_ftype func = info->fprintf_func; - if (print_insn_coprocessor (pc, info, given, TRUE)) + if (print_insn_coprocessor (pc, info, given, true)) return; - if (print_insn_neon (info, given, TRUE)) + if (print_insn_neon (info, given, true)) return; for (insn = thumb32_opcodes; insn->assembler; insn++) @@ -3475,7 +3472,7 @@ print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given) unsigned int op = (given & 0x00000f00) >> 8; unsigned int i12 = (given & 0x00000fff); unsigned int i8 = (given & 0x000000ff); - bfd_boolean writeback = FALSE, postind = FALSE; + bfd_boolean writeback = false, postind = false; int offset = 0; func (stream, "[%s", arm_regnames[Rn]); @@ -3505,22 +3502,22 @@ print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given) case 0xF: /* 8-bit + preindex with wb */ offset = i8; - writeback = TRUE; + writeback = true; break; case 0xD: /* 8-bit - preindex with wb */ offset = -i8; - writeback = TRUE; + writeback = true; break; case 0xB: /* 8-bit + postindex */ offset = i8; - postind = TRUE; + postind = true; break; case 0x9: /* 8-bit - postindex */ offset = -i8; - postind = TRUE; + postind = true; break; default: @@ -3893,12 +3890,12 @@ print_insn_arm (bfd_vma pc, struct disassemble_info *info) unsigned char b[4]; long given; int status; - int is_thumb = FALSE; - int is_data = FALSE; + int is_thumb = false; + int is_data = false; unsigned int size = 4; void (*printer) (bfd_vma, struct disassemble_info *, long); #if 0 - bfd_boolean found = FALSE; + bfd_boolean found = false; if (info->disassembler_options) { @@ -3921,7 +3918,7 @@ print_insn_arm (bfd_vma pc, struct disassemble_info *info) if (pc <= last_mapping_addr) last_mapping_sym = -1; is_thumb = (last_type == MAP_THUMB); - found = FALSE; + found = false; /* Start scanning at the start of the function, or wherever we finished last time. */ n = info->symtab_pos + 1; @@ -3939,7 +3936,7 @@ print_insn_arm (bfd_vma pc, struct disassemble_info *info) && get_sym_code_type (info, n, &type)) { last_sym = n; - found = TRUE; + found = true; } } @@ -3956,7 +3953,7 @@ print_insn_arm (bfd_vma pc, struct disassemble_info *info) if (get_sym_code_type (info, n, &type)) { last_sym = n; - found = TRUE; + found = true; break; } } @@ -4028,7 +4025,7 @@ print_insn_arm (bfd_vma pc, struct disassemble_info *info) #endif if (force_thumb) - is_thumb = TRUE; + is_thumb = true; info->bytes_per_line = 4; diff --git a/qemu/configure b/qemu/configure index cc3cbd62..69a5502b 100644 --- a/qemu/configure +++ b/qemu/configure @@ -1686,6 +1686,16 @@ QEMU_CFLAGS="-U_FORTIFY_SOURCE $QEMU_CFLAGS" QEMU_CFLAGS="-I. -I\$(SRC_PATH) -MMD -MP -MT \$@ $QEMU_CFLAGS" LDFLAGS="-g $LDFLAGS" +gcc_flags="-Wold-style-declaration -Wold-style-definition" +cat > $TMPC << EOF +int main(void) { } +EOF +for flag in $gcc_flags; do + if compile_prog "$QEMU_CFLAGS" "$flag" ; then + QEMU_CFLAGS="$flag $QEMU_CFLAGS" + fi +done + # Consult white-list to determine whether to enable werror # by default. Only enable by default for git builds if test -z "$werror" ; then @@ -1861,7 +1871,7 @@ if test $profiler = "yes" ; then fi if test "$slirp" = "yes" ; then echo "CONFIG_SLIRP=y" >> $config_host_mak - CFLAGS="-I\$(SRC_PATH)/slirp $CFLAGS" + QEMU_CFLAGS="-I\$(SRC_PATH)/slirp $QEMU_CFLAGS" fi if test "$vde" = "yes" ; then echo "CONFIG_VDE=y" >> $config_host_mak diff --git a/qemu/cris-dis.c b/qemu/cris-dis.c index f6932a05..455ba8af 100644 --- a/qemu/cris-dis.c +++ b/qemu/cris-dis.c @@ -26,8 +26,6 @@ void *qemu_malloc(size_t len); /* can't include qemu-common.h here */ -#define FALSE 0 -#define TRUE 1 #define CONST_STRNEQ(STR1,STR2) (strncmp ((STR1), (STR2), sizeof (STR2) - 1) == 0) /* cris-opc.c -- Table of opcodes for the CRIS processor. @@ -1320,7 +1318,7 @@ cris_parse_disassembler_options (disassemble_info *info, info->private_data = calloc (1, sizeof (struct cris_disasm_data)); disdata = (struct cris_disasm_data *) info->private_data; if (disdata == NULL) - return FALSE; + return false; /* Default true. */ disdata->trace_case @@ -1328,7 +1326,7 @@ cris_parse_disassembler_options (disassemble_info *info, || (strcmp (info->disassembler_options, "nocase") != 0)); disdata->distype = distype; - return TRUE; + return true; } static const struct cris_spec_reg * @@ -2779,7 +2777,7 @@ print_insn_cris_with_register_prefix (bfd_vma vma, if (info->private_data == NULL && !cris_parse_disassembler_options (info, cris_dis_v0_v10)) return -1; - return print_insn_cris_generic (vma, info, TRUE); + return print_insn_cris_generic (vma, info, true); } #endif /* Disassemble, prefixing register names with `$'. CRIS v32. */ @@ -2791,7 +2789,7 @@ print_insn_crisv32_with_register_prefix (bfd_vma vma, if (info->private_data == NULL && !cris_parse_disassembler_options (info, cris_dis_v32)) return -1; - return print_insn_cris_generic (vma, info, TRUE); + return print_insn_cris_generic (vma, info, true); } #if 0 @@ -2805,7 +2803,7 @@ print_insn_crisv10_v32_with_register_prefix (bfd_vma vma, if (info->private_data == NULL && !cris_parse_disassembler_options (info, cris_dis_common_v10_v32)) return -1; - return print_insn_cris_generic (vma, info, TRUE); + return print_insn_cris_generic (vma, info, true); } /* Disassemble, no prefixes on register names. CRIS v0..v10. */ @@ -2817,7 +2815,7 @@ print_insn_cris_without_register_prefix (bfd_vma vma, if (info->private_data == NULL && !cris_parse_disassembler_options (info, cris_dis_v0_v10)) return -1; - return print_insn_cris_generic (vma, info, FALSE); + return print_insn_cris_generic (vma, info, false); } /* Disassemble, no prefixes on register names. CRIS v32. */ @@ -2829,7 +2827,7 @@ print_insn_crisv32_without_register_prefix (bfd_vma vma, if (info->private_data == NULL && !cris_parse_disassembler_options (info, cris_dis_v32)) return -1; - return print_insn_cris_generic (vma, info, FALSE); + return print_insn_cris_generic (vma, info, false); } /* Disassemble, no prefixes on register names. @@ -2842,7 +2840,7 @@ print_insn_crisv10_v32_without_register_prefix (bfd_vma vma, if (info->private_data == NULL && !cris_parse_disassembler_options (info, cris_dis_common_v10_v32)) return -1; - return print_insn_cris_generic (vma, info, FALSE); + return print_insn_cris_generic (vma, info, false); } #endif diff --git a/qemu/dis-asm.h b/qemu/dis-asm.h index 74f87335..0e0f277d 100644 --- a/qemu/dis-asm.h +++ b/qemu/dis-asm.h @@ -20,6 +20,7 @@ #define DIS_ASM_H #include +#include #include #include #include @@ -491,7 +492,6 @@ bfd_vma bfd_getl32 (const bfd_byte *addr); bfd_vma bfd_getb32 (const bfd_byte *addr); bfd_vma bfd_getl16 (const bfd_byte *addr); bfd_vma bfd_getb16 (const bfd_byte *addr); -typedef enum bfd_boolean {false, true} boolean; -typedef boolean bfd_boolean; +typedef bool bfd_boolean; #endif /* ! defined (DIS_ASM_H) */ diff --git a/qemu/gdbstub.c b/qemu/gdbstub.c index 34a67b89..4e1d9964 100644 --- a/qemu/gdbstub.c +++ b/qemu/gdbstub.c @@ -505,8 +505,9 @@ static const int gpr_map[16] = { 8, 9, 10, 11, 12, 13, 14, 15 }; #else -static const int gpr_map[8] = {0, 1, 2, 3, 4, 5, 6, 7}; +#define gpr_map gpr_map32 #endif +static const int gpr_map32[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; #define NUM_CORE_REGS (CPU_NB_REGS * 2 + 25) @@ -520,7 +521,11 @@ static const int gpr_map[8] = {0, 1, 2, 3, 4, 5, 6, 7}; static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n) { if (n < CPU_NB_REGS) { - GET_REGL(env->regs[gpr_map[n]]); + if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) { + GET_REG64(env->regs[gpr_map[n]]); + } else if (n < CPU_NB_REGS32) { + GET_REG32(env->regs[gpr_map32[n]]); + } } else if (n >= IDX_FP_REGS && n < IDX_FP_REGS + 8) { #ifdef USE_X86LDOUBLE /* FIXME: byteswap float values - after fixing fpregs layout. */ @@ -531,12 +536,20 @@ static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n) return 10; } else if (n >= IDX_XMM_REGS && n < IDX_XMM_REGS + CPU_NB_REGS) { n -= IDX_XMM_REGS; - stq_p(mem_buf, env->xmm_regs[n].XMM_Q(0)); - stq_p(mem_buf + 8, env->xmm_regs[n].XMM_Q(1)); - return 16; + if (n < CPU_NB_REGS32 || + (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK)) { + stq_p(mem_buf, env->xmm_regs[n].XMM_Q(0)); + stq_p(mem_buf + 8, env->xmm_regs[n].XMM_Q(1)); + return 16; + } } else { switch (n) { - case IDX_IP_REG: GET_REGL(env->eip); + case IDX_IP_REG: + if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) { + GET_REG64(env->eip); + } else { + GET_REG32(env->eip); + } case IDX_FLAGS_REG: GET_REG32(env->eflags); case IDX_SEG_REGS: GET_REG32(env->segs[R_CS].selector); @@ -592,8 +605,15 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n) uint32_t tmp; if (n < CPU_NB_REGS) { - env->regs[gpr_map[n]] = ldtul_p(mem_buf); - return sizeof(target_ulong); + if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) { + env->regs[gpr_map[n]] = ldtul_p(mem_buf); + return sizeof(target_ulong); + } else if (n < CPU_NB_REGS32) { + n = gpr_map32[n]; + env->regs[n] &= ~0xffffffffUL; + env->regs[n] |= (uint32_t)ldl_p(mem_buf); + return 4; + } } else if (n >= IDX_FP_REGS && n < IDX_FP_REGS + 8) { #ifdef USE_X86LDOUBLE /* FIXME: byteswap float values - after fixing fpregs layout. */ @@ -602,14 +622,23 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n) return 10; } else if (n >= IDX_XMM_REGS && n < IDX_XMM_REGS + CPU_NB_REGS) { n -= IDX_XMM_REGS; - env->xmm_regs[n].XMM_Q(0) = ldq_p(mem_buf); - env->xmm_regs[n].XMM_Q(1) = ldq_p(mem_buf + 8); - return 16; + if (n < CPU_NB_REGS32 || + (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK)) { + env->xmm_regs[n].XMM_Q(0) = ldq_p(mem_buf); + env->xmm_regs[n].XMM_Q(1) = ldq_p(mem_buf + 8); + return 16; + } } else { switch (n) { case IDX_IP_REG: - env->eip = ldtul_p(mem_buf); - return sizeof(target_ulong); + if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) { + env->eip = ldq_p(mem_buf); + return 8; + } else { + env->eip &= ~0xffffffffUL; + env->eip |= (uint32_t)ldl_p(mem_buf); + return 4; + } case IDX_FLAGS_REG: env->eflags = ldl_p(mem_buf); return 4; diff --git a/qemu/hw/hw.h b/qemu/hw/hw.h index cabf6335..8c223f84 100644 --- a/qemu/hw/hw.h +++ b/qemu/hw/hw.h @@ -10,6 +10,7 @@ #include "cpu-common.h" #endif +#include #include "ioport.h" #include "irq.h" @@ -299,6 +300,7 @@ typedef struct { enum VMStateFlags flags; const VMStateDescription *vmsd; int version_id; + bool (*field_exists)(void *opaque, int version_id); } VMStateField; struct VMStateDescription { @@ -345,6 +347,16 @@ extern const VMStateInfo vmstate_info_buffer; + type_check(_type,typeof_field(_state, _field)) \ } +#define VMSTATE_SINGLE_TEST(_field, _state, _test, _info, _type) { \ + .name = (stringify(_field)), \ + .field_exists = (_test), \ + .size = sizeof(_type), \ + .info = &(_info), \ + .flags = VMS_SINGLE, \ + .offset = offsetof(_state, _field) \ + + type_check(_type,typeof_field(_state, _field)) \ +} + #define VMSTATE_POINTER(_field, _state, _version, _info, _type) { \ .name = (stringify(_field)), \ .version_id = (_version), \ @@ -366,6 +378,17 @@ extern const VMStateInfo vmstate_info_buffer; + type_check_array(_type,typeof_field(_state, _field),_num) \ } +#define VMSTATE_ARRAY_TEST(_field, _state, _num, _test, _info, _type) {\ + .name = (stringify(_field)), \ + .field_exists = (_test), \ + .num = (_num), \ + .info = &(_info), \ + .size = sizeof(_type), \ + .flags = VMS_ARRAY, \ + .offset = offsetof(_state, _field) \ + + type_check_array(_type,typeof_field(_state, _field),_num) \ +} + #define VMSTATE_VARRAY(_field, _state, _field_num, _version, _info, _type) {\ .name = (stringify(_field)), \ .version_id = (_version), \ @@ -524,6 +547,9 @@ extern const VMStateDescription vmstate_i2c_slave; #define VMSTATE_INT32_LE(_f, _s) \ VMSTATE_SINGLE(_f, _s, 0, vmstate_info_int32_le, int32_t) +#define VMSTATE_UINT32_TEST(_f, _s, _t) \ + VMSTATE_SINGLE_TEST(_f, _s, _t, vmstate_info_uint32, uint32_t) + #define VMSTATE_TIMER_V(_f, _s, _v) \ VMSTATE_POINTER(_f, _s, _v, vmstate_info_timer, QEMUTimer *) diff --git a/qemu/hw/marvell_88w8618_audio.c b/qemu/hw/marvell_88w8618_audio.c index 21f8d387..d2fc7a8d 100644 --- a/qemu/hw/marvell_88w8618_audio.c +++ b/qemu/hw/marvell_88w8618_audio.c @@ -41,11 +41,11 @@ typedef struct mv88w8618_audio_state { uint32_t playback_mode; uint32_t status; uint32_t irq_enable; - unsigned long phys_buf; + uint32_t phys_buf; uint32_t target_buffer; - unsigned int threshold; - unsigned int play_pos; - unsigned int last_free; + uint32_t threshold; + uint32_t play_pos; + uint32_t last_free; uint32_t clock_div; DeviceState *wm; } mv88w8618_audio_state; @@ -58,22 +58,22 @@ static void mv88w8618_audio_callback(void *opaque, int free_out, int free_in) int8_t *mem_buffer; int pos, block_size; - if (!(s->playback_mode & MP_AUDIO_PLAYBACK_EN)) + if (!(s->playback_mode & MP_AUDIO_PLAYBACK_EN)) { return; - - if (s->playback_mode & MP_AUDIO_16BIT_SAMPLE) + } + if (s->playback_mode & MP_AUDIO_16BIT_SAMPLE) { free_out <<= 1; - - if (!(s->playback_mode & MP_AUDIO_MONO)) + } + if (!(s->playback_mode & MP_AUDIO_MONO)) { free_out <<= 1; - + } block_size = s->threshold / 2; - if (free_out - s->last_free < block_size) + if (free_out - s->last_free < block_size) { return; - - if (block_size > 4096) + } + if (block_size > 4096) { return; - + } cpu_physical_memory_read(s->target_buffer + s->play_pos, (void *)buf, block_size); mem_buffer = buf; @@ -85,9 +85,10 @@ static void mv88w8618_audio_callback(void *opaque, int free_out, int free_in) *codec_buffer++ = *(int16_t *)mem_buffer; mem_buffer += 2; } - } else + } else { memcpy(wm8750_dac_buffer(s->wm, block_size >> 2), (uint32_t *)mem_buffer, block_size); + } } else { if (s->playback_mode & MP_AUDIO_MONO) { codec_buffer = wm8750_dac_buffer(s->wm, block_size); @@ -115,19 +116,20 @@ static void mv88w8618_audio_callback(void *opaque, int free_out, int free_in) s->play_pos = 0; } - if (s->status & s->irq_enable) + if (s->status & s->irq_enable) { qemu_irq_raise(s->irq); + } } static void mv88w8618_audio_clock_update(mv88w8618_audio_state *s) { int rate; - if (s->playback_mode & MP_AUDIO_CLOCK_24MHZ) + if (s->playback_mode & MP_AUDIO_CLOCK_24MHZ) { rate = 24576000 / 64; /* 24.576MHz */ - else + } else { rate = 11289600 / 64; /* 11.2896MHz */ - + } rate /= ((s->clock_div >> 8) & 0xff) + 1; wm8750_set_bclk_in(s->wm, rate); @@ -188,8 +190,9 @@ static void mv88w8618_audio_write(void *opaque, target_phys_addr_t offset, case MP_AUDIO_IRQ_ENABLE: s->irq_enable = value; - if (s->status & s->irq_enable) + if (s->status & s->irq_enable) { qemu_irq_raise(s->irq); + } break; case MP_AUDIO_TX_START_LO: @@ -212,13 +215,17 @@ static void mv88w8618_audio_write(void *opaque, target_phys_addr_t offset, } } -static void mv88w8618_audio_reset(void *opaque) +static void mv88w8618_audio_reset(DeviceState *d) { - mv88w8618_audio_state *s = opaque; + mv88w8618_audio_state *s = FROM_SYSBUS(mv88w8618_audio_state, + sysbus_from_qdev(d)); s->playback_mode = 0; s->status = 0; s->irq_enable = 0; + s->clock_div = 0; + s->threshold = 0; + s->phys_buf = 0; } static CPUReadMemoryFunc * const mv88w8618_audio_readfn[] = { @@ -246,15 +253,34 @@ static int mv88w8618_audio_init(SysBusDevice *dev) mv88w8618_audio_writefn, s); sysbus_init_mmio(dev, MP_AUDIO_SIZE, iomemtype); - qemu_register_reset(mv88w8618_audio_reset, s); - return 0; } +static const VMStateDescription mv88w8618_audio_vmsd = { + .name = "mv88w8618_audio", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(playback_mode, mv88w8618_audio_state), + VMSTATE_UINT32(status, mv88w8618_audio_state), + VMSTATE_UINT32(irq_enable, mv88w8618_audio_state), + VMSTATE_UINT32(phys_buf, mv88w8618_audio_state), + VMSTATE_UINT32(target_buffer, mv88w8618_audio_state), + VMSTATE_UINT32(threshold, mv88w8618_audio_state), + VMSTATE_UINT32(play_pos, mv88w8618_audio_state), + VMSTATE_UINT32(last_free, mv88w8618_audio_state), + VMSTATE_UINT32(clock_div, mv88w8618_audio_state), + VMSTATE_END_OF_LIST() + } +}; + static SysBusDeviceInfo mv88w8618_audio_info = { .init = mv88w8618_audio_init, .qdev.name = "mv88w8618_audio", .qdev.size = sizeof(mv88w8618_audio_state), + .qdev.reset = mv88w8618_audio_reset, + .qdev.vmsd = &mv88w8618_audio_vmsd, .qdev.props = (Property[]) { { .name = "wm8750", diff --git a/qemu/hw/mc146818rtc.c b/qemu/hw/mc146818rtc.c index 2f8405ee..94f87b61 100644 --- a/qemu/hw/mc146818rtc.c +++ b/qemu/hw/mc146818rtc.c @@ -108,8 +108,8 @@ static void rtc_coalesced_timer_update(RTCState *s) } else { /* divide each RTC interval to 2 - 8 smaller intervals */ int c = MIN(s->irq_coalesced, 7) + 1; - int64_t next_clock = qemu_get_clock(vm_clock) + - muldiv64(s->period / c, get_ticks_per_sec(), 32768); + int64_t next_clock = qemu_get_clock(rtc_clock) + + muldiv64(s->period / c, get_ticks_per_sec(), 32768); qemu_mod_timer(s->coalesced_timer, next_clock); } } @@ -161,7 +161,8 @@ static void rtc_timer_update(RTCState *s, int64_t current_time) /* compute 32 khz clock */ cur_clock = muldiv64(current_time, 32768, get_ticks_per_sec()); next_irq_clock = (cur_clock & ~(period - 1)) + period; - s->next_periodic_time = muldiv64(next_irq_clock, get_ticks_per_sec(), 32768) + 1; + s->next_periodic_time = + muldiv64(next_irq_clock, get_ticks_per_sec(), 32768) + 1; qemu_mod_timer(s->periodic_timer, s->next_periodic_time); } else { #ifdef TARGET_I386 @@ -232,7 +233,7 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) /* UIP bit is read only */ s->cmos_data[RTC_REG_A] = (data & ~REG_A_UIP) | (s->cmos_data[RTC_REG_A] & REG_A_UIP); - rtc_timer_update(s, qemu_get_clock(vm_clock)); + rtc_timer_update(s, qemu_get_clock(rtc_clock)); break; case RTC_REG_B: if (data & REG_B_SET) { @@ -246,7 +247,7 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) } } s->cmos_data[RTC_REG_B] = data; - rtc_timer_update(s, qemu_get_clock(vm_clock)); + rtc_timer_update(s, qemu_get_clock(rtc_clock)); break; case RTC_REG_C: case RTC_REG_D: @@ -605,18 +606,17 @@ static int rtc_initfn(ISADevice *dev) rtc_set_date_from_host(s); - s->periodic_timer = qemu_new_timer(vm_clock, - rtc_periodic_timer, s); + s->periodic_timer = qemu_new_timer(rtc_clock, rtc_periodic_timer, s); #ifdef TARGET_I386 if (rtc_td_hack) - s->coalesced_timer = qemu_new_timer(vm_clock, rtc_coalesced_timer, s); + s->coalesced_timer = + qemu_new_timer(rtc_clock, rtc_coalesced_timer, s); #endif - s->second_timer = qemu_new_timer(vm_clock, - rtc_update_second, s); - s->second_timer2 = qemu_new_timer(vm_clock, - rtc_update_second2, s); + s->second_timer = qemu_new_timer(rtc_clock, rtc_update_second, s); + s->second_timer2 = qemu_new_timer(rtc_clock, rtc_update_second2, s); - s->next_second_time = qemu_get_clock(vm_clock) + (get_ticks_per_sec() * 99) / 100; + s->next_second_time = + qemu_get_clock(rtc_clock) + (get_ticks_per_sec() * 99) / 100; qemu_mod_timer(s->second_timer2, s->next_second_time); register_ioport_write(base, 2, 1, cmos_ioport_write, s); @@ -747,14 +747,12 @@ RTCState *rtc_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq, s->base_year = base_year; rtc_set_date_from_host(s); - s->periodic_timer = qemu_new_timer(vm_clock, - rtc_periodic_timer, s); - s->second_timer = qemu_new_timer(vm_clock, - rtc_update_second, s); - s->second_timer2 = qemu_new_timer(vm_clock, - rtc_update_second2, s); + s->periodic_timer = qemu_new_timer(rtc_clock, rtc_periodic_timer, s); + s->second_timer = qemu_new_timer(rtc_clock, rtc_update_second, s); + s->second_timer2 = qemu_new_timer(rtc_clock, rtc_update_second2, s); - s->next_second_time = qemu_get_clock(vm_clock) + (get_ticks_per_sec() * 99) / 100; + s->next_second_time = + qemu_get_clock(rtc_clock) + (get_ticks_per_sec() * 99) / 100; qemu_mod_timer(s->second_timer2, s->next_second_time); io_memory = cpu_register_io_memory(rtc_mm_read, rtc_mm_write, s); diff --git a/qemu/hw/musicpal.c b/qemu/hw/musicpal.c index 1c4f17cb..1fad36f2 100644 --- a/qemu/hw/musicpal.c +++ b/qemu/hw/musicpal.c @@ -146,7 +146,7 @@ typedef struct mv88w8618_eth_state { uint32_t icr; uint32_t imr; int mmio_index; - int vlan_header; + uint32_t vlan_header; uint32_t tx_queue[2]; uint32_t rx_queue[4]; uint32_t frx_queue[4]; @@ -188,8 +188,9 @@ static ssize_t eth_receive(VLANClientState *vc, const uint8_t *buf, size_t size) for (i = 0; i < 4; i++) { desc_addr = s->cur_rx[i]; - if (!desc_addr) + if (!desc_addr) { continue; + } do { eth_rx_desc_get(desc_addr, &desc); if ((desc.cmdstat & MP_ETH_RX_OWN) && desc.buffer_size >= size) { @@ -200,8 +201,9 @@ static ssize_t eth_receive(VLANClientState *vc, const uint8_t *buf, size_t size) s->cur_rx[i] = desc.next; s->icr |= MP_ETH_IRQ_RX; - if (s->icr & s->imr) + if (s->icr & s->imr) { qemu_irq_raise(s->irq); + } eth_rx_desc_put(desc_addr, &desc); return size; } @@ -238,7 +240,9 @@ static void eth_send(mv88w8618_eth_state *s, int queue_index) uint8_t buf[2048]; int len; - + if (!desc_addr) { + return; + } do { eth_tx_desc_get(desc_addr, &desc); if (desc.cmdstat & MP_ETH_TX_OWN) { @@ -311,12 +315,15 @@ static void mv88w8618_eth_write(void *opaque, target_phys_addr_t offset, break; case MP_ETH_SDCMR: - if (value & MP_ETH_CMD_TXHI) + if (value & MP_ETH_CMD_TXHI) { eth_send(s, 1); - if (value & MP_ETH_CMD_TXLO) + } + if (value & MP_ETH_CMD_TXLO) { eth_send(s, 0); - if (value & (MP_ETH_CMD_TXHI | MP_ETH_CMD_TXLO) && s->icr & s->imr) + } + if (value & (MP_ETH_CMD_TXHI | MP_ETH_CMD_TXLO) && s->icr & s->imr) { qemu_irq_raise(s->irq); + } break; case MP_ETH_ICR: @@ -325,8 +332,9 @@ static void mv88w8618_eth_write(void *opaque, target_phys_addr_t offset, case MP_ETH_IMR: s->imr = value; - if (s->icr & s->imr) + if (s->icr & s->imr) { qemu_irq_raise(s->irq); + } break; case MP_ETH_FRDP0 ... MP_ETH_FRDP3: @@ -379,6 +387,31 @@ static int mv88w8618_eth_init(SysBusDevice *dev) return 0; } +static const VMStateDescription mv88w8618_eth_vmsd = { + .name = "mv88w8618_eth", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(smir, mv88w8618_eth_state), + VMSTATE_UINT32(icr, mv88w8618_eth_state), + VMSTATE_UINT32(imr, mv88w8618_eth_state), + VMSTATE_UINT32(vlan_header, mv88w8618_eth_state), + VMSTATE_UINT32_ARRAY(tx_queue, mv88w8618_eth_state, 2), + VMSTATE_UINT32_ARRAY(rx_queue, mv88w8618_eth_state, 4), + VMSTATE_UINT32_ARRAY(frx_queue, mv88w8618_eth_state, 4), + VMSTATE_UINT32_ARRAY(cur_rx, mv88w8618_eth_state, 4), + VMSTATE_END_OF_LIST() + } +}; + +static SysBusDeviceInfo mv88w8618_eth_info = { + .init = mv88w8618_eth_init, + .qdev.name = "mv88w8618_eth", + .qdev.size = sizeof(mv88w8618_eth_state), + .qdev.vmsd = &mv88w8618_eth_vmsd, +}; + /* LCD register offsets */ #define MP_LCD_IRQCTRL 0x180 #define MP_LCD_IRQSTAT 0x184 @@ -403,8 +436,8 @@ typedef struct musicpal_lcd_state { uint32_t brightness; uint32_t mode; uint32_t irqctrl; - int page; - int page_off; + uint32_t page; + uint32_t page_off; DisplayState *ds; uint8_t video_ram[128*64/8]; } musicpal_lcd_state; @@ -451,12 +484,15 @@ static void lcd_refresh(void *opaque) col = func(scale_lcd_color(s, (MP_LCD_TEXTCOLOR >> 16) & 0xff), \ scale_lcd_color(s, (MP_LCD_TEXTCOLOR >> 8) & 0xff), \ scale_lcd_color(s, MP_LCD_TEXTCOLOR & 0xff)); \ - for (x = 0; x < 128; x++) \ - for (y = 0; y < 64; y++) \ - if (s->video_ram[x + (y/8)*128] & (1 << (y % 8))) \ + for (x = 0; x < 128; x++) { \ + for (y = 0; y < 64; y++) { \ + if (s->video_ram[x + (y/8)*128] & (1 << (y % 8))) { \ glue(set_lcd_pixel, depth)(s, x, y, col); \ - else \ + } else { \ glue(set_lcd_pixel, depth)(s, x, y, 0); \ + } \ + } \ + } \ break; LCD_REFRESH(8, rgb_to_pixel8) LCD_REFRESH(16, rgb_to_pixel16) @@ -476,7 +512,7 @@ static void lcd_invalidate(void *opaque) static void musicpal_lcd_gpio_brigthness_in(void *opaque, int irq, int level) { - musicpal_lcd_state *s = (musicpal_lcd_state *) opaque; + musicpal_lcd_state *s = opaque; s->brightness &= ~(1 << irq); s->brightness |= level << irq; } @@ -505,10 +541,11 @@ static void musicpal_lcd_write(void *opaque, target_phys_addr_t offset, break; case MP_LCD_SPICTRL: - if (value == MP_LCD_SPI_DATA || value == MP_LCD_SPI_CMD) + if (value == MP_LCD_SPI_DATA || value == MP_LCD_SPI_CMD) { s->mode = value; - else + } else { s->mode = MP_LCD_SPI_INVALID; + } break; case MP_LCD_INST: @@ -565,6 +602,29 @@ static int musicpal_lcd_init(SysBusDevice *dev) return 0; } +static const VMStateDescription musicpal_lcd_vmsd = { + .name = "musicpal_lcd", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(brightness, musicpal_lcd_state), + VMSTATE_UINT32(mode, musicpal_lcd_state), + VMSTATE_UINT32(irqctrl, musicpal_lcd_state), + VMSTATE_UINT32(page, musicpal_lcd_state), + VMSTATE_UINT32(page_off, musicpal_lcd_state), + VMSTATE_BUFFER(video_ram, musicpal_lcd_state), + VMSTATE_END_OF_LIST() + } +}; + +static SysBusDeviceInfo musicpal_lcd_info = { + .init = musicpal_lcd_init, + .qdev.name = "musicpal_lcd", + .qdev.size = sizeof(musicpal_lcd_state), + .qdev.vmsd = &musicpal_lcd_vmsd, +}; + /* PIC register offsets */ #define MP_PIC_STATUS 0x00 #define MP_PIC_ENABLE_SET 0x08 @@ -587,10 +647,11 @@ static void mv88w8618_pic_set_irq(void *opaque, int irq, int level) { mv88w8618_pic_state *s = opaque; - if (level) + if (level) { s->level |= 1 << irq; - else + } else { s->level &= ~(1 << irq); + } mv88w8618_pic_update(s); } @@ -625,9 +686,10 @@ static void mv88w8618_pic_write(void *opaque, target_phys_addr_t offset, mv88w8618_pic_update(s); } -static void mv88w8618_pic_reset(void *opaque) +static void mv88w8618_pic_reset(DeviceState *d) { - mv88w8618_pic_state *s = opaque; + mv88w8618_pic_state *s = FROM_SYSBUS(mv88w8618_pic_state, + sysbus_from_qdev(d)); s->level = 0; s->enabled = 0; @@ -655,11 +717,29 @@ static int mv88w8618_pic_init(SysBusDevice *dev) iomemtype = cpu_register_io_memory(mv88w8618_pic_readfn, mv88w8618_pic_writefn, s); sysbus_init_mmio(dev, MP_PIC_SIZE, iomemtype); - - qemu_register_reset(mv88w8618_pic_reset, s); return 0; } +static const VMStateDescription mv88w8618_pic_vmsd = { + .name = "mv88w8618_pic", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(level, mv88w8618_pic_state), + VMSTATE_UINT32(enabled, mv88w8618_pic_state), + VMSTATE_END_OF_LIST() + } +}; + +static SysBusDeviceInfo mv88w8618_pic_info = { + .init = mv88w8618_pic_init, + .qdev.name = "mv88w8618_pic", + .qdev.size = sizeof(mv88w8618_pic_state), + .qdev.reset = mv88w8618_pic_reset, + .qdev.vmsd = &mv88w8618_pic_vmsd, +}; + /* PIT register offsets */ #define MP_PIT_TIMER1_LENGTH 0x00 /* ... */ @@ -683,7 +763,6 @@ typedef struct mv88w8618_timer_state { typedef struct mv88w8618_pit_state { SysBusDevice busdev; mv88w8618_timer_state timer[4]; - uint32_t control; } mv88w8618_pit_state; static void mv88w8618_timer_tick(void *opaque) @@ -731,28 +810,47 @@ static void mv88w8618_pit_write(void *opaque, target_phys_addr_t offset, case MP_PIT_TIMER1_LENGTH ... MP_PIT_TIMER4_LENGTH: t = &s->timer[offset >> 2]; t->limit = value; - ptimer_set_limit(t->ptimer, t->limit, 1); + if (t->limit > 0) { + ptimer_set_limit(t->ptimer, t->limit, 1); + } else { + ptimer_stop(t->ptimer); + } break; case MP_PIT_CONTROL: for (i = 0; i < 4; i++) { - if (value & 0xf) { - t = &s->timer[i]; + t = &s->timer[i]; + if (value & 0xf && t->limit > 0) { ptimer_set_limit(t->ptimer, t->limit, 0); ptimer_set_freq(t->ptimer, t->freq); ptimer_run(t->ptimer, 0); + } else { + ptimer_stop(t->ptimer); } value >>= 4; } break; case MP_BOARD_RESET: - if (value == MP_BOARD_RESET_MAGIC) + if (value == MP_BOARD_RESET_MAGIC) { qemu_system_reset_request(); + } break; } } +static void mv88w8618_pit_reset(DeviceState *d) +{ + mv88w8618_pit_state *s = FROM_SYSBUS(mv88w8618_pit_state, + sysbus_from_qdev(d)); + int i; + + for (i = 0; i < 4; i++) { + ptimer_stop(s->timer[i].ptimer); + s->timer[i].limit = 0; + } +} + static CPUReadMemoryFunc * const mv88w8618_pit_readfn[] = { mv88w8618_pit_read, mv88w8618_pit_read, @@ -783,6 +881,38 @@ static int mv88w8618_pit_init(SysBusDevice *dev) return 0; } +static const VMStateDescription mv88w8618_timer_vmsd = { + .name = "timer", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_PTIMER(ptimer, mv88w8618_timer_state), + VMSTATE_UINT32(limit, mv88w8618_timer_state), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription mv88w8618_pit_vmsd = { + .name = "mv88w8618_pit", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_STRUCT_ARRAY(timer, mv88w8618_pit_state, 4, 1, + mv88w8618_timer_vmsd, mv88w8618_timer_state), + VMSTATE_END_OF_LIST() + } +}; + +static SysBusDeviceInfo mv88w8618_pit_info = { + .init = mv88w8618_pit_init, + .qdev.name = "mv88w8618_pit", + .qdev.size = sizeof(mv88w8618_pit_state), + .qdev.reset = mv88w8618_pit_reset, + .qdev.vmsd = &mv88w8618_pit_vmsd, +}; + /* Flash config register offsets */ #define MP_FLASHCFG_CFGR0 0x04 @@ -836,11 +966,29 @@ static int mv88w8618_flashcfg_init(SysBusDevice *dev) s->cfgr0 = 0xfffe4285; /* Default as set by U-Boot for 8 MB flash */ iomemtype = cpu_register_io_memory(mv88w8618_flashcfg_readfn, - mv88w8618_flashcfg_writefn, s); + mv88w8618_flashcfg_writefn, s); sysbus_init_mmio(dev, MP_FLASHCFG_SIZE, iomemtype); return 0; } +static const VMStateDescription mv88w8618_flashcfg_vmsd = { + .name = "mv88w8618_flashcfg", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(cfgr0, mv88w8618_flashcfg_state), + VMSTATE_END_OF_LIST() + } +}; + +static SysBusDeviceInfo mv88w8618_flashcfg_info = { + .init = mv88w8618_flashcfg_init, + .qdev.name = "mv88w8618_flashcfg", + .qdev.size = sizeof(mv88w8618_flashcfg_state), + .qdev.vmsd = &mv88w8618_flashcfg_vmsd, +}; + /* Misc register offsets */ #define MP_MISC_BOARD_REVISION 0x18 @@ -933,16 +1081,19 @@ static int mv88w8618_wlan_init(SysBusDevice *dev) #define MP_GPIO_OE_LO 0x008 #define MP_GPIO_OUT_LO 0x00c #define MP_GPIO_IN_LO 0x010 +#define MP_GPIO_IER_LO 0x014 +#define MP_GPIO_IMR_LO 0x018 #define MP_GPIO_ISR_LO 0x020 #define MP_GPIO_OE_HI 0x508 #define MP_GPIO_OUT_HI 0x50c #define MP_GPIO_IN_HI 0x510 +#define MP_GPIO_IER_HI 0x514 +#define MP_GPIO_IMR_HI 0x518 #define MP_GPIO_ISR_HI 0x520 /* GPIO bits & masks */ #define MP_GPIO_LCD_BRIGHTNESS 0x00070000 #define MP_GPIO_I2C_DATA_BIT 29 -#define MP_GPIO_I2C_DATA (1 << MP_GPIO_I2C_DATA_BIT) #define MP_GPIO_I2C_CLOCK_BIT 30 /* LCD brightness bits in GPIO_OE_HI */ @@ -953,12 +1104,11 @@ typedef struct musicpal_gpio_state { uint32_t lcd_brightness; uint32_t out_state; uint32_t in_state; + uint32_t ier; + uint32_t imr; uint32_t isr; - uint32_t i2c_read_data; - uint32_t key_released; - uint32_t keys_event; /* store the received key event */ qemu_irq irq; - qemu_irq out[5]; + qemu_irq out[5]; /* 3 brightness out + 2 lcd (data and clock ) */ } musicpal_gpio_state; static void musicpal_gpio_brightness_update(musicpal_gpio_state *s) { @@ -1001,57 +1151,31 @@ static void musicpal_gpio_brightness_update(musicpal_gpio_state *s) { } /* set lcd brightness GPIOs */ - for (i = 0; i <= 2; i++) + for (i = 0; i <= 2; i++) { qemu_set_irq(s->out[i], (brightness >> i) & 1); + } } -static void musicpal_gpio_keys_update(musicpal_gpio_state *s) -{ - int gpio_mask = 0; - - /* transform the key state for GPIO usage */ - gpio_mask |= (s->keys_event & 15) << 8; - gpio_mask |= ((s->keys_event >> 4) & 15) << 19; - - /* update GPIO state */ - if (s->key_released) { - s->in_state |= gpio_mask; - } else { - s->in_state &= ~gpio_mask; - s->isr = gpio_mask; - qemu_irq_raise(s->irq); - } -} - -static void musicpal_gpio_irq(void *opaque, int irq, int level) +static void musicpal_gpio_pin_event(void *opaque, int pin, int level) { - musicpal_gpio_state *s = (musicpal_gpio_state *) opaque; - - if (irq == 10) { - s->i2c_read_data = level; + musicpal_gpio_state *s = opaque; + uint32_t mask = 1 << pin; + uint32_t delta = level << pin; + uint32_t old = s->in_state & mask; + + s->in_state &= ~mask; + s->in_state |= delta; + + if ((old ^ delta) && + ((level && (s->imr & mask)) || (!level && (s->ier & mask)))) { + s->isr = mask; + qemu_irq_raise(s->irq); } - - /* receives keys bits */ - if (irq <= 7) { - s->keys_event &= ~(1 << irq); - s->keys_event |= level << irq; - return; - } - - /* receives key press/release */ - if (irq == 8) { - s->key_released = level; - return; - } - - /* a key has been transmited */ - if (irq == 9 && level == 1) - musicpal_gpio_keys_update(s); } static uint32_t musicpal_gpio_read(void *opaque, target_phys_addr_t offset) { - musicpal_gpio_state *s = (musicpal_gpio_state *) opaque; + musicpal_gpio_state *s = opaque; switch (offset) { case MP_GPIO_OE_HI: /* used for LCD brightness control */ @@ -1065,11 +1189,18 @@ static uint32_t musicpal_gpio_read(void *opaque, target_phys_addr_t offset) case MP_GPIO_IN_LO: return s->in_state & 0xFFFF; case MP_GPIO_IN_HI: - /* Update received I2C data */ - s->in_state = (s->in_state & ~MP_GPIO_I2C_DATA) | - (s->i2c_read_data << MP_GPIO_I2C_DATA_BIT); return s->in_state >> 16; + case MP_GPIO_IER_LO: + return s->ier & 0xFFFF; + case MP_GPIO_IER_HI: + return s->ier >> 16; + + case MP_GPIO_IMR_LO: + return s->imr & 0xFFFF; + case MP_GPIO_IMR_HI: + return s->imr >> 16; + case MP_GPIO_ISR_LO: return s->isr & 0xFFFF; case MP_GPIO_ISR_HI: @@ -1083,7 +1214,7 @@ static uint32_t musicpal_gpio_read(void *opaque, target_phys_addr_t offset) static void musicpal_gpio_write(void *opaque, target_phys_addr_t offset, uint32_t value) { - musicpal_gpio_state *s = (musicpal_gpio_state *) opaque; + musicpal_gpio_state *s = opaque; switch (offset) { case MP_GPIO_OE_HI: /* used for LCD brightness control */ s->lcd_brightness = (s->lcd_brightness & MP_GPIO_LCD_BRIGHTNESS) | @@ -1103,6 +1234,19 @@ static void musicpal_gpio_write(void *opaque, target_phys_addr_t offset, qemu_set_irq(s->out[4], (s->out_state >> MP_GPIO_I2C_CLOCK_BIT) & 1); break; + case MP_GPIO_IER_LO: + s->ier = (s->ier & 0xFFFF0000) | (value & 0xFFFF); + break; + case MP_GPIO_IER_HI: + s->ier = (s->ier & 0xFFFF) | (value << 16); + break; + + case MP_GPIO_IMR_LO: + s->imr = (s->imr & 0xFFFF0000) | (value & 0xFFFF); + break; + case MP_GPIO_IMR_HI: + s->imr = (s->imr & 0xFFFF) | (value << 16); + break; } } @@ -1118,12 +1262,16 @@ static CPUWriteMemoryFunc * const musicpal_gpio_writefn[] = { musicpal_gpio_write, }; -static void musicpal_gpio_reset(musicpal_gpio_state *s) +static void musicpal_gpio_reset(DeviceState *d) { + musicpal_gpio_state *s = FROM_SYSBUS(musicpal_gpio_state, + sysbus_from_qdev(d)); + + s->lcd_brightness = 0; + s->out_state = 0; s->in_state = 0xffffffff; - s->i2c_read_data = 1; - s->key_released = 0; - s->keys_event = 0; + s->ier = 0; + s->imr = 0; s->isr = 0; } @@ -1138,16 +1286,39 @@ static int musicpal_gpio_init(SysBusDevice *dev) musicpal_gpio_writefn, s); sysbus_init_mmio(dev, MP_GPIO_SIZE, iomemtype); - musicpal_gpio_reset(s); + musicpal_gpio_reset(&dev->qdev); + + qdev_init_gpio_out(&dev->qdev, s->out, ARRAY_SIZE(s->out)); - /* 3 brightness out + 2 lcd (data and clock ) */ - qdev_init_gpio_out(&dev->qdev, s->out, 5); - /* 10 gpio button input + 1 I2C data input */ - qdev_init_gpio_in(&dev->qdev, musicpal_gpio_irq, 11); + qdev_init_gpio_in(&dev->qdev, musicpal_gpio_pin_event, 32); return 0; } +static const VMStateDescription musicpal_gpio_vmsd = { + .name = "musicpal_gpio", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(lcd_brightness, musicpal_gpio_state), + VMSTATE_UINT32(out_state, musicpal_gpio_state), + VMSTATE_UINT32(in_state, musicpal_gpio_state), + VMSTATE_UINT32(ier, musicpal_gpio_state), + VMSTATE_UINT32(imr, musicpal_gpio_state), + VMSTATE_UINT32(isr, musicpal_gpio_state), + VMSTATE_END_OF_LIST() + } +}; + +static SysBusDeviceInfo musicpal_gpio_info = { + .init = musicpal_gpio_init, + .qdev.name = "musicpal_gpio", + .qdev.size = sizeof(musicpal_gpio_state), + .qdev.reset = musicpal_gpio_reset, + .qdev.vmsd = &musicpal_gpio_vmsd, +}; + /* Keyboard codes & masks */ #define KEY_RELEASED 0x80 #define KEY_CODE 0x7f @@ -1163,7 +1334,7 @@ static int musicpal_gpio_init(SysBusDevice *dev) #define KEYCODE_LEFT 0x4b #define KEYCODE_RIGHT 0x4d -#define MP_KEY_WHEEL_VOL (1) +#define MP_KEY_WHEEL_VOL (1 << 0) #define MP_KEY_WHEEL_VOL_INV (1 << 1) #define MP_KEY_WHEEL_NAV (1 << 2) #define MP_KEY_WHEEL_NAV_INV (1 << 3) @@ -1175,13 +1346,13 @@ static int musicpal_gpio_init(SysBusDevice *dev) typedef struct musicpal_key_state { SysBusDevice busdev; uint32_t kbd_extended; - uint32_t keys_state; - qemu_irq out[10]; + uint32_t pressed_keys; + qemu_irq out[8]; } musicpal_key_state; static void musicpal_key_event(void *opaque, int keycode) { - musicpal_key_state *s = (musicpal_key_state *) opaque; + musicpal_key_state *s = opaque; uint32_t event = 0; int i; @@ -1190,7 +1361,7 @@ static void musicpal_key_event(void *opaque, int keycode) return; } - if (s->kbd_extended) + if (s->kbd_extended) { switch (keycode & KEY_CODE) { case KEYCODE_UP: event = MP_KEY_WHEEL_NAV | MP_KEY_WHEEL_NAV_INV; @@ -1208,7 +1379,7 @@ static void musicpal_key_event(void *opaque, int keycode) event = MP_KEY_WHEEL_VOL; break; } - else { + } else { switch (keycode & KEY_CODE) { case KEYCODE_F: event = MP_KEY_BTN_FAVORITS; @@ -1227,27 +1398,30 @@ static void musicpal_key_event(void *opaque, int keycode) break; } /* Do not repeat already pressed buttons */ - if (!(keycode & KEY_RELEASED) && !(s->keys_state & event)) + if (!(keycode & KEY_RELEASED) && (s->pressed_keys & event)) { event = 0; + } } if (event) { - - /* transmit key event on GPIOS */ - for (i = 0; i <= 7; i++) - qemu_set_irq(s->out[i], (event >> i) & 1); - - /* handle key press/release */ + /* Raise GPIO pin first if repeating a key */ + if (!(keycode & KEY_RELEASED) && (s->pressed_keys & event)) { + for (i = 0; i <= 7; i++) { + if (event & (1 << i)) { + qemu_set_irq(s->out[i], 1); + } + } + } + for (i = 0; i <= 7; i++) { + if (event & (1 << i)) { + qemu_set_irq(s->out[i], !!(keycode & KEY_RELEASED)); + } + } if (keycode & KEY_RELEASED) { - s->keys_state |= event; - qemu_irq_raise(s->out[8]); + s->pressed_keys &= ~event; } else { - s->keys_state &= ~event; - qemu_irq_lower(s->out[8]); + s->pressed_keys |= event; } - - /* signal that a key event occured */ - qemu_irq_pulse(s->out[9]); } s->kbd_extended = 0; @@ -1260,16 +1434,34 @@ static int musicpal_key_init(SysBusDevice *dev) sysbus_init_mmio(dev, 0x0, 0); s->kbd_extended = 0; - s->keys_state = 0; + s->pressed_keys = 0; - /* 8 key event GPIO + 1 key press/release + 1 strobe */ - qdev_init_gpio_out(&dev->qdev, s->out, 10); + qdev_init_gpio_out(&dev->qdev, s->out, ARRAY_SIZE(s->out)); qemu_add_kbd_event_handler(musicpal_key_event, s); return 0; } +static const VMStateDescription musicpal_key_vmsd = { + .name = "musicpal_key", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(kbd_extended, musicpal_key_state), + VMSTATE_UINT32(pressed_keys, musicpal_key_state), + VMSTATE_END_OF_LIST() + } +}; + +static SysBusDeviceInfo musicpal_key_info = { + .init = musicpal_key_init, + .qdev.name = "musicpal_key", + .qdev.size = sizeof(musicpal_key_state), + .qdev.vmsd = &musicpal_key_vmsd, +}; + static struct arm_boot_info musicpal_binfo = { .loader_start = 0x0, .board_id = 0x20e, @@ -1297,9 +1489,9 @@ static void musicpal_init(ram_addr_t ram_size, DriveInfo *dinfo; ram_addr_t sram_off; - if (!cpu_model) + if (!cpu_model) { cpu_model = "arm926"; - + } env = cpu_init(cpu_model); if (!env) { fprintf(stderr, "Unable to find CPU definition\n"); @@ -1323,12 +1515,14 @@ static void musicpal_init(ram_addr_t ram_size, pic[MP_TIMER2_IRQ], pic[MP_TIMER3_IRQ], pic[MP_TIMER4_IRQ], NULL); - if (serial_hds[0]) + if (serial_hds[0]) { serial_mm_init(MP_UART1_BASE, 2, pic[MP_UART1_IRQ], 1825000, serial_hds[0], 1); - if (serial_hds[1]) + } + if (serial_hds[1]) { serial_mm_init(MP_UART2_BASE, 2, pic[MP_UART2_IRQ], 1825000, serial_hds[1], 1); + } /* Register flash */ dinfo = drive_get(IF_PFLASH, 0, 0); @@ -1373,17 +1567,22 @@ static void musicpal_init(ram_addr_t ram_size, key_dev = sysbus_create_simple("musicpal_key", 0, NULL); /* I2C read data */ - qdev_connect_gpio_out(i2c_dev, 0, qdev_get_gpio_in(dev, 10)); + qdev_connect_gpio_out(i2c_dev, 0, + qdev_get_gpio_in(dev, MP_GPIO_I2C_DATA_BIT)); /* I2C data */ qdev_connect_gpio_out(dev, 3, qdev_get_gpio_in(i2c_dev, 0)); /* I2C clock */ qdev_connect_gpio_out(dev, 4, qdev_get_gpio_in(i2c_dev, 1)); - for (i = 0; i < 3; i++) + for (i = 0; i < 3; i++) { qdev_connect_gpio_out(dev, i, qdev_get_gpio_in(lcd_dev, i)); - - for (i = 0; i < 10; i++) - qdev_connect_gpio_out(key_dev, i, qdev_get_gpio_in(dev, i)); + } + for (i = 0; i < 4; i++) { + qdev_connect_gpio_out(key_dev, i, qdev_get_gpio_in(dev, i + 8)); + } + for (i = 4; i < 8; i++) { + qdev_connect_gpio_out(key_dev, i, qdev_get_gpio_in(dev, i + 15)); + } #ifdef HAS_AUDIO wm8750_dev = i2c_create_slave(i2c, "wm8750", MP_WM_ADDR); @@ -1417,22 +1616,15 @@ machine_init(musicpal_machine_init); static void musicpal_register_devices(void) { - sysbus_register_dev("mv88w8618_pic", sizeof(mv88w8618_pic_state), - mv88w8618_pic_init); - sysbus_register_dev("mv88w8618_pit", sizeof(mv88w8618_pit_state), - mv88w8618_pit_init); - sysbus_register_dev("mv88w8618_flashcfg", sizeof(mv88w8618_flashcfg_state), - mv88w8618_flashcfg_init); - sysbus_register_dev("mv88w8618_eth", sizeof(mv88w8618_eth_state), - mv88w8618_eth_init); + sysbus_register_withprop(&mv88w8618_pic_info); + sysbus_register_withprop(&mv88w8618_pit_info); + sysbus_register_withprop(&mv88w8618_flashcfg_info); + sysbus_register_withprop(&mv88w8618_eth_info); sysbus_register_dev("mv88w8618_wlan", sizeof(SysBusDevice), mv88w8618_wlan_init); - sysbus_register_dev("musicpal_lcd", sizeof(musicpal_lcd_state), - musicpal_lcd_init); - sysbus_register_dev("musicpal_gpio", sizeof(musicpal_gpio_state), - musicpal_gpio_init); - sysbus_register_dev("musicpal_key", sizeof(musicpal_key_state), - musicpal_key_init); + sysbus_register_withprop(&musicpal_lcd_info); + sysbus_register_withprop(&musicpal_gpio_info); + sysbus_register_withprop(&musicpal_key_info); } device_init(musicpal_register_devices) diff --git a/qemu/hw/pci-hotplug.c b/qemu/hw/pci-hotplug.c index f3dc4210..89974a06 100644 --- a/qemu/hw/pci-hotplug.c +++ b/qemu/hw/pci-hotplug.c @@ -46,6 +46,10 @@ static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon, monitor_printf(mon, "Parameter addr not supported\n"); return NULL; } + + if (nd_table[ret].model && !pci_nic_supported(nd_table[ret].model)) + return NULL; + return pci_nic_init(&nd_table[ret], "rtl8139", devaddr); } diff --git a/qemu/hw/pci.c b/qemu/hw/pci.c index 314c2d0f..46429634 100644 --- a/qemu/hw/pci.c +++ b/qemu/hw/pci.c @@ -806,6 +806,17 @@ static const char * const pci_nic_names[] = { NULL }; +int pci_nic_supported(const char *model) +{ + int i; + + for (i = 0; pci_nic_names[i]; i++) + if (strcmp(model, pci_nic_names[i]) == 0) + return 1; + + return 0; +} + /* Initialize a PCI NIC. */ PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model, const char *default_devaddr) diff --git a/qemu/hw/pci.h b/qemu/hw/pci.h index caba5c85..ba748ff9 100644 --- a/qemu/hw/pci.h +++ b/qemu/hw/pci.h @@ -252,6 +252,7 @@ PCIBus *pci_register_bus(DeviceState *parent, const char *name, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, void *irq_opaque, int devfn_min, int nirq); +int pci_nic_supported(const char *model); PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model, const char *default_devaddr); void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len); diff --git a/qemu/kvm-all.c b/qemu/kvm-all.c index 7dcc5531..5ea0dd8b 100644 --- a/qemu/kvm-all.c +++ b/qemu/kvm-all.c @@ -905,11 +905,15 @@ void kvm_setup_guest_memory(void *start, size_t size) #ifdef KVM_CAP_SET_GUEST_DEBUG static void on_vcpu(CPUState *env, void (*func)(void *data), void *data) { +#ifdef CONFIG_IOTHREAD if (env == cpu_single_env) { func(data); return; } abort(); +#else + func(data); +#endif } struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *env, @@ -938,7 +942,13 @@ struct kvm_set_guest_debug_data { static void kvm_invoke_set_guest_debug(void *data) { struct kvm_set_guest_debug_data *dbg_data = data; - dbg_data->err = kvm_vcpu_ioctl(dbg_data->env, KVM_SET_GUEST_DEBUG, &dbg_data->dbg); + CPUState *env = dbg_data->env; + + if (env->kvm_state->regs_modified) { + kvm_arch_put_registers(env); + env->kvm_state->regs_modified = 0; + } + dbg_data->err = kvm_vcpu_ioctl(env, KVM_SET_GUEST_DEBUG, &dbg_data->dbg); } int kvm_update_guest_debug(CPUState *env, unsigned long reinject_trap) diff --git a/qemu/microblaze-dis.c b/qemu/microblaze-dis.c index 6144334e..016b25e8 100644 --- a/qemu/microblaze-dis.c +++ b/qemu/microblaze-dis.c @@ -543,7 +543,7 @@ print_insn_microblaze (bfd_vma memaddr, struct disassemble_info * info) unsigned long inst, prev_inst; struct op_code_struct * op, *pop; int immval = 0; - boolean immfound = false; + bfd_boolean immfound = false; static bfd_vma prev_insn_addr = -1; /*init the prev insn addr */ static int prev_insn_vma = -1; /*init the prev insn vma */ int curr_insn_vma = info->buffer_vma; diff --git a/qemu/net.c b/qemu/net.c index 2686f78b..bcc51763 100644 --- a/qemu/net.c +++ b/qemu/net.c @@ -2803,8 +2803,13 @@ void net_client_uninit(NICInfo *nd) { nd->vlan->nb_guest_devs--; nb_nics--; - nd->used = 0; - free((void *)nd->model); + + qemu_free((void *)nd->model); + qemu_free((void *)nd->name); + qemu_free((void *)nd->devaddr); + qemu_free((void *)nd->id); + + memset(nd, 0, sizeof(*nd)); } static int net_host_check_device(const char *device) diff --git a/qemu/qemu-common.h b/qemu/qemu-common.h index e407cac4..eda4fea4 100644 --- a/qemu/qemu-common.h +++ b/qemu/qemu-common.h @@ -121,6 +121,8 @@ typedef signed int ssize_t; // more posixyness #ifndef PATH_MAX #define PATH_MAX MAX_PATH + +int gettimeofday(struct timeval* tp, struct timezone* tzp); #endif #endif // end MSVC sections diff --git a/qemu/qemu-config.c b/qemu/qemu-config.c index 555c7ba0..785b1468 100644 --- a/qemu/qemu-config.c +++ b/qemu/qemu-config.c @@ -151,6 +151,26 @@ QemuOptsList qemu_device_opts = { }, }; +QemuOptsList qemu_rtc_opts = { + .name = "rtc", + .head = QTAILQ_HEAD_INITIALIZER(qemu_rtc_opts.head), + .desc = { + { + .name = "base", + .type = QEMU_OPT_STRING, + },{ + .name = "clock", + .type = QEMU_OPT_STRING, +#ifdef TARGET_I386 + },{ + .name = "driftfix", + .type = QEMU_OPT_STRING, +#endif + }, + { /* end if list */ } + }, +}; + static QemuOptsList *lists[] = { &qemu_drive_opts, &qemu_chardev_opts, diff --git a/qemu/qemu-config.h b/qemu/qemu-config.h index 13b0f193..4ae7b74f 100644 --- a/qemu/qemu-config.h +++ b/qemu/qemu-config.h @@ -4,6 +4,7 @@ extern QemuOptsList qemu_drive_opts; extern QemuOptsList qemu_chardev_opts; extern QemuOptsList qemu_device_opts; +extern QemuOptsList qemu_rtc_opts; int qemu_set_option(const char *str); diff --git a/qemu/qemu-monitor.h b/qemu/qemu-monitor.h index 36792961..3152caa2 100644 --- a/qemu/qemu-monitor.h +++ b/qemu/qemu-monitor.h @@ -2,7 +2,7 @@ { "help|?", "name:s?", do_help_cmd, "[cmd]", "show the help" }, -{ "commit", "device:s", do_commit, +{ "commit", "device:B", do_commit, "device|all", "commit changes to the disk images (if -snapshot is used) or backing files" }, { "info", "item:s?", do_info, @@ -93,7 +93,7 @@ "index", "set which mouse device receives events" }, #ifdef HAS_AUDIO -{ "wavcapture", "path:s,freq:i?,bits:i?,nchannels:i?", do_wav_capture, +{ "wavcapture", "path:F,freq:i?,bits:i?,nchannels:i?", do_wav_capture, "path [frequency [bits [channels]]]", "capture audio to a wave file (default frequency=44100 bits=16 channels=2)" }, #endif diff --git a/qemu/qemu-options.h b/qemu/qemu-options.h index 00f940b4..6a7bbc28 100644 --- a/qemu/qemu-options.h +++ b/qemu/qemu-options.h @@ -168,8 +168,7 @@ DEF("win2k-hack", 0, QEMU_OPTION_win2k_hack, #endif #ifdef TARGET_I386 -DEF("rtc-td-hack", 0, QEMU_OPTION_rtc_td_hack, -"-rtc-td-hack use it to fix time drift in Windows ACPI HAL\n") +DEF("rtc-td-hack", 0, QEMU_OPTION_rtc_td_hack, "") #endif #ifdef TARGET_I386 @@ -307,6 +306,7 @@ DEF("net", HAS_ARG, QEMU_OPTION_net, // END HEAVILY MODIFIED SECTION + DEF("bt", HAS_ARG, QEMU_OPTION_bt, \ "\n" \ "-bt hci,null dumb bluetooth HCI - doesn't respond to commands\n" \ @@ -416,11 +416,19 @@ DEF("clock", HAS_ARG, QEMU_OPTION_clock, \ "-clock force the use of the given methods for timer alarm.\n" \ " To see what timers are available use -clock ?\n") -DEF("localtime", 0, QEMU_OPTION_localtime, \ -"-localtime set the real time clock to local time [default=utc]\n") +DEF("localtime", 0, QEMU_OPTION_localtime, "") +DEF("startdate", HAS_ARG, QEMU_OPTION_startdate, "") + +#ifdef TARGET_I386 +DEF("rtc", HAS_ARG, QEMU_OPTION_rtc, \ +"-rtc [base=utc|localtime|date][,clock=host|vm][,driftfix=none|slew]\n" \ +" set the RTC base and clock, enable drift fix for clock ticks\n") +#else +DEF("rtc", HAS_ARG, QEMU_OPTION_rtc, \ +"-rtc [base=utc|localtime|date][,clock=host|vm]\n" \ +" set the RTC base and clock\n") +#endif -DEF("startdate", HAS_ARG, QEMU_OPTION_startdate, \ -"-startdate select initial date of the clock\n") DEF("icount", HAS_ARG, QEMU_OPTION_icount, \ "-icount [N|auto]\n" \ diff --git a/qemu/qemu-options.hx b/qemu/qemu-options.hx index d3aa55b6..f21e9f9d 100644 --- a/qemu/qemu-options.hx +++ b/qemu/qemu-options.hx @@ -681,15 +681,9 @@ slows down the IDE transfers). ETEXI #ifdef TARGET_I386 -DEF("rtc-td-hack", 0, QEMU_OPTION_rtc_td_hack, - "-rtc-td-hack use it to fix time drift in Windows ACPI HAL\n") +HXCOMM Deprecated by -rtc +DEF("rtc-td-hack", 0, QEMU_OPTION_rtc_td_hack, "") #endif -STEXI -@item -rtc-td-hack -Use it if you experience time drift problem in Windows with ACPI HAL. -This option will try to figure out how many timer interrupts were not -processed by the Windows guest and will re-inject them. -ETEXI #ifdef TARGET_I386 DEF("no-fd-bootchk", 0, QEMU_OPTION_no_fd_bootchk, @@ -1500,23 +1494,38 @@ Force the use of the given methods for timer alarm. To see what timers are available use -clock ?. ETEXI -DEF("localtime", 0, QEMU_OPTION_localtime, \ - "-localtime set the real time clock to local time [default=utc]\n") -STEXI -@item -localtime -Set the real time clock to local time (the default is to UTC -time). This option is needed to have correct date in MS-DOS or -Windows. -ETEXI +HXCOMM Options deprecated by -rtc +DEF("localtime", 0, QEMU_OPTION_localtime, "") +DEF("startdate", HAS_ARG, QEMU_OPTION_startdate, "") + +#ifdef TARGET_I386 +DEF("rtc", HAS_ARG, QEMU_OPTION_rtc, \ + "-rtc [base=utc|localtime|date][,clock=host|vm][,driftfix=none|slew]\n" \ + " set the RTC base and clock, enable drift fix for clock ticks\n") +#else +DEF("rtc", HAS_ARG, QEMU_OPTION_rtc, \ + "-rtc [base=utc|localtime|date][,clock=host|vm]\n" \ + " set the RTC base and clock\n") +#endif -DEF("startdate", HAS_ARG, QEMU_OPTION_startdate, \ - "-startdate select initial date of the clock\n") STEXI -@item -startdate @var{date} -Set the initial date of the real time clock. Valid formats for -@var{date} are: @code{now} or @code{2006-06-17T16:01:21} or -@code{2006-06-17}. The default value is @code{now}. +@item -rtc [base=utc|localtime|@var{date}][,clock=host|vm][,driftfix=none|slew] +Specify @option{base} as @code{utc} or @code{localtime} to let the RTC start at the current +UTC or local time, respectively. @code{localtime} is required for correct date in +MS-DOS or Windows. To start at a specific point in time, provide @var{date} in the +format @code{2006-06-17T16:01:21} or @code{2006-06-17}. The default base is UTC. + +By default the RTC is driven by the host system time. This allows to use the +RTC as accurate reference clock inside the guest, specifically if the host +time is smoothly following an accurate external reference clock, e.g. via NTP. +If you want to isolate the guest time from the host, even prevent it from +progressing during suspension, you can set @option{clock} to @code{vm} instead. + +Enable @option{driftfix} (i386 targets only) if you experience time drift problems, +specifically with Windows' ACPI HAL. This option will try to figure out how +many timer interrupts were not processed by the Windows guest and will +re-inject them. ETEXI DEF("icount", HAS_ARG, QEMU_OPTION_icount, \ diff --git a/qemu/qemu-timer.h b/qemu/qemu-timer.h index e44c3342..e7eaa043 100644 --- a/qemu/qemu-timer.h +++ b/qemu/qemu-timer.h @@ -17,6 +17,13 @@ extern QEMUClock *rt_clock; precision clock, usually cpu cycles (use ticks_per_sec). */ extern QEMUClock *vm_clock; +/* The host clock should be use for device models that emulate accurate + real time sources. It will continue to run when the virtual machine + is suspended, and it will reflect system time changes the host may + undergo (e.g. due to NTP). The host clock has the same precision as + the virtual clock. */ +extern QEMUClock *host_clock; + int64_t qemu_get_clock(QEMUClock *clock); QEMUTimer *qemu_new_timer(QEMUClock *clock, QEMUTimerCB *cb, void *opaque); diff --git a/qemu/savevm.c b/qemu/savevm.c index da6bd24c..d817de58 100644 --- a/qemu/savevm.c +++ b/qemu/savevm.c @@ -1056,7 +1056,10 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd, return ret; } while(field->name) { - if (field->version_id <= version_id) { + if ((field->field_exists && + field->field_exists(opaque, version_id)) || + (!field->field_exists && + field->version_id <= version_id)) { void *base_addr = (char *)opaque + field->offset; int ret, i, n_elems = 1; @@ -1072,7 +1075,7 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd, void *addr = (char *)base_addr + field->size * i; if (field->flags & VMS_ARRAY_OF_POINTER) { - addr = *(void**)addr; + addr = *(void **)addr; } if (field->flags & VMS_STRUCT) { ret = vmstate_load_state(f, field->vmsd, addr, field->vmsd->version_id); @@ -1101,25 +1104,28 @@ void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd, if (vmsd->pre_save) { vmsd->pre_save(opaque); } - while(field->name) { - void *base_addr = (char *)opaque + field->offset; - int i, n_elems = 1; + while (field->name) { + if (!field->field_exists || + field->field_exists(opaque, vmsd->version_id)) { + void* base_addr = (char *)opaque + field->offset; + int i, n_elems = 1; - if (field->flags & VMS_ARRAY) { - n_elems = field->num; - } else if (field->flags & VMS_VARRAY) { + if (field->flags & VMS_ARRAY) { + n_elems = field->num; + } else if (field->flags & VMS_VARRAY) { n_elems = *(size_t *)((char *)opaque+field->num_offset); - } - if (field->flags & VMS_POINTER) { - base_addr = *(void **)base_addr; - } - for (i = 0; i < n_elems; i++) { + } + if (field->flags & VMS_POINTER) { + base_addr = *(void **)base_addr; + } + for (i = 0; i < n_elems; i++) { void *addr = (char *)base_addr + field->size * i; - if (field->flags & VMS_STRUCT) { - vmstate_save_state(f, field->vmsd, addr); - } else { - field->info->put(f, addr, field->size); + if (field->flags & VMS_STRUCT) { + vmstate_save_state(f, field->vmsd, addr); + } else { + field->info->put(f, addr, field->size); + } } } field++; diff --git a/qemu/sysemu.h b/qemu/sysemu.h index 9d99e413..da087baf 100644 --- a/qemu/sysemu.h +++ b/qemu/sysemu.h @@ -5,6 +5,7 @@ #include "qemu-common.h" #include "qemu-option.h" #include "qemu-queue.h" +#include "qemu-timer.h" #include "qdict.h" #ifdef _WIN32 @@ -137,6 +138,7 @@ extern int no_quit; extern int semihosting_enabled; extern int old_param; extern int boot_menu; +extern QEMUClock *rtc_clock; #define MAX_NODES 64 extern int nb_numa_nodes; diff --git a/qemu/target-i386/cpu.h b/qemu/target-i386/cpu.h index a9c0e0b9..d35ca925 100644 --- a/qemu/target-i386/cpu.h +++ b/qemu/target-i386/cpu.h @@ -583,10 +583,13 @@ typedef struct { uint64_t mask; } MTRRVar; +#define CPU_NB_REGS64 16 +#define CPU_NB_REGS32 8 + #ifdef TARGET_X86_64 -#define CPU_NB_REGS 16 +#define CPU_NB_REGS CPU_NB_REGS64 #else -#define CPU_NB_REGS 8 +#define CPU_NB_REGS CPU_NB_REGS32 #endif #define NB_MMU_MODES 2 diff --git a/qemu/target-i386/machine.c b/qemu/target-i386/machine.c index e59b4ebe..c0082098 100644 --- a/qemu/target-i386/machine.c +++ b/qemu/target-i386/machine.c @@ -21,16 +21,302 @@ static const VMStateDescription vmstate_segment = { } }; -static void cpu_put_seg(QEMUFile *f, SegmentCache *dt) +#define VMSTATE_SEGMENT(_field, _state) { \ + .name = (stringify(_field)), \ + .size = sizeof(SegmentCache), \ + .vmsd = &vmstate_segment, \ + .flags = VMS_STRUCT, \ + .offset = offsetof(_state, _field) \ + + type_check(SegmentCache,typeof_field(_state, _field)) \ +} + +#define VMSTATE_SEGMENT_ARRAY(_field, _state, _n) \ + VMSTATE_STRUCT_ARRAY(_field, _state, _n, 0, vmstate_segment, SegmentCache) + +static const VMStateDescription vmstate_xmm_reg = { + .name = "xmm_reg", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINT64(XMM_Q(0), XMMReg), + VMSTATE_UINT64(XMM_Q(1), XMMReg), + VMSTATE_END_OF_LIST() + } +}; + +#define VMSTATE_XMM_REGS(_field, _state, _n) \ + VMSTATE_STRUCT_ARRAY(_field, _state, _n, 0, vmstate_xmm_reg, XMMReg) + +static const VMStateDescription vmstate_mtrr_var = { + .name = "mtrr_var", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINT64(base, MTRRVar), + VMSTATE_UINT64(mask, MTRRVar), + VMSTATE_END_OF_LIST() + } +}; + +#define VMSTATE_MTRR_VARS(_field, _state, _n, _v) \ + VMSTATE_STRUCT_ARRAY(_field, _state, _n, _v, vmstate_mtrr_var, MTRRVar) + +static void put_fpreg_error(QEMUFile *f, void *opaque, size_t size) +{ + fprintf(stderr, "call put_fpreg() with invalid arguments\n"); + exit(0); +} + +#ifdef USE_X86LDOUBLE +/* XXX: add that in a FPU generic layer */ +union x86_longdouble { + uint64_t mant; + uint16_t exp; +}; + +#define MANTD1(fp) (fp & ((1LL << 52) - 1)) +#define EXPBIAS1 1023 +#define EXPD1(fp) ((fp >> 52) & 0x7FF) +#define SIGND1(fp) ((fp >> 32) & 0x80000000) + +static void fp64_to_fp80(union x86_longdouble *p, uint64_t temp) +{ + int e; + /* mantissa */ + p->mant = (MANTD1(temp) << 11) | (1LL << 63); + /* exponent + sign */ + e = EXPD1(temp) - EXPBIAS1 + 16383; + e |= SIGND1(temp) >> 16; + p->exp = e; +} + +static int get_fpreg(QEMUFile *f, void *opaque, size_t size) +{ + FPReg *fp_reg = opaque; + uint64_t mant; + uint16_t exp; + + qemu_get_be64s(f, &mant); + qemu_get_be16s(f, &exp); + fp_reg->d = cpu_set_fp80(mant, exp); + return 0; +} + +static void put_fpreg(QEMUFile *f, void *opaque, size_t size) +{ + FPReg *fp_reg = opaque; + uint64_t mant; + uint16_t exp; + /* we save the real CPU data (in case of MMX usage only 'mant' + contains the MMX register */ + cpu_get_fp80(&mant, &exp, fp_reg->d); + qemu_put_be64s(f, &mant); + qemu_put_be16s(f, &exp); +} + +const VMStateInfo vmstate_fpreg = { + .name = "fpreg", + .get = get_fpreg, + .put = put_fpreg, +}; + +static int get_fpreg_1_mmx(QEMUFile *f, void *opaque, size_t size) +{ + union x86_longdouble *p = opaque; + uint64_t mant; + + qemu_get_be64s(f, &mant); + p->mant = mant; + p->exp = 0xffff; + return 0; +} + +const VMStateInfo vmstate_fpreg_1_mmx = { + .name = "fpreg_1_mmx", + .get = get_fpreg_1_mmx, + .put = put_fpreg_error, +}; + +static int get_fpreg_1_no_mmx(QEMUFile *f, void *opaque, size_t size) +{ + union x86_longdouble *p = opaque; + uint64_t mant; + + qemu_get_be64s(f, &mant); + fp64_to_fp80(p, mant); + return 0; +} + +const VMStateInfo vmstate_fpreg_1_no_mmx = { + .name = "fpreg_1_no_mmx", + .get = get_fpreg_1_no_mmx, + .put = put_fpreg_error, +}; + +static bool fpregs_is_0(void *opaque, int version_id) +{ + CPUState *env = opaque; + + return (env->fpregs_format_vmstate == 0); +} + +static bool fpregs_is_1_mmx(void *opaque, int version_id) +{ + CPUState *env = opaque; + int guess_mmx; + + guess_mmx = ((env->fptag_vmstate == 0xff) && + (env->fpus_vmstate & 0x3800) == 0); + return (guess_mmx && (env->fpregs_format_vmstate == 1)); +} + +static bool fpregs_is_1_no_mmx(void *opaque, int version_id) +{ + CPUState *env = opaque; + int guess_mmx; + + guess_mmx = ((env->fptag_vmstate == 0xff) && + (env->fpus_vmstate & 0x3800) == 0); + return (!guess_mmx && (env->fpregs_format_vmstate == 1)); +} + +#define VMSTATE_FP_REGS(_field, _state, _n) \ + VMSTATE_ARRAY_TEST(_field, _state, _n, fpregs_is_0, vmstate_fpreg, FPReg), \ + VMSTATE_ARRAY_TEST(_field, _state, _n, fpregs_is_1_mmx, vmstate_fpreg_1_mmx, FPReg), \ + VMSTATE_ARRAY_TEST(_field, _state, _n, fpregs_is_1_no_mmx, vmstate_fpreg_1_no_mmx, FPReg) + +#else +static int get_fpreg(QEMUFile *f, void *opaque, size_t size) +{ + FPReg *fp_reg = opaque; + + qemu_get_be64s(f, &fp_reg->mmx.MMX_Q(0)); + return 0; +} + +static void put_fpreg(QEMUFile *f, void *opaque, size_t size) +{ + FPReg *fp_reg = opaque; + /* if we use doubles for float emulation, we save the doubles to + avoid losing information in case of MMX usage. It can give + problems if the image is restored on a CPU where long + doubles are used instead. */ + qemu_put_be64s(f, &fp_reg->mmx.MMX_Q(0)); +} + +const VMStateInfo vmstate_fpreg = { + .name = "fpreg", + .get = get_fpreg, + .put = put_fpreg, +}; + +static int get_fpreg_0_mmx(QEMUFile *f, void *opaque, size_t size) +{ + FPReg *fp_reg = opaque; + uint64_t mant; + uint16_t exp; + + qemu_get_be64s(f, &mant); + qemu_get_be16s(f, &exp); + fp_reg->mmx.MMX_Q(0) = mant; + return 0; +} + +const VMStateInfo vmstate_fpreg_0_mmx = { + .name = "fpreg_0_mmx", + .get = get_fpreg_0_mmx, + .put = put_fpreg_error, +}; + +static int get_fpreg_0_no_mmx(QEMUFile *f, void *opaque, size_t size) +{ + FPReg *fp_reg = opaque; + uint64_t mant; + uint16_t exp; + + qemu_get_be64s(f, &mant); + qemu_get_be16s(f, &exp); + + fp_reg->d = cpu_set_fp80(mant, exp); + return 0; +} + +const VMStateInfo vmstate_fpreg_0_no_mmx = { + .name = "fpreg_0_no_mmx", + .get = get_fpreg_0_no_mmx, + .put = put_fpreg_error, +}; + +static bool fpregs_is_1(void *opaque, int version_id) +{ + CPUState *env = opaque; + + return env->fpregs_format_vmstate == 1; +} + +static bool fpregs_is_0_mmx(void *opaque, int version_id) +{ + CPUState *env = opaque; + int guess_mmx; + + guess_mmx = ((env->fptag_vmstate == 0xff) && + (env->fpus_vmstate & 0x3800) == 0); + return guess_mmx && env->fpregs_format_vmstate == 0; +} + +static bool fpregs_is_0_no_mmx(void *opaque, int version_id) { - vmstate_save_state(f, &vmstate_segment, dt); + CPUState *env = opaque; + int guess_mmx; + + guess_mmx = ((env->fptag_vmstate == 0xff) && + (env->fpus_vmstate & 0x3800) == 0); + return !guess_mmx && env->fpregs_format_vmstate == 0; } -static void cpu_get_seg(QEMUFile *f, SegmentCache *dt) +#define VMSTATE_FP_REGS(_field, _state, _n) \ + VMSTATE_ARRAY_TEST(_field, _state, _n, fpregs_is_1, vmstate_fpreg, FPReg), \ + VMSTATE_ARRAY_TEST(_field, _state, _n, fpregs_is_0_mmx, vmstate_fpreg_0_mmx, FPReg), \ + VMSTATE_ARRAY_TEST(_field, _state, _n, fpregs_is_0_no_mmx, vmstate_fpreg_0_no_mmx, FPReg) + +#endif /* USE_X86LDOUBLE */ + +static bool version_is_5(void *opaque, int version_id) { - vmstate_load_state(f, &vmstate_segment, dt, vmstate_segment.version_id); + return version_id == 5; } +#ifdef TARGET_X86_64 +static bool less_than_7(void *opaque, int version_id) +{ + return version_id < 7; +} + +static int get_uint64_as_uint32(QEMUFile *f, void *pv, size_t size) +{ + uint64_t *v = pv; + *v = qemu_get_be32(f); + return 0; +} + +static void put_uint64_as_uint32(QEMUFile *f, void *pv, size_t size) +{ + uint64_t *v = pv; + qemu_put_be32(f, *v); +} + +const VMStateInfo vmstate_hack_uint64_as_uint32 = { + .name = "uint64_as_uint32", + .get = get_uint64_as_uint32, + .put = put_uint64_as_uint32, +}; + +#define VMSTATE_HACK_UINT32(_f, _s, _t) \ + VMSTATE_SINGLE_TEST(_f, _s, _t, vmstate_hack_uint64_as_uint32, uint64_t) +#endif + static void cpu_pre_save(void *opaque) { CPUState *env = opaque; @@ -63,148 +349,6 @@ static void cpu_pre_save(void *opaque) } } -void cpu_save(QEMUFile *f, void *opaque) -{ - CPUState *env = opaque; - int i; - - cpu_pre_save(opaque); - - for(i = 0; i < CPU_NB_REGS; i++) - qemu_put_betls(f, &env->regs[i]); - qemu_put_betls(f, &env->eip); - qemu_put_betls(f, &env->eflags); - qemu_put_be32s(f, &env->hflags); - - /* FPU */ - qemu_put_be16s(f, &env->fpuc); - qemu_put_be16s(f, &env->fpus_vmstate); - qemu_put_be16s(f, &env->fptag_vmstate); - - qemu_put_be16s(f, &env->fpregs_format_vmstate); - - for(i = 0; i < 8; i++) { -#ifdef USE_X86LDOUBLE - { - uint64_t mant; - uint16_t exp; - /* we save the real CPU data (in case of MMX usage only 'mant' - contains the MMX register */ - cpu_get_fp80(&mant, &exp, env->fpregs[i].d); - qemu_put_be64(f, mant); - qemu_put_be16(f, exp); - } -#else - /* if we use doubles for float emulation, we save the doubles to - avoid losing information in case of MMX usage. It can give - problems if the image is restored on a CPU where long - doubles are used instead. */ - qemu_put_be64(f, env->fpregs[i].mmx.MMX_Q(0)); -#endif - } - - for(i = 0; i < 6; i++) - cpu_put_seg(f, &env->segs[i]); - cpu_put_seg(f, &env->ldt); - cpu_put_seg(f, &env->tr); - cpu_put_seg(f, &env->gdt); - cpu_put_seg(f, &env->idt); - - qemu_put_be32s(f, &env->sysenter_cs); - qemu_put_betls(f, &env->sysenter_esp); - qemu_put_betls(f, &env->sysenter_eip); - - qemu_put_betls(f, &env->cr[0]); - qemu_put_betls(f, &env->cr[2]); - qemu_put_betls(f, &env->cr[3]); - qemu_put_betls(f, &env->cr[4]); - - for(i = 0; i < 8; i++) - qemu_put_betls(f, &env->dr[i]); - - /* MMU */ - qemu_put_sbe32s(f, &env->a20_mask); - - /* XMM */ - qemu_put_be32s(f, &env->mxcsr); - for(i = 0; i < CPU_NB_REGS; i++) { - qemu_put_be64s(f, &env->xmm_regs[i].XMM_Q(0)); - qemu_put_be64s(f, &env->xmm_regs[i].XMM_Q(1)); - } - -#ifdef TARGET_X86_64 - qemu_put_be64s(f, &env->efer); - qemu_put_be64s(f, &env->star); - qemu_put_be64s(f, &env->lstar); - qemu_put_be64s(f, &env->cstar); - qemu_put_be64s(f, &env->fmask); - qemu_put_be64s(f, &env->kernelgsbase); -#endif - qemu_put_be32s(f, &env->smbase); - - qemu_put_be64s(f, &env->pat); - qemu_put_be32s(f, &env->hflags2); - - qemu_put_be64s(f, &env->vm_hsave); - qemu_put_be64s(f, &env->vm_vmcb); - qemu_put_be64s(f, &env->tsc_offset); - qemu_put_be64s(f, &env->intercept); - qemu_put_be16s(f, &env->intercept_cr_read); - qemu_put_be16s(f, &env->intercept_cr_write); - qemu_put_be16s(f, &env->intercept_dr_read); - qemu_put_be16s(f, &env->intercept_dr_write); - qemu_put_be32s(f, &env->intercept_exceptions); - qemu_put_8s(f, &env->v_tpr); - - /* MTRRs */ - for(i = 0; i < 11; i++) - qemu_put_be64s(f, &env->mtrr_fixed[i]); - qemu_put_be64s(f, &env->mtrr_deftype); - for(i = 0; i < 8; i++) { - qemu_put_be64s(f, &env->mtrr_var[i].base); - qemu_put_be64s(f, &env->mtrr_var[i].mask); - } - - /* KVM-related states */ - - qemu_put_sbe32s(f, &env->pending_irq_vmstate); - qemu_put_be32s(f, &env->mp_state); - qemu_put_be64s(f, &env->tsc); - - /* MCE */ - qemu_put_be64s(f, &env->mcg_cap); - qemu_put_be64s(f, &env->mcg_status); - qemu_put_be64s(f, &env->mcg_ctl); - for (i = 0; i < MCE_BANKS_DEF * 4; i++) { - qemu_put_be64s(f, &env->mce_banks[i]); - } - qemu_put_be64s(f, &env->tsc_aux); - } - -#ifdef USE_X86LDOUBLE -/* XXX: add that in a FPU generic layer */ -union x86_longdouble { - uint64_t mant; - uint16_t exp; -}; - -#define MANTD1(fp) (fp & ((1LL << 52) - 1)) -#define EXPBIAS1 1023 -#define EXPD1(fp) ((fp >> 52) & 0x7FF) -#define SIGND1(fp) ((fp >> 32) & 0x80000000) - -static void fp64_to_fp80(union x86_longdouble *p, uint64_t temp) -{ - int e; - /* mantissa */ - p->mant = (MANTD1(temp) << 11) | (1LL << 63); - /* exponent + sign */ - e = EXPD1(temp) - EXPBIAS1 + 16383; - e |= SIGND1(temp) >> 16; - p->exp = e; -} -#endif - static int cpu_pre_load(void *opaque) { CPUState *env = opaque; @@ -242,162 +386,104 @@ static int cpu_post_load(void *opaque, int version_id) return cpu_post_load(env, version_id); } -int cpu_load(QEMUFile *f, void *opaque, int version_id) -{ - CPUState *env = opaque; - int i, guess_mmx; - - cpu_pre_load(env); - - if (version_id < 3 || version_id > CPU_SAVE_VERSION) - return -EINVAL; - for(i = 0; i < CPU_NB_REGS; i++) - qemu_get_betls(f, &env->regs[i]); - qemu_get_betls(f, &env->eip); - qemu_get_betls(f, &env->eflags); - qemu_get_be32s(f, &env->hflags); - - qemu_get_be16s(f, &env->fpuc); - qemu_get_be16s(f, &env->fpus_vmstate); - qemu_get_be16s(f, &env->fptag_vmstate); - qemu_get_be16s(f, &env->fpregs_format_vmstate); - - /* NOTE: we cannot always restore the FPU state if the image come - from a host with a different 'USE_X86LDOUBLE' define. We guess - if we are in an MMX state to restore correctly in that case. */ - guess_mmx = ((env->fptag_vmstate == 0xff) && (env->fpus_vmstate & 0x3800) == 0); - for(i = 0; i < 8; i++) { - uint64_t mant; - uint16_t exp; - - switch(env->fpregs_format_vmstate) { - case 0: - mant = qemu_get_be64(f); - exp = qemu_get_be16(f); -#ifdef USE_X86LDOUBLE - env->fpregs[i].d = cpu_set_fp80(mant, exp); -#else - /* difficult case */ - if (guess_mmx) - env->fpregs[i].mmx.MMX_Q(0) = mant; - else - env->fpregs[i].d = cpu_set_fp80(mant, exp); -#endif - break; - case 1: - mant = qemu_get_be64(f); -#ifdef USE_X86LDOUBLE - { - union x86_longdouble *p; - /* difficult case */ - p = (void *)&env->fpregs[i]; - if (guess_mmx) { - p->mant = mant; - p->exp = 0xffff; - } else { - fp64_to_fp80(p, mant); - } - } +const VMStateDescription vmstate_cpu = { + .name = "cpu", + .version_id = CPU_SAVE_VERSION, + .minimum_version_id = 3, + .minimum_version_id_old = 3, + .pre_save = cpu_pre_save, + .pre_load = cpu_pre_load, + .post_load = cpu_post_load, + .fields = (VMStateField []) { + VMSTATE_UINTTL_ARRAY(regs, CPUState, CPU_NB_REGS), + VMSTATE_UINTTL(eip, CPUState), + VMSTATE_UINTTL(eflags, CPUState), + VMSTATE_UINT32(hflags, CPUState), + /* FPU */ + VMSTATE_UINT16(fpuc, CPUState), + VMSTATE_UINT16(fpus_vmstate, CPUState), + VMSTATE_UINT16(fptag_vmstate, CPUState), + VMSTATE_UINT16(fpregs_format_vmstate, CPUState), + VMSTATE_FP_REGS(fpregs, CPUState, 8), + + VMSTATE_SEGMENT_ARRAY(segs, CPUState, 6), + VMSTATE_SEGMENT(ldt, CPUState), + VMSTATE_SEGMENT(tr, CPUState), + VMSTATE_SEGMENT(gdt, CPUState), + VMSTATE_SEGMENT(idt, CPUState), + + VMSTATE_UINT32(sysenter_cs, CPUState), +#ifdef TARGET_X86_64 + /* Hack: In v7 size changed from 32 to 64 bits on x86_64 */ + VMSTATE_HACK_UINT32(sysenter_esp, CPUState, less_than_7), + VMSTATE_HACK_UINT32(sysenter_eip, CPUState, less_than_7), + VMSTATE_UINTTL_V(sysenter_esp, CPUState, 7), + VMSTATE_UINTTL_V(sysenter_eip, CPUState, 7), #else - env->fpregs[i].mmx.MMX_Q(0) = mant; + VMSTATE_UINTTL(sysenter_esp, CPUState), + VMSTATE_UINTTL(sysenter_eip, CPUState), #endif - break; - default: - return -EINVAL; - } - } - - for(i = 0; i < 6; i++) - cpu_get_seg(f, &env->segs[i]); - cpu_get_seg(f, &env->ldt); - cpu_get_seg(f, &env->tr); - cpu_get_seg(f, &env->gdt); - cpu_get_seg(f, &env->idt); - - qemu_get_be32s(f, &env->sysenter_cs); - if (version_id >= 7) { - qemu_get_betls(f, &env->sysenter_esp); - qemu_get_betls(f, &env->sysenter_eip); - } else { - env->sysenter_esp = qemu_get_be32(f); - env->sysenter_eip = qemu_get_be32(f); - } - - qemu_get_betls(f, &env->cr[0]); - qemu_get_betls(f, &env->cr[2]); - qemu_get_betls(f, &env->cr[3]); - qemu_get_betls(f, &env->cr[4]); - for(i = 0; i < 8; i++) - qemu_get_betls(f, &env->dr[i]); - - qemu_get_sbe32s(f, &env->a20_mask); - - qemu_get_be32s(f, &env->mxcsr); - for(i = 0; i < CPU_NB_REGS; i++) { - qemu_get_be64s(f, &env->xmm_regs[i].XMM_Q(0)); - qemu_get_be64s(f, &env->xmm_regs[i].XMM_Q(1)); - } + VMSTATE_UINTTL(cr[0], CPUState), + VMSTATE_UINTTL(cr[2], CPUState), + VMSTATE_UINTTL(cr[3], CPUState), + VMSTATE_UINTTL(cr[4], CPUState), + VMSTATE_UINTTL_ARRAY(dr, CPUState, 8), + /* MMU */ + VMSTATE_INT32(a20_mask, CPUState), + /* XMM */ + VMSTATE_UINT32(mxcsr, CPUState), + VMSTATE_XMM_REGS(xmm_regs, CPUState, CPU_NB_REGS), #ifdef TARGET_X86_64 - qemu_get_be64s(f, &env->efer); - qemu_get_be64s(f, &env->star); - qemu_get_be64s(f, &env->lstar); - qemu_get_be64s(f, &env->cstar); - qemu_get_be64s(f, &env->fmask); - qemu_get_be64s(f, &env->kernelgsbase); + VMSTATE_UINT64(efer, CPUState), + VMSTATE_UINT64(star, CPUState), + VMSTATE_UINT64(lstar, CPUState), + VMSTATE_UINT64(cstar, CPUState), + VMSTATE_UINT64(fmask, CPUState), + VMSTATE_UINT64(kernelgsbase, CPUState), #endif - if (version_id >= 4) { - qemu_get_be32s(f, &env->smbase); - } - if (version_id >= 5) { - qemu_get_be64s(f, &env->pat); - qemu_get_be32s(f, &env->hflags2); - if (version_id < 6) - qemu_get_be32s(f, &env->halted); - - qemu_get_be64s(f, &env->vm_hsave); - qemu_get_be64s(f, &env->vm_vmcb); - qemu_get_be64s(f, &env->tsc_offset); - qemu_get_be64s(f, &env->intercept); - qemu_get_be16s(f, &env->intercept_cr_read); - qemu_get_be16s(f, &env->intercept_cr_write); - qemu_get_be16s(f, &env->intercept_dr_read); - qemu_get_be16s(f, &env->intercept_dr_write); - qemu_get_be32s(f, &env->intercept_exceptions); - qemu_get_8s(f, &env->v_tpr); - } - - if (version_id >= 8) { + VMSTATE_UINT32_V(smbase, CPUState, 4), + + VMSTATE_UINT64_V(pat, CPUState, 5), + VMSTATE_UINT32_V(hflags2, CPUState, 5), + + VMSTATE_UINT32_TEST(halted, CPUState, version_is_5), + VMSTATE_UINT64_V(vm_hsave, CPUState, 5), + VMSTATE_UINT64_V(vm_vmcb, CPUState, 5), + VMSTATE_UINT64_V(tsc_offset, CPUState, 5), + VMSTATE_UINT64_V(intercept, CPUState, 5), + VMSTATE_UINT16_V(intercept_cr_read, CPUState, 5), + VMSTATE_UINT16_V(intercept_cr_write, CPUState, 5), + VMSTATE_UINT16_V(intercept_dr_read, CPUState, 5), + VMSTATE_UINT16_V(intercept_dr_write, CPUState, 5), + VMSTATE_UINT32_V(intercept_exceptions, CPUState, 5), + VMSTATE_UINT8_V(v_tpr, CPUState, 5), /* MTRRs */ - for(i = 0; i < 11; i++) - qemu_get_be64s(f, &env->mtrr_fixed[i]); - qemu_get_be64s(f, &env->mtrr_deftype); - for(i = 0; i < 8; i++) { - qemu_get_be64s(f, &env->mtrr_var[i].base); - qemu_get_be64s(f, &env->mtrr_var[i].mask); - } - } - - if (version_id >= 9) { - qemu_get_sbe32s(f, &env->pending_irq_vmstate); - qemu_get_be32s(f, &env->mp_state); - qemu_get_be64s(f, &env->tsc); - } - - if (version_id >= 10) { - qemu_get_be64s(f, &env->mcg_cap); - qemu_get_be64s(f, &env->mcg_status); - qemu_get_be64s(f, &env->mcg_ctl); - for (i = 0; i < MCE_BANKS_DEF * 4; i++) { - qemu_get_be64s(f, &env->mce_banks[i]); - } + VMSTATE_UINT64_ARRAY_V(mtrr_fixed, CPUState, 11, 8), + VMSTATE_UINT64_V(mtrr_deftype, CPUState, 8), + VMSTATE_MTRR_VARS(mtrr_var, CPUState, 8, 8), + /* KVM-related states */ + VMSTATE_INT32_V(pending_irq_vmstate, CPUState, 9), + VMSTATE_UINT32_V(mp_state, CPUState, 9), + VMSTATE_UINT64_V(tsc, CPUState, 9), + /* MCE */ + VMSTATE_UINT64_V(mcg_cap, CPUState, 10), + VMSTATE_UINT64_V(mcg_status, CPUState, 10), + VMSTATE_UINT64_V(mcg_ctl, CPUState, 10), + VMSTATE_UINT64_ARRAY_V(mce_banks, CPUState, MCE_BANKS_DEF *4, 10), + /* rdtscp */ + VMSTATE_UINT64_V(tsc_aux, CPUState, 11), + VMSTATE_END_OF_LIST() } +}; - if (version_id >= 11) { - qemu_get_be64s(f, &env->tsc_aux); - } +void cpu_save(QEMUFile *f, void *opaque) +{ + vmstate_save_state(f, &vmstate_cpu, opaque); +} - tlb_flush(env, 1); - return 0; +int cpu_load(QEMUFile *f, void *opaque, int version_id) +{ + return vmstate_load_state(f, &vmstate_cpu, opaque, version_id); } diff --git a/qemu/vl.c b/qemu/vl.c index 1907dea3..e74e6951 100644 --- a/qemu/vl.c +++ b/qemu/vl.c @@ -207,6 +207,7 @@ int vm_running; int autostart; static int rtc_utc = 1; static int rtc_date_offset = -1; /* -1 means no change */ +QEMUClock *rtc_clock; int vga_interface_type = VGA_CIRRUS; #ifdef TARGET_SPARC int graphic_width = 1024; @@ -542,6 +543,14 @@ uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) /***********************************************************/ /* real time host monotonic timer */ +static int64_t get_clock_realtime(void) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000000000LL + (tv.tv_usec * 1000); +} + #ifdef WIN32 static int64_t clock_freq; @@ -596,9 +605,7 @@ static int64_t get_clock(void) { /* XXX: using gettimeofday leads to problems if the date changes, so it should be avoided. */ - struct timeval tv; - gettimeofday(&tv, NULL); - return tv.tv_sec * 1000000000LL + (tv.tv_usec * 1000); + return get_clock_realtime(); } } #endif @@ -687,8 +694,9 @@ void cpu_disable_ticks(void) /***********************************************************/ /* timers */ -#define QEMU_TIMER_REALTIME 0 -#define QEMU_TIMER_VIRTUAL 1 +#define QEMU_CLOCK_REALTIME 0 +#define QEMU_CLOCK_VIRTUAL 1 +#define QEMU_CLOCK_HOST 2 struct QEMUClock { int type; @@ -915,10 +923,13 @@ static void configure_alarms(char const *opt) } } +#define QEMU_NUM_CLOCKS 3 + QEMUClock *rt_clock; QEMUClock *vm_clock; +QEMUClock *host_clock; -static QEMUTimer *active_timers[2]; +static QEMUTimer *active_timers[QEMU_NUM_CLOCKS]; static QEMUClock *qemu_new_clock(int type) { @@ -1036,23 +1047,28 @@ static void qemu_run_timers(QEMUTimer **ptimer_head, int64_t current_time) int64_t qemu_get_clock(QEMUClock *clock) { switch(clock->type) { - case QEMU_TIMER_REALTIME: + case QEMU_CLOCK_REALTIME: return get_clock() / 1000000; default: - case QEMU_TIMER_VIRTUAL: + case QEMU_CLOCK_VIRTUAL: if (use_icount) { return cpu_get_icount(); } else { return cpu_get_clock(); } + case QEMU_CLOCK_HOST: + return get_clock_realtime(); } } -static void init_timers(void) +static void init_clocks(void) { init_get_clock(); - rt_clock = qemu_new_clock(QEMU_TIMER_REALTIME); - vm_clock = qemu_new_clock(QEMU_TIMER_VIRTUAL); + rt_clock = qemu_new_clock(QEMU_CLOCK_REALTIME); + vm_clock = qemu_new_clock(QEMU_CLOCK_VIRTUAL); + host_clock = qemu_new_clock(QEMU_CLOCK_HOST); + + rtc_clock = host_clock; } /* save a timer */ @@ -1134,10 +1150,12 @@ static void host_alarm_handler(int host_signum) #endif if (alarm_has_dynticks(alarm_timer) || (!use_icount && - qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL], + qemu_timer_expired(active_timers[QEMU_CLOCK_VIRTUAL], qemu_get_clock(vm_clock))) || - qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME], - qemu_get_clock(rt_clock))) { + qemu_timer_expired(active_timers[QEMU_CLOCK_REALTIME], + qemu_get_clock(rt_clock)) || + qemu_timer_expired(active_timers[QEMU_CLOCK_HOST], + qemu_get_clock(host_clock))) { qemu_event_increment(); if (alarm_timer) alarm_timer->flags |= ALARM_FLAG_EXPIRED; @@ -1154,14 +1172,18 @@ static void host_alarm_handler(int host_signum) static int64_t qemu_next_deadline(void) { - int64_t delta; + /* To avoid problems with overflow limit this to 2^32. */ + int64_t delta = INT32_MAX; - if (active_timers[QEMU_TIMER_VIRTUAL]) { - delta = active_timers[QEMU_TIMER_VIRTUAL]->expire_time - + if (active_timers[QEMU_CLOCK_VIRTUAL]) { + delta = active_timers[QEMU_CLOCK_VIRTUAL]->expire_time - qemu_get_clock(vm_clock); - } else { - /* To avoid problems with overflow limit this to 2^32. */ - delta = INT32_MAX; + } + if (active_timers[QEMU_CLOCK_HOST]) { + int64_t hdelta = active_timers[QEMU_CLOCK_HOST]->expire_time - + qemu_get_clock(host_clock); + if (hdelta < delta) + delta = hdelta; } if (delta < 0) @@ -1170,7 +1192,7 @@ static int64_t qemu_next_deadline(void) return delta; } -#if defined(__linux__) || defined(_WIN32) +#if defined(__linux__) static uint64_t qemu_next_deadline_dyntick(void) { int64_t delta; @@ -1181,8 +1203,8 @@ static uint64_t qemu_next_deadline_dyntick(void) else delta = (qemu_next_deadline() + 999) / 1000; - if (active_timers[QEMU_TIMER_REALTIME]) { - rtdelta = (active_timers[QEMU_TIMER_REALTIME]->expire_time - + if (active_timers[QEMU_CLOCK_REALTIME]) { + rtdelta = (active_timers[QEMU_CLOCK_REALTIME]->expire_time - qemu_get_clock(rt_clock))*1000; if (rtdelta < delta) delta = rtdelta; @@ -1364,8 +1386,9 @@ static void dynticks_rearm_timer(struct qemu_alarm_timer *t) int64_t nearest_delta_us = INT64_MAX; int64_t current_us; - if (!active_timers[QEMU_TIMER_REALTIME] && - !active_timers[QEMU_TIMER_VIRTUAL]) + if (!active_timers[QEMU_CLOCK_REALTIME] && + !active_timers[QEMU_CLOCK_VIRTUAL] && + !active_timers[QEMU_CLOCK_HOST]) return; nearest_delta_us = qemu_next_deadline_dyntick(); @@ -1479,15 +1502,12 @@ static void win32_stop_timer(struct qemu_alarm_timer *t) static void win32_rearm_timer(struct qemu_alarm_timer *t) { struct qemu_alarm_win32 *data = t->priv; - uint64_t nearest_delta_us; - if (!active_timers[QEMU_TIMER_REALTIME] && - !active_timers[QEMU_TIMER_VIRTUAL]) + if (!active_timers[QEMU_CLOCK_REALTIME] && + !active_timers[QEMU_CLOCK_VIRTUAL] && + !active_timers[QEMU_CLOCK_HOST]) return; - nearest_delta_us = qemu_next_deadline_dyntick(); - nearest_delta_us /= 1000; - timeKillEvent(data->timerId); data->timerId = timeSetEvent(1, @@ -1576,6 +1596,85 @@ int qemu_timedate_diff(struct tm *tm) return seconds - time(NULL); } +static void configure_rtc_date_offset(const char *startdate, int legacy) +{ + time_t rtc_start_date; + struct tm tm; + + if (!strcmp(startdate, "now") && legacy) { + rtc_date_offset = -1; + } else { + if (sscanf(startdate, "%d-%d-%dT%d:%d:%d", + &tm.tm_year, + &tm.tm_mon, + &tm.tm_mday, + &tm.tm_hour, + &tm.tm_min, + &tm.tm_sec) == 6) { + /* OK */ + } else if (sscanf(startdate, "%d-%d-%d", + &tm.tm_year, + &tm.tm_mon, + &tm.tm_mday) == 3) { + tm.tm_hour = 0; + tm.tm_min = 0; + tm.tm_sec = 0; + } else { + goto date_fail; + } + tm.tm_year -= 1900; + tm.tm_mon--; + rtc_start_date = mktimegm(&tm); + if (rtc_start_date == -1) { + date_fail: + fprintf(stderr, "Invalid date format. Valid formats are:\n" + "'2006-06-17T16:01:21' or '2006-06-17'\n"); + exit(1); + } + rtc_date_offset = time(NULL) - rtc_start_date; + } +} + +static void configure_rtc(QemuOpts *opts) +{ + const char *value; + + value = qemu_opt_get(opts, "base"); + if (value) { + if (!strcmp(value, "utc")) { + rtc_utc = 1; + } else if (!strcmp(value, "localtime")) { + rtc_utc = 0; + } else { + configure_rtc_date_offset(value, 0); + } + } + value = qemu_opt_get(opts, "clock"); + if (value) { + if (!strcmp(value, "host")) { + rtc_clock = host_clock; + } else if (!strcmp(value, "vm")) { + rtc_clock = vm_clock; + } else { + fprintf(stderr, "qemu: invalid option value '%s'\n", value); + 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); + } + } +#endif +} + #ifdef _WIN32 static void socket_cleanup(void) { @@ -3603,9 +3702,14 @@ void qemu_cpu_kick(void *_env) qemu_thread_signal(env->thread, SIGUSR1); } -int qemu_cpu_self(void *env) +int qemu_cpu_self(void *_env) { - return (cpu_single_env != NULL); + CPUState *env = _env; + QemuThread this; + + qemu_thread_self(&this); + + return qemu_thread_equal(&this, env->thread); } static void cpu_signal(int sig) @@ -3919,14 +4023,17 @@ void main_loop_wait(int timeout) /* vm time timers */ if (vm_running) { if (!cur_cpu || likely(!(cur_cpu->singlestep_enabled & SSTEP_NOTIMER))) - qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL], - qemu_get_clock(vm_clock)); + qemu_run_timers(&active_timers[QEMU_CLOCK_VIRTUAL], + qemu_get_clock(vm_clock)); } /* real time timers */ - qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME], + qemu_run_timers(&active_timers[QEMU_CLOCK_REALTIME], qemu_get_clock(rt_clock)); + qemu_run_timers(&active_timers[QEMU_CLOCK_HOST], + qemu_get_clock(host_clock)); + /* Check bottom-halves last in case any of the earlier events triggered them. */ qemu_bh_poll(); @@ -4678,6 +4785,8 @@ int __declspec(dllexport) qemu_main(int argc, char** argv, char** envp) CPUState *env; int show_vnc_port = 0; + init_clocks(); + qemu_errors_to_file(stderr); qemu_cache_utils_init(envp); @@ -5374,42 +5483,15 @@ int __declspec(dllexport) qemu_main(int argc, char** argv, char** envp) configure_alarms(optarg); break; case QEMU_OPTION_startdate: - { - struct tm tm; - time_t rtc_start_date; - if (!strcmp(optarg, "now")) { - rtc_date_offset = -1; - } else { - if (sscanf(optarg, "%d-%d-%dT%d:%d:%d", - &tm.tm_year, - &tm.tm_mon, - &tm.tm_mday, - &tm.tm_hour, - &tm.tm_min, - &tm.tm_sec) == 6) { - /* OK */ - } else if (sscanf(optarg, "%d-%d-%d", - &tm.tm_year, - &tm.tm_mon, - &tm.tm_mday) == 3) { - tm.tm_hour = 0; - tm.tm_min = 0; - tm.tm_sec = 0; - } else { - goto date_fail; - } - tm.tm_year -= 1900; - tm.tm_mon--; - rtc_start_date = mktimegm(&tm); - if (rtc_start_date == -1) { - date_fail: - fprintf(stderr, "Invalid date format. Valid format are:\n" - "'now' or '2006-06-17T16:01:21' or '2006-06-17'\n"); - exit(1); - } - rtc_date_offset = time(NULL) - rtc_start_date; - } + configure_rtc_date_offset(optarg, 1); + break; + case QEMU_OPTION_rtc: + opts = qemu_opts_parse(&qemu_rtc_opts, optarg, NULL); + if (!opts) { + fprintf(stderr, "parse error: %s\n", optarg); + exit(1); } + configure_rtc(opts); break; case QEMU_OPTION_tb_size: tb_size = strtol(optarg, NULL, 0); @@ -5570,7 +5652,6 @@ int __declspec(dllexport) qemu_main(int argc, char** argv, char** envp) setvbuf(stdout, NULL, _IOLBF, 0); #endif - init_timers(); if (init_timer_alarm() < 0) { fprintf(stderr, "could not initialize alarm timer\n"); exit(1);