WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [xen-unstable] [HVM] Intercept ACPI pm-timer registers

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] [HVM] Intercept ACPI pm-timer registers
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Mon, 26 Mar 2007 04:40:06 -0700
Delivery-date: Mon, 26 Mar 2007 04:40:15 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User Tim Deegan <Tim.Deegan@xxxxxxxxxxxxx>
# Date 1174900383 0
# Node ID 3afefd64e39271dbd0d9ea26f79f41a05b89fdd8
# Parent  dccb274295ae4df8812a645ea4809e82ae54b2e0
[HVM] Intercept ACPI pm-timer registers
Bring the PM1a_STS and PM1a_EN registers into Xen and use them to deliver
SCI to the guest before it sees the MSB of the pm-timer change.
Also correct some of the semantics of the registers.
Signed-off-by: Tim Deegan <Tim.Deegan@xxxxxxxxxxxxx>
---
 tools/ioemu/hw/piix4acpi.c    |  243 ++----------------------------------------
 xen/arch/x86/hvm/hvm.c        |    3 
 xen/arch/x86/hvm/pmtimer.c    |  220 ++++++++++++++++++++++++++++++++++----
 xen/include/asm-x86/hvm/io.h  |    2 
 xen/include/asm-x86/hvm/vpt.h |    4 
 xen/include/public/hvm/save.h |    4 
 6 files changed, 220 insertions(+), 256 deletions(-)

diff -r dccb274295ae -r 3afefd64e392 tools/ioemu/hw/piix4acpi.c
--- a/tools/ioemu/hw/piix4acpi.c        Mon Mar 26 01:13:16 2007 +0100
+++ b/tools/ioemu/hw/piix4acpi.c        Mon Mar 26 09:13:03 2007 +0000
@@ -52,126 +52,16 @@ typedef struct AcpiDeviceState AcpiDevic
 typedef struct AcpiDeviceState AcpiDeviceState;
 AcpiDeviceState *acpi_device_table;
 
-typedef struct PM1Event_BLK {
-    uint16_t pm1_status; /* pm1a_EVT_BLK */
-    uint16_t pm1_enable; /* pm1a_EVT_BLK+2 */
-}PM1Event_BLK;
-
 typedef struct PCIAcpiState {
     PCIDevice dev;
-    uint16_t irq;
-    uint16_t pm1_status; /* pm1a_EVT_BLK */
-    uint16_t pm1_enable; /* pm1a_EVT_BLK+2 */
     uint16_t pm1_control; /* pm1a_ECNT_BLK */
-    uint32_t pm1_timer; /* pmtmr_BLK */
-    uint64_t old_vmck_ticks; /* using vm_clock counter */
 } PCIAcpiState;
