]> rtime.felk.cvut.cz Git - jailhouse.git/commitdiff
x86/tools/inmates: Account for 32-bit PM timers
authorValentine Sinitsyn <valentine.sinitsyn@gmail.com>
Thu, 9 Oct 2014 17:00:36 +0000 (23:00 +0600)
committerJan Kiszka <jan.kiszka@siemens.com>
Wed, 15 Oct 2014 09:48:55 +0000 (11:48 +0200)
Some systems may use 32-bit PM timer (as defined by TMR_VAL_EXT feature
flag in FADT), however pm_timer_read() assumes it is always 24-bit. Where
this assumption is wrong, return value becomes incorrect, and the error
grows over time leading to obscure bugs, including lockups in the hypervisor.

To fix this, TMR_VAL_EXT is made part of platform config and is passed to
inmates in the communication region. Config generator was also adapted
to parse FADT to get TMR_VAL_EXT value for target system. pm_timer_init()
function was also introduced to the inmates framework to the overflow value.

Signed-off-by: Valentine Sinitsyn <valentine.sinitsyn@gmail.com>
[Jan: mark jailhouse_comm_region as packed]
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
hypervisor/arch/x86/control.c
hypervisor/arch/x86/include/asm/jailhouse_hypercall.h
hypervisor/include/jailhouse/cell-config.h
inmates/demos/x86/apic-demo.c
inmates/demos/x86/e1000-demo.c
inmates/demos/x86/tiny-demo.c
inmates/lib/x86/inmate.h
inmates/lib/x86/timing.c
tools/jailhouse-config-create
tools/root-cell-config.c.tmpl

index fe42fcfc3710c792144cc37c6ef6d83e012e5735..0dfd56ace942a4ac4e762ff88116d9081e13e62e 100644 (file)
@@ -51,6 +51,9 @@ int arch_cell_create(struct cell *cell)
        cell->comm_page.comm_region.pm_timer_address =
                system_config->platform_info.x86.pm_timer_address;
 
+       cell->comm_page.comm_region.pm_timer_val_ext =
+               system_config->platform_info.x86.pm_timer_val_ext;
+
        return 0;
 
 error_iommu_exit:
