blob: 7e6c55cd587f043a4671647715c5f0ec6c0e4627 [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
19#include <cf9_reset.h>
20#endif
21
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +010022#include "txt.h"
23#include "txt_register.h"
24#include "txt_getsec.h"
25
Angel Pons1fc43aa2020-08-04 17:54:01 +020026/* Usual security practice: if an unexpected error happens, reboot */
27static void __noreturn txt_reset_platform(void)
28{
29#if CONFIG(SOC_INTEL_COMMON_BLOCK_SA)
30 global_reset();
31#else
32 full_reset();
33#endif
34}
35
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +010036/**
37 * Dump the ACM error status bits.
38 *
39 * @param acm_error The status register to dump
40 * @return -1 on error (register is not valid)
41 * 0 on error (Class > 0 and Major > 0)
42 * 1 on success (Class == 0 and Major == 0 and progress > 0)
43 */
44int intel_txt_log_acm_error(const uint32_t acm_error)
45{
46 if (!(acm_error & ACMERROR_TXT_VALID))
47 return -1;
48
49 const uint8_t type = (acm_error & ACMERROR_TXT_TYPE_CODE)
50 >> ACMERROR_TXT_TYPE_SHIFT;
51
52 switch (type) {
53 case ACMERROR_TXT_AC_MODULE_TYPE_BIOS:
54 printk(BIOS_ERR, "BIOSACM");
55 break;
56 case ACMERROR_TXT_AC_MODULE_TYPE_SINIT:
57 printk(BIOS_ERR, "SINIT");
58 break;
59 default:
60 printk(BIOS_ERR, "ACM");
61 break;
62 }
63 printk(BIOS_ERR, ": Error code valid\n");
64
65 if (acm_error & ACMERROR_TXT_EXTERNAL)
66 printk(BIOS_ERR, " Caused by: External\n");
67 else
68 printk(BIOS_ERR, " Caused by: Processor\n");
69
70 const uint32_t class = (acm_error & ACMERROR_TXT_CLASS_CODE)
71 >> ACMERROR_TXT_CLASS_SHIFT;
72 const uint32_t major = (acm_error & ACMERROR_TXT_MAJOR_CODE)
73 >> ACMERROR_TXT_MAJOR_SHIFT;
74 const uint32_t minor = (acm_error & ACMERROR_TXT_MINOR_CODE)
75 >> ACMERROR_TXT_MINOR_SHIFT;
76 const uint32_t progress = (acm_error & ACMERROR_TXT_PROGRESS_CODE)
77 >> ACMERROR_TXT_PROGRESS_SHIFT;
78
79 if (!minor) {
80 if (class == 0 && major == 0 && progress > 0) {
81 printk(BIOS_ERR, " Execution successful\n");
82 printk(BIOS_ERR, " Progress code 0x%x\n", progress);
83 } else {
84 printk(BIOS_ERR, " Error Class: %x\n", class);
85 printk(BIOS_ERR, " Error: %x.%x\n", major, progress);
86 }
87 } else {
88 printk(BIOS_ERR, " ACM didn't start\n");
89 printk(BIOS_ERR, " Error Type: 0x%x\n", acm_error & 0xffffff);
90 return -1;
91 }
92
93 return (acm_error & ACMERROR_TXT_EXTERNAL) && class == 0 && major == 0 && progress > 0;
94}
95
96void intel_txt_log_spad(void)
97{
98 const uint64_t acm_status = read64((void *)TXT_SPAD);
99
100 printk(BIOS_INFO, "TXT-STS: ACM verification ");
101
102 if (acm_status & ACMSTS_VERIFICATION_ERROR)
103 printk(BIOS_INFO, "error\n");
104 else
105 printk(BIOS_INFO, "successful\n");
106
107 printk(BIOS_INFO, "TXT-STS: IBB ");
108
109 if (acm_status & ACMSTS_IBB_MEASURED)
110 printk(BIOS_INFO, "measured\n");
111 else
112 printk(BIOS_INFO, "not measured\n");
113
114 printk(BIOS_INFO, "TXT-STS: TXT is ");
115
116 if (acm_status & ACMSTS_TXT_DISABLED)
117 printk(BIOS_INFO, "disabled\n");
118 else
119 printk(BIOS_INFO, "not disabled\n");
120
121 printk(BIOS_INFO, "TXT-STS: BIOS is ");
122
123 if (acm_status & ACMSTS_BIOS_TRUSTED)
124 printk(BIOS_INFO, "trusted\n");
125 else
126 printk(BIOS_INFO, "not trusted\n");
127}
128
129/* Returns true if secrets might be in memory */
130bool intel_txt_memory_has_secrets(void)
131{
132 bool ret;
133 if (!CONFIG(INTEL_TXT))
134 return false;
135
136 ret = (read8((void *)TXT_ESTS) & TXT_ESTS_WAKE_ERROR_STS) ||
137 (read64((void *)TXT_E2STS) & TXT_E2STS_SECRET_STS);
138
139 if (ret)
140 printk(BIOS_CRIT, "TXT-STS: Secrets in memory!\n");
141 return ret;
142}
143
Michał Żygowski9734e802021-11-21 12:29:58 +0100144bool intel_txt_chipset_is_production_fused(void)
145{
146 /*
147 * Certain chipsets report production fused information in either
148 * TXT.VER.FSBIF or TXT.VER.EMIF/TXT.VER.QPIIF.
149 * Chapter B.1.7 and B.1.9
150 * Intel TXT Software Development Guide (Document: 315168-015)
151 */
152 uint32_t reg = read32((void *)TXT_VER_FSBIF);
153
154 if (reg == 0 || reg == UINT32_MAX)
155 reg = read32((void *)TXT_VER_QPIIF);
156
157 return (reg & TXT_VER_PRODUCTION_FUSED) ? true : false;
158}
159
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100160static struct acm_info_table *find_info_table(const void *ptr)
161{
162 const struct acm_header_v0 *acm_header = (struct acm_header_v0 *)ptr;
163
164 return (struct acm_info_table *)(ptr +
165 (acm_header->header_len + acm_header->scratch_size) * sizeof(uint32_t));
166}
167
168/**
Martin Roth50863da2021-10-01 14:37:30 -0600169 * Validate that the provided ACM is usable on this platform.
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100170 */
171static int validate_acm(const void *ptr)
172{
173 const struct acm_header_v0 *acm_header = (struct acm_header_v0 *)ptr;
174 uint32_t max_size_acm_area = 0;
175
176 if (acm_header->module_type != CHIPSET_ACM)
177 return ACM_E_TYPE_NOT_MATCH;
178
179 /* Seems inconsistent across generations. */
180 if (acm_header->module_sub_type != 0 && acm_header->module_sub_type != 1)
181 return ACM_E_MODULE_SUB_TYPE_WRONG;
182
183 if (acm_header->module_vendor != INTEL_ACM_VENDOR)
184 return ACM_E_MODULE_VENDOR_NOT_INTEL;
185
John Zhao536e9652020-08-04 11:29:08 -0700186 if (acm_header->size == 0)
187 return ACM_E_SIZE_INCORRECT;
188
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100189 if (((acm_header->header_len + acm_header->scratch_size) * sizeof(uint32_t) +
190 sizeof(struct acm_info_table)) > (acm_header->size & 0xffffff) * sizeof(uint32_t)) {
191 return ACM_E_SIZE_INCORRECT;
192 }
193
194 if (!getsec_parameter(NULL, NULL, &max_size_acm_area, NULL, NULL, NULL))
195 return ACM_E_CANT_CALL_GETSEC;
196
197 /*
198 * Causes #GP if acm_header->size > processor internal authenticated
199 * code area capacity.
200 * SAFER MODE EXTENSIONS REFERENCE.
201 * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D
202 */
203 const size_t acm_len = 1UL << log2_ceil((acm_header->size & 0xffffff) << 2);
204 if (max_size_acm_area < acm_len) {
205 printk(BIOS_ERR, "TEE-TXT: BIOS ACM doesn't fit into AC execution region\n");
206 return ACM_E_NOT_FIT_INTO_CPU_ACM_MEM;
207 }
208
209 struct acm_info_table *info = find_info_table(ptr);
210 if (!info)
211 return ACM_E_NO_INFO_TABLE;
212 if (info->chipset_acm_type != BIOS)
213 return ACM_E_NOT_BIOS_ACM;
214
215 static const u8 acm_uuid[] = {
216 0xaa, 0x3a, 0xc0, 0x7f, 0xa7, 0x46, 0xdb, 0x18,
217 0x2e, 0xac, 0x69, 0x8f, 0x8d, 0x41, 0x7f, 0x5a,
218 };
219 if (memcmp(acm_uuid, info->uuid, sizeof(acm_uuid)) != 0)
220 return ACM_E_UUID_NOT_MATCH;
221
Michał Żygowski9734e802021-11-21 12:29:58 +0100222 const bool production_acm = !(acm_header->flags & ACM_FORMAT_FLAGS_DEBUG);
223 if (production_acm != intel_txt_chipset_is_production_fused())
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100224 return ACM_E_PLATFORM_IS_NOT_PROD;
225
226 return 0;
227}
228
229/*
Angel Pons7b4d67cf2020-10-20 14:17:42 +0200230 * Prepare to run the BIOS ACM: mmap it from the CBFS and verify that it
231 * can be launched. Returns pointer to ACM on success, NULL on failure.
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100232 */
Angel Pons7b4d67cf2020-10-20 14:17:42 +0200233static void *intel_txt_prepare_bios_acm(struct region_device *acm, size_t *acm_len)
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100234{
Angel Pons7b4d67cf2020-10-20 14:17:42 +0200235 void *acm_data = NULL;
236
237 if (!acm || !acm_len)
238 return NULL;
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100239
Julius Werner77639e42021-02-05 16:51:25 -0800240 acm_data = cbfs_map(CONFIG_INTEL_TXT_CBFS_BIOS_ACM, acm_len);
241 if (!acm_data) {
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100242 printk(BIOS_ERR, "TEE-TXT: Couldn't locate BIOS ACM in CBFS.\n");
Angel Pons7b4d67cf2020-10-20 14:17:42 +0200243 return NULL;
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100244 }
245
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100246 /*
247 * CPU enforces only 4KiB alignment.
248 * Chapter A.1.1
249 * Intel TXT Software Development Guide (Document: 315168-015)
250 */
251 if (!IS_ALIGNED((uintptr_t)acm_data, 4096)) {
252 printk(BIOS_ERR, "TEE-TXT: BIOS ACM isn't mapped at page boundary.\n");
Julius Werner77639e42021-02-05 16:51:25 -0800253 cbfs_unmap(acm_data);
Angel Pons7b4d67cf2020-10-20 14:17:42 +0200254 return NULL;
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100255 }
256
257 /*
258 * Causes #GP if not multiple of 64.
259 * SAFER MODE EXTENSIONS REFERENCE.
260 * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D
261 */
Angel Pons7b4d67cf2020-10-20 14:17:42 +0200262 if (!IS_ALIGNED(*acm_len, 64)) {
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100263 printk(BIOS_ERR, "TEE-TXT: BIOS ACM size isn't multiple of 64.\n");
Julius Werner77639e42021-02-05 16:51:25 -0800264 cbfs_unmap(acm_data);
Angel Pons7b4d67cf2020-10-20 14:17:42 +0200265 return NULL;
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100266 }
267
268 /*
269 * The ACM should be aligned to it's size, but that's not possible, as
270 * some ACMs are not power of two. Use the next power of two for verification.
271 */
Angel Pons7b4d67cf2020-10-20 14:17:42 +0200272 if (!IS_ALIGNED((uintptr_t)acm_data, (1UL << log2_ceil(*acm_len)))) {
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100273 printk(BIOS_ERR, "TEE-TXT: BIOS ACM isn't aligned to its size.\n");
Julius Werner77639e42021-02-05 16:51:25 -0800274 cbfs_unmap(acm_data);
Angel Pons7b4d67cf2020-10-20 14:17:42 +0200275 return NULL;
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100276 }
277
Angel Pons038cef92020-10-14 17:58:36 +0200278 /*
279 * When setting up the MTRRs to cache the BIOS ACM, one must cache less than
280 * a page (4 KiB) of unused memory after the BIOS ACM. On Haswell, failure
281 * to do so will cause a TXT reset with Class Code 5, Major Error Code 2.
282 */
Angel Pons7b4d67cf2020-10-20 14:17:42 +0200283 if (popcnt(ALIGN_UP(*acm_len, 4096)) > get_var_mtrr_count()) {
Angel Pons038cef92020-10-14 17:58:36 +0200284 printk(BIOS_ERR, "TEE-TXT: Not enough MTRRs to cache this BIOS ACM's size.\n");
Julius Werner77639e42021-02-05 16:51:25 -0800285 cbfs_unmap(acm_data);
Angel Pons7b4d67cf2020-10-20 14:17:42 +0200286 return NULL;
Angel Pons038cef92020-10-14 17:58:36 +0200287 }
288
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100289 if (CONFIG(INTEL_TXT_LOGGING))
290 txt_dump_acm_info(acm_data);
291
Angel Pons7b4d67cf2020-10-20 14:17:42 +0200292 const int ret = validate_acm(acm_data);
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100293 if (ret < 0) {
294 printk(BIOS_ERR, "TEE-TXT: Validation of ACM failed with: %d\n", ret);
Julius Werner77639e42021-02-05 16:51:25 -0800295 cbfs_unmap(acm_data);
Angel Pons7b4d67cf2020-10-20 14:17:42 +0200296 return NULL;
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100297 }
298
Angel Pons7b4d67cf2020-10-20 14:17:42 +0200299 return acm_data;
300}
301
Angel Pons6c49f402020-08-28 02:02:00 +0200302#define MCU_BASE_ADDR (TXT_BASE + 0x278)
303#define BIOACM_ADDR (TXT_BASE + 0x27c)
304#define APINIT_ADDR (TXT_BASE + 0x290)
305#define SEMAPHORE (TXT_BASE + 0x294)
306
307/* Returns on failure, resets the computer on success */
308void intel_txt_run_sclean(void)
309{
310 struct region_device acm;
311 size_t acm_len;
312
313 void *acm_data = intel_txt_prepare_bios_acm(&acm, &acm_len);
314
315 if (!acm_data)
316 return;
317
318 /* FIXME: Do we need to program these two? */
319 //write32((void *)MCU_BASE_ADDR, 0xffe1a990);
320 //write32((void *)APINIT_ADDR, 0xfffffff0);
321
322 write32((void *)BIOACM_ADDR, (uintptr_t)acm_data);
323 write32((void *)SEMAPHORE, 0);
324
325 /*
326 * The time SCLEAN will take depends on the installed RAM size.
327 * On Haswell with 8 GiB of DDR3, it takes five or ten minutes. (rough estimate)
328 */
329 printk(BIOS_ALERT, "TEE-TXT: Invoking SCLEAN. This can take several minutes.\n");
330
331 /*
332 * Invoke the BIOS ACM. If successful, the system will reset with memory unlocked.
333 */
334 getsec_sclean((uintptr_t)acm_data, acm_len);
335
336 /*
337 * However, if this function returns, the BIOS ACM could not be invoked. This is bad.
338 */
339 printk(BIOS_CRIT, "TEE-TXT: getsec_sclean could not launch the BIOS ACM.\n");
340
341 rdev_munmap(&acm, acm_data);
342}
343
Angel Pons7b4d67cf2020-10-20 14:17:42 +0200344/*
345 * Test all bits for TXT execution.
346 *
347 * @return 0 on success
348 */
349int intel_txt_run_bios_acm(const u8 input_params)
350{
351 struct region_device acm;
352 size_t acm_len;
353
354 void *acm_data = intel_txt_prepare_bios_acm(&acm, &acm_len);
355
356 if (!acm_data)
357 return -1;
358
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100359 /* Call into assembly which invokes the referenced ACM */
360 getsec_enteraccs(input_params, (uintptr_t)acm_data, acm_len);
361
362 rdev_munmap(&acm, acm_data);
363
364 const uint64_t acm_status = read64((void *)TXT_SPAD);
365 if (acm_status & ACMERROR_TXT_VALID) {
366 printk(BIOS_ERR, "TEE-TXT: FATAL ACM launch error !\n");
367 /*
368 * WARNING !
369 * To clear TXT.BIOSACM.ERRORCODE you must issue a cold reboot!
370 */
371 intel_txt_log_acm_error(read32((void *)TXT_BIOSACM_ERRORCODE));
372 return -1;
373 }
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100374
375 return 0;
376}
377
378 /* Returns true if cond is not met */
379static bool check_precondition(const int cond)
380{
381 printk(BIOS_DEBUG, "%s\n", cond ? "true" : "false");
382 return !cond;
383}
384
385/*
386 * Test all bits that are required for Intel TXT.
387 * Enable SMX if available.
388 *
389 * @return 0 on success
390 */
391bool intel_txt_prepare_txt_env(void)
392{
393 bool failure = false;
394 uint32_t txt_feature_flags = 0;
395
396 unsigned int ecx = cpuid_ecx(1);
397
398 printk(BIOS_DEBUG, "TEE-TXT: CPU supports SMX: ");
399 failure |= check_precondition(ecx & CPUID_SMX);
400
401 printk(BIOS_DEBUG, "TEE-TXT: CPU supports VMX: ");
402 failure |= check_precondition(ecx & CPUID_VMX);
403
404 msr_t msr = rdmsr(IA32_FEATURE_CONTROL);
405 if (!(msr.lo & BIT(0))) {
406 printk(BIOS_ERR, "TEE-TXT: IA32_FEATURE_CONTROL is not locked\n");
Angel Pons1fc43aa2020-08-04 17:54:01 +0200407 txt_reset_platform();
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100408 }
409
410 printk(BIOS_DEBUG, "TEE-TXT: IA32_FEATURE_CONTROL\n");
411 printk(BIOS_DEBUG, " VMXON in SMX enable: ");
412 failure |= check_precondition(msr.lo & BIT(1));
413
414 printk(BIOS_DEBUG, " VMXON outside SMX enable: ");
415 failure |= check_precondition(msr.lo & FEATURE_ENABLE_VMX);
416
417 printk(BIOS_DEBUG, " register is locked: ");
418 failure |= check_precondition(msr.lo & BIT(0));
419
420 /* IA32_FEATURE_CONTROL enables getsec instructions */
421 printk(BIOS_DEBUG, " GETSEC (all instructions) is enabled: ");
422 failure |= check_precondition((msr.lo & 0xff00) == 0xff00);
423
424 /* Prevent crash and opt out early */
425 if (failure)
426 return true;
427
428 uint32_t eax = 0;
429 /*
430 * GetSec[CAPABILITIES]
431 * SAFER MODE EXTENSIONS REFERENCE.
432 * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D
433 * Must check BIT0 of TXT chipset has been detected by CPU.
434 */
435 if (!getsec_capabilities(&eax))
436 return true;
437
438 printk(BIOS_DEBUG, "TEE-TXT: GETSEC[CAPABILITIES] returned:\n");
439 printk(BIOS_DEBUG, " TXT capable chipset: %s\n", (eax & BIT(0)) ? "true" : "false");
440
441 printk(BIOS_DEBUG, " ENTERACCS available: %s\n", (eax & BIT(2)) ? "true" : "false");
442 printk(BIOS_DEBUG, " EXITAC available: %s\n", (eax & BIT(3)) ? "true" : "false");
443 printk(BIOS_DEBUG, " SENTER available: %s\n", (eax & BIT(4)) ? "true" : "false");
444 printk(BIOS_DEBUG, " SEXIT available: %s\n", (eax & BIT(5)) ? "true" : "false");
445 printk(BIOS_DEBUG, " PARAMETERS available: %s\n", (eax & BIT(6)) ? "true" : "false");
446
447 /*
448 * Causes #GP if function is not supported by getsec.
449 * SAFER MODE EXTENSIONS REFERENCE.
450 * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D
451 * Order Number: 325383-060US
452 */
453 if ((eax & 0x7d) != 0x7d)
454 failure = true;
455
456 const uint64_t status = read64((void *)TXT_SPAD);
457
458 if (status & ACMSTS_TXT_DISABLED) {
459 printk(BIOS_INFO, "TEE-TXT: TXT disabled by BIOS policy in FIT.\n");
460 failure = true;
461 }
462
463 /*
464 * Only the BSP must call getsec[ENTERACCS].
465 * SAFER MODE EXTENSIONS REFERENCE.
466 * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D
467 * Order Number: 325383-060US
468 */
469 if (!boot_cpu()) {
470 printk(BIOS_ERR, "TEE-TXT: BSP flag not set in APICBASE_MSR.\n");
471 failure = true;
472 }
473
474 /*
475 * There must be no MCEs pending.
476 * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D
477 * Order Number: 325383-060US
478 */
479 msr = rdmsr(IA32_MCG_STATUS);
480 if (msr.lo & 0x4) {
481 printk(BIOS_ERR, "TEE-TXT: IA32_MCG_STATUS.MCIP is set.\n");
482 failure = true;
483 }
484
485 if (!getsec_parameter(NULL, NULL, NULL, NULL, NULL, &txt_feature_flags)) {
486 return true;
487 } else {
488 printk(BIOS_DEBUG, "TEE-TXT: Machine Check Register: ");
489 if (txt_feature_flags & GETSEC_PARAMS_TXT_EXT_MACHINE_CHECK)
490 printk(BIOS_DEBUG, "preserved\n");
491 else
492 printk(BIOS_DEBUG, "must be clear\n");
493 }
494
495 if (!(txt_feature_flags & GETSEC_PARAMS_TXT_EXT_MACHINE_CHECK)) {
496 /*
497 * Make sure there are no uncorrectable MCE errors.
498 * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D
499 */
Felix Held7cf37872021-07-09 23:05:21 +0200500 size_t max_mc_msr = mca_get_bank_count();
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100501 for (size_t i = 0; i < max_mc_msr; i++) {
Felix Held1b46e762021-07-13 00:54:32 +0200502 msr = rdmsr(IA32_MC_STATUS(i));
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100503 if (!(msr.hi & MCA_STATUS_HI_UC))
504 continue;
505
506 printk(BIOS_ERR, "TEE-TXT: IA32_MC%zd_STATUS.UC is set.\n", i);
507 failure = true;
508 break;
509 }
510 }
511
512 /* Need to park all APs. */
513 if (CONFIG(PARALLEL_MP_AP_WORK))
514 mp_park_aps();
515
516 return failure;
517}