From: Joseph Cihula <joseph.cihula@intel.com>
To: linux-kernel@vger.kernel.org
Cc: mingo@elte.hu, arjan@linux.intel.com, chrisw@sous-sol.org,
jmorris@namei.org, jbeulich@novell.com, peterm@redhat.com,
joseph.cihula@intel.com, gang.wei@intel.com,
shane.wang@intel.com
Subject: [RFC v2][PATCH 1/1] intel_txt: Intel(R) TXT and tboot kernel support
Date: Mon, 30 Mar 2009 22:14:19 -0700 [thread overview]
Message-ID: <49D1A6AB.5090808@intel.com> (raw)
Linux support for Intel(R) Trusted Execution Technology.
arch/x86/configs/i386_defconfig | 1
arch/x86/configs/x86_64_defconfig | 1
arch/x86/include/asm/bootparam.h | 1
arch/x86/include/asm/fixmap.h | 3
arch/x86/include/asm/tboot.h | 152 +++++++++++++++
arch/x86/kernel/Makefile | 1
arch/x86/kernel/reboot.c | 18 +
arch/x86/kernel/setup.c | 4
arch/x86/kernel/smpboot.c | 6
arch/x86/kernel/tboot.c | 371 ++++++++++++++++++++++++++++++++++++++
drivers/acpi/acpica/hwsleep.c | 34 +++
drivers/acpi/sleep.c | 3
drivers/pci/dmar.c | 6
kernel/cpu.c | 6
kernel/power/disk.c | 2
security/Kconfig | 17 +
16 files changed, 622 insertions(+), 4 deletions(-)
Signed-off-by: Shane Wang <shane.wang@intel.com>
Signed-off-by: Joseph Cihula <joseph.cihula@intel.com>
Signed-off-by: Gang Wei <gang.wei@intel.com>
---
diff -uprN ../linux.trees.git/arch/x86/configs/i386_defconfig ./arch/x86/configs/i386_defconfig
--- ../linux.trees.git/arch/x86/configs/i386_defconfig 2009-03-29 12:12:13.000000000 -0700
+++ ./arch/x86/configs/i386_defconfig 2009-03-30 13:03:26.000000000 -0700
@@ -51,6 +51,7 @@ CONFIG_X86_BIOS_REBOOT=y
CONFIG_X86_TRAMPOLINE=y
CONFIG_KTIME_SCALAR=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+# CONFIG_INTEL_TXT is not set
#
# General setup
diff -uprN ../linux.trees.git/arch/x86/configs/x86_64_defconfig ./arch/x86/configs/x86_64_defconfig
--- ../linux.trees.git/arch/x86/configs/x86_64_defconfig 2009-03-29 12:12:13.000000000 -0700
+++ ./arch/x86/configs/x86_64_defconfig 2009-03-30 13:03:26.000000000 -0700
@@ -52,6 +52,7 @@ CONFIG_X86_BIOS_REBOOT=y
CONFIG_X86_TRAMPOLINE=y
# CONFIG_KTIME_SCALAR is not set
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+# CONFIG_INTEL_TXT is not set
#
# General setup
diff -uprN ../linux.trees.git/arch/x86/include/asm/bootparam.h ./arch/x86/include/asm/bootparam.h
--- ../linux.trees.git/arch/x86/include/asm/bootparam.h 2009-03-29 12:12:13.000000000 -0700
+++ ./arch/x86/include/asm/bootparam.h 2009-03-30 13:03:25.000000000 -0700
@@ -62,6 +62,7 @@ struct setup_header {
__u32 payload_offset;
__u32 payload_length;
__u64 setup_data;
+ __u32 tboot_shared_addr;
} __attribute__((packed));
struct sys_desc_table {
diff -uprN ../linux.trees.git/arch/x86/include/asm/fixmap.h ./arch/x86/include/asm/fixmap.h
--- ../linux.trees.git/arch/x86/include/asm/fixmap.h 2009-03-29 12:12:13.000000000 -0700
+++ ./arch/x86/include/asm/fixmap.h 2009-03-30 13:03:25.000000000 -0700
@@ -132,6 +132,9 @@ enum fixed_addresses {
#ifdef CONFIG_X86_32
FIX_WP_TEST,
#endif
+#ifdef CONFIG_INTEL_TXT
+ FIX_TBOOT_SHARED_BASE,
+#endif
__end_of_fixed_addresses
};
diff -uprN ../linux.trees.git/arch/x86/include/asm/tboot.h ./arch/x86/include/asm/tboot.h
--- ../linux.trees.git/arch/x86/include/asm/tboot.h 1969-12-31 16:00:00.000000000 -0800
+++ ./arch/x86/include/asm/tboot.h 2009-03-30 13:03:26.000000000 -0700
@@ -0,0 +1,152 @@
+/*
+ * tboot.h: shared data structure with tboot and kernel and functions
+ * used by kernel for runtime support of Intel(R) Trusted
+ * Execution Technology
+ *
+ * Copyright (c) 2006-2009, 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef _ASM_TBOOT_H
+#define _ASM_TBOOT_H
+
+#include <acpi/acpi.h>
+
+#define TB_SHUTDOWN_REBOOT 0
+#define TB_SHUTDOWN_S5 1
+#define TB_SHUTDOWN_S4 2
+#define TB_SHUTDOWN_S3 3
+#define TB_SHUTDOWN_HALT 4
+#define TB_SHUTDOWN_WFS 5
+
+#ifdef CONFIG_INTEL_TXT
+
+struct tboot_uuid {
+ u32 data1;
+ u16 data2;
+ u16 data3;
+ u16 data4;
+ u8 data5[6];
+} __attribute__ ((__packed__));
+
+/* used to communicate between tboot and the launched kernel */
+
+#define TB_KEY_SIZE 64 /* 512 bits */
+
+#define MAX_TB_MAC_REGIONS 32
+struct tboot_mac_region {
+ u64 start; /* must be 64 byte -aligned */
+ u32 size; /* must be 64 byte -granular */
+} __attribute__ ((__packed__));
+
+/* GAS - Generic Address Structure (ACPI 2.0+) */
+struct tboot_acpi_generic_address {
+ u8 space_id;
+ u8 bit_width;
+ u8 bit_offset;
+ u8 access_width;
+ u64 address;
+} __attribute__ ((__packed__));
+
+struct tboot_acpi_sleep_info {
+ struct tboot_acpi_generic_address pm1a_cnt_blk;
+ struct tboot_acpi_generic_address pm1b_cnt_blk;
+ struct tboot_acpi_generic_address pm1a_evt_blk;
+ struct tboot_acpi_generic_address pm1b_evt_blk;
+ u16 pm1a_cnt_val;
+ u16 pm1b_cnt_val;
+ u64 wakeup_vector;
+ u32 vector_width;
+ u64 kernel_s3_resume_vector;
+} __attribute__ ((__packed__));
+
+struct tboot_shared {
+ /* version 3+ fields: */
+ struct tboot_uuid uuid; /* TBOOT_SHARED_UUID */
+ u32 version; /* Version number: 5 is current */
+ u32 log_addr; /* physical addr of tb_log_t log */
+ u32 shutdown_entry; /* entry point for tboot shutdown */
+ u32 shutdown_type; /* type of shutdown (TB_SHUTDOWN_*) */
+ struct tboot_acpi_sleep_info
+ acpi_sinfo; /* where kernel put acpi sleep info in Sx */
+ u32 tboot_base; /* starting addr for tboot */
+ u32 tboot_size; /* size of tboot */
+ u8 num_mac_regions; /* number mem regions to MAC on S3 */
+ /* contig regions memory to MAC on S3 */
+ struct tboot_mac_region mac_regions[MAX_TB_MAC_REGIONS];
+ /* version 4+ fields: */
+ /* populated by tboot; will be encrypted */
+ u8 s3_key[TB_KEY_SIZE];
+ /* version 5+ fields: */
+ u8 reserved_align[3]; /* used to 4byte-align num_in_wfs */
+ u32 num_in_wfs; /* number of processors in wait-for-SIPI */
+} __attribute__ ((__packed__));
+
+/* UUID for tboot_shared data struct to facilitate matching */
+/* {663C8DFF-E8B3-4b82-AABF-19EA4D057A08} */
+#define TBOOT_SHARED_UUID \
+ ((struct tboot_uuid){ 0x663c8dff, 0xe8b3, 0x4b82, 0xaabf, \
+ { 0x19, 0xea, 0x4d, 0x5, 0x7a, 0x8 } })
+
+extern struct tboot_shared *tboot_shared;
+
+static inline int tboot_in_measured_env(void)
+{
+ return tboot_shared != NULL;
+}
+
+extern void tboot_probe(void);
+extern void tboot_shutdown(u32 shutdown_type);
+extern void tboot_sleep(u8 sleep_state);
+extern void tboot_wait_for_aps(int num_aps);
+extern void tboot_sx_resume(u32 state);
+extern struct acpi_table_header *tboot_get_dmar_table(void);
+
+#else /* CONFIG_INTEL_TXT */
+
+static inline int tboot_in_measured_env(void)
+{
+ return 0;
+}
+
+static inline void tboot_probe(void)
+{
+}
+
+static inline void tboot_shutdown(u32 shutdown_type)
+{
+}
+
+static inline void tboot_sleep(u8 sleep_state)
+{
+}
+
+static inline void tboot_wait_for_aps(int num_aps)
+{
+}
+
+static inline void tboot_sx_resume(u32 state)
+{
+}
+
+static inline struct acpi_table_header *tboot_get_dmar_table(void)
+{
+ return NULL;
+}
+
+#endif /* !CONFIG_INTEL_TXT */
+
+#endif /* _ASM_TBOOT_H */
diff -uprN ../linux.trees.git/arch/x86/kernel/Makefile ./arch/x86/kernel/Makefile
--- ../linux.trees.git/arch/x86/kernel/Makefile 2009-03-29 12:12:13.000000000 -0700
+++ ./arch/x86/kernel/Makefile 2009-03-30 13:03:25.000000000 -0700
@@ -47,6 +47,7 @@ obj-$(CONFIG_X86_DS) += ds.o
obj-$(CONFIG_X86_32) += tls.o
obj-$(CONFIG_IA32_EMULATION) += tls.o
obj-y += step.o
+obj-$(CONFIG_INTEL_TXT) += tboot.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-y += cpu/
obj-y += acpi/
diff -uprN ../linux.trees.git/arch/x86/kernel/reboot.c ./arch/x86/kernel/reboot.c
--- ../linux.trees.git/arch/x86/kernel/reboot.c 2009-03-29 12:12:13.000000000 -0700
+++ ./arch/x86/kernel/reboot.c 2009-03-30 13:03:25.000000000 -0700
@@ -24,6 +24,8 @@
# include <asm/iommu.h>
#endif
+#include <asm/tboot.h>
+
/*
* Power off function, if any
*/
@@ -435,6 +437,8 @@ static void native_machine_emergency_res
if (reboot_emergency)
emergency_vmx_disable_all();
+ tboot_shutdown(TB_SHUTDOWN_REBOOT);
+
/* Tell the BIOS if we want cold or warm reboot */
*((unsigned short *)__va(0x472)) = reboot_mode;
@@ -500,11 +504,17 @@ static void native_machine_emergency_res
void native_machine_shutdown(void)
{
- /* Stop the cpus and apics */
#ifdef CONFIG_SMP
-
/* The boot cpu is always logical cpu 0 */
int reboot_cpu_id = 0;
+#endif
+
+ /* TXT requires VMX to be off for all shutdowns */
+ if (tboot_in_measured_env())
+ emergency_vmx_disable_all();
+
+ /* Stop the cpus and apics */
+#ifdef CONFIG_SMP
#ifdef CONFIG_X86_32
/* See if there has been given a command line override */
@@ -561,6 +571,8 @@ static void native_machine_halt(void)
/* stop other cpus and apics */
machine_shutdown();
+ tboot_shutdown(TB_SHUTDOWN_HALT);
+
/* stop this cpu */
stop_this_cpu(NULL);
}
@@ -572,6 +584,8 @@ static void native_machine_power_off(voi
machine_shutdown();
pm_power_off();
}
+ /* a fallback in case there is no PM info available */
+ tboot_shutdown(TB_SHUTDOWN_HALT);
}
struct machine_ops machine_ops = {
diff -uprN ../linux.trees.git/arch/x86/kernel/setup.c ./arch/x86/kernel/setup.c
--- ../linux.trees.git/arch/x86/kernel/setup.c 2009-03-29 12:12:13.000000000 -0700
+++ ./arch/x86/kernel/setup.c 2009-03-30 13:03:25.000000000 -0700
@@ -137,6 +137,8 @@ struct boot_params __initdata boot_param
struct boot_params boot_params;
#endif
+#include <asm/tboot.h>
+
/*
* Machine setup..
*/
@@ -940,6 +942,8 @@ void __init setup_arch(char **cmdline_p)
paravirt_pagetable_setup_done(swapper_pg_dir);
paravirt_post_allocator_init();
+ tboot_probe();
+
#ifdef CONFIG_X86_64
map_vsyscall();
#endif
diff -uprN ../linux.trees.git/arch/x86/kernel/smpboot.c ./arch/x86/kernel/smpboot.c
--- ../linux.trees.git/arch/x86/kernel/smpboot.c 2009-03-29 12:12:13.000000000 -0700
+++ ./arch/x86/kernel/smpboot.c 2009-03-30 13:03:25.000000000 -0700
@@ -62,6 +62,7 @@
#include <asm/vmi.h>
#include <asm/apic.h>
#include <asm/setup.h>
+#include <asm/tboot.h>
#include <asm/uv/uv.h>
#include <linux/mc146818rtc.h>
@@ -1313,7 +1314,10 @@ void play_dead_common(void)
void native_play_dead(void)
{
play_dead_common();
- wbinvd_halt();
+ if (tboot_in_measured_env())
+ tboot_shutdown(TB_SHUTDOWN_WFS);
+ else
+ wbinvd_halt();
}
#else /* ... !CONFIG_HOTPLUG_CPU */
diff -uprN ../linux.trees.git/arch/x86/kernel/tboot.c ./arch/x86/kernel/tboot.c
--- ../linux.trees.git/arch/x86/kernel/tboot.c 1969-12-31 16:00:00.000000000 -0800
+++ ./arch/x86/kernel/tboot.c 2009-03-30 13:03:25.000000000 -0700
@@ -0,0 +1,371 @@
+/*
+ * tboot.c: main implementation of helper functions used by kernel for
+ * runtime support of Intel(R) Trusted Execution Technology
+ *
+ * Copyright (c) 2006-2009, 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/pfn.h>
+#include <linux/mm.h>
+#include <linux/spinlock.h>
+#include <linux/init_task.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/processor.h>
+#include <asm/bootparam.h>
+#include <asm/setup.h>
+#include <asm/io.h>
+#include <asm/tboot.h>
+
+/* Global pointer to shared data; NULL means no measured launch. */
+struct tboot_shared *tboot_shared;
+
+static spinlock_t pgtable_lock;
+
+void __init tboot_probe(void)
+{
+ /* Look for valid page-aligned address for shared page. */
+ if (boot_params.hdr.tboot_shared_addr == 0)
+ return;
+
+ /* Map and check for tboot UUID. */
+ set_fixmap(FIX_TBOOT_SHARED_BASE, boot_params.hdr.tboot_shared_addr);
+ tboot_shared = (struct tboot_shared *)
+ fix_to_virt(FIX_TBOOT_SHARED_BASE);
+ if (memcmp(&TBOOT_SHARED_UUID, &tboot_shared->uuid,
+ sizeof(struct tboot_uuid))) {
+ printk(KERN_WARNING "tboot_shared at 0x%lx is invalid\n",
+ (unsigned long)boot_params.hdr.tboot_shared_addr);
+ tboot_shared = NULL;
+ return;
+ }
+ if (tboot_shared->version < 5) {
+ printk(KERN_WARNING "tboot_shared version is invalid: %u\n",
+ tboot_shared->version);
+ tboot_shared = NULL;
+ return;
+ }
+
+ spin_lock_init(&pgtable_lock);
+
+ printk(KERN_INFO "TBOOT: found shared page at phys addr 0x%lx:\n",
+ (unsigned long)boot_params.hdr.tboot_shared_addr);
+ printk(KERN_DEBUG " version: %d\n", tboot_shared->version);
+ printk(KERN_DEBUG " log_addr: 0x%08x\n", tboot_shared->log_addr);
+ printk(KERN_DEBUG " shutdown_entry: 0x%x\n",
+ tboot_shared->shutdown_entry);
+ printk(KERN_DEBUG " tboot_base: 0x%08x\n", tboot_shared->tboot_base);
+ printk(KERN_DEBUG " tboot_size: 0x%x\n", tboot_shared->tboot_size);
+}
+
+static pgd_t *tboot_pg_dir;
+static u32 map_base, map_size;
+static struct mm_struct tboot_mm = INIT_MM(tboot_mm);
+
+static inline void switch_to_tboot_pt(void)
+{
+ wbinvd();
+ native_write_cr3(virt_to_phys(tboot_pg_dir));
+}
+
+static void clean_up_tboot_mapping(void)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+ unsigned long vaddr, i, j;
+
+ if (!tboot_in_measured_env())
+ return;
+
+ /* The following loop is to release the pages allocated for building
+ * tboot page table. It releases pte pages, then pmd pages, then pud
+ * pages and finally the pgd page by using variable i to control
+ * the process, where
+ * i = 0 denotes to release pte,
+ * i = 1 denotes to release pmd,
+ * i = 2 denotes to release pud,
+ * and i > 2 denotes to release pgd
+ */
+ i = 0;
+ while (tboot_pg_dir) {
+ for (j = 0, vaddr = map_base << PAGE_SHIFT;
+ j < map_size;
+ j++, vaddr += PAGE_SIZE) {
+ if (i > 2) {
+ if (tboot_pg_dir)
+ pgd_free(&tboot_mm, tboot_pg_dir);
+ tboot_pg_dir = 0;
+ break;
+ } else {
+ pgd = pgd_offset(&tboot_mm, vaddr);
+ if ((!pgd) || (!pgd_present(*pgd)))
+ continue;
+ }
+
+ if (i == 2) {
+ /* release pud */
+ pud = pud_offset(pgd, 0);
+ if (pud)
+ pud_free(&tboot_mm, pud);
+ pgd_clear(pgd);
+ continue;
+ } else {
+ pud = pud_offset(pgd, vaddr);
+ if ((!pud) || (!pud_present(*pud)))
+ continue;
+ }
+
+ if (i == 1) {
+ /* release pmd */
+ pmd = pmd_offset(pud, 0);
+ if (pmd)
+ pmd_free(&tboot_mm, pmd);
+ pud_clear(pud);
+ continue;
+ }
+
+ pmd = pmd_offset(pud, vaddr);
+ if ((!pmd) || (!pmd_present(*pmd)))
+ continue;
+
+ /* release pte */
+ pte = pte_offset_kernel(pmd, 0);
+ if (pte)
+ pte_free_kernel(&tboot_mm, pte);
+ pmd_clear(pmd);
+ }
+ i++;
+ }
+}
+
+static int map_page_for_tboot(unsigned long vaddr, unsigned long pfn,
+ pgprot_t prot)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+
+ pgd = pgd_offset(&tboot_mm, vaddr);
+ pud = pud_alloc(&tboot_mm, pgd, vaddr);
+ if (!pud)
+ return -1;
+ pmd = pmd_alloc(&tboot_mm, pud, vaddr);
+ if (!pmd)
+ return -1;
+ pte = pte_alloc_map(&tboot_mm, pmd, vaddr);
+ if (!pte)
+ return -1;
+ set_pte_at(&tboot_mm, vaddr, pte, pfn_pte(pfn, prot));
+ pte_unmap(pte);
+ return 0;
+}
+
+static int map_pages_for_tboot(unsigned long vaddr, unsigned long start_pfn,
+ unsigned long nr)
+{
+ /* Reuse the original kernel mapping */
+ tboot_pg_dir = pgd_alloc(&tboot_mm);
+ if (!tboot_pg_dir)
+ return -1;
+
+ for (; nr > 0; nr--, vaddr += PAGE_SIZE, start_pfn++) {
+ if (map_page_for_tboot(vaddr, start_pfn, PAGE_KERNEL_EXEC))
+ return -1;
+ }
+
+ return 0;
+}
+
+#include "acpi/realmode/wakeup.h"
+#include <asm/trampoline.h>
+
+void tboot_shutdown(u32 shutdown_type)
+{
+ if (!tboot_in_measured_env())
+ return;
+
+ /* only create the table once */
+ spin_lock(&pgtable_lock);
+ if (!tboot_pg_dir) {
+ /* page alloc routines need interrupts enabled else they */
+ /* generate debug warnings; we'll disable them afterwards */
+ local_irq_enable();
+
+ /* Create identity map for tboot shutdown code. */
+ map_base = PFN_DOWN(tboot_shared->tboot_base);
+ map_size = PFN_UP(tboot_shared->tboot_size);
+ if (map_pages_for_tboot(map_base << PAGE_SHIFT, map_base,
+ map_size)) {
+ printk(KERN_WARNING "error mapping tboot pages (mfns)"
+ " @ 0x%x, 0x%x\n", map_base, map_size);
+ clean_up_tboot_mapping();
+ BUG();
+ }
+ }
+ spin_unlock(&pgtable_lock);
+
+ local_irq_disable();
+
+ /* if this is S3 then set regions to MAC */
+ if (shutdown_type == TB_SHUTDOWN_S3) {
+ tboot_shared->num_mac_regions = 3;
+ /* S3 resume code */
+ tboot_shared->mac_regions[0].start =
+ PFN_PHYS(PFN_DOWN(acpi_wakeup_address));
+ tboot_shared->mac_regions[0].size =
+ PFN_UP(WAKEUP_SIZE) << PAGE_SHIFT;
+ /* AP trampoline code */
+ tboot_shared->mac_regions[1].start =
+ PFN_PHYS(PFN_DOWN(virt_to_phys(trampoline_base)));
+ tboot_shared->mac_regions[1].size =
+ PFN_UP(TRAMPOLINE_SIZE) << PAGE_SHIFT;
+ /* kernel code + data + bss */
+ tboot_shared->mac_regions[2].start =
+ PFN_PHYS(PFN_DOWN(virt_to_phys(&_text)));
+ tboot_shared->mac_regions[2].size =
+ PFN_PHYS(PFN_UP(virt_to_phys(&_end))) -
+ PFN_PHYS(PFN_DOWN(virt_to_phys(&_text)));
+ }
+
+ tboot_shared->shutdown_type = shutdown_type;
+
+ switch_to_tboot_pt();
+
+ ((void(*)(void))(unsigned long)tboot_shared->shutdown_entry)();
+
+ BUG(); /* should not reach here */
+}
+
+void tboot_sleep(u8 sleep_state)
+{
+ uint32_t shutdown_type;
+
+ switch (sleep_state) {
+ case ACPI_STATE_S3:
+ shutdown_type = TB_SHUTDOWN_S3;
+ break;
+ case ACPI_STATE_S4:
+ shutdown_type = TB_SHUTDOWN_S4;
+ break;
+ case ACPI_STATE_S5:
+ shutdown_type = TB_SHUTDOWN_S5;
+ break;
+ default:
+ return;
+ }
+
+ tboot_shutdown(shutdown_type);
+}
+
+void tboot_wait_for_aps(int num_aps)
+{
+ if (!tboot_in_measured_env())
+ return;
+
+ while (atomic_read((atomic_t *)&tboot_shared->num_in_wfs) != num_aps)
+ cpu_relax();
+}
+
+/*
+ * TXT configuration registers (offsets from TXT_{PUB, PRIV}_CONFIG_REGS_BASE)
+ */
+
+#define TXT_PUB_CONFIG_REGS_BASE 0xfed30000
+#define TXT_PRIV_CONFIG_REGS_BASE 0xfed20000
+
+/* # pages for each config regs space - used by fixmap */
+#define NR_TXT_CONFIG_PAGES ((TXT_PUB_CONFIG_REGS_BASE - \
+ TXT_PRIV_CONFIG_REGS_BASE) >> PAGE_SHIFT)
+
+/* offsets from pub/priv config space */
+#define TXTCR_HEAP_BASE 0x0300
+#define TXTCR_HEAP_SIZE 0x0308
+
+#define SHA1_SIZE 20
+struct sha1_hash {
+ u8 hash[SHA1_SIZE];
+};
+
+struct sinit_mle_data {
+ u32 version; /* currently 6 */
+ struct sha1_hash bios_acm_id;
+ u32 edx_senter_flags;
+ u64 mseg_valid;
+ struct sha1_hash sinit_hash;
+ struct sha1_hash mle_hash;
+ struct sha1_hash stm_hash;
+ struct sha1_hash lcp_policy_hash;
+ u32 lcp_policy_control;
+ u32 rlp_wakeup_addr;
+ u32 reserved;
+ u32 num_mdrs;
+ u32 mdrs_off;
+ u32 num_vtd_dmars;
+ u32 vtd_dmars_off;
+} __attribute__ ((__packed__));
+
+struct acpi_table_header *tboot_get_dmar_table(void)
+{
+ void *heap_base, *heap_ptr, *config;
+ struct acpi_table_header *dmar_table;
+
+ /* ACPI tables may not be DMA protected by tboot, so use DMAR copy */
+ /* SINIT saved in SinitMleData in TXT heap (which is DMA protected) */
+
+ /* map config space in order to get heap addr */
+ config = ioremap(TXT_PUB_CONFIG_REGS_BASE, NR_TXT_CONFIG_PAGES *
+ PAGE_SIZE);
+ if (config == NULL)
+ return NULL;
+
+ /* now map TXT heap */
+ heap_base = ioremap(*(u64 *)(config + TXTCR_HEAP_BASE),
+ *(u64 *)(config + TXTCR_HEAP_SIZE));
+ iounmap(config);
+ if (heap_base == NULL)
+ return NULL;
+
+ /* walk heap to SinitMleData */
+ /* skip BiosData */
+ heap_ptr = heap_base + *(uint64_t *)heap_base;
+ /* 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 +
+ ((struct sinit_mle_data *)heap_ptr)->vtd_dmars_off -
+ sizeof(uint64_t));
+
+ /* don't unmap heap because dmar.c needs access to this */
+
+ return dmar_table;
+}
+
+void tboot_sx_resume(u32 state)
+{
+ /* Clean up memory mapping for tboot range */
+ if (tboot_in_measured_env())
+ clean_up_tboot_mapping();
+}
diff -uprN ../linux.trees.git/drivers/acpi/acpica/hwsleep.c ./drivers/acpi/acpica/hwsleep.c
--- ../linux.trees.git/drivers/acpi/acpica/hwsleep.c 2009-03-29 12:12:13.000000000 -0700
+++ ./drivers/acpi/acpica/hwsleep.c 2009-03-30 13:02:55.000000000 -0700
@@ -45,6 +45,7 @@
#include <acpi/acpi.h>
#include "accommon.h"
#include "actables.h"
+#include <asm/tboot.h>
#define _COMPONENT ACPI_HARDWARE
ACPI_MODULE_NAME("hwsleep")
@@ -333,6 +334,39 @@ acpi_status asmlinkage acpi_enter_sleep_
PM1Acontrol |= sleep_enable_reg_info->access_bit_mask;
PM1Bcontrol |= sleep_enable_reg_info->access_bit_mask;
+#ifdef CONFIG_INTEL_TXT
+#define TB_COPY_GAS(tbg, g) \
+ tbg.space_id = g.space_id; \
+ tbg.bit_width = g.bit_width; \
+ tbg.bit_offset = g.bit_offset; \
+ tbg.access_width = g.access_width; \
+ tbg.address = g.address;
+
+ if (tboot_in_measured_env()) {
+ TB_COPY_GAS(tboot_shared->acpi_sinfo.pm1a_cnt_blk,
+ acpi_gbl_FADT.xpm1a_control_block);
+ TB_COPY_GAS(tboot_shared->acpi_sinfo.pm1b_cnt_blk,
+ acpi_gbl_FADT.xpm1b_control_block);
+ TB_COPY_GAS(tboot_shared->acpi_sinfo.pm1a_evt_blk,
+ acpi_gbl_FADT.xpm1a_event_block);
+ TB_COPY_GAS(tboot_shared->acpi_sinfo.pm1b_evt_blk,
+ acpi_gbl_FADT.xpm1b_event_block);
+ tboot_shared->acpi_sinfo.pm1a_cnt_val = PM1Acontrol;
+ tboot_shared->acpi_sinfo.pm1b_cnt_val = PM1Bcontrol;
+ /* we need phys addr of waking vector, but can't use
+ virt_to_phys() on &acpi_gbl_FACS because it is ioremap'ed,
+ so calc from FACS phys addr */
+ tboot_shared->acpi_sinfo.wakeup_vector = acpi_gbl_FADT.facs +
+ ((void *)&acpi_gbl_FACS->firmware_waking_vector -
+ (void *)acpi_gbl_FACS);
+ tboot_shared->acpi_sinfo.vector_width = 32;
+ tboot_shared->acpi_sinfo.kernel_s3_resume_vector =
+ acpi_wakeup_address;
+
+ tboot_sleep(sleep_state);
+ }
+#endif
+
/* Write #2: SLP_TYP + SLP_EN */
ACPI_FLUSH_CPU_CACHE();
diff -uprN ../linux.trees.git/drivers/acpi/sleep.c ./drivers/acpi/sleep.c
--- ../linux.trees.git/drivers/acpi/sleep.c 2009-03-29 12:12:13.000000000 -0700
+++ ./drivers/acpi/sleep.c 2009-03-30 13:02:56.000000000 -0700
@@ -22,6 +22,7 @@
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include "sleep.h"
+#include <asm/tboot.h>
u8 sleep_states[ACPI_S_STATE_COUNT];
static u32 acpi_target_sleep_state = ACPI_STATE_S0;
@@ -246,6 +247,8 @@ static int acpi_suspend_enter(suspend_st
break;
}
+ tboot_sx_resume(acpi_state);
+
/* If ACPI is not enabled by the BIOS, we need to enable it here. */
if (set_sci_en_on_resume)
acpi_set_register(ACPI_BITREG_SCI_ENABLE, 1);
diff -uprN ../linux.trees.git/drivers/pci/dmar.c ./drivers/pci/dmar.c
--- ../linux.trees.git/drivers/pci/dmar.c 2009-03-29 12:12:15.000000000 -0700
+++ ./drivers/pci/dmar.c 2009-03-30 13:11:08.000000000 -0700
@@ -33,6 +33,7 @@
#include <linux/timer.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
+#include <asm/tboot.h>
#undef PREFIX
#define PREFIX "DMAR:"
@@ -319,6 +320,11 @@ parse_dmar_table(void)
*/
dmar_table_detect();
+ /* 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 (tboot_in_measured_env())
+ dmar_tbl = tboot_get_dmar_table();
+
dmar = (struct acpi_table_dmar *)dmar_tbl;
if (!dmar)
return -ENODEV;
diff -uprN ../linux.trees.git/kernel/cpu.c ./kernel/cpu.c
--- ../linux.trees.git/kernel/cpu.c 2009-03-29 12:12:19.000000000 -0700
+++ ./kernel/cpu.c 2009-03-30 13:03:07.000000000 -0700
@@ -14,6 +14,7 @@
#include <linux/kthread.h>
#include <linux/stop_machine.h>
#include <linux/mutex.h>
+#include <asm/tboot.h>
#ifdef CONFIG_SMP
/* Serializes the updates to cpu_online_mask, cpu_present_mask */
@@ -379,7 +380,7 @@ static cpumask_var_t frozen_cpus;
int disable_nonboot_cpus(void)
{
- int cpu, first_cpu, error;
+ int cpu, first_cpu, error, num_cpus = 0;
error = stop_machine_create();
if (error)
@@ -394,6 +395,7 @@ int disable_nonboot_cpus(void)
for_each_online_cpu(cpu) {
if (cpu == first_cpu)
continue;
+ num_cpus++;
error = _cpu_down(cpu, 1);
if (!error) {
cpumask_set_cpu(cpu, frozen_cpus);
@@ -404,6 +406,8 @@ int disable_nonboot_cpus(void)
break;
}
}
+ /* ensure all CPUs have gone into wait-for-SIPI */
+ tboot_wait_for_aps(num_cpus);
if (!error) {
BUG_ON(num_online_cpus() > 1);
/* Make sure the CPUs won't be enabled by someone else */
diff -uprN ../linux.trees.git/kernel/power/disk.c ./kernel/power/disk.c
--- ../linux.trees.git/kernel/power/disk.c 2009-03-29 12:12:19.000000000 -0700
+++ ./kernel/power/disk.c 2009-03-30 13:03:07.000000000 -0700
@@ -22,6 +22,7 @@
#include <linux/console.h>
#include <linux/cpu.h>
#include <linux/freezer.h>
+#include <asm/tboot.h>
#include "power.h"
@@ -308,6 +309,7 @@ int hibernation_snapshot(int platform_mo
}
Enable_cpus:
enable_nonboot_cpus();
+ tboot_sx_resume(ACPI_STATE_S4);
Finish:
platform_finish(platform_mode);
Resume_devices:
diff -uprN ../linux.trees.git/security/Kconfig ./security/Kconfig
--- ../linux.trees.git/security/Kconfig 2009-03-29 12:12:20.000000000 -0700
+++ ./security/Kconfig 2009-03-30 13:03:07.000000000 -0700
@@ -132,6 +132,23 @@ config SECURITY_DEFAULT_MMAP_MIN_ADDR
/proc/sys/vm/mmap_min_addr tunable.
+config INTEL_TXT
+ bool "Enable Intel(R) Trusted Execution Technology (Intel(R) TXT)"
+ depends on EXPERIMENTAL && X86
+ help
+ This option enables support for booting the kernel with
+ the Trusted Boot (tboot) module. This will utilize
+ Intel(R) Trusted Execution Technology to perform a
+ measured launch of the kernel. If the system does not
+ support Intel(R) TXT, this will have no effect.
+
+ See <http://www.intel.com/technology/security/> for more
+ information about Intel(R) TXT.
+ And see <http://tboot.sourceforge.net> for more information
+ about tboot.
+
+ If you are unsure as to whether this is required, answer N.
+
source security/selinux/Kconfig
source security/smack/Kconfig
next reply other threads:[~2009-03-31 5:15 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-03-31 5:14 Joseph Cihula [this message]
2009-04-18 10:02 ` [RFC v2][PATCH 1/1] intel_txt: Intel(R) TXT and tboot kernel support Andi Kleen
2009-04-18 20:29 ` [RFC v2][PATCH 1/1] intel_txt: Intel(R) TXT and tboot kernel support II Andi Kleen
2009-04-22 20:31 ` [RFC v2][PATCH 1/1] intel_txt: Intel(R) TXT and tboot kernel support Jeremy Fitzhardinge
2009-04-22 20:40 ` Andi Kleen
2009-04-22 20:47 ` Cihula, Joseph
2009-04-24 21:57 ` Cihula, Joseph
2009-04-25 15:56 ` Andi Kleen
2009-04-28 16:50 ` Cihula, Joseph
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=49D1A6AB.5090808@intel.com \
--to=joseph.cihula@intel.com \
--cc=arjan@linux.intel.com \
--cc=chrisw@sous-sol.org \
--cc=gang.wei@intel.com \
--cc=jbeulich@novell.com \
--cc=jmorris@namei.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@elte.hu \
--cc=peterm@redhat.com \
--cc=shane.wang@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.