]> git.proxmox.com Git - qemu.git/commitdiff
Enable host-clock-based RTC
authorJan Kiszka <jan.kiszka@siemens.com>
Tue, 15 Sep 2009 11:36:04 +0000 (13:36 +0200)
committerAnthony Liguori <aliguori@us.ibm.com>
Mon, 5 Oct 2009 14:32:45 +0000 (09:32 -0500)
Switch RTC emulations to the new host_clock instead of vm_clock by
default. This has the advantage that the emulated RTC will follow
automatically the host time while it might be tuned via NTP. vm_clock
can still be selected by passing '-rtc clock=vm' on the command line.

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 but
only converts MC146818 for now.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
hw/mc146818rtc.c
qemu-config.c
qemu-options.hx
sysemu.h
vl.c

index 9d6a62751fe3f418e41897641aebdb3a07d2d597..bec5687e42a570fd3e732621e20b4f909fe6993c 100644 (file)
@@ -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);
index 3dce91d80ecdf2d82b370699e82636fc45fb0573..785b1468b70cc16f52a0894ced8837da1e5c8646 100644 (file)
@@ -158,6 +158,9 @@ QemuOptsList qemu_rtc_opts = {
         {
             .name = "base",
             .type = QEMU_OPT_STRING,
+        },{
+            .name = "clock",
+            .type = QEMU_OPT_STRING,
 #ifdef TARGET_I386
         },{
             .name = "driftfix",
index 586474e39b10ac47790208a605aa3a4b2b01c12a..f21e9f9da22060b5ae917d639e05dc6d41e2a53d 100644 (file)
@@ -1500,22 +1500,28 @@ DEF("startdate", HAS_ARG, QEMU_OPTION_startdate, "")
 
 #ifdef TARGET_I386
 DEF("rtc", HAS_ARG, QEMU_OPTION_rtc, \
-    "-rtc [base=utc|localtime|date][,driftfix=none|slew]\n" \
-    "                set the RTC base, enable drift fix for clock ticks\n")
+    "-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]\n" \
+    "-rtc [base=utc|localtime|date][,clock=host|vm]\n" \
     "                set the RTC base and clock\n")
 #endif
 
 STEXI
 
-@item -rtc [base=utc|localtime|@var{date}][,driftfix=none|slew]
+@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
index 8bf90ee357a541fe687f5e1e04f3d09bc9b8fd9e..ea4e2c129b9497911f203765928578e33e95e672 100644 (file)
--- a/sysemu.h
+++ b/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
@@ -134,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 31f3ad2500cc458b67a56df7b119b7bd9c4be1f4..dd2de980e8b1563b1f9e3241f0562224dee189a5 100644 (file)
--- a/vl.c
+++ b/vl.c
@@ -196,6 +196,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;
@@ -1055,6 +1056,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 = host_clock;
 }
 
 /* save a timer */
@@ -1635,6 +1638,17 @@ static void configure_rtc(QemuOpts *opts)
             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) {
@@ -4754,6 +4768,8 @@ int 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);
 
@@ -5619,7 +5635,6 @@ int main(int argc, char **argv, char **envp)
     setvbuf(stdout, NULL, _IOLBF, 0);
 #endif
 
-    init_clocks();
     if (init_timer_alarm() < 0) {
         fprintf(stderr, "could not initialize alarm timer\n");
         exit(1);