blob: 61ff0eb5eb951b2de3b94e7f243d7e8ca74391aa [file] [log] [blame]
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +01001/* SPDX-License-Identifier: GPL-2.0-only */
2
3#include <arch/mmio.h>
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +01004#include <console/console.h>
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +01005#include <cbfs.h>
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +01006#include <cpu/x86/cr.h>
Angel Pons52082be2020-10-05 12:34:29 +02007#include <cpu/x86/lapic.h>
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +01008#include <cpu/x86/mp.h>
Felix Held7b6a3972021-07-09 23:08:07 +02009#include <cpu/x86/msr.h>
Angel Pons038cef92020-10-14 17:58:36 +020010#include <cpu/x86/mtrr.h>
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +010011#include <lib.h>
12#include <smp/node.h>
Angel Pons52082be2020-10-05 12:34:29 +020013#include <string.h>
14#include <types.h>
Angel Pons1fc43aa2020-08-04 17:54:01 +020015
16#if CONFIG(SOC_INTEL_COMMON_BLOCK_SA)
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +010017#include <soc/intel/common/reset.h>
Angel Pons1fc43aa2020-08-04 17:54:01 +020018#else
Michał Żygowskide8c8ec2021-11-21 12:50:48 +010019#if CONFIG(SOUTHBRIDGE_INTEL_COMMON_ME)
20#include <southbridge/intel/common/me.h>
21#endif
Angel Pons1fc43aa2020-08-04 17:54:01 +020022#include <cf9_reset.h>
23#endif
24
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +010025#include "txt.h"
26#include "txt_register.h"
27#include "txt_getsec.h"
28
Angel Pons1fc43aa2020-08-04 17:54:01 +020029/* Usual security practice: if an unexpected error happens, reboot */
30static void __noreturn txt_reset_platform(void)
31{
32#if CONFIG(SOC_INTEL_COMMON_BLOCK_SA)
33 global_reset();
34#else
Michał Żygowskide8c8ec2021-11-21 12:50:48 +010035#if CONFIG(SOUTHBRIDGE_INTEL_COMMON_ME)
36 set_global_reset(1);
37#endif
Angel Pons1fc43aa2020-08-04 17:54:01 +020038 full_reset();
39#endif
40}
41
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +010042/**
43 * Dump the ACM error status bits.
44 *
45 * @param acm_error The status register to dump
46 * @return -1 on error (register is not valid)
47 * 0 on error (Class > 0 and Major > 0)
48 * 1 on success (Class == 0 and Major == 0 and progress > 0)
49 */
50int intel_txt_log_acm_error(const uint32_t acm_error)
51{
52 if (!(acm_error & ACMERROR_TXT_VALID))
53 return -1;
54
55 const uint8_t type = (acm_error & ACMERROR_TXT_TYPE_CODE)
56 >> ACMERROR_TXT_TYPE_SHIFT;
57
58 switch (type) {
59 case ACMERROR_TXT_AC_MODULE_TYPE_BIOS:
60 printk(BIOS_ERR, "BIOSACM");
61 break;
62 case ACMERROR_TXT_AC_MODULE_TYPE_SINIT:
63 printk(BIOS_ERR, "SINIT");
64 break;
65 default:
66 printk(BIOS_ERR, "ACM");
67 break;
68 }
69 printk(BIOS_ERR, ": Error code valid\n");
70
71 if (acm_error & ACMERROR_TXT_EXTERNAL)
72 printk(BIOS_ERR, " Caused by: External\n");
73 else
74 printk(BIOS_ERR, " Caused by: Processor\n");
75
76 const uint32_t class = (acm_error & ACMERROR_TXT_CLASS_CODE)
77 >> ACMERROR_TXT_CLASS_SHIFT;
78 const uint32_t major = (acm_error & ACMERROR_TXT_MAJOR_CODE)
79 >> ACMERROR_TXT_MAJOR_SHIFT;
80 const uint32_t minor = (acm_error & ACMERROR_TXT_MINOR_CODE)
81 >> ACMERROR_TXT_MINOR_SHIFT;
82 const uint32_t progress = (acm_error & ACMERROR_TXT_PROGRESS_CODE)
83 >> ACMERROR_TXT_PROGRESS_SHIFT;
84
85 if (!minor) {
86 if (class == 0 && major == 0 && progress > 0) {
87 printk(BIOS_ERR, " Execution successful\n");
88 printk(BIOS_ERR, " Progress code 0x%x\n", progress);
89 } else {
90 printk(BIOS_ERR, " Error Class: %x\n", class);
91 printk(BIOS_ERR, " Error: %x.%x\n", major, progress);
92 }
93 } else {
94 printk(BIOS_ERR, " ACM didn't start\n");
95 printk(BIOS_ERR, " Error Type: 0x%x\n", acm_error & 0xffffff);
96 return -1;
97 }
98
99 return (acm_error & ACMERROR_TXT_EXTERNAL) && class == 0 && major == 0 && progress > 0;
100}
101
102void intel_txt_log_spad(void)
103{
104 const uint64_t acm_status = read64((void *)TXT_SPAD);
105
106 printk(BIOS_INFO, "TXT-STS: ACM verification ");
107
108 if (acm_status & ACMSTS_VERIFICATION_ERROR)
109 printk(BIOS_INFO, "error\n");
110 else
111 printk(BIOS_INFO, "successful\n");
112
113 printk(BIOS_INFO, "TXT-STS: IBB ");
114
115 if (acm_status & ACMSTS_IBB_MEASURED)
116 printk(BIOS_INFO, "measured\n");
117 else
118 printk(BIOS_INFO, "not measured\n");
119
120 printk(BIOS_INFO, "TXT-STS: TXT is ");
121
122 if (acm_status & ACMSTS_TXT_DISABLED)
123 printk(BIOS_INFO, "disabled\n");
124 else
125 printk(BIOS_INFO, "not disabled\n");
126
127 printk(BIOS_INFO, "TXT-STS: BIOS is ");
128
129 if (acm_status & ACMSTS_BIOS_TRUSTED)
130 printk(BIOS_INFO, "trusted\n");
131 else
132 printk(BIOS_INFO, "not trusted\n");
133}
134
135/* Returns true if secrets might be in memory */
136bool intel_txt_memory_has_secrets(void)
137{
138 bool ret;
139 if (!CONFIG(INTEL_TXT))
140 return false;
141
142 ret = (read8((void *)TXT_ESTS) & TXT_ESTS_WAKE_ERROR_STS) ||
143 (read64((void *)TXT_E2STS) & TXT_E2STS_SECRET_STS);
144
145 if (ret)
146 printk(BIOS_CRIT, "TXT-STS: Secrets in memory!\n");
147 return ret;
148}
149
Michał Żygowski9734e802021-11-21 12:29:58 +0100150bool intel_txt_chipset_is_production_fused(void)
151{
152 /*
153 * Certain chipsets report production fused information in either
154 * TXT.VER.FSBIF or TXT.VER.EMIF/TXT.VER.QPIIF.
155 * Chapter B.1.7 and B.1.9
156 * Intel TXT Software Development Guide (Document: 315168-015)
157 */
158 uint32_t reg = read32((void *)TXT_VER_FSBIF);
159
160 if (reg == 0 || reg == UINT32_MAX)
161 reg = read32((void *)TXT_VER_QPIIF);
162
163 return (reg & TXT_VER_PRODUCTION_FUSED) ? true : false;
164}
165
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100166static struct acm_info_table *find_info_table(const void *ptr)
167{
168 const struct acm_header_v0 *acm_header = (struct acm_header_v0 *)ptr;
169
170 return (struct acm_info_table *)(ptr +
171 (acm_header->header_len + acm_header->scratch_size) * sizeof(uint32_t));
172}
173
174/**
Martin Roth50863da2021-10-01 14:37:30 -0600175 * Validate that the provided ACM is usable on this platform.
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100176 */
177static int validate_acm(const void *ptr)
178{
179 const struct acm_header_v0 *acm_header = (struct acm_header_v0 *)ptr;
180 uint32_t max_size_acm_area = 0;
181
182 if (acm_header->module_type != CHIPSET_ACM)
183 return ACM_E_TYPE_NOT_MATCH;
184
185 /* Seems inconsistent across generations. */
186 if (acm_header->module_sub_type != 0 && acm_header->module_sub_type != 1)
187 return ACM_E_MODULE_SUB_TYPE_WRONG;
188
189 if (acm_header->module_vendor != INTEL_ACM_VENDOR)
190 return ACM_E_MODULE_VENDOR_NOT_INTEL;
191
John Zhao536e9652020-08-04 11:29:08 -0700192 if (acm_header->size == 0)
193 return ACM_E_SIZE_INCORRECT;
194
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100195 if (((acm_header->header_len + acm_header->scratch_size) * sizeof(uint32_t) +
196 sizeof(struct acm_info_table)) > (acm_header->size & 0xffffff) * sizeof(uint32_t)) {
197 return ACM_E_SIZE_INCORRECT;
198 }
199
200 if (!getsec_parameter(NULL, NULL, &max_size_acm_area, NULL, NULL, NULL))
201 return ACM_E_CANT_CALL_GETSEC;
202
203 /*
204 * Causes #GP if acm_header->size > processor internal authenticated
205 * code area capacity.
206 * SAFER MODE EXTENSIONS REFERENCE.
207 * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D
208 */
209 const size_t acm_len = 1UL << log2_ceil((acm_header->size & 0xffffff) << 2);
210 if (max_size_acm_area < acm_len) {
211 printk(BIOS_ERR, "TEE-TXT: BIOS ACM doesn't fit into AC execution region\n");
212 return ACM_E_NOT_FIT_INTO_CPU_ACM_MEM;
213 }
214
215 struct acm_info_table *info = find_info_table(ptr);
216 if (!info)
217 return ACM_E_NO_INFO_TABLE;
218 if (info->chipset_acm_type != BIOS)
219 return ACM_E_NOT_BIOS_ACM;
220
221 static const u8 acm_uuid[] = {
222 0xaa, 0x3a, 0xc0, 0x7f, 0xa7, 0x46, 0xdb, 0x18,
223 0x2e, 0xac, 0x69, 0x8f, 0x8d, 0x41, 0x7f, 0x5a,
224 };
225 if (memcmp(acm_uuid, info->uuid, sizeof(acm_uuid)) != 0)
226 return ACM_E_UUID_NOT_MATCH;
227
Michał Żygowski9734e802021-11-21 12:29:58 +0100228 const bool production_acm = !(acm_header->flags & ACM_FORMAT_FLAGS_DEBUG);
229 if (production_acm != intel_txt_chipset_is_production_fused())
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100230 return ACM_E_PLATFORM_IS_NOT_PROD;
231
232 return 0;
233}
234
235/*
Angel Pons7b4d67cf2020-10-20 14:17:42 +0200236 * Prepare to run the BIOS ACM: mmap it from the CBFS and verify that it
237 * can be launched. Returns pointer to ACM on success, NULL on failure.
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100238 */
Michał Żygowski76565712021-11-21 12:38:07 +0100239static void *intel_txt_prepare_bios_acm(size_t *acm_len)
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100240{
Angel Pons7b4d67cf2020-10-20 14:17:42 +0200241 void *acm_data = NULL;
242
Michał Żygowski76565712021-11-21 12:38:07 +0100243 if (!acm_len)
Angel Pons7b4d67cf2020-10-20 14:17:42 +0200244 return NULL;
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100245
Julius Werner77639e42021-02-05 16:51:25 -0800246 acm_data = cbfs_map(CONFIG_INTEL_TXT_CBFS_BIOS_ACM, acm_len);
247 if (!acm_data) {
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100248 printk(BIOS_ERR, "TEE-TXT: Couldn't locate BIOS ACM in CBFS.\n");
Angel Pons7b4d67cf2020-10-20 14:17:42 +0200249 return NULL;
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100250 }
251
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100252 /*
253 * CPU enforces only 4KiB alignment.
254 * Chapter A.1.1
255 * Intel TXT Software Development Guide (Document: 315168-015)
256 */
257 if (!IS_ALIGNED((uintptr_t)acm_data, 4096)) {
258 printk(BIOS_ERR, "TEE-TXT: BIOS ACM isn't mapped at page boundary.\n");
Julius Werner77639e42021-02-05 16:51:25 -0800259 cbfs_unmap(acm_data);
Angel Pons7b4d67cf2020-10-20 14:17:42 +0200260 return NULL;
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100261 }
262
263 /*
264 * Causes #GP if not multiple of 64.
265 * SAFER MODE EXTENSIONS REFERENCE.
266 * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D
267 */
Angel Pons7b4d67cf2020-10-20 14:17:42 +0200268 if (!IS_ALIGNED(*acm_len, 64)) {
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100269 printk(BIOS_ERR, "TEE-TXT: BIOS ACM size isn't multiple of 64.\n");
Julius Werner77639e42021-02-05 16:51:25 -0800270 cbfs_unmap(acm_data);
Angel Pons7b4d67cf2020-10-20 14:17:42 +0200271 return NULL;
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100272 }
273
274 /*
275 * The ACM should be aligned to it's size, but that's not possible, as
276 * some ACMs are not power of two. Use the next power of two for verification.
277 */
Angel Pons7b4d67cf2020-10-20 14:17:42 +0200278 if (!IS_ALIGNED((uintptr_t)acm_data, (1UL << log2_ceil(*acm_len)))) {
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100279 printk(BIOS_ERR, "TEE-TXT: BIOS ACM isn't aligned to its size.\n");
Julius Werner77639e42021-02-05 16:51:25 -0800280 cbfs_unmap(acm_data);
Angel Pons7b4d67cf2020-10-20 14:17:42 +0200281 return NULL;
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100282 }
283
Angel Pons038cef92020-10-14 17:58:36 +0200284 /*
285 * When setting up the MTRRs to cache the BIOS ACM, one must cache less than
286 * a page (4 KiB) of unused memory after the BIOS ACM. On Haswell, failure
287 * to do so will cause a TXT reset with Class Code 5, Major Error Code 2.
288 */
Angel Pons7b4d67cf2020-10-20 14:17:42 +0200289 if (popcnt(ALIGN_UP(*acm_len, 4096)) > get_var_mtrr_count()) {
Angel Pons038cef92020-10-14 17:58:36 +0200290 printk(BIOS_ERR, "TEE-TXT: Not enough MTRRs to cache this BIOS ACM's size.\n");
Julius Werner77639e42021-02-05 16:51:25 -0800291 cbfs_unmap(acm_data);
Angel Pons7b4d67cf2020-10-20 14:17:42 +0200292 return NULL;
Angel Pons038cef92020-10-14 17:58:36 +0200293 }
294
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100295 if (CONFIG(INTEL_TXT_LOGGING))
296 txt_dump_acm_info(acm_data);
297
Angel Pons7b4d67cf2020-10-20 14:17:42 +0200298 const int ret = validate_acm(acm_data);
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100299 if (ret < 0) {
300 printk(BIOS_ERR, "TEE-TXT: Validation of ACM failed with: %d\n", ret);
Julius Werner77639e42021-02-05 16:51:25 -0800301 cbfs_unmap(acm_data);
Angel Pons7b4d67cf2020-10-20 14:17:42 +0200302 return NULL;
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100303 }
304
Angel Pons7b4d67cf2020-10-20 14:17:42 +0200305 return acm_data;
306}
307
Angel Pons6c49f402020-08-28 02:02:00 +0200308#define MCU_BASE_ADDR (TXT_BASE + 0x278)
309#define BIOACM_ADDR (TXT_BASE + 0x27c)
310#define APINIT_ADDR (TXT_BASE + 0x290)
311#define SEMAPHORE (TXT_BASE + 0x294)
312
313/* Returns on failure, resets the computer on success */
314void intel_txt_run_sclean(void)
315{
Angel Pons6c49f402020-08-28 02:02:00 +0200316 size_t acm_len;
317
Michał Żygowski76565712021-11-21 12:38:07 +0100318 void *acm_data = intel_txt_prepare_bios_acm(&acm_len);
Angel Pons6c49f402020-08-28 02:02:00 +0200319
320 if (!acm_data)
321 return;
322
323 /* FIXME: Do we need to program these two? */
324 //write32((void *)MCU_BASE_ADDR, 0xffe1a990);
325 //write32((void *)APINIT_ADDR, 0xfffffff0);
326
327 write32((void *)BIOACM_ADDR, (uintptr_t)acm_data);
328 write32((void *)SEMAPHORE, 0);
329
330 /*
331 * The time SCLEAN will take depends on the installed RAM size.
332 * On Haswell with 8 GiB of DDR3, it takes five or ten minutes. (rough estimate)
333 */
334 printk(BIOS_ALERT, "TEE-TXT: Invoking SCLEAN. This can take several minutes.\n");
335
336 /*
337 * Invoke the BIOS ACM. If successful, the system will reset with memory unlocked.
338 */
339 getsec_sclean((uintptr_t)acm_data, acm_len);
340
341 /*
342 * However, if this function returns, the BIOS ACM could not be invoked. This is bad.
343 */
344 printk(BIOS_CRIT, "TEE-TXT: getsec_sclean could not launch the BIOS ACM.\n");
345
Michał Żygowski76565712021-11-21 12:38:07 +0100346 cbfs_unmap(acm_data);
Angel Pons6c49f402020-08-28 02:02:00 +0200347}
348
Angel Pons7b4d67cf2020-10-20 14:17:42 +0200349/*
350 * Test all bits for TXT execution.
351 *
352 * @return 0 on success
353 */
354int intel_txt_run_bios_acm(const u8 input_params)
355{
Angel Pons7b4d67cf2020-10-20 14:17:42 +0200356 size_t acm_len;
357
Michał Żygowski76565712021-11-21 12:38:07 +0100358 void *acm_data = intel_txt_prepare_bios_acm(&acm_len);
Angel Pons7b4d67cf2020-10-20 14:17:42 +0200359
360 if (!acm_data)
361 return -1;
362
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100363 /* Call into assembly which invokes the referenced ACM */
364 getsec_enteraccs(input_params, (uintptr_t)acm_data, acm_len);
365
Michał Żygowski76565712021-11-21 12:38:07 +0100366 cbfs_unmap(acm_data);
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100367
368 const uint64_t acm_status = read64((void *)TXT_SPAD);
369 if (acm_status & ACMERROR_TXT_VALID) {
370 printk(BIOS_ERR, "TEE-TXT: FATAL ACM launch error !\n");
371 /*
372 * WARNING !
373 * To clear TXT.BIOSACM.ERRORCODE you must issue a cold reboot!
374 */
375 intel_txt_log_acm_error(read32((void *)TXT_BIOSACM_ERRORCODE));
376 return -1;
377 }
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100378
379 return 0;
380}
381
382 /* Returns true if cond is not met */
383static bool check_precondition(const int cond)
384{
385 printk(BIOS_DEBUG, "%s\n", cond ? "true" : "false");
386 return !cond;
387}
388
389/*
390 * Test all bits that are required for Intel TXT.
391 * Enable SMX if available.
392 *
393 * @return 0 on success
394 */
395bool intel_txt_prepare_txt_env(void)
396{
397 bool failure = false;
398 uint32_t txt_feature_flags = 0;
399
400 unsigned int ecx = cpuid_ecx(1);
401
402 printk(BIOS_DEBUG, "TEE-TXT: CPU supports SMX: ");
403 failure |= check_precondition(ecx & CPUID_SMX);
404
405 printk(BIOS_DEBUG, "TEE-TXT: CPU supports VMX: ");
406 failure |= check_precondition(ecx & CPUID_VMX);
407
408 msr_t msr = rdmsr(IA32_FEATURE_CONTROL);
409 if (!(msr.lo & BIT(0))) {
410 printk(BIOS_ERR, "TEE-TXT: IA32_FEATURE_CONTROL is not locked\n");
Angel Pons1fc43aa2020-08-04 17:54:01 +0200411 txt_reset_platform();
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100412 }
413
414 printk(BIOS_DEBUG, "TEE-TXT: IA32_FEATURE_CONTROL\n");
415 printk(BIOS_DEBUG, " VMXON in SMX enable: ");
416 failure |= check_precondition(msr.lo & BIT(1));
417
418 printk(BIOS_DEBUG, " VMXON outside SMX enable: ");
419 failure |= check_precondition(msr.lo & FEATURE_ENABLE_VMX);
420
421 printk(BIOS_DEBUG, " register is locked: ");
422 failure |= check_precondition(msr.lo & BIT(0));
423
424 /* IA32_FEATURE_CONTROL enables getsec instructions */
425 printk(BIOS_DEBUG, " GETSEC (all instructions) is enabled: ");
426 failure |= check_precondition((msr.lo & 0xff00) == 0xff00);
427
428 /* Prevent crash and opt out early */
429 if (failure)
430 return true;
431
432 uint32_t eax = 0;
433 /*
434 * GetSec[CAPABILITIES]
435 * SAFER MODE EXTENSIONS REFERENCE.
436 * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D
437 * Must check BIT0 of TXT chipset has been detected by CPU.
438 */
439 if (!getsec_capabilities(&eax))
440 return true;
441
442 printk(BIOS_DEBUG, "TEE-TXT: GETSEC[CAPABILITIES] returned:\n");
443 printk(BIOS_DEBUG, " TXT capable chipset: %s\n", (eax & BIT(0)) ? "true" : "false");
444
445 printk(BIOS_DEBUG, " ENTERACCS available: %s\n", (eax & BIT(2)) ? "true" : "false");
446 printk(BIOS_DEBUG, " EXITAC available: %s\n", (eax & BIT(3)) ? "true" : "false");
447 printk(BIOS_DEBUG, " SENTER available: %s\n", (eax & BIT(4)) ? "true" : "false");
448 printk(BIOS_DEBUG, " SEXIT available: %s\n", (eax & BIT(5)) ? "true" : "false");
449 printk(BIOS_DEBUG, " PARAMETERS available: %s\n", (eax & BIT(6)) ? "true" : "false");
Michał Żygowski7480e872021-11-21 12:47:14 +0100450 printk(BIOS_DEBUG, " SMCTRL available: %s\n", (eax & BIT(7)) ? "true" : "false");
451 printk(BIOS_DEBUG, " WAKEUP available: %s\n", (eax & BIT(8)) ? "true" : "false");
452
453 txt_dump_getsec_parameters();
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100454
455 /*
456 * Causes #GP if function is not supported by getsec.
457 * SAFER MODE EXTENSIONS REFERENCE.
458 * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D
459 * Order Number: 325383-060US
460 */
461 if ((eax & 0x7d) != 0x7d)
462 failure = true;
463
464 const uint64_t status = read64((void *)TXT_SPAD);
465
466 if (status & ACMSTS_TXT_DISABLED) {
467 printk(BIOS_INFO, "TEE-TXT: TXT disabled by BIOS policy in FIT.\n");
468 failure = true;
469 }
470
471 /*
472 * Only the BSP must call getsec[ENTERACCS].
473 * SAFER MODE EXTENSIONS REFERENCE.
474 * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D
475 * Order Number: 325383-060US
476 */
477 if (!boot_cpu()) {
478 printk(BIOS_ERR, "TEE-TXT: BSP flag not set in APICBASE_MSR.\n");
479 failure = true;
480 }
481
482 /*
483 * There must be no MCEs pending.
484 * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D
485 * Order Number: 325383-060US
486 */
487 msr = rdmsr(IA32_MCG_STATUS);
488 if (msr.lo & 0x4) {
489 printk(BIOS_ERR, "TEE-TXT: IA32_MCG_STATUS.MCIP is set.\n");
490 failure = true;
491 }
492
493 if (!getsec_parameter(NULL, NULL, NULL, NULL, NULL, &txt_feature_flags)) {
494 return true;
495 } else {
496 printk(BIOS_DEBUG, "TEE-TXT: Machine Check Register: ");
497 if (txt_feature_flags & GETSEC_PARAMS_TXT_EXT_MACHINE_CHECK)
498 printk(BIOS_DEBUG, "preserved\n");
499 else
500 printk(BIOS_DEBUG, "must be clear\n");
501 }
502
503 if (!(txt_feature_flags & GETSEC_PARAMS_TXT_EXT_MACHINE_CHECK)) {
504 /*
505 * Make sure there are no uncorrectable MCE errors.
506 * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D
507 */
Felix Held7cf37872021-07-09 23:05:21 +0200508 size_t max_mc_msr = mca_get_bank_count();
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100509 for (size_t i = 0; i < max_mc_msr; i++) {
Felix Held1b46e762021-07-13 00:54:32 +0200510 msr = rdmsr(IA32_MC_STATUS(i));
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100511 if (!(msr.hi & MCA_STATUS_HI_UC))
512 continue;
513
514 printk(BIOS_ERR, "TEE-TXT: IA32_MC%zd_STATUS.UC is set.\n", i);
515 failure = true;
516 break;
517 }
518 }
519
520 /* Need to park all APs. */
521 if (CONFIG(PARALLEL_MP_AP_WORK))
522 mp_park_aps();
523
524 return failure;
525}