Merge commit 'v2.6.31-rc8' into x86/txt
authorIngo Molnar <mingo@elte.hu>
Wed, 2 Sep 2009 06:17:56 +0000 (08:17 +0200)
committerIngo Molnar <mingo@elte.hu>
Wed, 2 Sep 2009 06:17:56 +0000 (08:17 +0200)
Conflicts:
arch/x86/kernel/reboot.c
security/Kconfig

Merge reason: resolve the conflicts, bump up from rc3 to rc8.

Signed-off-by: Ingo Molnar <mingo@elte.hu>
16 files changed:
Documentation/intel_txt.txt [new file with mode: 0644]
Documentation/x86/zero-page.txt
arch/x86/Kconfig
arch/x86/include/asm/bootparam.h
arch/x86/include/asm/fixmap.h
arch/x86/kernel/Makefile
arch/x86/kernel/reboot.c
arch/x86/kernel/setup.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/tboot.c [new file with mode: 0644]
drivers/acpi/acpica/hwsleep.c
drivers/pci/dmar.c
drivers/pci/intel-iommu.c
include/linux/tboot.h [new file with mode: 0644]
kernel/cpu.c
security/Kconfig

diff --git a/Documentation/intel_txt.txt b/Documentation/intel_txt.txt
new file mode 100644 (file)
index 0000000..f40a1f0
--- /dev/null
@@ -0,0 +1,210 @@
+Intel(R) TXT Overview:
+=====================
+
+Intel's technology for safer computing, Intel(R) Trusted Execution
+Technology (Intel(R) TXT), defines platform-level enhancements that
+provide the building blocks for creating trusted platforms.
+
+Intel TXT was formerly known by the code name LaGrande Technology (LT).
+
+Intel TXT in Brief:
+o  Provides dynamic root of trust for measurement (DRTM)
+o  Data protection in case of improper shutdown
+o  Measurement and verification of launched environment
+
+Intel TXT is part of the vPro(TM) brand and is also available some
+non-vPro systems.  It is currently available on desktop systems
+based on the Q35, X38, Q45, and Q43 Express chipsets (e.g. Dell
+Optiplex 755, HP dc7800, etc.) and mobile systems based on the GM45,
+PM45, and GS45 Express chipsets.
+
+For more information, see http://www.intel.com/technology/security/.
+This site also has a link to the Intel TXT MLE Developers Manual,
+which has been updated for the new released platforms.
+
+Intel TXT has been presented at various events over the past few
+years, some of which are:
+      LinuxTAG 2008:
+          http://www.linuxtag.org/2008/en/conf/events/vp-donnerstag/
+          details.html?talkid=110
+      TRUST2008:
+          http://www.trust2008.eu/downloads/Keynote-Speakers/
+          3_David-Grawrock_The-Front-Door-of-Trusted-Computing.pdf
+      IDF 2008, Shanghai:
+          http://inteldeveloperforum.com.edgesuite.net/shanghai_2008/
+          aep/PROS003/index.html
+      IDFs 2006, 2007 (I'm not sure if/where they are online)
+
+Trusted Boot Project Overview:
+=============================
+
+Trusted Boot (tboot) is an open source, pre- kernel/VMM module that
+uses Intel TXT to perform a measured and verified launch of an OS
+kernel/VMM.
+
+It is hosted on SourceForge at http://sourceforge.net/projects/tboot.
+The mercurial source repo is available at http://www.bughost.org/
+repos.hg/tboot.hg.
+
+Tboot currently supports launching Xen (open source VMM/hypervisor
+w/ TXT support since v3.2), and now Linux kernels.
+
+
+Value Proposition for Linux or "Why should you care?"
+=====================================================
+
+While there are many products and technologies that attempt to
+measure or protect the integrity of a running kernel, they all
+assume the kernel is "good" to begin with.  The Integrity
+Measurement Architecture (IMA) and Linux Integrity Module interface
+are examples of such solutions.
+
+To get trust in the initial kernel without using Intel TXT, a
+static root of trust must be used.  This bases trust in BIOS
+starting at system reset and requires measurement of all code
+executed between system reset through the completion of the kernel
+boot as well as data objects used by that code.  In the case of a
+Linux kernel, this means all of BIOS, any option ROMs, the
+bootloader and the boot config.  In practice, this is a lot of
+code/data, much of which is subject to change from boot to boot
+(e.g. changing NICs may change option ROMs).  Without reference
+hashes, these measurement changes are difficult to assess or
+confirm as benign.  This process also does not provide DMA
+protection, memory configuration/alias checks and locks, crash
+protection, or policy support.
+
+By using the hardware-based root of trust that Intel TXT provides,
+many of these issues can be mitigated.  Specifically: many
+pre-launch components can be removed from the trust chain, DMA
+protection is provided to all launched components, a large number
+of platform configuration checks are performed and values locked,
+protection is provided for any data in the event of an improper
+shutdown, and there is support for policy-based execution/verification.
+This provides a more stable measurement and a higher assurance of
+system configuration and initial state than would be otherwise
+possible.  Since the tboot project is open source, source code for
+almost all parts of the trust chain is available (excepting SMM and
+Intel-provided firmware).
+
+How Does it Work?
+=================
+
+o  Tboot is an executable that is launched by the bootloader as
+   the "kernel" (the binary the bootloader executes).
+o  It performs all of the work necessary to determine if the
+   platform supports Intel TXT and, if so, executes the GETSEC[SENTER]
+   processor instruction that initiates the dynamic root of trust.
+   -  If tboot determines that the system does not support Intel TXT
+      or is not configured correctly (e.g. the SINIT AC Module was
+      incorrect), it will directly launch the kernel with no changes
+      to any state.
+   -  Tboot will output various information about its progress to the
+      terminal, serial port, and/or an in-memory log; the output
+      locations can be configured with a command line switch.
+o  The GETSEC[SENTER] instruction will return control to tboot and
+   tboot then verifies certain aspects of the environment (e.g. TPM NV
+   lock, e820 table does not have invalid entries, etc.).
+o  It will wake the APs from the special sleep state the GETSEC[SENTER]
+   instruction had put them in and place them into a wait-for-SIPI
+   state.
+   -  Because the processors will not respond to an INIT or SIPI when
+      in the TXT environment, it is necessary to create a small VT-x
+      guest for the APs.  When they run in this guest, they will
+      simply wait for the INIT-SIPI-SIPI sequence, which will cause
+      VMEXITs, and then disable VT and jump to the SIPI vector.  This
+      approach seemed like a better choice than having to insert
+      special code into the kernel's MP wakeup sequence.
+o  Tboot then applies an (optional) user-defined launch policy to
+   verify the kernel and initrd.
+   -  This policy is rooted in TPM NV and is described in the tboot
+      project.  The tboot project also contains code for tools to
+      create and provision the policy.
+   -  Policies are completely under user control and if not present
+      then any kernel will be launched.
+   -  Policy action is flexible and can include halting on failures
+      or simply logging them and continuing.
+o  Tboot adjusts the e820 table provided by the bootloader to reserve
+   its own location in memory as well as to reserve certain other
+   TXT-related regions.
+o  As part of it's launch, tboot DMA protects all of RAM (using the
+   VT-d PMRs).  Thus, the kernel must be booted with 'intel_iommu=on'
+   in order to remove this blanket protection and use VT-d's
+   page-level protection.
+o  Tboot will populate a shared page with some data about itself and
+   pass this to the Linux kernel as it transfers control.
+   -  The location of the shared page is passed via the boot_params
+      struct as a physical address.
+o  The kernel will look for the tboot shared page address and, if it
+   exists, map it.
+o  As one of the checks/protections provided by TXT, it makes a copy
+   of the VT-d DMARs in a DMA-protected region of memory and verifies
+   them for correctness.  The VT-d code will detect if the kernel was
+   launched with tboot and use this copy instead of the one in the
+   ACPI table.
+o  At this point, tboot and TXT are out of the picture until a
+   shutdown (S<n>)
+o  In order to put a system into any of the sleep states after a TXT
+   launch, TXT must first be exited.  This is to prevent attacks that
+   attempt to crash the system to gain control on reboot and steal
+   data left in memory.
+   -  The kernel will perform all of its sleep preparation and
+      populate the shared page with the ACPI data needed to put the
+      platform in the desired sleep state.
+   -  Then the kernel jumps into tboot via the vector specified in the
+      shared page.
+   -  Tboot will clean up the environment and disable TXT, then use the
+      kernel-provided ACPI information to actually place the platform
+      into the desired sleep state.
+   -  In the case of S3, tboot will also register itself as the resume
+      vector.  This is necessary because it must re-establish the
+      measured environment upon resume.  Once the TXT environment
+      has been restored, it will restore the TPM PCRs and then
+      transfer control back to the kernel's S3 resume vector.
+      In order to preserve system integrity across S3, the kernel
+      provides tboot with a set of memory ranges (kernel
+      code/data/bss, S3 resume code, and AP trampoline) that tboot
+      will calculate a MAC (message authentication code) over and then
+      seal with the TPM.  On resume and once the measured environment
+      has been re-established, tboot will re-calculate the MAC and
+      verify it against the sealed value.  Tboot's policy determines
+      what happens if the verification fails.
+
+That's pretty much it for TXT support.
+
+
+Configuring the System:
+======================
+
+This code works with 32bit, 32bit PAE, and 64bit (x86_64) kernels.
+
+In BIOS, the user must enable:  TPM, TXT, VT-x, VT-d.  Not all BIOSes
+allow these to be individually enabled/disabled and the screens in
+which to find them are BIOS-specific.
+
+grub.conf needs to be modified as follows:
+        title Linux 2.6.29-tip w/ tboot
+          root (hd0,0)
+                kernel /tboot.gz logging=serial,vga,memory
+                module /vmlinuz-2.6.29-tip intel_iommu=on ro
+                       root=LABEL=/ rhgb console=ttyS0,115200 3
+                module /initrd-2.6.29-tip.img
+                module /Q35_SINIT_17.BIN
+
+The kernel option for enabling Intel TXT support is found under the
+Security top-level menu and is called "Enable Intel(R) Trusted
+Execution Technology (TXT)".  It is marked as EXPERIMENTAL and
+depends on the generic x86 support (to allow maximum flexibility in
+kernel build options), since the tboot code will detect whether the
+platform actually supports Intel TXT and thus whether any of the
+kernel code is executed.
+
+The Q35_SINIT_17.BIN file is what Intel TXT refers to as an
+Authenticated Code Module.  It is specific to the chipset in the
+system and can also be found on the Trusted Boot site.  It is an
+(unencrypted) module signed by Intel that is used as part of the
+DRTM process to verify and configure the system.  It is signed
+because it operates at a higher privilege level in the system than
+any other macrocode and its correct operation is critical to the
+establishment of the DRTM.  The process for determining the correct
+SINIT ACM for a system is documented in the SINIT-guide.txt file
+that is on the tboot SourceForge site under the SINIT ACM downloads.
index 4f913857b8a26bae558c5b0f30a6bba0799fcbf9..feb37e177010517f8f1f1d1edee3a96ed77f793f 100644 (file)
@@ -12,6 +12,7 @@ Offset        Proto   Name            Meaning
 000/040        ALL     screen_info     Text mode or frame buffer information
                                (struct screen_info)
 040/014        ALL     apm_bios_info   APM BIOS information (struct apm_bios_info)
