qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PATCH 5/5] Enable host-clock-based RTC


From: Jan Kiszka
Subject: [Qemu-devel] [PATCH 5/5] Enable host-clock-based RTC
Date: Wed, 09 Sep 2009 17:11:12 +0200
User-agent: StGIT/0.14.3

Allow RTC emulations to use the new host_clock instead of vm_clock. This
has the advantage that the emulated RTC will follow automatically the
host time while it might be tuned via NTP.

Note that some RTC emulations (at least M48T59) already use the host
time unconditionally while others (namely MC146818) do not. This patch
introduces the required infrastructure for selecting the base clock and
only converts MC146818 for now.

Signed-off-by: Jan Kiszka <address@hidden>
---

 hw/mc146818rtc.c |   35 ++++++++++++++++-------------------
 qemu-options.hx  |   14 ++++++++++----
 sysemu.h         |    1 +
 vl.c             |   15 ++++++++++++++-
 4 files changed, 41 insertions(+), 24 deletions(-)

diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index 5c8676e..d339b7a 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -107,8 +107,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, ticks_per_sec, 32768);
+        int64_t next_clock = qemu_get_clock(rtc_clock) +
+            muldiv64(s->period / c, ticks_per_sec, 32768);
         qemu_mod_timer(s->coalesced_timer, next_clock);
     }
 }
@@ -231,7 +231,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) {
@@ -245,7 +245,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:
@@ -604,18 +604,17 @@ RTCState *rtc_init_sqw(int base, qemu_irq irq, qemu_irq 
sqw_irq, int base_year)
     s->base_year = base_year;
     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) + (ticks_per_sec * 99) / 
100;
+    s->next_second_time =
+        qemu_get_clock(rtc_clock) + (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);
@@ -725,14 +724,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) + (ticks_per_sec * 99) / 
100;
+    s->next_second_time =
+        qemu_get_clock(rtc_clock) + (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-options.hx b/qemu-options.hx
index ea672ee..253180b 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1498,22 +1498,28 @@ DEF("startdate", HAS_ARG, QEMU_OPTION_startdate, "")
 
 #ifdef TARGET_I386
 DEF("rtc", HAS_ARG, QEMU_OPTION_rtc, \
-    "-rtc [base=utc|localtime|date][,drift-fix=on|off]\n" \
-    "                Set the RTC base, enable Windows time drift fix\n")
+    "-rtc [base=utc|localtime|date][,clock=vm|host][,drift-fix=on|off]\n" \
+    "                Set the RTC base and clock, enable Windows time drift 
fix\n")
 #else
 DEF("rtc", HAS_ARG, QEMU_OPTION_rtc, \
-    "-rtc [base=utc|localtime|date]\n" \
+    "-rtc [base=utc|localtime|date][,clock=vm|host]\n" \
     "                Set the RTC base and clock\n")
 #endif
 
 STEXI
 
address@hidden -rtc [base=utc|localtime|@var{date}][,drift-fix=on|off]
address@hidden -rtc 
[base=utc|localtime|@var{date}][,clock=vm|rt][,drift-fix=on|off]
 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 a virtual clock (@code{vm}) which is not 
subject
+to host time adjustments and does not jump when the guest is supended and
+resumed or migrated. To use the host's system time instead, set @option{clock} 
to
address@hidden This is useful if the host time is smoothly following an accurate
+reference clock, e.g. via NTP, and wants to propagate this into the guest.
+
 Enable @option{drift-fix} (i386 targets only) if you experience time drift 
problems
 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.
diff --git a/sysemu.h b/sysemu.h
index a018b47..fe4eb53 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -135,6 +135,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/vl.c b/vl.c
index 8437d2c..52bfefe 100644
--- a/vl.c
+++ b/vl.c
@@ -194,6 +194,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;
@@ -1051,6 +1052,8 @@ static void init_clocks(void)
     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 = vm_clock;
 }
 
 /* save a timer */
@@ -1630,7 +1633,7 @@ static void configure_rtc_date_offset(const char 
*startdate, int legacy)
 static void configure_rtc(const char *options)
 {
     static const char * const params[] = {
-        "base",
+        "base", "clock",
 #ifdef CONFIG_TARGET_I386
         "td-hack",
 #endif
@@ -1652,6 +1655,16 @@ static void configure_rtc(const char *options)
             configure_rtc_date_offset(buf, 0);
         }
     }
+    if (get_param_value(buf, sizeof(buf), "clock", options)) {
+        if (!strcmp(buf, "vm")) {
+            rtc_clock = vm_clock;
+        } else if (!strcmp(buf, "host")) {
+            rtc_clock = host_clock;
+        } else {
+            fprintf(stderr, "qemu: invalid option value '%s'\n", buf);
+            exit(1);
+        }
+    }
 #ifdef CONFIG_TARGET_I386
     if (get_param_value(buf, sizeof(buf), "drift-hack", options)) {
         if (!strcmp(buf, "on")) {





reply via email to

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