diff --git a/hw/omap1.c b/hw/omap1.c index 2a341bfe7f..80d47f0b85 100644 --- a/hw/omap1.c +++ b/hw/omap1.c @@ -2888,7 +2888,7 @@ static void omap_rtc_reset(struct omap_rtc_s *s) s->pm_am = 0; s->auto_comp = 0; s->round = 0; - s->tick = qemu_get_clock_ms(rt_clock); + s->tick = qemu_get_clock_ms(rtc_clock); memset(&s->alarm_tm, 0, sizeof(s->alarm_tm)); s->alarm_tm.tm_mday = 0x01; s->status = 1 << 7; @@ -2909,7 +2909,7 @@ static struct omap_rtc_s *omap_rtc_init(MemoryRegion *system_memory, s->irq = timerirq; s->alarm = alarmirq; - s->clk = qemu_new_timer_ms(rt_clock, omap_rtc_tick, s); + s->clk = qemu_new_timer_ms(rtc_clock, omap_rtc_tick, s); omap_rtc_reset(s); @@ -3497,9 +3497,9 @@ static void omap_lpg_tick(void *opaque) struct omap_lpg_s *s = opaque; if (s->cycle) - qemu_mod_timer(s->tm, qemu_get_clock_ms(rt_clock) + s->period - s->on); + qemu_mod_timer(s->tm, qemu_get_clock_ms(vm_clock) + s->period - s->on); else - qemu_mod_timer(s->tm, qemu_get_clock_ms(rt_clock) + s->on); + qemu_mod_timer(s->tm, qemu_get_clock_ms(vm_clock) + s->on); s->cycle = !s->cycle; printf("%s: LED is %s\n", __FUNCTION__, s->cycle ? "on" : "off"); @@ -3617,7 +3617,7 @@ static struct omap_lpg_s *omap_lpg_init(MemoryRegion *system_memory, struct omap_lpg_s *s = (struct omap_lpg_s *) g_malloc0(sizeof(struct omap_lpg_s)); - s->tm = qemu_new_timer_ms(rt_clock, omap_lpg_tick, s); + s->tm = qemu_new_timer_ms(vm_clock, omap_lpg_tick, s); omap_lpg_reset(s); diff --git a/hw/pl031.c b/hw/pl031.c index 69abc4f345..9602664da6 100644 --- a/hw/pl031.c +++ b/hw/pl031.c @@ -13,6 +13,7 @@ #include "sysbus.h" #include "qemu-timer.h" +#include "sysemu.h" //#define DEBUG_PL031 @@ -38,6 +39,11 @@ typedef struct { QEMUTimer *timer; qemu_irq irq; + /* Needed to preserve the tick_count across migration, even if the + * absolute value of the rtc_clock is different on the source and + * destination. + */ + uint32_t tick_offset_vmstate; uint32_t tick_offset; uint32_t mr; @@ -47,21 +53,6 @@ typedef struct { uint32_t is; } pl031_state; -static const VMStateDescription vmstate_pl031 = { - .name = "pl031", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(tick_offset, pl031_state), - VMSTATE_UINT32(mr, pl031_state), - VMSTATE_UINT32(lr, pl031_state), - VMSTATE_UINT32(cr, pl031_state), - VMSTATE_UINT32(im, pl031_state), - VMSTATE_UINT32(is, pl031_state), - VMSTATE_END_OF_LIST() - } -}; - static const unsigned char pl031_id[] = { 0x31, 0x10, 0x14, 0x00, /* Device ID */ 0x0d, 0xf0, 0x05, 0xb1 /* Cell ID */ @@ -83,27 +74,23 @@ static void pl031_interrupt(void * opaque) static uint32_t pl031_get_count(pl031_state *s) { - /* This assumes qemu_get_clock_ns returns the time since the machine was - created. */ - return s->tick_offset + qemu_get_clock_ns(vm_clock) / get_ticks_per_sec(); + int64_t now = qemu_get_clock_ns(rtc_clock); + return s->tick_offset + now / get_ticks_per_sec(); } static void pl031_set_alarm(pl031_state *s) { - int64_t now; uint32_t ticks; - now = qemu_get_clock_ns(vm_clock); - ticks = s->tick_offset + now / get_ticks_per_sec(); - /* The timer wraps around. This subtraction also wraps in the same way, and gives correct results when alarm < now_ticks. */ - ticks = s->mr - ticks; + ticks = s->mr - pl031_get_count(s); DPRINTF("Alarm set in %ud ticks\n", ticks); if (ticks == 0) { qemu_del_timer(s->timer); pl031_interrupt(s); } else { + int64_t now = qemu_get_clock_ns(rtc_clock); qemu_mod_timer(s->timer, now + (int64_t)ticks * get_ticks_per_sec()); } } @@ -205,14 +192,50 @@ static int pl031_init(SysBusDevice *dev) sysbus_init_mmio(dev, &s->iomem); sysbus_init_irq(dev, &s->irq); - /* ??? We assume vm_clock is zero at this point. */ qemu_get_timedate(&tm, 0); - s->tick_offset = mktimegm(&tm); + s->tick_offset = mktimegm(&tm) - qemu_get_clock_ns(rtc_clock) / get_ticks_per_sec(); - s->timer = qemu_new_timer_ns(vm_clock, pl031_interrupt, s); + s->timer = qemu_new_timer_ns(rtc_clock, pl031_interrupt, s); return 0; } +static void pl031_pre_save(void *opaque) +{ + pl031_state *s = opaque; + + /* tick_offset is base_time - rtc_clock base time. Instead, we want to + * store the base time relative to the vm_clock for backwards-compatibility. */ + int64_t delta = qemu_get_clock_ns(rtc_clock) - qemu_get_clock_ns(vm_clock); + s->tick_offset_vmstate = s->tick_offset + delta / get_ticks_per_sec(); +} + +static int pl031_post_load(void *opaque, int version_id) +{ + pl031_state *s = opaque; + + int64_t delta = qemu_get_clock_ns(rtc_clock) - qemu_get_clock_ns(vm_clock); + s->tick_offset = s->tick_offset_vmstate - delta / get_ticks_per_sec(); + pl031_set_alarm(s); + return 0; +} + +static const VMStateDescription vmstate_pl031 = { + .name = "pl031", + .version_id = 1, + .minimum_version_id = 1, + .pre_save = pl031_pre_save, + .post_load = pl031_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT32(tick_offset_vmstate, pl031_state), + VMSTATE_UINT32(mr, pl031_state), + VMSTATE_UINT32(lr, pl031_state), + VMSTATE_UINT32(cr, pl031_state), + VMSTATE_UINT32(im, pl031_state), + VMSTATE_UINT32(is, pl031_state), + VMSTATE_END_OF_LIST() + } +}; + static void pl031_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index 1d5c35f174..ddaa846882 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -875,7 +875,7 @@ static inline void pxa2xx_rtc_int_update(PXA2xxRTCState *s) static void pxa2xx_rtc_hzupdate(PXA2xxRTCState *s) { - int64_t rt = qemu_get_clock_ms(rt_clock); + int64_t rt = qemu_get_clock_ms(rtc_clock); s->last_rcnr += ((rt - s->last_hz) << 15) / (1000 * ((s->rttr & 0xffff) + 1)); s->last_rdcr += ((rt - s->last_hz) << 15) / @@ -885,7 +885,7 @@ static void pxa2xx_rtc_hzupdate(PXA2xxRTCState *s) static void pxa2xx_rtc_swupdate(PXA2xxRTCState *s) { - int64_t rt = qemu_get_clock_ms(rt_clock); + int64_t rt = qemu_get_clock_ms(rtc_clock); if (s->rtsr & (1 << 12)) s->last_swcr += (rt - s->last_sw) / 10; s->last_sw = rt; @@ -893,7 +893,7 @@ static void pxa2xx_rtc_swupdate(PXA2xxRTCState *s) static void pxa2xx_rtc_piupdate(PXA2xxRTCState *s) { - int64_t rt = qemu_get_clock_ms(rt_clock); + int64_t rt = qemu_get_clock_ms(rtc_clock); if (s->rtsr & (1 << 15)) s->last_swcr += rt - s->last_pi; s->last_pi = rt; @@ -1019,16 +1019,16 @@ static uint64_t pxa2xx_rtc_read(void *opaque, target_phys_addr_t addr, case PIAR: return s->piar; case RCNR: - return s->last_rcnr + ((qemu_get_clock_ms(rt_clock) - s->last_hz) << 15) / + return s->last_rcnr + ((qemu_get_clock_ms(rtc_clock) - s->last_hz) << 15) / (1000 * ((s->rttr & 0xffff) + 1)); case RDCR: - return s->last_rdcr + ((qemu_get_clock_ms(rt_clock) - s->last_hz) << 15) / + return s->last_rdcr + ((qemu_get_clock_ms(rtc_clock) - s->last_hz) << 15) / (1000 * ((s->rttr & 0xffff) + 1)); case RYCR: return s->last_rycr; case SWCR: if (s->rtsr & (1 << 12)) - return s->last_swcr + (qemu_get_clock_ms(rt_clock) - s->last_sw) / 10; + return s->last_swcr + (qemu_get_clock_ms(rtc_clock) - s->last_sw) / 10; else return s->last_swcr; default: @@ -1168,14 +1168,14 @@ static int pxa2xx_rtc_init(SysBusDevice *dev) s->last_swcr = (tm.tm_hour << 19) | (tm.tm_min << 13) | (tm.tm_sec << 7); s->last_rtcpicr = 0; - s->last_hz = s->last_sw = s->last_pi = qemu_get_clock_ms(rt_clock); + s->last_hz = s->last_sw = s->last_pi = qemu_get_clock_ms(rtc_clock); - s->rtc_hz = qemu_new_timer_ms(rt_clock, pxa2xx_rtc_hz_tick, s); - s->rtc_rdal1 = qemu_new_timer_ms(rt_clock, pxa2xx_rtc_rdal1_tick, s); - s->rtc_rdal2 = qemu_new_timer_ms(rt_clock, pxa2xx_rtc_rdal2_tick, s); - s->rtc_swal1 = qemu_new_timer_ms(rt_clock, pxa2xx_rtc_swal1_tick, s); - s->rtc_swal2 = qemu_new_timer_ms(rt_clock, pxa2xx_rtc_swal2_tick, s); - s->rtc_pi = qemu_new_timer_ms(rt_clock, pxa2xx_rtc_pi_tick, s); + s->rtc_hz = qemu_new_timer_ms(rtc_clock, pxa2xx_rtc_hz_tick, s); + s->rtc_rdal1 = qemu_new_timer_ms(rtc_clock, pxa2xx_rtc_rdal1_tick, s); + s->rtc_rdal2 = qemu_new_timer_ms(rtc_clock, pxa2xx_rtc_rdal2_tick, s); + s->rtc_swal1 = qemu_new_timer_ms(rtc_clock, pxa2xx_rtc_swal1_tick, s); + s->rtc_swal2 = qemu_new_timer_ms(rtc_clock, pxa2xx_rtc_swal2_tick, s); + s->rtc_pi = qemu_new_timer_ms(rtc_clock, pxa2xx_rtc_pi_tick, s); sysbus_init_irq(dev, &s->rtc_irq); diff --git a/hw/strongarm.c b/hw/strongarm.c index 4d5b60fd1f..1b15f399f1 100644 --- a/hw/strongarm.c +++ b/hw/strongarm.c @@ -255,7 +255,7 @@ static inline void strongarm_rtc_int_update(StrongARMRTCState *s) static void strongarm_rtc_hzupdate(StrongARMRTCState *s) { - int64_t rt = qemu_get_clock_ms(rt_clock); + int64_t rt = qemu_get_clock_ms(rtc_clock); s->last_rcnr += ((rt - s->last_hz) << 15) / (1000 * ((s->rttr & 0xffff) + 1)); s->last_hz = rt; @@ -308,7 +308,7 @@ static uint64_t strongarm_rtc_read(void *opaque, target_phys_addr_t addr, return s->rtar; case RCNR: return s->last_rcnr + - ((qemu_get_clock_ms(rt_clock) - s->last_hz) << 15) / + ((qemu_get_clock_ms(rtc_clock) - s->last_hz) << 15) / (1000 * ((s->rttr & 0xffff) + 1)); default: printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr); @@ -374,10 +374,10 @@ static int strongarm_rtc_init(SysBusDevice *dev) qemu_get_timedate(&tm, 0); s->last_rcnr = (uint32_t) mktimegm(&tm); - s->last_hz = qemu_get_clock_ms(rt_clock); + s->last_hz = qemu_get_clock_ms(rtc_clock); - s->rtc_alarm = qemu_new_timer_ms(rt_clock, strongarm_rtc_alarm_tick, s); - s->rtc_hz = qemu_new_timer_ms(rt_clock, strongarm_rtc_hz_tick, s); + s->rtc_alarm = qemu_new_timer_ms(rtc_clock, strongarm_rtc_alarm_tick, s); + s->rtc_hz = qemu_new_timer_ms(rtc_clock, strongarm_rtc_hz_tick, s); sysbus_init_irq(dev, &s->rtc_irq); sysbus_init_irq(dev, &s->rtc_hz_irq); diff --git a/hw/twl92230.c b/hw/twl92230.c index 22da6f8001..0d70d8498d 100644 --- a/hw/twl92230.c +++ b/hw/twl92230.c @@ -22,6 +22,7 @@ #include "hw.h" #include "qemu-timer.h" #include "i2c.h" +#include "sysemu.h" #include "console.h" #define VERBOSE 1 @@ -71,14 +72,14 @@ static inline void menelaus_update(MenelausState *s) static inline void menelaus_rtc_start(MenelausState *s) { - s->rtc.next += qemu_get_clock_ms(rt_clock); + s->rtc.next += qemu_get_clock_ms(rtc_clock); qemu_mod_timer(s->rtc.hz_tm, s->rtc.next); } static inline void menelaus_rtc_stop(MenelausState *s) { qemu_del_timer(s->rtc.hz_tm); - s->rtc.next -= qemu_get_clock_ms(rt_clock); + s->rtc.next -= qemu_get_clock_ms(rtc_clock); if (s->rtc.next < 1) s->rtc.next = 1; } @@ -781,7 +782,7 @@ static void menelaus_pre_save(void *opaque) { MenelausState *s = opaque; /* Should be <= 1000 */ - s->rtc_next_vmstate = s->rtc.next - qemu_get_clock_ms(rt_clock); + s->rtc_next_vmstate = s->rtc.next - qemu_get_clock_ms(rtc_clock); } static int menelaus_post_load(void *opaque, int version_id) @@ -842,7 +843,7 @@ static int twl92230_init(I2CSlave *i2c) { MenelausState *s = FROM_I2C_SLAVE(MenelausState, i2c); - s->rtc.hz_tm = qemu_new_timer_ms(rt_clock, menelaus_rtc_hz, s); + s->rtc.hz_tm = qemu_new_timer_ms(rtc_clock, menelaus_rtc_hz, s); /* Three output pins plus one interrupt pin. */ qdev_init_gpio_out(&i2c->qdev, s->out, 4); diff --git a/qemu-options.hx b/qemu-options.hx index fe88939805..f72f9a0fdf 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2453,7 +2453,7 @@ DEF("localtime", 0, QEMU_OPTION_localtime, "", QEMU_ARCH_ALL) DEF("startdate", HAS_ARG, QEMU_OPTION_startdate, "", QEMU_ARCH_ALL) DEF("rtc", HAS_ARG, QEMU_OPTION_rtc, \ - "-rtc [base=utc|localtime|date][,clock=host|vm][,driftfix=none|slew]\n" \ + "-rtc [base=utc|localtime|date][,clock=host|rt|vm][,driftfix=none|slew]\n" \ " set the RTC base and clock, enable drift fix for clock ticks (x86 only)\n", QEMU_ARCH_ALL) @@ -2469,8 +2469,9 @@ 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. +If you want to isolate the guest time from the host, you can set @option{clock} +to @code{rt} instead. To even prevent it from progressing during suspension, +you can set it to @code{vm}. 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 diff --git a/vl.c b/vl.c index e575401d29..ae91a8ab01 100644 --- a/vl.c +++ b/vl.c @@ -530,6 +530,8 @@ static void configure_rtc(QemuOpts *opts) if (value) { if (!strcmp(value, "host")) { rtc_clock = host_clock; + } else if (!strcmp(value, "rt")) { + rtc_clock = rt_clock; } else if (!strcmp(value, "vm")) { rtc_clock = vm_clock; } else {