+058/008        ALL     tboot_addr      Physical address of tboot shared page
 060/010        ALL     ist_info        Intel SpeedStep (IST) BIOS support information
                                (struct ist_info)
 080/010        ALL     hd0_info        hd0 disk parameter, OBSOLETE!!
index 13ffa5df37d75120e6a3965102b24a05d3ee0fb7..1401d4f0ed4834e055e3c080253bda047aa23b10 100644 (file)
@@ -179,6 +179,10 @@ config ARCH_SUPPORTS_OPTIMIZED_INLINING
 config ARCH_SUPPORTS_DEBUG_PAGEALLOC
        def_bool y
 
+config HAVE_INTEL_TXT
+       def_bool y
+       depends on EXPERIMENTAL && DMAR && ACPI
+
 # Use the generic interrupt handling code in kernel/irq/:
 config GENERIC_HARDIRQS
        bool
index 1724e8de317c59518daebdb305f75b23bb4fcaf6..6ca20218dd7211063c68ddfbede68eb2fba4c777 100644 (file)
@@ -85,7 +85,8 @@ struct efi_info {
 struct boot_params {
        struct screen_info screen_info;                 /* 0x000 */
        struct apm_bios_info apm_bios_info;             /* 0x040 */
-       __u8  _pad2[12];                                /* 0x054 */
+       __u8  _pad2[4];                                 /* 0x054 */
+       __u64  tboot_addr;                              /* 0x058 */
        struct ist_info ist_info;                       /* 0x060 */
        __u8  _pad3[16];                                /* 0x070 */
        __u8  hd0_info[16];     /* obsolete! */         /* 0x080 */
index 7b2d71df39a6ac42fc631628239f4f41c1be243b..14f9890eb495a31a203fa780b3caf16b018d68ef 100644 (file)
@@ -131,6 +131,9 @@ enum fixed_addresses {
 #endif
 #ifdef CONFIG_X86_32
        FIX_WP_TEST,
+#endif
+#ifdef CONFIG_INTEL_TXT
+       FIX_TBOOT_BASE,
 #endif
        __end_of_fixed_addresses
 };
index 430d5b24af7b210faf695f0c3619a1d66ae8acf5..832cb838cb48baa4279303bb87cc7d4cedfde859 100644 (file)
@@ -52,6 +52,7 @@ obj-$(CONFIG_X86_DS_SELFTEST)         += ds_selftest.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/
index a06e8d1018449dd70e4aac4b1098b6b06c4b9bd1..27349f92a6d79078bca5bce37cfcf23f490ab84a 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/pm.h>
 #include <linux/efi.h>
 #include <linux/dmi.h>
+#include <linux/tboot.h>
 #include <acpi/reboot.h>
 #include <asm/io.h>
 #include <asm/apic.h>
@@ -508,6 +509,8 @@ static void native_machine_emergency_restart(void)
        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;
 
@@ -634,6 +637,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);
 }
