From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1LCtaK-0002CW-0e for qemu-devel@nongnu.org; Wed, 17 Dec 2008 05:24:56 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1LCtaI-0002C2-Ve for qemu-devel@nongnu.org; Wed, 17 Dec 2008 05:24:55 -0500 Received: from [199.232.76.173] (port=60463 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1LCtaI-0002Bw-Px for qemu-devel@nongnu.org; Wed, 17 Dec 2008 05:24:54 -0500 Received: from mx2.redhat.com ([66.187.237.31]:58661) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1LCtaI-0006JH-7Z for qemu-devel@nongnu.org; Wed, 17 Dec 2008 05:24:54 -0500 Received: from int-mx2.corp.redhat.com (int-mx2.corp.redhat.com [172.16.27.26]) by mx2.redhat.com (8.13.8/8.13.8) with ESMTP id mBHAOriO021509 for ; Wed, 17 Dec 2008 05:24:53 -0500 Received: from ns3.rdu.redhat.com (ns3.rdu.redhat.com [10.11.255.199]) by int-mx2.corp.redhat.com (8.13.1/8.13.1) with ESMTP id mBHAOqU5019006 for ; Wed, 17 Dec 2008 05:24:52 -0500 Received: from dhcp-1-237.tlv.redhat.com (dhcp-1-237.tlv.redhat.com [10.35.1.237]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id mBHAOo72002498 for ; Wed, 17 Dec 2008 05:24:51 -0500 Date: Wed, 17 Dec 2008 12:25:43 +0200 From: Gleb Natapov Subject: Re: [Qemu-devel] [PATCH] Time drift again. Message-ID: <20081217102543.GI13794@redhat.com> References: <20081216122511.GE13794@redhat.com> <4947C1BB.2060202@codemonkey.ws> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <4947C1BB.2060202@codemonkey.ws> Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org > Modulo documentation, I think this patch is just about the best we can > do. I'm inclined to commit this once you've sent out an updated patch > unless anyone has major objections. > Here is the latest version with all comments addressed: Signed-off-by: Gleb Natapov diff --git a/hw/apic.c b/hw/apic.c index a2915f8..dfe51d8 100644 --- a/hw/apic.c +++ b/hw/apic.c @@ -100,6 +100,8 @@ struct IOAPICState { static int apic_io_memory; static APICState *local_apics[MAX_APICS + 1]; static int last_apic_id = 0; +static int apic_irq_delivered; + static void apic_init_ipi(APICState *s); static void apic_set_irq(APICState *s, int vector_num, int trigger_mode); @@ -133,6 +135,14 @@ static inline void reset_bit(uint32_t *tab, int index) tab[i] &= ~mask; } +static inline int get_bit(uint32_t *tab, int index) +{ + int i, mask; + i = index >> 5; + mask = 1 << (index & 0x1f); + return !!(tab[i] & mask); +} + static void apic_local_deliver(CPUState *env, int vector) { APICState *s = env->apic_state; @@ -349,8 +359,20 @@ static void apic_update_irq(APICState *s) cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD); } +void apic_reset_irq_delivered(void) +{ + apic_irq_delivered = 0; +} + +int apic_get_irq_delivered(void) +{ + return apic_irq_delivered; +} + static void apic_set_irq(APICState *s, int vector_num, int trigger_mode) { + apic_irq_delivered += !get_bit(s->irr, vector_num); + set_bit(s->irr, vector_num); if (trigger_mode) set_bit(s->tmr, vector_num); diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index ac41a94..a8f31bf 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -65,6 +65,10 @@ struct RTCState { int64_t next_periodic_time; /* second update */ int64_t next_second_time; +#ifdef TARGET_I386 + uint32_t irq_coalesced; + uint32_t period; +#endif QEMUTimer *second_timer; QEMUTimer *second_timer2; }; @@ -84,12 +88,20 @@ static void rtc_timer_update(RTCState *s, int64_t current_time) period_code += 7; /* period in 32 Khz cycles */ period = 1 << (period_code - 1); +#ifdef TARGET_I386 + if(period != s->period) + s->irq_coalesced = (s->irq_coalesced * s->period) / period; + s->period = period; +#endif /* compute 32 khz clock */ cur_clock = muldiv64(current_time, 32768, ticks_per_sec); next_irq_clock = (cur_clock & ~(period - 1)) + period; s->next_periodic_time = muldiv64(next_irq_clock, ticks_per_sec, 32768) + 1; qemu_mod_timer(s->periodic_timer, s->next_periodic_time); } else { +#ifdef TARGET_I386 + s->irq_coalesced = 0; +#endif qemu_del_timer(s->periodic_timer); } } @@ -99,6 +111,12 @@ static void rtc_periodic_timer(void *opaque) RTCState *s = opaque; rtc_timer_update(s, s->next_periodic_time); +#ifdef TARGET_I386 + if ((s->cmos_data[RTC_REG_C] & 0xc0) && rtc_td_hack) { + s->irq_coalesced++; + return; + } +#endif s->cmos_data[RTC_REG_C] |= 0xc0; qemu_irq_raise(s->irq); } @@ -359,6 +377,15 @@ static uint32_t cmos_ioport_read(void *opaque, uint32_t addr) case RTC_REG_C: ret = s->cmos_data[s->cmos_index]; qemu_irq_lower(s->irq); +#ifdef TARGET_I386 + if(s->irq_coalesced) { + apic_reset_irq_delivered(); + qemu_irq_raise(s->irq); + if (apic_get_irq_delivered()) + s->irq_coalesced--; + break; + } +#endif s->cmos_data[RTC_REG_C] = 0x00; break; default: @@ -453,6 +480,28 @@ static int rtc_load(QEMUFile *f, void *opaque, int version_id) return 0; } +#ifdef TARGET_I386 +static void rtc_save_td(QEMUFile *f, void *opaque) +{ + RTCState *s = opaque; + + qemu_put_be32(f, s->irq_coalesced); + qemu_put_be32(f, s->period); +} + +static int rtc_load_td(QEMUFile *f, void *opaque, int version_id) +{ + RTCState *s = opaque; + + if (version_id != 1) + return -EINVAL; + + s->irq_coalesced = qemu_get_be32(f); + s->period = qemu_get_be32(f); + return 0; +} +#endif + RTCState *rtc_init(int base, qemu_irq irq) { RTCState *s; @@ -483,6 +532,10 @@ RTCState *rtc_init(int base, qemu_irq irq) register_ioport_read(base, 2, 1, cmos_ioport_read, s); register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s); +#ifdef TARGET_I386 + if (rtc_td_hack) + register_savevm("mc146818rtc-td", base, 1, rtc_save_td, rtc_load_td, s); +#endif return s; } @@ -589,5 +642,9 @@ RTCState *rtc_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq) cpu_register_physical_memory(base, 2 << it_shift, io_memory); register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s); +#ifdef TARGET_I386 + if (rtc_td_hack) + register_savevm("mc146818rtc-td", base, 1, rtc_save_td, rtc_load_td, s); +#endif return s; } diff --git a/hw/pc.h b/hw/pc.h index 39b220f..840f00a 100644 --- a/hw/pc.h +++ b/hw/pc.h @@ -46,6 +46,8 @@ void apic_deliver_pic_intr(CPUState *env, int level); int apic_get_interrupt(CPUState *env); IOAPICState *ioapic_init(void); void ioapic_set_irq(void *opaque, int vector, int level); +void apic_reset_irq_delivered(void); +int apic_get_irq_delivered(void); /* i8254.c */ diff --git a/qemu-doc.texi b/qemu-doc.texi index 698e0d5..dfbddab 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -418,6 +418,11 @@ Use it when installing Windows 2000 to avoid a disk full bug. After Windows 2000 is installed, you no longer need this option (this option slows down the IDE transfers). +@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. + @item -option-rom @var{file} Load the contents of @var{file} as an option ROM. This option is useful to load things like EtherBoot. diff --git a/sysemu.h b/sysemu.h index 94cffaf..4a24f12 100644 --- a/sysemu.h +++ b/sysemu.h @@ -89,6 +89,7 @@ extern int graphic_depth; extern int nographic; extern const char *keyboard_layout; extern int win2k_install_hack; +extern int rtc_td_hack; extern int alt_grab; extern int usb_enabled; extern int smp_cpus; diff --git a/vl.c b/vl.c index 0a02151..b1f32b4 100644 --- a/vl.c +++ b/vl.c @@ -219,6 +219,7 @@ CharDriverState *serial_hds[MAX_SERIAL_PORTS]; CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; #ifdef TARGET_I386 int win2k_install_hack = 0; +int rtc_td_hack = 0; #endif int usb_enabled = 0; int smp_cpus = 1; @@ -3868,6 +3869,7 @@ static void help(int exitcode) "-full-screen start in full screen\n" #ifdef TARGET_I386 "-win2k-hack use it when installing Windows 2000 to avoid a disk full bug\n" + "-rtc-td-hack use it to fix time drift in Windows ACPI HAL\n" #endif "-usb enable the USB driver (will be the default soon)\n" "-usbdevice name add the host or guest USB device 'name'\n" @@ -4062,6 +4064,7 @@ enum { QEMU_OPTION_kernel_kqemu, QEMU_OPTION_enable_kvm, QEMU_OPTION_win2k_hack, + QEMU_OPTION_rtc_td_hack, QEMU_OPTION_usb, QEMU_OPTION_usbdevice, QEMU_OPTION_smp, @@ -4169,6 +4172,7 @@ static const QEMUOption qemu_options[] = { #endif { "pidfile", HAS_ARG, QEMU_OPTION_pidfile }, { "win2k-hack", 0, QEMU_OPTION_win2k_hack }, + { "rtc-td-hack", 0, QEMU_OPTION_rtc_td_hack }, { "usbdevice", HAS_ARG, QEMU_OPTION_usbdevice }, { "smp", HAS_ARG, QEMU_OPTION_smp }, { "vnc", HAS_ARG, QEMU_OPTION_vnc }, @@ -4975,6 +4979,9 @@ int main(int argc, char **argv, char **envp) case QEMU_OPTION_win2k_hack: win2k_install_hack = 1; break; + case QEMU_OPTION_rtc_td_hack: + rtc_td_hack = 1; + break; #endif #ifdef USE_KQEMU case QEMU_OPTION_no_kqemu: -- Gleb.