Angel Pons has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/46608 )
Change subject: haswell: Add Intel TXT support in romstage ......................................................................
haswell: Add Intel TXT support in romstage
Provide necessary romstage hooks to allow unblocking the memory with SCLEAN. Note that this is slow, and took four minutes with 4 GiB of RAM.
Tested on Asrock B85M Pro4 with tboot. When Linux has tboot support compiled in, booting as well as S3 suspend and resume are functional. However, SINIT will TXT reset when the iGPU is enabled, and using a dGPU will result in DMAR-related problems as soon as the IOMMU is enabled.
Change-Id: I60beb7d79a30f460bbd5d94e4cba0244318c124e Signed-off-by: Angel Pons th3fanbus@gmail.com --- M src/northbridge/intel/haswell/romstage.c M src/security/intel/txt/Makefile.inc M src/security/intel/txt/common.c A src/security/intel/txt/romstage.c M src/security/intel/txt/txt.h M src/security/intel/txt/txt_register.h 6 files changed, 200 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/08/46608/1
diff --git a/src/northbridge/intel/haswell/romstage.c b/src/northbridge/intel/haswell/romstage.c index 5b025eb..3227c02 100644 --- a/src/northbridge/intel/haswell/romstage.c +++ b/src/northbridge/intel/haswell/romstage.c @@ -4,11 +4,14 @@ #include <console/console.h> #include <cf9_reset.h> #include <device/device.h> +#include <device/mmio.h> #include <timestamp.h> #include <cpu/x86/lapic.h> #include <cbmem.h> #include <commonlib/helpers.h> #include <romstage_handoff.h> +#include <security/intel/txt/txt.h> +#include <security/intel/txt/txt_register.h> #include <cpu/intel/haswell/haswell.h> #include <northbridge/intel/haswell/chip.h> #include <northbridge/intel/haswell/haswell.h> @@ -108,12 +111,27 @@
report_platform_info();
+ if (CONFIG(INTEL_TXT)) + intel_txt_romstage_init(); + copy_spd(&pei_data);
sdram_initialize(&pei_data);
timestamp_add_now(TS_AFTER_INITRAM);
+ if (CONFIG(INTEL_TXT)) { + printk(BIOS_DEBUG, "Check TXT_ERROR register after MRC\n"); + + intel_txt_log_acm_error(read32((void *)TXT_ERROR)); + + intel_txt_log_spad(); + + intel_txt_memory_has_secrets(); + + txt_dump_regions(); + } + post_code(0x3b);
intel_early_me_status(); diff --git a/src/security/intel/txt/Makefile.inc b/src/security/intel/txt/Makefile.inc index 64726cd..f7d6f9c 100644 --- a/src/security/intel/txt/Makefile.inc +++ b/src/security/intel/txt/Makefile.inc @@ -1,6 +1,8 @@ ifeq ($(CONFIG_INTEL_TXT),y)
+romstage-y += romstage.c romstage-y += getsec_sclean.S +romstage-y += getsec.c
romstage-y += common.c romstage-$(CONFIG_INTEL_TXT_LOGGING) += logging.c diff --git a/src/security/intel/txt/common.c b/src/security/intel/txt/common.c index 88e2b5d..4dd4ad3 100644 --- a/src/security/intel/txt/common.c +++ b/src/security/intel/txt/common.c @@ -290,6 +290,48 @@ return acm_data; }
+#define MCU_BASE_ADDR (TXT_BASE + 0x278) +#define BIOACM_ADDR (TXT_BASE + 0x27c) +#define APINIT_ADDR (TXT_BASE + 0x290) +#define SEMAPHORE (TXT_BASE + 0x294) + +/* Returns on failure, resets the computer on success */ +void intel_txt_run_sclean(void) +{ + struct region_device acm; + size_t acm_len; + + void *acm_data = intel_txt_prepare_bios_acm(&acm, &acm_len); + + if (!acm_data) + return; + + /* FIXME: Do we need to program these two? */ + //write32((void *)MCU_BASE_ADDR, 0xffe1a990); + //write32((void *)APINIT_ADDR, 0xfffffff0); + + write32((void *)BIOACM_ADDR, (uintptr_t)acm_data); + write32((void *)SEMAPHORE, 0); + + /* + * The time SCLEAN will take depends on the installed RAM size. + * On Haswell with 8 GiB of DDR3, it takes five or ten minutes. (rough estimate) + */ + printk(BIOS_ALERT, "TEE-TXT: Invoking SCLEAN. This can take several minutes.\n"); + + /* + * Invoke the BIOS ACM. If successful, the system will reset with memory unlocked. + */ + getsec_sclean((uintptr_t)acm_data, acm_len); + + /* + * However, if this function returns, the BIOS ACM could not be invoked. This is bad. + */ + printk(BIOS_CRIT, "TEE-TXT: getsec_sclean could not launch the BIOS ACM.\n"); + + rdev_munmap(&acm, acm_data); +} + /* * Test all bits for TXT execution. * diff --git a/src/security/intel/txt/romstage.c b/src/security/intel/txt/romstage.c new file mode 100644 index 0000000..7a12deb --- /dev/null +++ b/src/security/intel/txt/romstage.c @@ -0,0 +1,125 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <arch/mmio.h> +#include <cf9_reset.h> +#include <console/console.h> +#include <cpu/intel/common/common.h> +#include <cpu/x86/msr.h> +#include <southbridge/intel/common/pmbase.h> +#include <timer.h> +#include <types.h> + +#include <security/tpm/tis.h> + +#include "txt.h" +#include "txt_register.h" +#include "txt_getsec.h" + +static bool is_establishment_bit_asserted(void) +{ + struct stopwatch timer; + uint8_t access; + + /* Spec says no less than 30 milliseconds */ + stopwatch_init_msecs_expire(&timer, 50); + + while (true) { + access = read8((void *)TPM_ACCESS_REG); + + /* Register returns all ones if TPM is missing */ + if (access == 0xff) + return false; + + if (access & TPM_ACCESS_VALID) + break; + + /* On timeout, assume that the TPM is not working */ + if (stopwatch_expired(&timer)) + return false; + } + + /* This bit uses inverted logic: if cleared, establishment is asserted */ + return !(access & TPM_ACCESS_ESTABLISHMENT); +} + +static bool is_txt_cpu(void) +{ + const uint32_t ecx = cpu_get_feature_flags_ecx(); + + return (ecx & (CPUID_SMX | CPUID_VMX)) == (CPUID_SMX | CPUID_VMX); +} + +static bool is_txt_chipset(void) +{ + uint32_t eax; + + const bool success = getsec_capabilities(&eax); + + return success && eax & 1; +} + +/* Print the bad news */ +static void print_memory_is_locked(void) +{ + if (!CONFIG(INTEL_TXT_LOGGING)) + return; + + printk(BIOS_EMERG, "FATAL: Cannot run SCLEAN. Memory will remain locked.\n"); + printk(BIOS_EMERG, "\n"); + printk(BIOS_EMERG, "If you still want to boot, your options are:\n"); + printk(BIOS_EMERG, "\n"); + printk(BIOS_EMERG, " 1. Flash a coreboot image with a valid BIOS ACM.\n"); + printk(BIOS_EMERG, " Then, try again and hope it works this time.\n"); + printk(BIOS_EMERG, "\n"); + printk(BIOS_EMERG, " 2. If possible, remove the TPM from the system.\n"); + printk(BIOS_EMERG, " Reinstalling the TPM might lock memory again.\n"); + printk(BIOS_EMERG, "\n"); + printk(BIOS_EMERG, " 3. Disconnect all power sources, and RTC battery.\n"); + printk(BIOS_EMERG, " This may not work on all TXT-enabled platforms.\n"); + printk(BIOS_EMERG, "\n"); +} + +void intel_txt_romstage_init(void) +{ + /* Bail early if the CPU doesn't support TXT */ + if (!is_txt_cpu()) + return; + + /* We need to use GETSEC here, so enable it */ + enable_getsec_or_reset(); + + if (!is_txt_chipset()) + return; + + const uint8_t txt_ests = read8((void *)TXT_ESTS); + + const bool establishment = is_establishment_bit_asserted(); + const bool is_wake_error = !!(txt_ests & TXT_ESTS_WAKE_ERROR_STS); + + if (CONFIG(INTEL_TXT_LOGGING)) { + + printk(BIOS_INFO, "TEE-TXT: TPM established: %s\n", + establishment ? "true" : "false"); + } + + if (establishment && is_wake_error) { + + printk(BIOS_ERR, "TEE-TXT: Secrets remain in memory. SCLEAN is required.\n"); + + if (txt_ests & TXT_ESTS_TXT_RESET_STS) { + printk(BIOS_ERR, "TEE-TXT: TXT_RESET bit set, doing full reset!\n"); + full_reset(); + } + + /* FIXME: Clear SLP_TYP# */ + write_pmbase32(4, read_pmbase32(4) & ~(0x7 << 10)); + + intel_txt_run_sclean(); + + /* If running the BIOS ACM is impossible, manual intervention is required */ + print_memory_is_locked(); + + /* FIXME: vboot A/B could be used to recover, but has not been tested */ + die("Could not execute BIOS ACM to unlock the memory.\n"); + } +} diff --git a/src/security/intel/txt/txt.h b/src/security/intel/txt/txt.h index fc5c49e..976cc74 100644 --- a/src/security/intel/txt/txt.h +++ b/src/security/intel/txt/txt.h @@ -17,10 +17,13 @@ #define ACM_E_UUID_NOT_MATCH 0x09 #define ACM_E_PLATFORM_IS_NOT_PROD 0x10
+void intel_txt_romstage_init(void); + void intel_txt_log_bios_acm_error(void); int intel_txt_log_acm_error(const uint32_t acm_error); void intel_txt_log_spad(void); bool intel_txt_memory_has_secrets(void); +void intel_txt_run_sclean(void); int intel_txt_run_bios_acm(const u8 input_params); bool intel_txt_prepare_txt_env(void);
diff --git a/src/security/intel/txt/txt_register.h b/src/security/intel/txt/txt_register.h index c19ec13..bb735b6 100644 --- a/src/security/intel/txt/txt_register.h +++ b/src/security/intel/txt/txt_register.h @@ -99,6 +99,16 @@ #define TXT_E2STS_SECRET_STS (1ull << 1)
/* + * TCG PC Client Platform TPM Profile (PTP) Specification + * + * Note: Only locality 0 registers are publicly accessible. + */ + +#define TPM_BASE 0xfed40000UL + +#define TPM_ACCESS_REG (TPM_BASE + 0x00) + +/* * TXT Memory regions * Chapter 5.3 * Intel Trusted Execution Technology Lab Handout
Arthur Heymans has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46608 )
Change subject: haswell: Add Intel TXT support in romstage ......................................................................
Patch Set 4: Code-Review+2
Michał Żygowski has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46608 )
Change subject: haswell: Add Intel TXT support in romstage ......................................................................
Patch Set 5:
(1 comment)
https://review.coreboot.org/c/coreboot/+/46608/5/src/security/intel/txt/comm... File src/security/intel/txt/common.c:
https://review.coreboot.org/c/coreboot/+/46608/5/src/security/intel/txt/comm... PS5, Line 310: //write32((void *)MCU_BASE_ADDR, 0xffe1a990); I know where these come from. They were used to setup APs for ACM launch. Do we setup APs somewhere?
Michał Żygowski has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46608 )
Change subject: haswell: Add Intel TXT support in romstage ......................................................................
Patch Set 5:
I was working on it for ivybridge, but unline haswell and later platforms it requires manual APs setup before calling GETSEC. There is much assembly code to configure MTRRs, clean MCEs and rendezvous the APs right before the GETSEC call. Based on all the TXT patches I saw on gerrit, we do not do it for APs anywhere. If I am not mistaken it is related to the FIT table and loading ACM before reset vector?
Angel Pons has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46608 )
Change subject: haswell: Add Intel TXT support in romstage ......................................................................
Patch Set 5:
(1 comment)
Patch Set 5:
I was working on it for ivybridge, but unline haswell and later platforms it requires manual APs setup before calling GETSEC. There is much assembly code to configure MTRRs, clean MCEs and rendezvous the APs right before the GETSEC call. Based on all the TXT patches I saw on gerrit, we do not do it for APs anywhere. If I am not mistaken it is related to the FIT table and loading ACM before reset vector?
Thank you for the insight. The TXT code was originally tested on Broadwell-DE, and LT-SX platforms handle wiping of secrets differently. Since testing on remote Broadwell-DE boxes is cumbersome at best, I decided to make TXT work on the Asrock B85M Pro4, a Haswell board I own.
Support for Haswell required some adjustments to account for differences between LT-SX and LT-CX. The biggest one is SCLEAN, since it's the only way to recover from TXT-blocked memory (without manual intervention). Looks like the memory block simply prevents the MPLL (Memory PLL) from ever powering up, which is simple but effective. To run SCLEAN in romstage, I had to adapt the ACM calling code to tear down CAR, among other stuff. I also figured out the original implementation would fail when ACM sizes were not a power of two, which I CB:44880 addressed. After trying to read reference assembly code, I decided to write a new implementation from scratch, which turned out to be much simpler and easy to read, IMHO.
I also saw that there's something about AP init in the SCLEAN launch assembly code, but wasn't sure if it was required for Haswell and decided to not implement it at that time. I was worried because I somehow had successfully locked myself out without being able to run the ACM, and wanted to recover as soon as possible. After figuring out I had a too old ACM without TPM2 support, I got it to run and eventually made everything work (including S3 suspend/resume!), except that SCLEAN automatic reset sometimes fails. I imagine the missing AP init and microcode update loading could be to blame, so I guess I'll have to torture myself again and try to wrap my head around the AP init assembly code...
https://review.coreboot.org/c/coreboot/+/46608/5/src/security/intel/txt/comm... File src/security/intel/txt/common.c:
https://review.coreboot.org/c/coreboot/+/46608/5/src/security/intel/txt/comm... PS5, Line 310: //write32((void *)MCU_BASE_ADDR, 0xffe1a990);
I know where these come from. They were used to setup APs for ACM launch. […]
Thanks for the pointer. We don't set up the APs anywhere. I'm not sure if this is required for Haswell: sometimes SCLEAN will not complete, and I suspect the missing AP init might be why.
Michał Żygowski has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46608 )
Change subject: haswell: Add Intel TXT support in romstage ......................................................................
Patch Set 5:
Support for Haswell required some adjustments to account for differences between LT-SX and LT-CX. The biggest one is SCLEAN, since it's the only way to recover from TXT-blocked memory (without manual intervention). Looks like the memory block simply prevents the MPLL (Memory PLL) from ever powering up, which is simple but effective. To run SCLEAN in romstage, I had to adapt the ACM calling code to tear down CAR, among other stuff. I also figured out the original implementation would fail when ACM sizes were not a power of two, which I CB:44880 addressed. After trying to read reference assembly code, I decided to write a new implementation from scratch, which turned out to be much simpler and easy to read, IMHO.
I saw this reference code too and I agree it is not so simple. About the suspend/resume note there is an undocumented parameter for SCHECK for resume path. According to comments and papers it should indicate to ACM that it doesn't have to perform all the task during normal boot path.
Hello Philipp Deppenwiese, build bot (Jenkins), Patrick Georgi, Martin Roth, Patrick Rudolph, Christian Walter, Arthur Heymans, Patrick Rudolph,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/46608
to look at the new patch set (#6).
Change subject: haswell: Add Intel TXT support in romstage ......................................................................
haswell: Add Intel TXT support in romstage
Provide necessary romstage hooks to allow unblocking the memory with SCLEAN. Note that this is slow, and took four minutes with 4 GiB of RAM.
Tested on Asrock B85M Pro4 with tboot. When Linux has tboot support compiled in, booting as well as S3 suspend and resume are functional. However, SINIT will TXT reset when the iGPU is enabled, and using a dGPU will result in DMAR-related problems as soon as the IOMMU is enabled.
However, SCLEAN seems to hang sometimes. This may be because the AP initialization that reference code does before SCLEAN is missing, but the ACM is still able to unblock the memory. Considering that SCLEAN is critical to recover an otherwise-bricked platform but is hardly ever necessary, prefer having a partially-working solution over none at all.
Change-Id: I60beb7d79a30f460bbd5d94e4cba0244318c124e Signed-off-by: Angel Pons th3fanbus@gmail.com --- M src/northbridge/intel/haswell/romstage.c M src/security/intel/txt/Makefile.inc M src/security/intel/txt/common.c A src/security/intel/txt/romstage.c M src/security/intel/txt/txt.h M src/security/intel/txt/txt_register.h 6 files changed, 200 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/08/46608/6
Angel Pons has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46608 )
Change subject: haswell: Add Intel TXT support in romstage ......................................................................
Patch Set 6:
(1 comment)
https://review.coreboot.org/c/coreboot/+/46608/5/src/security/intel/txt/comm... File src/security/intel/txt/common.c:
https://review.coreboot.org/c/coreboot/+/46608/5/src/security/intel/txt/comm... PS5, Line 310: //write32((void *)MCU_BASE_ADDR, 0xffe1a990);
Thanks for the pointer. We don't set up the APs anywhere. […]
I'm going to merge this as-is, as I'd like to ensure the upcoming coreboot release has the means to recover from TXT-blocked memory. Even if the current approach doesn't always succeed on the first try, it's much better than not trying at all.
I've updated the commit message to explain this issue, and I will look into implementing the AP init sequence in the (hopefully near) future.
Angel Pons has submitted this change. ( https://review.coreboot.org/c/coreboot/+/46608 )
Change subject: haswell: Add Intel TXT support in romstage ......................................................................
haswell: Add Intel TXT support in romstage
Provide necessary romstage hooks to allow unblocking the memory with SCLEAN. Note that this is slow, and took four minutes with 4 GiB of RAM.
Tested on Asrock B85M Pro4 with tboot. When Linux has tboot support compiled in, booting as well as S3 suspend and resume are functional. However, SINIT will TXT reset when the iGPU is enabled, and using a dGPU will result in DMAR-related problems as soon as the IOMMU is enabled.
However, SCLEAN seems to hang sometimes. This may be because the AP initialization that reference code does before SCLEAN is missing, but the ACM is still able to unblock the memory. Considering that SCLEAN is critical to recover an otherwise-bricked platform but is hardly ever necessary, prefer having a partially-working solution over none at all.
Change-Id: I60beb7d79a30f460bbd5d94e4cba0244318c124e Signed-off-by: Angel Pons th3fanbus@gmail.com Reviewed-on: https://review.coreboot.org/c/coreboot/+/46608 Tested-by: build bot (Jenkins) no-reply@coreboot.org Reviewed-by: Arthur Heymans arthur@aheymans.xyz --- M src/northbridge/intel/haswell/romstage.c M src/security/intel/txt/Makefile.inc M src/security/intel/txt/common.c A src/security/intel/txt/romstage.c M src/security/intel/txt/txt.h M src/security/intel/txt/txt_register.h 6 files changed, 200 insertions(+), 0 deletions(-)
Approvals: build bot (Jenkins): Verified Arthur Heymans: Looks good to me, approved
diff --git a/src/northbridge/intel/haswell/romstage.c b/src/northbridge/intel/haswell/romstage.c index 5b025eb..3227c02 100644 --- a/src/northbridge/intel/haswell/romstage.c +++ b/src/northbridge/intel/haswell/romstage.c @@ -4,11 +4,14 @@ #include <console/console.h> #include <cf9_reset.h> #include <device/device.h> +#include <device/mmio.h> #include <timestamp.h> #include <cpu/x86/lapic.h> #include <cbmem.h> #include <commonlib/helpers.h> #include <romstage_handoff.h> +#include <security/intel/txt/txt.h> +#include <security/intel/txt/txt_register.h> #include <cpu/intel/haswell/haswell.h> #include <northbridge/intel/haswell/chip.h> #include <northbridge/intel/haswell/haswell.h> @@ -108,12 +111,27 @@
report_platform_info();
+ if (CONFIG(INTEL_TXT)) + intel_txt_romstage_init(); + copy_spd(&pei_data);
sdram_initialize(&pei_data);
timestamp_add_now(TS_AFTER_INITRAM);
+ if (CONFIG(INTEL_TXT)) { + printk(BIOS_DEBUG, "Check TXT_ERROR register after MRC\n"); + + intel_txt_log_acm_error(read32((void *)TXT_ERROR)); + + intel_txt_log_spad(); + + intel_txt_memory_has_secrets(); + + txt_dump_regions(); + } + post_code(0x3b);
intel_early_me_status(); diff --git a/src/security/intel/txt/Makefile.inc b/src/security/intel/txt/Makefile.inc index 762256f..eab47b9 100644 --- a/src/security/intel/txt/Makefile.inc +++ b/src/security/intel/txt/Makefile.inc @@ -1,6 +1,8 @@ ifeq ($(CONFIG_INTEL_TXT),y)
+romstage-y += romstage.c romstage-y += getsec_sclean.S +romstage-y += getsec.c
romstage-y += common.c romstage-$(CONFIG_INTEL_TXT_LOGGING) += logging.c diff --git a/src/security/intel/txt/common.c b/src/security/intel/txt/common.c index 88e2b5d..4dd4ad3 100644 --- a/src/security/intel/txt/common.c +++ b/src/security/intel/txt/common.c @@ -290,6 +290,48 @@ return acm_data; }
+#define MCU_BASE_ADDR (TXT_BASE + 0x278) +#define BIOACM_ADDR (TXT_BASE + 0x27c) +#define APINIT_ADDR (TXT_BASE + 0x290) +#define SEMAPHORE (TXT_BASE + 0x294) + +/* Returns on failure, resets the computer on success */ +void intel_txt_run_sclean(void) +{ + struct region_device acm; + size_t acm_len; + + void *acm_data = intel_txt_prepare_bios_acm(&acm, &acm_len); + + if (!acm_data) + return; + + /* FIXME: Do we need to program these two? */ + //write32((void *)MCU_BASE_ADDR, 0xffe1a990); + //write32((void *)APINIT_ADDR, 0xfffffff0); + + write32((void *)BIOACM_ADDR, (uintptr_t)acm_data); + write32((void *)SEMAPHORE, 0); + + /* + * The time SCLEAN will take depends on the installed RAM size. + * On Haswell with 8 GiB of DDR3, it takes five or ten minutes. (rough estimate) + */ + printk(BIOS_ALERT, "TEE-TXT: Invoking SCLEAN. This can take several minutes.\n"); + + /* + * Invoke the BIOS ACM. If successful, the system will reset with memory unlocked. + */ + getsec_sclean((uintptr_t)acm_data, acm_len); + + /* + * However, if this function returns, the BIOS ACM could not be invoked. This is bad. + */ + printk(BIOS_CRIT, "TEE-TXT: getsec_sclean could not launch the BIOS ACM.\n"); + + rdev_munmap(&acm, acm_data); +} + /* * Test all bits for TXT execution. * diff --git a/src/security/intel/txt/romstage.c b/src/security/intel/txt/romstage.c new file mode 100644 index 0000000..7a12deb --- /dev/null +++ b/src/security/intel/txt/romstage.c @@ -0,0 +1,125 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <arch/mmio.h> +#include <cf9_reset.h> +#include <console/console.h> +#include <cpu/intel/common/common.h> +#include <cpu/x86/msr.h> +#include <southbridge/intel/common/pmbase.h> +#include <timer.h> +#include <types.h> + +#include <security/tpm/tis.h> + +#include "txt.h" +#include "txt_register.h" +#include "txt_getsec.h" + +static bool is_establishment_bit_asserted(void) +{ + struct stopwatch timer; + uint8_t access; + + /* Spec says no less than 30 milliseconds */ + stopwatch_init_msecs_expire(&timer, 50); + + while (true) { + access = read8((void *)TPM_ACCESS_REG); + + /* Register returns all ones if TPM is missing */ + if (access == 0xff) + return false; + + if (access & TPM_ACCESS_VALID) + break; + + /* On timeout, assume that the TPM is not working */ + if (stopwatch_expired(&timer)) + return false; + } + + /* This bit uses inverted logic: if cleared, establishment is asserted */ + return !(access & TPM_ACCESS_ESTABLISHMENT); +} + +static bool is_txt_cpu(void) +{ + const uint32_t ecx = cpu_get_feature_flags_ecx(); + + return (ecx & (CPUID_SMX | CPUID_VMX)) == (CPUID_SMX | CPUID_VMX); +} + +static bool is_txt_chipset(void) +{ + uint32_t eax; + + const bool success = getsec_capabilities(&eax); + + return success && eax & 1; +} + +/* Print the bad news */ +static void print_memory_is_locked(void) +{ + if (!CONFIG(INTEL_TXT_LOGGING)) + return; + + printk(BIOS_EMERG, "FATAL: Cannot run SCLEAN. Memory will remain locked.\n"); + printk(BIOS_EMERG, "\n"); + printk(BIOS_EMERG, "If you still want to boot, your options are:\n"); + printk(BIOS_EMERG, "\n"); + printk(BIOS_EMERG, " 1. Flash a coreboot image with a valid BIOS ACM.\n"); + printk(BIOS_EMERG, " Then, try again and hope it works this time.\n"); + printk(BIOS_EMERG, "\n"); + printk(BIOS_EMERG, " 2. If possible, remove the TPM from the system.\n"); + printk(BIOS_EMERG, " Reinstalling the TPM might lock memory again.\n"); + printk(BIOS_EMERG, "\n"); + printk(BIOS_EMERG, " 3. Disconnect all power sources, and RTC battery.\n"); + printk(BIOS_EMERG, " This may not work on all TXT-enabled platforms.\n"); + printk(BIOS_EMERG, "\n"); +} + +void intel_txt_romstage_init(void) +{ + /* Bail early if the CPU doesn't support TXT */ + if (!is_txt_cpu()) + return; + + /* We need to use GETSEC here, so enable it */ + enable_getsec_or_reset(); + + if (!is_txt_chipset()) + return; + + const uint8_t txt_ests = read8((void *)TXT_ESTS); + + const bool establishment = is_establishment_bit_asserted(); + const bool is_wake_error = !!(txt_ests & TXT_ESTS_WAKE_ERROR_STS); + + if (CONFIG(INTEL_TXT_LOGGING)) { + + printk(BIOS_INFO, "TEE-TXT: TPM established: %s\n", + establishment ? "true" : "false"); + } + + if (establishment && is_wake_error) { + + printk(BIOS_ERR, "TEE-TXT: Secrets remain in memory. SCLEAN is required.\n"); + + if (txt_ests & TXT_ESTS_TXT_RESET_STS) { + printk(BIOS_ERR, "TEE-TXT: TXT_RESET bit set, doing full reset!\n"); + full_reset(); + } + + /* FIXME: Clear SLP_TYP# */ + write_pmbase32(4, read_pmbase32(4) & ~(0x7 << 10)); + + intel_txt_run_sclean(); + + /* If running the BIOS ACM is impossible, manual intervention is required */ + print_memory_is_locked(); + + /* FIXME: vboot A/B could be used to recover, but has not been tested */ + die("Could not execute BIOS ACM to unlock the memory.\n"); + } +} diff --git a/src/security/intel/txt/txt.h b/src/security/intel/txt/txt.h index fc5c49e..976cc74 100644 --- a/src/security/intel/txt/txt.h +++ b/src/security/intel/txt/txt.h @@ -17,10 +17,13 @@ #define ACM_E_UUID_NOT_MATCH 0x09 #define ACM_E_PLATFORM_IS_NOT_PROD 0x10
+void intel_txt_romstage_init(void); + void intel_txt_log_bios_acm_error(void); int intel_txt_log_acm_error(const uint32_t acm_error); void intel_txt_log_spad(void); bool intel_txt_memory_has_secrets(void); +void intel_txt_run_sclean(void); int intel_txt_run_bios_acm(const u8 input_params); bool intel_txt_prepare_txt_env(void);
diff --git a/src/security/intel/txt/txt_register.h b/src/security/intel/txt/txt_register.h index c19ec13..bb735b6 100644 --- a/src/security/intel/txt/txt_register.h +++ b/src/security/intel/txt/txt_register.h @@ -99,6 +99,16 @@ #define TXT_E2STS_SECRET_STS (1ull << 1)
/* + * TCG PC Client Platform TPM Profile (PTP) Specification + * + * Note: Only locality 0 registers are publicly accessible. + */ + +#define TPM_BASE 0xfed40000UL + +#define TPM_ACCESS_REG (TPM_BASE + 0x00) + +/* * TXT Memory regions * Chapter 5.3 * Intel Trusted Execution Technology Lab Handout