@@ -645,6 +650,8 @@ static void native_machine_power_off(void)
                        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 = {
index 63f32d220ef22e2d681078ec556698e15ff7645f..61f86f24142068146377c797edc6cf260ea4c217 100644 (file)
@@ -66,6 +66,7 @@
 
 #include <linux/percpu.h>
 #include <linux/crash_dump.h>
+#include <linux/tboot.h>
 
 #include <video/edid.h>
 
@@ -977,6 +978,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
index 2fecda69ee646a78402cc6a1d9e3d86a29ca06d6..7d9d8eea20a0853af561d98b3c1be9a4ba636897 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/bootmem.h>
 #include <linux/err.h>
 #include <linux/nmi.h>
+#include <linux/tboot.h>
 
 #include <asm/acpi.h>
 #include <asm/desc.h>
@@ -1317,6 +1318,7 @@ void play_dead_common(void)
 void native_play_dead(void)
 {
        play_dead_common();
+       tboot_shutdown(TB_SHUTDOWN_WFS);
        wbinvd_halt();
 }
 
diff --git a/arch/x86/kernel/tboot.c b/arch/x86/kernel/tboot.c
new file mode 100644 (file)
index 0000000..86c9f91
--- /dev/null
@@ -0,0 +1,447 @@
+/*
+ * 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/dma_remapping.h>
+#include <linux/init_task.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/dmar.h>
+#include <linux/cpu.h>
+#include <linux/pfn.h>
+#include <linux/mm.h>
+#include <linux/tboot.h>
+
+#include <asm/trampoline.h>
+#include <asm/processor.h>
+#include <asm/bootparam.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/fixmap.h>
+#include <asm/proto.h>
+#include <asm/setup.h>
+#include <asm/e820.h>
+#include <asm/io.h>
+
+#include "acpi/realmode/wakeup.h"
+
+/* Global pointer to shared data; NULL means no measured launch. */
+struct tboot *tboot __read_mostly;
+
+/* timeout for APs (in secs) to enter wait-for-SIPI state during shutdown */
+#define AP_WAIT_TIMEOUT                1
+
+#undef pr_fmt
+#define pr_fmt(fmt)    "tboot: " fmt
+
+static u8 tboot_uuid[16] __initdata = TBOOT_UUID;
+
+void __init tboot_probe(void)
+{
+       /* Look for valid page-aligned address for shared page. */
+       if (!boot_params.tboot_addr)
+               return;
+       /*
+        * also verify that it is mapped as we expect it before calling
+        * set_fixmap(), to reduce chance of garbage value causing crash
+        */
+       if (!e820_any_mapped(boot_params.tboot_addr,
+                            boot_params.tboot_addr, E820_RESERVED)) {
+               pr_warning("non-0 tboot_addr but it is not of type E820_RESERVED\n");
+               return;
+       }
+
+       /* only a natively booted kernel should be using TXT */
+       if (paravirt_enabled()) {
+               pr_warning("non-0 tboot_addr but pv_ops is enabled\n");
+               return;
+       }
+
+       /* Map and check for tboot UUID. */
+       set_fixmap(FIX_TBOOT_BASE, boot_params.tboot_addr);
+       tboot = (struct tboot *)fix_to_virt(FIX_TBOOT_BASE);
+       if (memcmp(&tboot_uuid, &tboot->uuid, sizeof(tboot->uuid))) {
+               pr_warning("tboot at 0x%llx is invalid\n",
+                          boot_params.tboot_addr);
+               tboot = NULL;
+               return;
+       }
+       if (tboot->version < 5) {
+               pr_warning("tboot version is invalid: %u\n", tboot->version);
+               tboot = NULL;
+               return;
+       }
+
+       pr_info("found shared page at phys addr 0x%llx:\n",
+               boot_params.tboot_addr);
+       pr_debug("version: %d\n", tboot->version);
+       pr_debug("log_addr: 0x%08x\n", tboot->log_addr);
+       pr_debug("shutdown_entry: 0x%x\n", tboot->shutdown_entry);
+       pr_debug("tboot_base: 0x%08x\n", tboot->tboot_base);
+       pr_debug("tboot_size: 0x%x\n", tboot->tboot_size);
+}
+
+static pgd_t *tboot_pg_dir;
+static struct mm_struct tboot_mm = {
+       .mm_rb          = RB_ROOT,
+       .pgd            = swapper_pg_dir,
+       .mm_users       = ATOMIC_INIT(2),
+       .mm_count       = ATOMIC_INIT(1),
+       .mmap_sem       = __RWSEM_INITIALIZER(init_mm.mmap_sem),
+       .page_table_lock =  __SPIN_LOCK_UNLOCKED(init_mm.page_table_lock),
+       .mmlist         = LIST_HEAD_INIT(init_mm.mmlist),
+       .cpu_vm_mask    = CPU_MASK_ALL,
+};
+
+static inline void switch_to_tboot_pt(void)
+{
+       write_cr3(virt_to_phys(tboot_pg_dir));
+}
+
+static int map_tboot_page(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_tboot_pages(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_tboot_page(vaddr, start_pfn, PAGE_KERNEL_EXEC))
+                       return -1;
+       }
+
+       return 0;
+}
+
+static void tboot_create_trampoline(void)
+{
+       u32 map_base, map_size;
+
+       /* Create identity map for tboot shutdown code. */
+       map_base = PFN_DOWN(tboot->tboot_base);
+       map_size = PFN_UP(tboot->tboot_size);
+       if (map_tboot_pages(map_base << PAGE_SHIFT, map_base, map_size))
+               panic("tboot: Error mapping tboot pages (mfns) @ 0x%x, 0x%x\n",
+                     map_base, map_size);
+}
+
+#ifdef CONFIG_ACPI_SLEEP
+
+static void add_mac_region(phys_addr_t start, unsigned long size)
+{
+       struct tboot_mac_region *mr;
+       phys_addr_t end = start + size;
+
+       if (start && size) {
+               mr = &tboot->mac_regions[tboot->num_mac_regions++];
+               mr->start = round_down(start, PAGE_SIZE);
+               mr->size  = round_up(end, PAGE_SIZE) - mr->start;
+       }
+}
+
+static int tboot_setup_sleep(void)
+{
+       tboot->num_mac_regions = 0;
+
+       /* S3 resume code */
+       add_mac_region(acpi_wakeup_address, WAKEUP_SIZE);
+
+#ifdef CONFIG_X86_TRAMPOLINE
+       /* AP trampoline code */
+       add_mac_region(virt_to_phys(trampoline_base), TRAMPOLINE_SIZE);
+#endif
+
+       /* kernel code + data + bss */
+       add_mac_region(virt_to_phys(_text), _end - _text);
+
+       tboot->acpi_sinfo.kernel_s3_resume_vector = acpi_wakeup_address;
+
+       return 0;
+}
+
+#else /* no CONFIG_ACPI_SLEEP */
+
+static int tboot_setup_sleep(void)
+{
+       /* S3 shutdown requested, but S3 not supported by the kernel... */
+       BUG();
+       return -1;
+}
+
+#endif
+
+void tboot_shutdown(u32 shutdown_type)
+{
+       void (*shutdown)(void);
+
+       if (!tboot_enabled())
+               return;
+
+       /*
+        * if we're being called before the 1:1 mapping is set up then just
+        * return and let the normal shutdown happen; this should only be
+        * due to very early panic()
+        */
+       if (!tboot_pg_dir)
+               return;
+
+       /* if this is S3 then set regions to MAC */
+       if (shutdown_type == TB_SHUTDOWN_S3)
+               if (tboot_setup_sleep())
+                       return;
+
+       tboot->shutdown_type = shutdown_type;
+
+       switch_to_tboot_pt();
+
+       shutdown = (void(*)(void))(unsigned long)tboot->shutdown_entry;
+       shutdown();
+
+       /* should not reach here */
+       while (1)
+               halt();
+}
+
+static void tboot_copy_fadt(const struct acpi_table_fadt *fadt)
+{
+#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;
+
+       TB_COPY_GAS(tboot->acpi_sinfo.pm1a_cnt_blk, fadt->xpm1a_control_block);
+       TB_COPY_GAS(tboot->acpi_sinfo.pm1b_cnt_blk, fadt->xpm1b_control_block);
+       TB_COPY_GAS(tboot->acpi_sinfo.pm1a_evt_blk, fadt->xpm1a_event_block);
+       TB_COPY_GAS(tboot->acpi_sinfo.pm1b_evt_blk, fadt->xpm1b_event_block);
+
+       /*
+        * 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->acpi_sinfo.wakeup_vector = fadt->facs +
+               offsetof(struct acpi_table_facs, firmware_waking_vector);
+}
+
+void tboot_sleep(u8 sleep_state, u32 pm1a_control, u32 pm1b_control)
+{
+       static u32 acpi_shutdown_map[ACPI_S_STATE_COUNT] = {
+               /* S0,1,2: */ -1, -1, -1,
+               /* S3: */ TB_SHUTDOWN_S3,
+               /* S4: */ TB_SHUTDOWN_S4,
+               /* S5: */ TB_SHUTDOWN_S5 };
+
+       if (!tboot_enabled())
+               return;
+
+       tboot_copy_fadt(&acpi_gbl_FADT);
+       tboot->acpi_sinfo.pm1a_cnt_val = pm1a_control;
+       tboot->acpi_sinfo.pm1b_cnt_val = pm1b_control;
+       /* we always use the 32b wakeup vector */
+       tboot->acpi_sinfo.vector_width = 32;
+
+       if (sleep_state >= ACPI_S_STATE_COUNT ||
+           acpi_shutdown_map[sleep_state] == -1) {
+               pr_warning("unsupported sleep state 0x%x\n", sleep_state);
+               return;
+       }
+
+       tboot_shutdown(acpi_shutdown_map[sleep_state]);
+}
+
+static atomic_t ap_wfs_count;
+
+static int tboot_wait_for_aps(int num_aps)
+{
+       unsigned long timeout;
+
+       timeout = AP_WAIT_TIMEOUT*HZ;
+       while (atomic_read((atomic_t *)&tboot->num_in_wfs) != num_aps &&
+              timeout) {
+               mdelay(1);
+               timeout--;
+       }
+
+       if (timeout)
+               pr_warning("tboot wait for APs timeout\n");
+
+       return !(atomic_read((atomic_t *)&tboot->num_in_wfs) == num_aps);
+}
+
+static int __cpuinit tboot_cpu_callback(struct notifier_block *nfb,
+                       unsigned long action, void *hcpu)
+{
+       switch (action) {
+       case CPU_DYING:
+               atomic_inc(&ap_wfs_count);
+               if (num_online_cpus() == 1)
+                       if (tboot_wait_for_aps(atomic_read(&ap_wfs_count)))
+                               return NOTIFY_BAD;
+               break;
+       }
+       return NOTIFY_OK;
+}
+
+static struct notifier_block tboot_cpu_notifier __cpuinitdata =
+{
+       .notifier_call = tboot_cpu_callback,
+};
+
+static __init int tboot_late_init(void)
+{
+       if (!tboot_enabled())
+               return 0;
+
+       tboot_create_trampoline();
+
+       atomic_set(&ap_wfs_count, 0);
+       register_hotcpu_notifier(&tboot_cpu_notifier);
+       return 0;
+}
+
+late_initcall(tboot_late_init);
+
+/*
+ * 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;
+} __packed;
+
+struct acpi_table_header *tboot_get_dmar_table(struct acpi_table_header *dmar_tbl)
+{
+       void *heap_base, *heap_ptr, *config;
+
+       if (!tboot_enabled())
+               return dmar_tbl;
+
+       /*
+        * 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)
+               return NULL;
+
+       /* now map TXT heap */
+       heap_base = ioremap(*(u64 *)(config + TXTCR_HEAP_BASE),
+                           *(u64 *)(config + TXTCR_HEAP_SIZE));
+       iounmap(config);
+       if (!heap_base)
+               return NULL;
+
+       /* walk heap to SinitMleData */
+       /* skip BiosData */
+       heap_ptr = heap_base + *(u64 *)heap_base;
+       /* skip OsMleData */
+       heap_ptr += *(u64 *)heap_ptr;
+       /* skip OsSinitData */
+       heap_ptr += *(u64 *)heap_ptr;
+       /* now points to SinitMleDataSize; set to SinitMleData */
+       heap_ptr += sizeof(u64);
+       /* get addr of DMAR table */
+       dmar_tbl = (struct acpi_table_header *)(heap_ptr +
+                  ((struct sinit_mle_data *)heap_ptr)->vtd_dmars_off -
+                  sizeof(u64));
+
+       /* don't unmap heap because dmar.c needs access to this */
+
+       return dmar_tbl;
+}
+
+int tboot_force_iommu(void)
+{
+       if (!tboot_enabled())
+               return 0;
+
+       if (no_iommu || swiotlb || dmar_disabled)
+               pr_warning("Forcing Intel-IOMMU to enabled\n");
+
+       dmar_disabled = 0;
+#ifdef CONFIG_SWIOTLB
+       swiotlb = 0;
+#endif
+       no_iommu = 0;
+
+       return 1;
+}
index db307a356f08b02edeb73597cc5893c1d3d45e9e..cc22f9a585b094fba931e775678661ce829ca21e 100644 (file)
@@ -45,6 +45,7 @@
 #include <acpi/acpi.h>
 #include "accommon.h"
 #include "actables.h"
