aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/x86/hvm/rtc.c
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@suse.com>2013-05-21 10:15:13 +0200
committerJan Beulich <jbeulich@suse.com>2013-05-21 10:15:13 +0200
commit3fa7fb8b86b89167153fa457b27620436d648969 (patch)
treedc4a0c3d75a1f4ca16065c34093b3b510ff2663d /xen/arch/x86/hvm/rtc.c
parent9607327abbd3e77bde6cc7b5327f3efd781fc06e (diff)
downloadxen-3fa7fb8b86b89167153fa457b27620436d648969.tar.gz
xen-3fa7fb8b86b89167153fa457b27620436d648969.tar.bz2
xen-3fa7fb8b86b89167153fa457b27620436d648969.zip
x86/HVM: RTC code must be in line with WAET flags passed by hvmloader
With hvmloader telling the guest that it may skip REG_C reads during the processing of RTC interrupts, the emulation code must not depend upon these reads to occur. Introduce two modes of operation for the emulation code, and short of a HVM parameter (too late to be introduced for 4.3) hard code the mode determination to always assume that Windows-conforming one for the time being. Signed-off-by: Jan Beulich <jbeulich@suse.com> Tested-by: Roger Pau Monné <roger.pau@citrix.com> (FreeBSD guest)
Diffstat (limited to 'xen/arch/x86/hvm/rtc.c')
-rw-r--r--xen/arch/x86/hvm/rtc.c19
1 files changed, 15 insertions, 4 deletions
diff --git a/xen/arch/x86/hvm/rtc.c b/xen/arch/x86/hvm/rtc.c
index 77b380f287..d1a6848fbb 100644
--- a/xen/arch/x86/hvm/rtc.c
+++ b/xen/arch/x86/hvm/rtc.c
@@ -45,6 +45,15 @@
#define epoch_year 1900
#define get_year(x) (x + epoch_year)
+enum rtc_mode {
+ rtc_mode_no_ack,
+ rtc_mode_strict
+};
+
+/* This must be in sync with how hvmloader sets the ACPI WAET flags. */
+#define mode_is(d, m) ((void)(d), rtc_mode_##m == rtc_mode_no_ack)
+#define rtc_mode_is(s, m) mode_is(vrtc_domain(s), m)
+
static void rtc_copy_date(RTCState *s);
static void rtc_set_time(RTCState *s);
static inline int from_bcd(RTCState *s, int a);
@@ -54,7 +63,7 @@ static void rtc_update_irq(RTCState *s)
{
ASSERT(spin_is_locked(&s->lock));
- if ( s->hw.cmos_data[RTC_REG_C] & RTC_IRQF )
+ if ( rtc_mode_is(s, strict) && (s->hw.cmos_data[RTC_REG_C] & RTC_IRQF) )
return;
/* IRQ is raised if any source is both raised & enabled */
@@ -64,6 +73,8 @@ static void rtc_update_irq(RTCState *s)
return;
s->hw.cmos_data[RTC_REG_C] |= RTC_IRQF;
+ if ( rtc_mode_is(s, no_ack) )
+ hvm_isa_irq_deassert(vrtc_domain(s), RTC_IRQ);
hvm_isa_irq_assert(vrtc_domain(s), RTC_IRQ);
}
@@ -73,8 +84,8 @@ bool_t rtc_periodic_interrupt(void *opaque)
bool_t ret;
spin_lock(&s->lock);
- ret = !(s->hw.cmos_data[RTC_REG_C] & RTC_IRQF);
- if ( !(s->hw.cmos_data[RTC_REG_C] & RTC_PF) )
+ ret = rtc_mode_is(s, no_ack) || !(s->hw.cmos_data[RTC_REG_C] & RTC_IRQF);
+ if ( rtc_mode_is(s, no_ack) || !(s->hw.cmos_data[RTC_REG_C] & RTC_PF) )
{
s->hw.cmos_data[RTC_REG_C] |= RTC_PF;
rtc_update_irq(s);
@@ -633,7 +644,7 @@ static uint32_t rtc_ioport_read(RTCState *s, uint32_t addr)
case RTC_REG_C:
ret = s->hw.cmos_data[s->hw.cmos_index];
s->hw.cmos_data[RTC_REG_C] = 0x00;
- if ( ret & RTC_IRQF )
+ if ( (ret & RTC_IRQF) && !rtc_mode_is(s, no_ack) )
hvm_isa_irq_deassert(d, RTC_IRQ);
rtc_update_irq(s);
check_update_timer(s);