aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/firmware/hvmloader/acpi/static_tables.c12
-rw-r--r--xen/arch/x86/hvm/rtc.c19
2 files changed, 23 insertions, 8 deletions
diff --git a/tools/firmware/hvmloader/acpi/static_tables.c b/tools/firmware/hvmloader/acpi/static_tables.c
index f98c8d2d10..323ae3124c 100644
--- a/tools/firmware/hvmloader/acpi/static_tables.c
+++ b/tools/firmware/hvmloader/acpi/static_tables.c
@@ -136,11 +136,15 @@ struct acpi_20_rsdp Rsdp = {
.length = sizeof(struct acpi_20_rsdp)
};
-#define ACPI_WAET_RTC_GOOD 0x00000001
-#define ACPI_WAET_PM_TIMER_GOOD 0x00000002
+#define ACPI_WAET_RTC_NO_ACK (1<<0) /* RTC requires no int acknowledge */
+#define ACPI_WAET_TIMER_ONE_READ (1<<1) /* PM timer requires only one read */
-#define ACPI_WAET_FLAGS (ACPI_WAET_RTC_GOOD | \
- ACPI_WAET_PM_TIMER_GOOD)
+/*
+ * The state of the RTC flag getting passed to the guest must be in
+ * sync with the mode selection in the hypervisor RTC emulation code.
+ */
+#define ACPI_WAET_FLAGS (ACPI_WAET_RTC_NO_ACK | \
+ ACPI_WAET_TIMER_ONE_READ)
struct acpi_20_waet Waet = {
.header = {
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);