qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH] Time drift again.


From: Gleb Natapov
Subject: Re: [Qemu-devel] [PATCH] Time drift again.
Date: Tue, 16 Dec 2008 17:02:11 +0200

On Tue, Dec 16, 2008 at 02:38:12PM +0200, Gleb Natapov wrote:
> On Tue, Dec 16, 2008 at 12:33:30PM +0000, Paul Brook wrote:
> > On Tuesday 16 December 2008, Gleb Natapov wrote:
> > > Hello,
> > >
> > >  After my last patch to fix interrupt coalescing was rejected
> > > on the basis that it is too intrusive we decided to make the
> > > fix much more localized and only fix the problem for RTC time
> > > source. Unfortunately it is impossible to fix the problem entirely
> > > inside RTC code like Andrzej proposed since Windows reads RTC
> > > register C more then once on each time interrupt so it is impossible
> > > to count reliably how many interrupt windows actually handled.
> > > Proposed solution is localized to I386 target and is disabled by
> > > default. To enable it "-rtc-td-hack" flag should be used.
> > 
> > You need documentation for the new option.
> > 
> Will add to the next patch.
> 

Here is the same patch with doc section.

Signed-off-by: Gleb Natapov <address@hidden>
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..acaba91 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,9 @@ 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
+    register_savevm("mc146818rtc-td", base, 1, rtc_save_td, rtc_load_td, s);
+#endif
     return s;
 }
 
@@ -589,5 +641,8 @@ 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
+    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).
 
address@hidden -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..a515f53 100644
--- a/vl.c
+++ b/vl.c
@@ -220,6 +220,7 @@ CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
 #ifdef TARGET_I386
 int win2k_install_hack = 0;
 #endif
+int rtc_td_hack = 0;
 int usb_enabled = 0;
 int smp_cpus = 1;
 const char *vnc_display;
@@ -3869,6 +3870,7 @@ static void help(int exitcode)
 #ifdef TARGET_I386
            "-win2k-hack     use it when installing Windows 2000 to avoid a 
disk full bug\n"
 #endif
+           "-rtc-td-hack    use it to fix time drift in Windows ACPI HAL\n"
            "-usb            enable the USB driver (will be the default soon)\n"
            "-usbdevice name add the host or guest USB device 'name'\n"
 #if defined(TARGET_PPC) || defined(TARGET_SPARC)
@@ -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 },
@@ -4976,6 +4980,9 @@ int main(int argc, char **argv, char **envp)
                 win2k_install_hack = 1;
                 break;
 #endif
+            case QEMU_OPTION_rtc_td_hack:
+                rtc_td_hack = 1;
+                break;
 #ifdef USE_KQEMU
             case QEMU_OPTION_no_kqemu:
                 kqemu_allowed = 0;
--
                        Gleb.




reply via email to

[Prev in Thread] Current Thread [Next in Thread]