+#include <linux/tboot.h>
 
 #define _COMPONENT          ACPI_HARDWARE
 ACPI_MODULE_NAME("hwsleep")
@@ -342,6 +343,8 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
 
        ACPI_FLUSH_CPU_CACHE();
 
+       tboot_sleep(sleep_state, pm1a_control, pm1b_control);
+
        /* Write #2: Write both SLP_TYP + SLP_EN */
 
        status = acpi_hw_write_pm1_control(pm1a_control, pm1b_control);
index 7b287cb38b7ad76b562d1fd3684b1bca676e4bb7..ab99783dccec9570c7aecd9e8141490a97cadc14 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/timer.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
+#include <linux/tboot.h>
 
 #undef PREFIX
 #define PREFIX "DMAR:"
@@ -413,6 +414,12 @@ 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)
+        */
+       dmar_tbl = tboot_get_dmar_table(dmar_tbl);
+
        dmar = (struct acpi_table_dmar *)dmar_tbl;
        if (!dmar)
                return -ENODEV;
index 2314ad7ee5fef4544ab2159cd7e253ed6e1d3889..562221e119172ffe19655b5ff6b5792098d89e48 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/iommu.h>
 #include <linux/intel-iommu.h>
 #include <linux/sysdev.h>
+#include <linux/tboot.h>
 #include <asm/cacheflush.h>
 #include <asm/iommu.h>
 #include "pci.h"
