aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/x86/tboot.c
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2009-01-29 12:44:31 +0000
committerKeir Fraser <keir.fraser@citrix.com>2009-01-29 12:44:31 +0000
commit1d87a30cef5b8c77684795a7ddf075e11f30b932 (patch)
tree10b0738841b91999ea6a79f178f74426ae6e2a27 /xen/arch/x86/tboot.c
parent04c749dc89c217757e5db33f011b761e8c1c52a3 (diff)
downloadxen-1d87a30cef5b8c77684795a7ddf075e11f30b932.tar.gz
xen-1d87a30cef5b8c77684795a7ddf075e11f30b932.tar.bz2
xen-1d87a30cef5b8c77684795a7ddf075e11f30b932.zip
tboot: use TXT's DMA-protected DMAR table to setup VT-d
Signed-off-by: Joseph Cihula <joseph.cihula@intel.com>
Diffstat (limited to 'xen/arch/x86/tboot.c')
-rw-r--r--xen/arch/x86/tboot.c128
1 files changed, 111 insertions, 17 deletions
diff --git a/xen/arch/x86/tboot.c b/xen/arch/x86/tboot.c
index a6646d5d7c..92f509ae95 100644
--- a/xen/arch/x86/tboot.c
+++ b/xen/arch/x86/tboot.c
@@ -18,6 +18,10 @@ tboot_shared_t *g_tboot_shared;
static const uuid_t tboot_shared_uuid = TBOOT_SHARED_UUID;
+/* 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 @@ static const uuid_t tboot_shared_uuid = TBOOT_SHARED_UUID;
extern char __init_begin[], __per_cpu_start[], __per_cpu_end[], __bss_start[];
+#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,33 +176,26 @@ int tboot_in_measured_env(void)
int __init tboot_protect_mem_regions(void)
{
- uint64_t base, size;
- uint32_t map_base, map_size;
- unsigned long map_addr;
int rc;
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 ( txt_heap_base == 0 )
+ return 0;
rc = e820_change_range_type(
- &e820, base, base + size, E820_RESERVED, E820_UNUSABLE);
+ &e820, txt_heap_base, txt_heap_base + txt_heap_size,
+ E820_RESERVED, E820_UNUSABLE);
if ( !rc )
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 ( sinit_base == 0 )
+ return 0;
rc = e820_change_range_type(
- &e820, base, base + size, E820_RESERVED, E820_UNUSABLE);
+ &e820, sinit_base, sinit_base + sinit_size,
+ E820_RESERVED, E820_UNUSABLE);
if ( !rc )
return 0;
@@ -163,11 +207,61 @@ int __init tboot_protect_mem_regions(void)
if ( !rc )
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;
}
/*