|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH] x86: detect CMOS aliasing on ports other then 0x70/0x71
... in order to also intercept accesses through the alias ports.
Also stop intercepting accesses to the CMOS ports if we won't ourselves
use the CMOS RTC.
Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
--- a/xen/arch/x86/setup.c
+++ b/xen/arch/x86/setup.c
@@ -1544,42 +1544,6 @@ int __hwdom_init xen_in_range(unsigned l
return 0;
}
-static int __hwdom_init io_bitmap_cb(unsigned long s, unsigned long e,
- void *ctx)
-{
- struct domain *d = ctx;
- unsigned int i;
-
- ASSERT(e <= INT_MAX);
- for ( i = s; i <= e; i++ )
- __clear_bit(i, d->arch.hvm_domain.io_bitmap);
-
- return 0;
-}
-
-void __hwdom_init setup_io_bitmap(struct domain *d)
-{
- int rc;
-
- if ( has_hvm_container_domain(d) )
- {
- bitmap_fill(d->arch.hvm_domain.io_bitmap, 0x10000);
- rc = rangeset_report_ranges(d->arch.ioport_caps, 0, 0x10000,
- io_bitmap_cb, d);
- BUG_ON(rc);
- /*
- * NB: we need to trap accesses to 0xcf8 in order to intercept
- * 4 byte accesses, that need to be handled by Xen in order to
- * keep consistency.
- * Access to 1 byte RTC ports also needs to be trapped in order
- * to keep consistency with PV.
- */
- __set_bit(0xcf8, d->arch.hvm_domain.io_bitmap);
- __set_bit(RTC_PORT(0), d->arch.hvm_domain.io_bitmap);
- __set_bit(RTC_PORT(1), d->arch.hvm_domain.io_bitmap);
- }
-}
-
/*
* Local variables:
* mode: C
--- a/xen/arch/x86/time.c
+++ b/xen/arch/x86/time.c
@@ -736,7 +736,10 @@ static unsigned long get_cmos_time(void)
if ( seconds < 60 )
{
if ( rtc.sec != seconds )
+ {
cmos_rtc_probe = 0;
+ acpi_gbl_FADT.boot_flags &= ~ACPI_FADT_NO_CMOS_RTC;
+ }
break;
}
--- a/xen/arch/x86/traps.c
+++ b/xen/arch/x86/traps.c
@@ -62,6 +62,7 @@
#include <asm/xstate.h>
#include <asm/debugger.h>
#include <asm/msr.h>
+#include <asm/setup.h>
#include <asm/shared.h>
#include <asm/x86_emulate.h>
#include <asm/traps.h>
@@ -105,6 +106,8 @@ idt_entry_t *idt_tables[NR_CPUS] __read_
void (*ioemul_handle_quirk)(
u8 opcode, char *io_emul_stub, struct cpu_user_regs *regs);
+static unsigned int __read_mostly cmos_alias_mask;
+
static int debug_stack_lines = 20;
integer_param("debug_stack_lines", debug_stack_lines);
@@ -1769,8 +1772,12 @@ static bool_t admin_io_okay(unsigned int
if ( (port == 0xcf8) && (bytes == 4) )
return 0;
- /* We also never permit direct access to the RTC/CMOS registers. */
- if ( ((port & ~1) == RTC_PORT(0)) )
+ /*
+ * We also never permit direct access to the RTC/CMOS registers
+ * if we may be accessing the RTC ones ourselves.
+ */
+ if ( !(acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_CMOS_RTC) &&
+ ((port & ~(cmos_alias_mask | 1)) == RTC_PORT(0)) )
return 0;
return ioports_access_permitted(d, port, port + bytes - 1);
@@ -1842,18 +1849,19 @@ uint32_t guest_io_read(unsigned int port
{
sub_data = pv_pit_handler(port, 0, 0);
}
- else if ( (port == RTC_PORT(0)) )
+ else if ( ((port & ~cmos_alias_mask) == RTC_PORT(0)) )
{
sub_data = currd->arch.cmos_idx;
}
- else if ( (port == RTC_PORT(1)) &&
- ioports_access_permitted(currd, RTC_PORT(0), RTC_PORT(1)) )
+ else if ( ((port & ~cmos_alias_mask) == RTC_PORT(1)) &&
+ ioports_access_permitted(currd, port - 1, port) )
{
unsigned long flags;
spin_lock_irqsave(&rtc_lock, flags);
- outb(currd->arch.cmos_idx & 0x7f, RTC_PORT(0));
- sub_data = inb(RTC_PORT(1));
+ outb(currd->arch.cmos_idx & (0xff >> (port == RTC_PORT(1))),
+ port - 1);
+ sub_data = inb(port);
spin_unlock_irqrestore(&rtc_lock, flags);
}
else if ( (port == 0xcf8) && (bytes == 4) )
@@ -1911,20 +1919,22 @@ void guest_io_write(unsigned int port, u
{
pv_pit_handler(port, (uint8_t)data, 1);
}
- else if ( (port == RTC_PORT(0)) )
+ else if ( ((port & ~cmos_alias_mask) == RTC_PORT(0)) )
{
currd->arch.cmos_idx = data;
}
- else if ( (port == RTC_PORT(1)) &&
- ioports_access_permitted(currd, RTC_PORT(0), RTC_PORT(1)) )
+ else if ( ((port & ~cmos_alias_mask) == RTC_PORT(1)) &&
+ ioports_access_permitted(currd, port - 1, port) )
{
+ unsigned int idx = currd->arch.cmos_idx &
+ (0xff >> (port == RTC_PORT(1)));
unsigned long flags;
if ( pv_rtc_handler )
- pv_rtc_handler(currd->arch.cmos_idx & 0x7f, data);
+ pv_rtc_handler(idx, data);
spin_lock_irqsave(&rtc_lock, flags);
- outb(currd->arch.cmos_idx & 0x7f, RTC_PORT(0));
- outb(data, RTC_PORT(1));
+ outb(idx, port - 1);
+ outb(data, port);
spin_unlock_irqrestore(&rtc_lock, flags);
}
else if ( (port == 0xcf8) && (bytes == 4) )
@@ -3727,6 +3737,84 @@ void __init trap_init(void)
open_softirq(PCI_SERR_SOFTIRQ, pci_serr_softirq);
}
+static int __init probe_cmos_alias(void)
+{
+ unsigned int i, offs;
+
+ if ( acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_CMOS_RTC )
+ return 0;
+
+ for ( offs = 2; offs < 8; offs <<= 1 )
+ {
+ bool_t read = 1;
+
+ for ( i = RTC_REG_D + 1; i < 0x80; ++i )
+ {
+ uint8_t normal, alt;
+ unsigned long flags;
+
+ if ( i == acpi_gbl_FADT.century )
+ continue;
+
+ spin_lock_irqsave(&rtc_lock, flags);
+
+ normal = CMOS_READ(i);
+ if ( inb(RTC_PORT(offs)) != i )
+ read = 0;
+
+ alt = inb(RTC_PORT(offs + 1));
+
+ spin_unlock_irqrestore(&rtc_lock, flags);
+
+ if ( normal != alt )
+ break;
+
+ process_pending_softirqs();
+ }
+ if ( i == 0x80 )
+ {
+ cmos_alias_mask |= offs;
+ printk(XENLOG_INFO "CMOS aliased at %02x, index %s\n",
+ RTC_PORT(offs), read ? "r/w" : "w/o");
+ }
+ }
+
+ return 0;
+}
+__initcall(probe_cmos_alias);
+
+static int __hwdom_init io_bitmap_cb(unsigned long s, unsigned long e,
+ void *ctx)
+{
+ const struct domain *d = ctx;
+ unsigned int i;
+
+ ASSERT(e <= INT_MAX);
+ for ( i = s; i <= e; i++ )
+ if ( admin_io_okay(i, 1, d) )
+ __clear_bit(i, d->arch.hvm_domain.io_bitmap);
+
+ return 0;
+}
+
+void __hwdom_init setup_io_bitmap(struct domain *d)
+{
+ if ( !has_hvm_container_domain(d) )
+ return;
+
+ bitmap_fill(d->arch.hvm_domain.io_bitmap, 0x10000);
+ if ( rangeset_report_ranges(d->arch.ioport_caps, 0, 0x10000,
+ io_bitmap_cb, d) )
+ BUG();
+
+ /*
+ * We need to trap 4-byte accesses to 0xcf8 (see admin_io_okay(),
+ * guest_io_read(), and guest_io_write()), which isn't covered by
+ * the admin_io_okay() check in io_bitmap_cb().
+ */
+ __set_bit(0xcf8, d->arch.hvm_domain.io_bitmap);
+}
+
long register_guest_nmi_callback(unsigned long address)
{
struct vcpu *v = current;
Attachment:
x86-CMOS-aliasing.patch _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |