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