index 04050251c1292f525daaf9c1150b1c8ad431cfad..1efe8d27dce081abfd9e0701fa17c3ded72bfb45 100644 (file)
@@ -33,7 +33,8 @@ struct jailhouse_comm_region {
        COMM_REGION_GENERIC_HEADER;
 
        __u16 pm_timer_address;
-};
+       __u8 pm_timer_val_ext;
+} __attribute__((packed));
 
 static inline __u32 jailhouse_call(__u32 num)
 {
index d0b034107fa642c350eb4c453954f3c0314bcf8e..d65894f43ac50e3504e8208614c7df0f8ad6a9fa 100644 (file)
@@ -90,7 +90,8 @@ struct jailhouse_system {
                struct {
                        __u64 mmconfig_base;
                        __u8 mmconfig_end_bus;
-                       __u8 padding[5];
+                       __u8 padding[4];
+                       __u8 pm_timer_val_ext;
                        __u16 pm_timer_address;
                        __u64 dmar_unit_base[JAILHOUSE_MAX_DMAR_UNITS];
                } __attribute__((packed)) x86;
index 17f4663848bfdc30aad121402947f114dd99d24a..9d620266875cc22494caa1312039e6b3d59ff981 100644 (file)
@@ -74,6 +74,7 @@ void inmate_main(void)
 
        comm_region->cell_state = JAILHOUSE_CELL_RUNNING_LOCKED;
 
+       pm_timer_init();
        init_apic();
 
        while (!terminate) {
index 49d9a36b8cfca04efb29279ce2313b58a4cd81c6..ab22ab2687364beede68b0884b23221faa0d4c94 100644 (file)
@@ -174,6 +174,7 @@ void inmate_main(void)
        int bdf;
 
        printk_uart_base = UART_BASE;
+       pm_timer_init();
 
        bdf = pci_find_device(PCI_ID_ANY, PCI_ID_ANY, 0);
        if (bdf < 0) {
index 8e1a0776178539267c6cdda133eb22c04fb7c187..cfd2082a2e1d053f69286ebed526593f3b8d2be6 100644 (file)
@@ -26,6 +26,8 @@ void inmate_main(void)
        printk_uart_base = UART_BASE;
        printk("Hello from this tiny cell!\n");
 
+       pm_timer_init();
+
        start = pm_timer_read();
        for (n = 0; n < 10; n++) {
                do {
index 801176b367bea18a23e52c7f3c43281736b325d3..0dcea56df1f389691de2827a9ae091e070fb0ce5 100644 (file)
@@ -218,6 +218,7 @@ void ioapic_pin_set_vector(unsigned int pin,
 
 void inmate_main(void);
 
+void pm_timer_init(void);
 unsigned long pm_timer_read(void);
 void delay_us(unsigned long microsecs);
 unsigned long apic_timer_init(unsigned int vector);
index bb53a89abe3f7a2ac640473c71044a8b95d1f3c0..5f12e0336335f40432e12b7d5a220356ba2ffa63 100644 (file)
@@ -2,9 +2,11 @@
  * Jailhouse, a Linux-based partitioning hypervisor
  *
  * Copyright (c) Siemens AG, 2013, 2014
+ * Copyright (c) Valentine Sinitsyn, 2014
  *
  * Authors:
  *  Jan Kiszka <jan.kiszka@siemens.com>
+ *  Valentine Sinitsyn <valentine.sinitsyn@gmail.com>
  *
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
@@ -13,7 +15,6 @@
 #include <inmate.h>
 
 #define PM_TIMER_HZ            3579545
-#define PM_TIMER_OVERFLOW      ((0x1000000 * 1000000000ULL) / PM_TIMER_HZ)
 
 #define X2APIC_LVTT            0x832
 #define X2APIC_TMICT           0x838
 #define X2APIC_TDCR            0x83e
 
 static unsigned long divided_apic_freq;
+static unsigned long pm_timer_overflow;
+
+void pm_timer_init(void)
+{
+       /* Initialize pm_timer overflow value, as per ACPI 5.0, Sect. 5.2.9. */
+       if (comm_region->pm_timer_val_ext)
+               pm_timer_overflow =
+                       ((0x100000000 * 1000000000ULL) / PM_TIMER_HZ);
+       else
+               pm_timer_overflow =
+                       ((0x1000000 * 1000000000ULL) / PM_TIMER_HZ);
+}
 
 unsigned long pm_timer_read(void)
 {
@@ -29,7 +42,7 @@ unsigned long pm_timer_read(void)
 
        tmr = (inl(comm_region->pm_timer_address) * NS_PER_SEC) / PM_TIMER_HZ;
        if (tmr < last)
-               overflows += PM_TIMER_OVERFLOW;
+               overflows += pm_timer_overflow;
        last = tmr;
        return tmr + overflows;
 }
index 7e5857390c473af1c3779b0469874e4343365e8c..8e840892e9b0b9ca48d7efe7b5ff520f4786b2b9 100755 (executable)
@@ -3,6 +3,7 @@
 # Jailhouse, a Linux-based partitioning hypervisor
 #
 # Copyright (c) Siemens AG, 2014
+# Copyright (c) Valentine Sinitsyn, 2014
 #
 # This work is licensed under the terms of the GNU GPL, version 2.  See
 # the COPYING file in the top-level directory.
@@ -80,6 +81,7 @@ inputs['files'].add('/sys/bus/pci/devices/*/config')
 inputs['files'].add('/sys/bus/pci/devices/*/class')
 inputs['files'].add('/sys/devices/system/cpu/cpu*/uevent')
 inputs['files'].add('/sys/firmware/acpi/tables/MCFG')
+inputs['files'].add('/sys/firmware/acpi/tables/FACP')
 ## optional files
 inputs['files_opt'].add('/sys/class/dmi/id/product_name')
 inputs['files_opt'].add('/sys/class/dmi/id/sys_vendor')
@@ -611,6 +613,19 @@ def parse_ioports():
     return pm_timer_base
 
 
+def parse_facp():
+    tmr_val_ext = 0
+    with input_open('/sys/firmware/acpi/tables/FACP', 'rb') as f:
+        signature = f.read(4)
+        if signature != b'FACP':
+            raise RuntimeError('FACP: incorrect input file format %s' %
+                               signature)
+        f.seek(112)
+        (flags,) = struct.unpack('>I', f.read(4))
+        tmr_val_ext = (flags & 256) >> 8
+    return tmr_val_ext
+
+
 class MMConfig:
     def __init__(self, base, end_bus):
         self.base = base
@@ -721,6 +736,7 @@ cpucount = count_cpus()
 
 pm_timer_base = parse_ioports()
 
+pm_timer_val_ext = parse_facp()
 
 f = open(options.file, 'w')
 tmpl = Template(filename=os.path.join(options.template_dir,
@@ -735,6 +751,7 @@ f.write(tmpl.render(regions=regions,
                     cpucount=cpucount,
                     ioapic_id=ioapic_id,
                     pm_timer_base=pm_timer_base,
+                    pm_timer_val_ext=pm_timer_val_ext,
                     mmconfig=mmconfig,
                     dmar_units=dmar_units))
 
index 8b61f04ca6bc80d32d1595469eb704391e4bd6ef..2a57a5a7f26debce7e7e85617a1340b0ed95fa97 100644 (file)
@@ -36,6 +36,7 @@ struct {
                        .mmconfig_base = ${hex(mmconfig.base)},
                        .mmconfig_end_bus = ${hex(mmconfig.end_bus)},
                        .pm_timer_address = ${hex(pm_timer_base)},
+                       .pm_timer_val_ext = ${pm_timer_val_ext},
                        % if dmar_units:
                        .dmar_unit_base = {
                                % for d in dmar_units: