coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
romstage.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <arch/cpu.h>
4 #include <arch/mmio.h>
5 #include <cf9_reset.h>
6 #include <console/console.h>
8 #include <cpu/x86/cr.h>
9 #include <cpu/x86/msr.h>
11 #include <timer.h>
12 #include <types.h>
13 
14 #include <security/tpm/tis.h>
15 
16 #include "txt.h"
17 #include "txt_register.h"
18 #include "txt_getsec.h"
19 
21 {
22  struct stopwatch timer;
23  uint8_t access;
24 
25  /* Spec says no less than 30 milliseconds */
26  stopwatch_init_msecs_expire(&timer, 50);
27 
28  while (true) {
29  access = read8((void *)TPM_ACCESS_REG);
30 
31  /* Register returns all ones if TPM is missing */
32  if (access == 0xff)
33  return false;
34 
35  if (access & TPM_ACCESS_VALID)
36  break;
37 
38  /* On timeout, assume that the TPM is not working */
39  if (stopwatch_expired(&timer))
40  return false;
41  }
42 
43  /* This bit uses inverted logic: if cleared, establishment is asserted */
44  return !(access & TPM_ACCESS_ESTABLISHMENT);
45 }
46 
47 static bool is_txt_cpu(void)
48 {
49  const uint32_t ecx = cpu_get_feature_flags_ecx();
50 
51  return (ecx & (CPUID_SMX | CPUID_VMX)) == (CPUID_SMX | CPUID_VMX);
52 }
53 
54 static bool is_txt_chipset(void)
55 {
56  uint32_t eax;
57 
58  const bool success = getsec_capabilities(&eax);
59 
60  return success && eax & 1;
61 }
62 
63 /* Print the bad news */
64 static void print_memory_is_locked(void)
65 {
66  if (!CONFIG(INTEL_TXT_LOGGING))
67  return;
68 
69  printk(BIOS_EMERG, "FATAL: Cannot run SCLEAN. Memory will remain locked.\n");
70  printk(BIOS_EMERG, "\n");
71  printk(BIOS_EMERG, "If you still want to boot, your options are:\n");
72  printk(BIOS_EMERG, "\n");
73  printk(BIOS_EMERG, " 1. Flash a coreboot image with a valid BIOS ACM.\n");
74  printk(BIOS_EMERG, " Then, try again and hope it works this time.\n");
75  printk(BIOS_EMERG, "\n");
76  printk(BIOS_EMERG, " 2. If possible, remove the TPM from the system.\n");
77  printk(BIOS_EMERG, " Reinstalling the TPM might lock memory again.\n");
78  printk(BIOS_EMERG, "\n");
79  printk(BIOS_EMERG, " 3. Disconnect all power sources, and RTC battery.\n");
80  printk(BIOS_EMERG, " This may not work on all TXT-enabled platforms.\n");
81  printk(BIOS_EMERG, "\n");
82 }
83 
85 {
86  /* Bail early if the CPU doesn't support TXT */
87  if (!is_txt_cpu()) {
88  printk(BIOS_ERR, "TEE-TXT: CPU not TXT capable.\n");
89  return;
90  }
91 
92  /*
93  * We need to use GETSEC here, so enable it.
94  * CR4_SMXE is all we need to be able to call GETSEC[CAPABILITIES]
95  * or GETSEC[ENTERACCS] for SCLEAN.
96  */
98 
99  if (!is_txt_chipset()) {
100  printk(BIOS_ERR, "TEE-TXT: Chipset not TXT capable.\n");
101  return;
102  }
103 
104  const uint8_t txt_ests = read8((void *)TXT_ESTS);
105 
106  const bool establishment = is_establishment_bit_asserted();
107  const bool is_wake_error = !!(txt_ests & TXT_ESTS_WAKE_ERROR_STS);
108 
109  if (CONFIG(INTEL_TXT_LOGGING)) {
110 
111  printk(BIOS_INFO, "TEE-TXT: TPM established: %s\n",
112  establishment ? "true" : "false");
113  }
114 
115  if (establishment && is_wake_error) {
116 
117  printk(BIOS_ERR, "TEE-TXT: Secrets remain in memory. SCLEAN is required.\n");
118 
119  if (txt_ests & TXT_ESTS_TXT_RESET_STS) {
120  printk(BIOS_ERR, "TEE-TXT: TXT_RESET bit set, doing global reset!\n");
122  }
123 
124  /* FIXME: Clear SLP_TYP# */
125  write_pmbase32(4, read_pmbase32(4) & ~(0x7 << 10));
126 
128 
129  /* If running the BIOS ACM is impossible, manual intervention is required */
131 
132  /* FIXME: vboot A/B could be used to recover, but has not been tested */
133  die("Could not execute BIOS ACM to unlock the memory.\n");
134  }
135 }
static uint8_t read8(const void *addr)
Definition: mmio.h:12
#define printk(level,...)
Definition: stdlib.h:16
void __noreturn die(const char *fmt,...)
Definition: die.c:17
uint32_t cpu_get_feature_flags_ecx(void)
Definition: cpu_common.c:72
#define CR4_SMXE
Definition: cr.h:126
static __always_inline void write_cr4(CRx_TYPE data)
Definition: cr.h:88
static __always_inline CRx_TYPE read_cr4(void)
Definition: cr.h:76
@ CONFIG
Definition: dsi_common.h:201
bool getsec_capabilities(uint32_t *eax)
Get capabilities as returned by getsec[CAPABILITIES].
Definition: getsec.c:147
#define CPUID_VMX
Definition: msr.h:24
#define CPUID_SMX
Definition: msr.h:25
static int stopwatch_expired(struct stopwatch *sw)
Definition: timer.h:152
static void stopwatch_init_msecs_expire(struct stopwatch *sw, long ms)
Definition: timer.h:133
#define BIOS_INFO
BIOS_INFO - Expected events.
Definition: loglevel.h:113
#define BIOS_EMERG
BIOS_EMERG - Emergency / Fatal.
Definition: loglevel.h:25
#define BIOS_ERR
BIOS_ERR - System in incomplete state.
Definition: loglevel.h:72
u32 read_pmbase32(const u8 addr)
Definition: pmbase.c:57
void write_pmbase32(const u8 addr, const u32 val)
Definition: pmbase.c:36
void __noreturn txt_reset_platform(void)
Definition: common.c:29
void intel_txt_run_sclean(void)
Definition: common.c:313
void intel_txt_romstage_init(void)
Definition: romstage.c:84
static bool is_establishment_bit_asserted(void)
Definition: romstage.c:20
static void print_memory_is_locked(void)
Definition: romstage.c:64
static bool is_txt_chipset(void)
Definition: romstage.c:54
static bool is_txt_cpu(void)
Definition: romstage.c:47
#define TPM_ACCESS_REG
Definition: tpm.c:27
unsigned int uint32_t
Definition: stdint.h:14
unsigned char uint8_t
Definition: stdint.h:8
@ TPM_ACCESS_ESTABLISHMENT
Definition: tis.h:15
@ TPM_ACCESS_VALID
Definition: tis.h:11
#define TXT_ESTS_WAKE_ERROR_STS
Definition: txt_register.h:23
#define TXT_ESTS
Definition: txt_register.h:17
#define TXT_ESTS_TXT_RESET_STS
Definition: txt_register.h:18