]> xenbits.xen.org Git - xenclient/xen.git/commitdiff
tboot patch 5/5 - use protected DMAR
authorRoss Philipson <ross.philipson@citrix.com>
Wed, 4 Feb 2009 16:17:52 +0000 (11:17 -0500)
committerRoss Philipson <ross.philipson@citrix.com>
Wed, 4 Feb 2009 16:17:52 +0000 (11:17 -0500)
The VT-d DMAR ACPI tables may not be DMA protected by tboot.
However, SINIT saves a copy of them in the SinitMleData struct
in the TXT heap (which is DMA protected). So we should read
the DMAR table from that copy if launched by tboot.

 Changes to be committed:
modified:   xen/arch/x86/tboot.c
modified:   xen/drivers/passthrough/vtd/dmar.c
modified:   xen/include/asm-x86/tboot.h

xen/arch/x86/tboot.c
xen/drivers/passthrough/vtd/dmar.c
xen/include/asm-x86/tboot.h

index 4577d0f06d7553a6f2eddd38f03b29e68422c710..608d34d39a41abe1547f244c22b2363c1728b9f6 100644 (file)
@@ -20,6 +20,10 @@ static const uuid_t tboot_shared_uuid = TBOOT_SHARED_UUID;
 
 extern char __init_begin[], __per_cpu_start[], __per_cpu_end[], __bss_start[];
 
+/* used by tboot_protect_mem_regions() and/or tboot_parse_dmar_table() */
+static uint64_t txt_heap_base, txt_heap_size;
+static uint64_t sinit_base, sinit_size;
+
 /*
  * TXT configuration registers (offsets from TXT_{PUB, PRIV}_CONFIG_REGS_BASE)
  */
@@ -37,10 +41,33 @@ extern char __init_begin[], __per_cpu_start[], __per_cpu_end[], __bss_start[];
 #define TXTCR_HEAP_BASE             0x0300
 #define TXTCR_HEAP_SIZE             0x0308
 
+#define SHA1_SIZE      20
+typedef uint8_t   sha1_hash_t[SHA1_SIZE];
+
+typedef struct __packed {
+    uint32_t     version;             /* currently 6 */
+    sha1_hash_t  bios_acm_id;
+    uint32_t     edx_senter_flags;
+    uint64_t     mseg_valid;
+    sha1_hash_t  sinit_hash;
+    sha1_hash_t  mle_hash;
+    sha1_hash_t  stm_hash;
+    sha1_hash_t  lcp_policy_hash;
+    uint32_t     lcp_policy_control;
+    uint32_t     rlp_wakeup_addr;
+    uint32_t     reserved;
+    uint32_t     num_mdrs;
+    uint32_t     mdrs_off;
+    uint32_t     num_vtd_dmars;
+    uint32_t     vtd_dmars_off;
+} sinit_mle_data_t;
+
 void __init tboot_probe(void)
 {
     tboot_shared_t *tboot_shared;
     unsigned long p_tboot_shared;
+    uint32_t map_base, map_size;
+    unsigned long map_addr;
 
     /* Look for valid page-aligned address for shared page. */
     p_tboot_shared = simple_strtoul(opt_tboot, NULL, 0);
@@ -68,6 +95,30 @@ void __init tboot_probe(void)
     printk("  shutdown_entry: 0x%08x\n", tboot_shared->shutdown_entry);
     printk("  tboot_base: 0x%08x\n", tboot_shared->tboot_base);
     printk("  tboot_size: 0x%x\n", tboot_shared->tboot_size);
+
+    /* these will be needed by tboot_protect_mem_regions() and/or
+       tboot_parse_dmar_table(), so get them now */
+
+    map_base = PFN_DOWN(TXT_PUB_CONFIG_REGS_BASE);
+    map_size = PFN_UP(NR_TXT_CONFIG_PAGES * PAGE_SIZE);
+    map_addr = (unsigned long)__va(map_base << PAGE_SHIFT);
+    if ( map_pages_to_xen(map_addr, map_base, map_size, __PAGE_HYPERVISOR) )
+        return;
+
+    /* TXT Heap */
+    txt_heap_base =
+        *(uint64_t *)__va(TXT_PUB_CONFIG_REGS_BASE + TXTCR_HEAP_BASE);
+    txt_heap_size =
+        *(uint64_t *)__va(TXT_PUB_CONFIG_REGS_BASE + TXTCR_HEAP_SIZE);
+
+    /* SINIT */
+    sinit_base =
+        *(uint64_t *)__va(TXT_PUB_CONFIG_REGS_BASE + TXTCR_SINIT_BASE);
+    sinit_size =
+        *(uint64_t *)__va(TXT_PUB_CONFIG_REGS_BASE + TXTCR_SINIT_SIZE);
+
+    destroy_xen_mappings((unsigned long)__va(map_base << PAGE_SHIFT),
+                         (unsigned long)__va((map_base + map_size) << PAGE_SHIFT));
 }
 
 void tboot_shutdown(uint32_t shutdown_type)