@@ -3183,12 +3184,22 @@ static int __init init_iommu_sysfs(void)
 int __init intel_iommu_init(void)
 {
        int ret = 0;
+       int force_on = 0;
 
-       if (dmar_table_init())
+       /* VT-d is required for a TXT/tboot launch, so enforce that */
+       force_on = tboot_force_iommu();
+
+       if (dmar_table_init()) {
+               if (force_on)
+                       panic("tboot: Failed to initialize DMAR table\n");
                return  -ENODEV;
+       }
 
-       if (dmar_dev_scope_init())
+       if (dmar_dev_scope_init()) {
+               if (force_on)
+                       panic("tboot: Failed to initialize DMAR device scope\n");
                return  -ENODEV;
+       }
 
        /*
         * Check the need for DMA-remapping initialization now.
@@ -3204,6 +3215,8 @@ int __init intel_iommu_init(void)
 
        ret = init_dmars();
        if (ret) {
+               if (force_on)
+                       panic("tboot: Failed to initialize DMARs\n");
                printk(KERN_ERR "IOMMU: dmar init failed\n");
                put_iova_domain(&reserved_iova_list);
                iommu_exit_mempool();
diff --git a/include/linux/tboot.h b/include/linux/tboot.h
new file mode 100644 (file)
index 0000000..bf2a0c7
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * 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 _LINUX_TBOOT_H
+#define _LINUX_TBOOT_H
+
+/* these must have the values from 0-5 in this order */
+enum {
+       TB_SHUTDOWN_REBOOT = 0,
+       TB_SHUTDOWN_S5,
+       TB_SHUTDOWN_S4,
+       TB_SHUTDOWN_S3,
+       TB_SHUTDOWN_HALT,
+       TB_SHUTDOWN_WFS
+};
+
+#ifdef CONFIG_INTEL_TXT
+#include <acpi/acpi.h>
+/* 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 */
+} __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;
+} __packed;
+
+/*
+ * combines Sx info from FADT and FACS tables per ACPI 2.0+ spec
+ * (http://www.acpi.info/)
+ */
+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;
+} __packed;
+
+/*
+ * shared memory page used for communication between tboot and kernel
+ */
+struct tboot {
+       /*
+        * version 3+ fields:
+        */
+
+       /* TBOOT_UUID */
+       u8 uuid[16];
+
+       /* version number: 5 is current */
+       u32 version;
+
+       /* physical addr of tb_log_t log */
+       u32 log_addr;
+
+       /*
+        * physical addr of entry point for tboot shutdown and
+        * type of shutdown (TB_SHUTDOWN_*) being requested
+        */
+       u32 shutdown_entry;
+       u32 shutdown_type;
+
+       /* kernel-specified ACPI info for Sx shutdown */
+       struct tboot_acpi_sleep_info acpi_sinfo;
+
+       /* tboot location in memory (physical) */
+       u32 tboot_base;
+       u32 tboot_size;
+
+       /* memory regions (phys addrs) for tboot to MAC on S3 */
+       u8 num_mac_regions;
+       struct tboot_mac_region mac_regions[MAX_TB_MAC_REGIONS];
+
+
+       /*
+        * version 4+ fields:
+        */
+
+       /* symmetric key for use by kernel; will be encrypted on S3 */
+       u8 s3_key[TB_KEY_SIZE];
+
+
+       /*
+        * version 5+ fields:
+        */
+
+       /* used to 4byte-align num_in_wfs */
+       u8 reserved_align[3];
+
+       /* number of processors in wait-for-SIPI */
+       u32 num_in_wfs;
+} __packed;
+
+/*
+ * UUID for tboot data struct to facilitate matching
+ * defined as {663C8DFF-E8B3-4b82-AABF-19EA4D057A08} by tboot, which is
+ * represented as {} in the char array used here
+ */
+#define TBOOT_UUID     {0xff, 0x8d, 0x3c, 0x66, 0xb3, 0xe8, 0x82, 0x4b, 0xbf,\
+                        0xaa, 0x19, 0xea, 0x4d, 0x5, 0x7a, 0x8}
+
+extern struct tboot *tboot;
+
+static inline int tboot_enabled(void)
+{
+       return tboot != NULL;
+}
+
+extern void tboot_probe(void);
+extern void tboot_shutdown(u32 shutdown_type);
+extern void tboot_sleep(u8 sleep_state, u32 pm1a_control, u32 pm1b_control);
+extern struct acpi_table_header *tboot_get_dmar_table(
+                                     struct acpi_table_header *dmar_tbl);
+extern int tboot_force_iommu(void);
+
+#else
+
+#define tboot_probe()                  do { } while (0)
+#define tboot_shutdown(shutdown_type)  do { } while (0)
+#define tboot_sleep(sleep_state, pm1a_control, pm1b_control)   \
+                                       do { } while (0)
+#define tboot_get_dmar_table(dmar_tbl) (dmar_tbl)
+#define tboot_force_iommu()            0
+
+#endif /* !CONFIG_INTEL_TXT */
+
+#endif /* _LINUX_TBOOT_H */
index 8ce10043e4aca1d9d48ab9f127e6079c8634f9fd..67a60076dd7e2f7eb81b50970a7f600d0011cc80 100644 (file)
@@ -401,6 +401,7 @@ int disable_nonboot_cpus(void)
                        break;
                }
        }