-
-static PCIAcpiState *acpi_state;
-
-static void acpi_reset(PCIAcpiState *s)
-{
-    uint8_t *pci_conf;
-    pci_conf = s->dev.config;
-
-    pci_conf[0x42] = 0x00;
-    pci_conf[0x43] = 0x00;
-    s->irq = 9;
-    s->pm1_status = 0;
-    s->pm1_enable = 0x00;    /* TMROF_EN should cleared */
-    s->pm1_control = SCI_EN; /* SCI_EN */
-    s->pm1_timer = 0;
-    s->old_vmck_ticks = qemu_get_clock(vm_clock);
-}
-
-/*byte access  */
-static void acpiPm1Status_writeb(void *opaque, uint32_t addr, uint32_t val)
-{
-    PCIAcpiState *s = opaque;
-
-    if ((val&TMROF_STS)==TMROF_STS)
-        s->pm1_status = s->pm1_status&!TMROF_STS;
-
-    if ((val&GBL_STS)==GBL_STS)
-        s->pm1_status = s->pm1_status&!GBL_STS;
-
-/*     printf("acpiPm1Status_writeb \n addr %x val:%x pm1_status:%x \n", addr, 
val,s->pm1_status); */
-}
-
-static uint32_t acpiPm1Status_readb(void *opaque, uint32_t addr)
-{
-    PCIAcpiState *s = opaque;
-    uint32_t val;
-
-    val = s->pm1_status;
-/*         printf("acpiPm1Status_readb \n addr %x val:%x\n", addr, val); */
-
-   return val;
-}
-
-static void acpiPm1StatusP1_writeb(void *opaque, uint32_t addr, uint32_t val)
-{
-    PCIAcpiState *s = opaque;
-
-    s->pm1_status = (val<<8)||(s->pm1_status);
-/*     printf("acpiPm1StatusP1_writeb \n addr %x val:%x\n", addr, val); */
-}
-
-static uint32_t acpiPm1StatusP1_readb(void *opaque, uint32_t addr)
-{
-    PCIAcpiState *s = opaque;
-    uint32_t val;
-
-    val = (s->pm1_status)>>8;
-    printf("acpiPm1StatusP1_readb \n addr %x val:%x\n", addr, val);
-
-    return val;
-}
-
-static void acpiPm1Enable_writeb(void *opaque, uint32_t addr, uint32_t val)
-{
-    PCIAcpiState *s = opaque;
-
-    s->pm1_enable = val;
-/*   printf("acpiPm1Enable_writeb \n addr %x val:%x\n", addr, val); */
-}
-
-static uint32_t acpiPm1Enable_readb(void *opaque, uint32_t addr)
-{
-    PCIAcpiState *s = opaque;
-    uint32_t val;
-
-    val = (s->pm1_enable)||0x1;
-/*  printf("acpiPm1Enable_readb \n addr %x val:%x\n", addr, val); */
-
-    return val;
-}
-
-static void acpiPm1EnableP1_writeb(void *opaque, uint32_t addr, uint32_t val)
-{
-    PCIAcpiState *s = opaque;
-
-    s->pm1_enable = (val<<8)||(s->pm1_enable);
-/*    printf("acpiPm1EnableP1_writeb \n addr %x val:%x\n", addr, val); */
-
-}
-
-static uint32_t acpiPm1EnableP1_readb(void *opaque, uint32_t addr)
-{
-    PCIAcpiState *s = opaque;
-    uint32_t val;
-
-    val = (s->pm1_enable)>>8;
-/*  printf("acpiPm1EnableP1_readb \n addr %x val:%x\n", addr, val); */
-
-    return val;
-}
 
 static void acpiPm1Control_writeb(void *opaque, uint32_t addr, uint32_t val)
 {
     PCIAcpiState *s = opaque;
 
-    s->pm1_control = val;
+    s->pm1_control = (s->pm1_control & 0xff00) | (val & 0xff);
 /*  printf("acpiPm1Control_writeb \n addr %x val:%x\n", addr, val); */
 
 }