@@ -125,29 +176,18 @@ int tboot_in_measured_env(void)
 
 int tboot_protect_mem_regions(void)
 {
-    uint64_t base, size;
-    uint32_t map_base, map_size;
-    unsigned long map_addr;
-
     if ( !tboot_in_measured_env() )
         return 1;
 
-    map_base = PFN_DOWN(TXT_PUB_CONFIG_REGS_BASE);
-    map_size = PFN_UP(NR_TXT_CONFIG_PAGES * PAGE_SIZE);
-    map_addr = (unsigned long)__va(map_base << PAGE_SHIFT);
-    if ( map_pages_to_xen(map_addr, map_base, map_size, __PAGE_HYPERVISOR) )
-        return 0;
-
     /* TXT Heap */
-    base = *(uint64_t *)__va(TXT_PUB_CONFIG_REGS_BASE + TXTCR_HEAP_BASE);
-    size = *(uint64_t *)__va(TXT_PUB_CONFIG_REGS_BASE + TXTCR_HEAP_SIZE);
-    if ( !reserve_e820_unusable(&e820, base, base + size) )
+    if ( txt_heap_base == 0 ||
+         !reserve_e820_unusable(&e820, txt_heap_base,
+                                txt_heap_base + txt_heap_size) )
         return 0;
 
     /* SINIT */
-    base = *(uint64_t *)__va(TXT_PUB_CONFIG_REGS_BASE + TXTCR_SINIT_BASE);
-    size = *(uint64_t *)__va(TXT_PUB_CONFIG_REGS_BASE + TXTCR_SINIT_SIZE);
-    if ( !reserve_e820_unusable(&e820, base, base + size) )
+    if ( sinit_base == 0 ||
+         !reserve_e820_unusable(&e820, sinit_base, sinit_base + sinit_size) )
         return 0;
 
     /* TXT Private Space */
@@ -155,10 +195,60 @@ int tboot_protect_mem_regions(void)
             TXT_PRIV_CONFIG_REGS_BASE + NR_TXT_CONFIG_PAGES * PAGE_SIZE) )
         return 0;
 
+    return 1;
+}
+
+int __init tboot_parse_dmar_table(acpi_table_handler dmar_handler)
+{
+    uint32_t map_base, map_size;
+    unsigned long map_vaddr;
+    void *heap_ptr;
+    struct acpi_table_header *dmar_table;
+    int rc;
+
+    if ( !tboot_in_measured_env() )
+        return acpi_table_parse(ACPI_SIG_DMAR, dmar_handler);
+
+    /* ACPI tables may not be DMA protected by tboot, so use DMAR copy */
+    /* SINIT saved in SinitMleData in TXT heap (which is DMA protected) */
+
+    if ( txt_heap_base == 0 )
+        return 1;
+
+    /* map TXT heap into Xen addr space */
+    map_base = PFN_DOWN(txt_heap_base);
+    map_size = PFN_UP(txt_heap_size);
+    map_vaddr = (unsigned long)__va(map_base << PAGE_SHIFT);
+    if ( map_pages_to_xen(map_vaddr, map_base, map_size, __PAGE_HYPERVISOR) )
+        return 1;
+
+    /* walk heap to SinitMleData */
+    heap_ptr = __va(txt_heap_base);
+    /* skip BiosData */
+    heap_ptr += *(uint64_t *)heap_ptr;
+    /* skip OsMleData */
+    heap_ptr += *(uint64_t *)heap_ptr;
+    /* skip OsSinitData */
+    heap_ptr += *(uint64_t *)heap_ptr;
+    /* now points to SinitMleDataSize; set to SinitMleData */
+    heap_ptr += sizeof(uint64_t);
+    /* get addr of DMAR table */
+    dmar_table = (struct acpi_table_header *)(heap_ptr +
+            ((sinit_mle_data_t *)heap_ptr)->vtd_dmars_off - sizeof(uint64_t));
+
+    rc = dmar_handler(dmar_table);
+
     destroy_xen_mappings((unsigned long)__va(map_base << PAGE_SHIFT),
                          (unsigned long)__va((map_base + map_size) << PAGE_SHIFT));
 
-    return 1;
+    /* acpi_parse_dmar() zaps APCI DMAR signature in TXT heap table */
+    /* but dom0 will read real table, so must zap it there too */
+    dmar_table = NULL;
+    acpi_get_table(ACPI_SIG_DMAR, 0, &dmar_table);
+    if ( dmar_table != NULL )
+        ((struct acpi_table_dmar *)dmar_table)->header.signature[0] = '\0';
+
+    return rc;
 }
 
 /*
index 43107b3ae345a8af6a0554facf6d24d43de814d3..ffcda32b437d58fcfb2df57dff41f6a5f3aa6a09 100644 (file)
@@ -28,6 +28,7 @@
 #include <xen/pci.h>
 #include <xen/pci_regs.h>
 #include <asm/string.h>
+#include <asm/tboot.h>
 #include "dmar.h"
 
 int vtd_enabled = 1;
@@ -496,7 +497,9 @@ int acpi_dmar_init(void)
     if ( !iommu_enabled )
         goto fail;
 
-    rc = acpi_table_parse(ACPI_SIG_DMAR, acpi_parse_dmar);
+    /* ACPI tables may not be DMA protected by tboot, so use DMAR copy */
+    /* SINIT saved in SinitMleData in TXT heap (which is DMA protected) */
+    rc = tboot_parse_dmar_table(acpi_parse_dmar);
     if ( rc )
         goto fail;
 
index 4aa89c0f946484eb4c33aa858dde0488ec2e82b9..471e11f25cc387791e21c10446919285712682ed 100644 (file)
@@ -37,6 +37,8 @@
 #ifndef __TBOOT_H__
 #define __TBOOT_H__
 
+#include <xen/acpi.h>
+
 #ifndef __packed
 #define __packed   __attribute__ ((packed))
 #endif
@@ -110,6 +112,7 @@ void tboot_probe(void);
 void tboot_shutdown(uint32_t shutdown_type);
 int tboot_in_measured_env(void);
 int tboot_protect_mem_regions(void);
+int tboot_parse_dmar_table(acpi_table_handler dmar_handler);
 
 #endif /* __TBOOT_H__ */