+
        if (!error) {
                BUG_ON(num_online_cpus() > 1);
                /* Make sure the CPUs won't be enabled by someone else */
index 4c865345caa01700451dd5aa7f8e290a2389690a..fb363cd81cf6db10753c69a3726c31143c3823b2 100644 (file)
@@ -113,6 +113,36 @@ config SECURITY_ROOTPLUG
 
          If you are unsure how to answer this question, answer N.
 
+config INTEL_TXT
+       bool "Enable Intel(R) Trusted Execution Technology (Intel(R) TXT)"
+       depends on HAVE_INTEL_TXT
+       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.
+
+         Intel TXT will provide higher assurance of system configuration and
+         initial state as well as data reset protection.  This is used to
+         create a robust initial kernel measurement and verification, which
+         helps to ensure that kernel security mechanisms are functioning
+         correctly. This level of protection requires a root of trust outside
+         of the kernel itself.
+
+         Intel TXT also helps solve real end user concerns about having
+         confidence that their hardware is running the VMM or kernel that
+         it was configured with, especially since they may be responsible for
+         providing such assurances to VMs and services running on it.
+
+         See <http://www.intel.com/technology/security/> for more information
+         about Intel(R) TXT.
+         See <http://tboot.sourceforge.net> for more information about tboot.
+         See Documentation/intel_txt.txt for a description of how to enable
+         Intel TXT support in a kernel boot.
+
+         If you are unsure as to whether this is required, answer N.
+
 config LSM_MMAP_MIN_ADDR
        int "Low address space for LSM to protect from user allocation"
        depends on SECURITY && SECURITY_SELINUX