@@ -181,7 +71,8 @@ static uint32_t acpiPm1Control_readb(voi
     PCIAcpiState *s = opaque;
     uint32_t val;
 
-    val = s->pm1_control;
+    /* Mask out the write-only bits */
+    val = s->pm1_control & ~(GBL_RLS|SLP_EN) & 0xff;
 /*    printf("acpiPm1Control_readb \n addr %x val:%x\n", addr, val); */
 
     return val;
@@ -191,14 +82,13 @@ static void acpiPm1ControlP1_writeb(void
 {
     PCIAcpiState *s = opaque;
 
-    s->pm1_control = (val<<8)||(s->pm1_control);
+    s->pm1_control = (s->pm1_control & 0xff) | (val << 8);
 /*    printf("acpiPm1ControlP1_writeb \n addr %x val:%x\n", addr, val); */
 
     // Check for power off request
-
+    val <<= 8;
     if (((val & SLP_EN) != 0) &&
         ((val & SLP_TYP_MASK) == SLP_VAL)) {
-        s->pm1_timer=0x0; //clear ACPI timer
         qemu_system_shutdown_request();
     }
 }
@@ -208,7 +98,8 @@ static uint32_t acpiPm1ControlP1_readb(v
     PCIAcpiState *s = opaque;
     uint32_t val;
 
-    val = (s->pm1_control)>>8;
+    /* Mask out the write-only bits */
+    val = (s->pm1_control & ~(GBL_RLS|SLP_EN)) >> 8;
 /*    printf("acpiPm1ControlP1_readb \n addr %x val:%x\n", addr, val); */
 
     return val;
@@ -216,50 +107,6 @@ static uint32_t acpiPm1ControlP1_readb(v
 
 
 /* word access   */
-
-static void acpiPm1Status_writew(void *opaque, uint32_t addr, uint32_t val)
-{
-    PCIAcpiState *s = opaque;
-
-    if ((val&TMROF_STS)==TMROF_STS)
-        s->pm1_status = s->pm1_status&!TMROF_STS;
-
-    if ((val&GBL_STS)==GBL_STS)
-        s->pm1_status = s->pm1_status&!GBL_STS;
-
-/*    printf("acpiPm1Status_writew \n addr %x val:%x pm1_status:%x \n", addr, 
val,s->pm1_status); */
-}
-
-static uint32_t acpiPm1Status_readw(void *opaque, uint32_t addr)
-{
-    PCIAcpiState *s = opaque;
-    uint32_t val;
-
-    val = s->pm1_status;
-/*    printf("acpiPm1Status_readw \n addr %x val:%x\n", addr, val); */
-
-    return val;
-}
-
-static void acpiPm1Enable_writew(void *opaque, uint32_t addr, uint32_t val)
-{
-    PCIAcpiState *s = opaque;
-
-    s->pm1_enable = val;
-/*    printf("acpiPm1Enable_writew \n addr %x val:%x\n", addr, val); */
-
-}
-
-static uint32_t acpiPm1Enable_readw(void *opaque, uint32_t addr)
-{
-    PCIAcpiState *s = opaque;
-    uint32_t val;
-
-    val = s->pm1_enable;
-/*    printf("acpiPm1Enable_readw \n addr %x val:%x\n", addr, val); */
-
-   return val;
-}
 
 static void acpiPm1Control_writew(void *opaque, uint32_t addr, uint32_t val)
 {
@@ -282,56 +129,13 @@ static uint32_t acpiPm1Control_readw(voi
     PCIAcpiState *s = opaque;
     uint32_t val;
 
-    val = s->pm1_control;
+    /* Mask out the write-only bits */
+    val = s->pm1_control & ~(GBL_RLS|SLP_EN);
 /*    printf("acpiPm1Control_readw \n addr %x val:%x\n", addr, val);  */
 
     return val;
 }
 
-/* dword access */
-
-static void acpiPm1Event_writel(void *opaque, uint32_t addr, uint32_t val)
-{
-    PCIAcpiState *s = opaque;
-
-    s->pm1_status = val;
-    s->pm1_enable = val>>16;
-/*     printf("acpiPm1Event_writel \n addr %x val:%x \n", addr, val); */
-
-}
-
-static uint32_t acpiPm1Event_readl(void *opaque, uint32_t addr)
-{
-    PCIAcpiState *s = opaque;
-    uint32_t val;
-
-    val = s->pm1_status|(s->pm1_enable<<16);
-/*    printf("acpiPm1Event_readl \n addr %x val:%x\n", addr, val);    */
-
-    return val;
-}
-
-static void acpiPm1Timer_writel(void *opaque, uint32_t addr, uint32_t val)
-{
-    PCIAcpiState *s = opaque;
-
-    s->pm1_timer = val;
-    s->old_vmck_ticks = qemu_get_clock(vm_clock) +
-        muldiv64(val, FREQUENCE_PMTIMER, ticks_per_sec);
-}
-
-static uint32_t acpiPm1Timer_readl(void *opaque, uint32_t addr)
-{
-    PCIAcpiState *s = opaque;
-    int64_t current_vmck_ticks = qemu_get_clock(vm_clock);
-    int64_t vmck_ticks_delta = current_vmck_ticks - s->old_vmck_ticks;
-
-    if (s->old_vmck_ticks)
-        s->pm1_timer += muldiv64(vmck_ticks_delta, FREQUENCE_PMTIMER,
-                                 ticks_per_sec);
-    s->old_vmck_ticks = current_vmck_ticks;
-    return s->pm1_timer;
-}
 
 static void acpi_map(PCIDevice *pci_dev, int region_num,
                     uint32_t addr, uint32_t size, int type)
@@ -341,37 +145,14 @@ static void acpi_map(PCIDevice *pci_dev,
     printf("register acpi io\n");
 
     /* Byte access */
-    register_ioport_write(addr, 1, 1, acpiPm1Status_writeb, d);
-    register_ioport_read(addr, 1, 1, acpiPm1Status_readb, d);
-    register_ioport_write(addr+1, 1, 1, acpiPm1StatusP1_writeb, d);
-    register_ioport_read(addr+1, 1, 1, acpiPm1StatusP1_readb, d);
-
-    register_ioport_write(addr + 2, 1, 1, acpiPm1Enable_writeb, d);
-    register_ioport_read(addr + 2, 1, 1, acpiPm1Enable_readb, d);
-    register_ioport_write(addr + 2 +1, 1, 1, acpiPm1EnableP1_writeb, d);
-    register_ioport_read(addr + 2 +1, 1, 1, acpiPm1EnableP1_readb, d);
-
     register_ioport_write(addr + 4, 1, 1, acpiPm1Control_writeb, d);
     register_ioport_read(addr + 4, 1, 1, acpiPm1Control_readb, d);
     register_ioport_write(addr + 4 + 1, 1, 1, acpiPm1ControlP1_writeb, d);
     register_ioport_read(addr + 4 +1, 1, 1, acpiPm1ControlP1_readb, d);
 
     /* Word access */
-    register_ioport_write(addr, 2, 2, acpiPm1Status_writew, d);
-    register_ioport_read(addr, 2, 2, acpiPm1Status_readw, d);
-
-    register_ioport_write(addr + 2, 2, 2, acpiPm1Enable_writew, d);
-    register_ioport_read(addr + 2, 2, 2, acpiPm1Enable_readw, d);
-
     register_ioport_write(addr + 4, 2, 2, acpiPm1Control_writew, d);
     register_ioport_read(addr + 4, 2, 2, acpiPm1Control_readw, d);
-
-    /* DWord access */
-    register_ioport_write(addr, 4, 4, acpiPm1Event_writel, d);
-    register_ioport_read(addr, 4, 4, acpiPm1Event_readl, d);
-
-    register_ioport_write(addr + 8, 4, 4, acpiPm1Timer_writel, d);
-    register_ioport_read(addr + 8, 4, 4, acpiPm1Timer_readl, d);
 }
 
 /* PIIX4 acpi pci configuration space, func 2 */
@@ -385,7 +166,6 @@ void pci_piix4_acpi_init(PCIBus *bus, in
         bus, "PIIX4 ACPI", sizeof(PCIAcpiState),
         devfn, NULL, NULL);
 
-    acpi_state = d;
     pci_conf = d->dev.config;
     pci_conf[0x00] = 0x86;  /* Intel */
     pci_conf[0x01] = 0x80;
@@ -408,6 +188,9 @@ void pci_piix4_acpi_init(PCIBus *bus, in
      */
     pci_conf[0x40] = 0x41; /* Special device-specific BAR at 0x40 */
     pci_conf[0x41] = 0x1f;
+    pci_conf[0x42] = 0x00;
+    pci_conf[0x43] = 0x00;
+    d->pm1_control = SCI_EN;
+
     acpi_map(d, 0, 0x1f40, 0x10, PCI_ADDRESS_SPACE_IO);
-    acpi_reset(d);
 }
diff -r dccb274295ae -r 3afefd64e392 xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c    Mon Mar 26 01:13:16 2007 +0100
+++ b/xen/arch/x86/hvm/hvm.c    Mon Mar 26 09:13:03 2007 +0000
@@ -218,6 +218,7 @@ void hvm_domain_destroy(struct domain *d
 {
     pit_deinit(d);
     rtc_deinit(d);
+    pmtimer_deinit(d);
     hpet_deinit(d);
 
     if ( d->arch.hvm_domain.shared_page_va )
@@ -303,7 +304,7 @@ int hvm_vcpu_initialise(struct vcpu *v)
 
     pit_init(v, cpu_khz);
     rtc_init(v, RTC_PORT(0));
-    pmtimer_init(v, ACPI_PM_TMR_BLK_ADDRESS);
+    pmtimer_init(v);
     hpet_init(v);
  
     /* Init guest TSC to start from zero. */
diff -r dccb274295ae -r 3afefd64e392 xen/arch/x86/hvm/pmtimer.c
--- a/xen/arch/x86/hvm/pmtimer.c        Mon Mar 26 01:13:16 2007 +0100
+++ b/xen/arch/x86/hvm/pmtimer.c        Mon Mar 26 09:13:03 2007 +0000
@@ -1,12 +1,172 @@
+/*
+ * hvm/pmtimer.c: emulation of the ACPI PM timer 
+ *
+ * Copyright (c) 2007, XenSource inc.
+ * Copyright (c) 2006, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ */
+
 #include <asm/hvm/vpt.h>
 #include <asm/hvm/io.h>
 #include <asm/hvm/support.h>
 
+/* Slightly more readable port I/O addresses for the registers we intercept */
+#define PM1a_STS_ADDR (ACPI_PM1A_EVT_BLK_ADDRESS)
+#define PM1a_EN_ADDR  (ACPI_PM1A_EVT_BLK_ADDRESS + 2)
+#define TMR_VAL_ADDR  (ACPI_PM_TMR_BLK_ADDRESS)
+
+/* The interesting bit of the PM1a_STS register */
+#define TMR_STS    (1 << 0)
+#define PWRBTN_STS (1 << 5)
+#define GBL_STS    (1 << 8)
+
+/* The same in PM1a_EN */
+#define TMR_EN     (1 << 0)
+#define PWRBTN_EN  (1 << 5)
+#define GBL_EN     (1 << 8)
+
+/* Mask of bits in PM1a_STS that can generate an SCI.  Although the ACPI
+ * spec lists other bits, the PIIX4, which we are emulating, only
+ * supports these three.  For now, we only use TMR_STS; in future we
+ * will let qemu set the other bits */
+#define SCI_MASK (TMR_STS|PWRBTN_STS|GBL_STS) 
+
+/* SCI IRQ number (must match SCI_INT number in ACPI FADT in hvmloader) */
+#define SCI_IRQ 9
+
+/* We provide a 32-bit counter (must match the TMR_VAL_EXT bit in the FADT) */
+#define TMR_VAL_MASK  (0xffffffff)
+#define TMR_VAL_MSB   (0x80000000)
+
+
+/* Dispatch SCIs based on the PM1a_STS and PM1a_EN registers */
+static void pmt_update_sci(PMTState *s)
+{
+    if ( s->pm.pm1a_en & s->pm.pm1a_sts & SCI_MASK )
+        hvm_isa_irq_assert(s->vcpu->domain, SCI_IRQ);
+    else
+        hvm_isa_irq_deassert(s->vcpu->domain, SCI_IRQ);
+}
+
+/* Set the correct value in the timer, accounting for time elapsed
+ * since the last time we did that. */
+static void pmt_update_time(PMTState *s)
+{
+    uint64_t curr_gtime;
+    uint32_t msb = s->pm.tmr_val & TMR_VAL_MSB;
+    
+    /* Update the timer */
+    curr_gtime = hvm_get_guest_time(s->vcpu);
+    s->pm.tmr_val += ((curr_gtime - s->last_gtime) * s->scale) >> 32;
+    s->pm.tmr_val &= TMR_VAL_MASK;
+    s->last_gtime = curr_gtime;
+    
+    /* If the counter's MSB has changed, set the status bit */
+    if ( (s->pm.tmr_val & TMR_VAL_MSB) != msb )
+    {
+        s->pm.pm1a_sts |= TMR_STS;
+        pmt_update_sci(s);
+    }
+}
+
+/* This function should be called soon after each time the MSB of the
+ * pmtimer register rolls over, to make sure we update the status
+ * registers and SCI at least once per rollover */
+static void pmt_timer_callback(void *opaque)
+{
+    PMTState *s = opaque;
+    uint32_t pmt_cycles_until_flip;
+    uint64_t time_until_flip;
+    
+    /* Recalculate the timer and make sure we get an SCI if we need one */
+    pmt_update_time(s);
+    
+    /* How close are we to the next MSB flip? */
+    pmt_cycles_until_flip = TMR_VAL_MSB - (s->pm.tmr_val & (TMR_VAL_MSB - 1));
+    
+    /* Overall time between MSB flips */
+    time_until_flip = (1000000000ULL << 31) / FREQUENCE_PMTIMER;
+    
+    /* Reduced appropriately */
+    time_until_flip = (time_until_flip * pmt_cycles_until_flip) / (1ULL<<31);
+    
+    /* Wake up again near the next bit-flip */
+    set_timer(&s->timer, NOW() + time_until_flip + MILLISECS(1));
+}
+
+
+/* Handle port I/O to the PM1a_STS and PM1a_EN registers */
+static int handle_evt_io(ioreq_t *p)
+{
+    struct vcpu *v = current;
+    PMTState *s = &v->domain->arch.hvm_domain.pl_time.vpmt;
+    uint32_t addr, data, byte;
+    int i;
+
+    if ( p->dir == 0 ) /* Write */
+    {
+        /* Handle this I/O one byte at a time */
+        for ( i = p->size, addr = p->addr, data = p->data;
+              i > 0;
+              i--, addr++, data >>= 8 )
+        {
+            byte = data & 0xff;
+            switch(addr) 
+            {
+                /* PM1a_STS register bits are write-to-clear */
+            case PM1a_STS_ADDR:
+                s->pm.pm1a_sts &= ~byte;
+                break;
+            case PM1a_STS_ADDR + 1:
+                s->pm.pm1a_sts &= ~(byte << 8);
+                break;
+                
+            case PM1a_EN_ADDR:
+                s->pm.pm1a_en = (s->pm.pm1a_en & 0xff00) | byte;
+                break;
+            case PM1a_EN_ADDR + 1:
+                s->pm.pm1a_en = (s->pm.pm1a_en & 0xff) | (byte << 8);
+                break;
+                
+            default:
+                gdprintk(XENLOG_WARNING, 
+                         "Bad ACPI PM register write: %"PRIu64
+                         " bytes (%#"PRIx64") at %"PRIx64"\n", 
+                         p->size, p->data, p->addr);
+            }
+        }
+        /* Fix up the SCI state to match the new register state */
+        pmt_update_sci(s);
+    }
+    else /* Read */
+    {
+        data = s->pm.pm1a_sts | (((uint32_t) s->pm.pm1a_en) << 16);
+        data >>= 8 * (p->addr - PM1a_STS_ADDR);
+        if ( p->size == 1 ) data &= 0xff;
+        else if ( p->size == 2 ) data &= 0xffff;
+        p->data = data;
+    }
+    return 1;
+}
+
+
+/* Handle port I/O to the TMR_VAL register */
 static int handle_pmt_io(ioreq_t *p)
 {
     struct vcpu *v = current;
     PMTState *s = &v->domain->arch.hvm_domain.pl_time.vpmt;
-    uint64_t curr_gtime;
 
     if (p->size != 4 ||
         p->data_is_ptr ||
@@ -19,12 +179,8 @@ static int handle_pmt_io(ioreq_t *p)
         /* PM_TMR_BLK is read-only */
         return 1;
     } else if (p->dir == 1) { /* read */
-        /* Set the correct value in the timer, accounting for time
-         * elapsed since the last time we did that. */
-        curr_gtime = hvm_get_guest_time(s->vcpu);
-        s->pm.timer += ((curr_gtime - s->last_gtime) * s->scale) >> 32;
-        p->data = s->pm.timer;
-        s->last_gtime = curr_gtime;
+        pmt_update_time(s);
+        p->data = s->pm.tmr_val;
         return 1;
     }
     return 0;
@@ -33,6 +189,7 @@ static int pmtimer_save(struct domain *d
 static int pmtimer_save(struct domain *d, hvm_domain_context_t *h)
 {
     PMTState *s = &d->arch.hvm_domain.pl_time.vpmt;
+    uint32_t msb = s->pm.tmr_val & TMR_VAL_MSB;
     uint32_t x;
 
     /* Update the counter to the guest's current time.  We always save
@@ -40,7 +197,12 @@ static int pmtimer_save(struct domain *d
      * last_gtime, but just in case, make sure we only go forwards */
     x = ((s->vcpu->arch.hvm_vcpu.guest_time - s->last_gtime) * s->scale) >> 32;
     if ( x < 1UL<<31 )
-        s->pm.timer += x;
+        s->pm.tmr_val += x;
+    if ( (s->pm.tmr_val & TMR_VAL_MSB) != msb )
+        s->pm.pm1a_sts |= TMR_STS;
+    /* No point in setting the SCI here because we'll already have saved the 
+     * IRQ and *PIC state; we'll fix it up when we restore the domain */
+
     return hvm_save_entry(PMTIMER, 0, h, &s->pm);
 }
 
@@ -48,12 +210,15 @@ static int pmtimer_load(struct domain *d
 {
     PMTState *s = &d->arch.hvm_domain.pl_time.vpmt;
 
-    /* Reload the counter */
+    /* Reload the registers */
     if ( hvm_load_entry(PMTIMER, h, &s->pm) )
         return -EINVAL;
 
     /* Calculate future counter values from now. */
     s->last_gtime = hvm_get_guest_time(s->vcpu);
+
+    /* Set the SCI state from the registers */ 
+    pmt_update_sci(s);
     
     return 0;
 }
@@ -62,19 +227,30 @@ HVM_REGISTER_SAVE_RESTORE(PMTIMER, pmtim
                           1, HVMSR_PER_DOM);
 
 
-void pmtimer_init(struct vcpu *v, int base)
-{
-    PMTState *s = &v->domain->arch.hvm_domain.pl_time.vpmt;
-
-    s->pm.timer = 0;
+void pmtimer_init(struct vcpu *v)
+{
+    PMTState *s = &v->domain->arch.hvm_domain.pl_time.vpmt;
+
+    s->pm.tmr_val = 0;
+    s->pm.pm1a_sts = 0;
+    s->pm.pm1a_en = 0;
+
     s->scale = ((uint64_t)FREQUENCE_PMTIMER << 32) / ticks_per_sec(v);
     s->vcpu = v;
 
-    /* Not implemented: we should set TMR_STS (bit 0 of PM1a_STS) every
-     * time the timer's top bit flips, and generate an SCI if TMR_EN
-     * (bit 0 of PM1a_EN) is set.  For now, those registers are in
-     * qemu-dm, and we just calculate the timer's value on demand. */  
-
-    register_portio_handler(v->domain, base, 4, handle_pmt_io);
-}
-
+    /* Intercept port I/O (need two handlers because PM1a_CNT is between
+     * PM1a_EN and TMR_VAL and is handled by qemu) */
+    register_portio_handler(v->domain, TMR_VAL_ADDR, 4, handle_pmt_io);
+    register_portio_handler(v->domain, PM1a_STS_ADDR, 4, handle_evt_io);
+
+    /* Set up callback to fire SCIs when the MSB of TMR_VAL changes */
+    init_timer(&s->timer, pmt_timer_callback, s, v->processor);
+    pmt_timer_callback(s);
+}
+
+
+void pmtimer_deinit(struct domain *d)
+{
+    PMTState *s = &d->arch.hvm_domain.pl_time.vpmt;
+    kill_timer(&s->timer);
+}
diff -r dccb274295ae -r 3afefd64e392 xen/include/asm-x86/hvm/io.h
--- a/xen/include/asm-x86/hvm/io.h      Mon Mar 26 01:13:16 2007 +0100
+++ b/xen/include/asm-x86/hvm/io.h      Mon Mar 26 09:13:03 2007 +0000
@@ -80,7 +80,7 @@ struct hvm_io_op {
     struct cpu_user_regs    io_context; /* current context */
 };
 
-#define MAX_IO_HANDLER              8
+#define MAX_IO_HANDLER              9
 
 #define HVM_PORTIO                  0
 #define HVM_MMIO                    1
diff -r dccb274295ae -r 3afefd64e392 xen/include/asm-x86/hvm/vpt.h
--- a/xen/include/asm-x86/hvm/vpt.h     Mon Mar 26 01:13:16 2007 +0100
+++ b/xen/include/asm-x86/hvm/vpt.h     Mon Mar 26 09:13:03 2007 +0000
@@ -101,6 +101,7 @@ typedef struct PMTState {
     struct vcpu *vcpu;          /* Keeps sync with this vcpu's guest-time */
     uint64_t last_gtime;        /* Last (guest) time we updated the timer */
     uint64_t scale;             /* Multiplier to get from tsc to timer ticks */
+    struct timer timer;         /* To make sure we send SCIs */
 } PMTState;
 
 struct pl_time {    /* platform time */
@@ -132,7 +133,8 @@ void rtc_migrate_timers(struct vcpu *v);
 void rtc_migrate_timers(struct vcpu *v);
 void rtc_deinit(struct domain *d);
 int is_rtc_periodic_irq(void *opaque);
-void pmtimer_init(struct vcpu *v, int base);
+void pmtimer_init(struct vcpu *v);
+void pmtimer_deinit(struct domain *d);
 
 void hpet_migrate_timers(struct vcpu *v);
 void hpet_init(struct vcpu *v);
diff -r dccb274295ae -r 3afefd64e392 xen/include/public/hvm/save.h
--- a/xen/include/public/hvm/save.h     Mon Mar 26 01:13:16 2007 +0100
+++ b/xen/include/public/hvm/save.h     Mon Mar 26 09:13:03 2007 +0000
@@ -392,7 +392,9 @@ DECLARE_HVM_SAVE_TYPE(HPET, 12, struct h
  */
 
 struct hvm_hw_pmtimer {
-    uint32_t timer;
+    uint32_t tmr_val;   /* PM_TMR_BLK.TMR_VAL: 24bit free-running counter */
+    uint16_t pm1a_sts;  /* PM1a_EVT_BLK.PM1a_STS: status register */
+    uint16_t pm1a_en;   /* PM1a_EVT_BLK.PM1a_EN: enable register */
 };
 
 DECLARE_HVM_SAVE_TYPE(PMTIMER, 13, struct hvm_hw_pmtimer);

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] [HVM] Intercept ACPI pm-timer registers, Xen patchbot-unstable <=