blob: e73defb912dd8b91eddd9677f7fe6c23b3dc09c9 [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>
9#include <lib.h>
10#include <smp/node.h>
Angel Pons52082be2020-10-05 12:34:29 +020011#include <string.h>
12#include <types.h>
Angel Pons1fc43aa2020-08-04 17:54:01 +020013
14#if CONFIG(SOC_INTEL_COMMON_BLOCK_SA)
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +010015#include <soc/intel/common/reset.h>
Angel Pons1fc43aa2020-08-04 17:54:01 +020016#else
17#include <cf9_reset.h>
18#endif
19
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +010020#include "txt.h"
21#include "txt_register.h"
22#include "txt_getsec.h"
23
Angel Pons1fc43aa2020-08-04 17:54:01 +020024/* Usual security practice: if an unexpected error happens, reboot */
25static void __noreturn txt_reset_platform(void)
26{
27#if CONFIG(SOC_INTEL_COMMON_BLOCK_SA)
28 global_reset();
29#else
30 full_reset();
31#endif
32}
33
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +010034/**
35 * Dump the ACM error status bits.
36 *
37 * @param acm_error The status register to dump
38 * @return -1 on error (register is not valid)
39 * 0 on error (Class > 0 and Major > 0)
40 * 1 on success (Class == 0 and Major == 0 and progress > 0)
41 */
42int intel_txt_log_acm_error(const uint32_t acm_error)
43{
44 if (!(acm_error & ACMERROR_TXT_VALID))
45 return -1;
46
47 const uint8_t type = (acm_error & ACMERROR_TXT_TYPE_CODE)
48 >> ACMERROR_TXT_TYPE_SHIFT;
49
50 switch (type) {
51 case ACMERROR_TXT_AC_MODULE_TYPE_BIOS:
52 printk(BIOS_ERR, "BIOSACM");
53 break;
54 case ACMERROR_TXT_AC_MODULE_TYPE_SINIT:
55 printk(BIOS_ERR, "SINIT");
56 break;
57 default:
58 printk(BIOS_ERR, "ACM");
59 break;
60 }
61 printk(BIOS_ERR, ": Error code valid\n");
62
63 if (acm_error & ACMERROR_TXT_EXTERNAL)
64 printk(BIOS_ERR, " Caused by: External\n");
65 else
66 printk(BIOS_ERR, " Caused by: Processor\n");
67
68 const uint32_t class = (acm_error & ACMERROR_TXT_CLASS_CODE)
69 >> ACMERROR_TXT_CLASS_SHIFT;
70 const uint32_t major = (acm_error & ACMERROR_TXT_MAJOR_CODE)
71 >> ACMERROR_TXT_MAJOR_SHIFT;
72 const uint32_t minor = (acm_error & ACMERROR_TXT_MINOR_CODE)
73 >> ACMERROR_TXT_MINOR_SHIFT;
74 const uint32_t progress = (acm_error & ACMERROR_TXT_PROGRESS_CODE)
75 >> ACMERROR_TXT_PROGRESS_SHIFT;
76
77 if (!minor) {
78 if (class == 0 && major == 0 && progress > 0) {
79 printk(BIOS_ERR, " Execution successful\n");
80 printk(BIOS_ERR, " Progress code 0x%x\n", progress);
81 } else {
82 printk(BIOS_ERR, " Error Class: %x\n", class);
83 printk(BIOS_ERR, " Error: %x.%x\n", major, progress);
84 }
85 } else {
86 printk(BIOS_ERR, " ACM didn't start\n");
87 printk(BIOS_ERR, " Error Type: 0x%x\n", acm_error & 0xffffff);
88 return -1;
89 }
90
91 return (acm_error & ACMERROR_TXT_EXTERNAL) && class == 0 && major == 0 && progress > 0;
92}
93
94void intel_txt_log_spad(void)
95{
96 const uint64_t acm_status = read64((void *)TXT_SPAD);
97
98 printk(BIOS_INFO, "TXT-STS: ACM verification ");
99
100 if (acm_status & ACMSTS_VERIFICATION_ERROR)
101 printk(BIOS_INFO, "error\n");
102 else
103 printk(BIOS_INFO, "successful\n");
104
105 printk(BIOS_INFO, "TXT-STS: IBB ");
106
107 if (acm_status & ACMSTS_IBB_MEASURED)
108 printk(BIOS_INFO, "measured\n");
109 else
110 printk(BIOS_INFO, "not measured\n");
111
112 printk(BIOS_INFO, "TXT-STS: TXT is ");
113
114 if (acm_status & ACMSTS_TXT_DISABLED)
115 printk(BIOS_INFO, "disabled\n");
116 else
117 printk(BIOS_INFO, "not disabled\n");
118
119 printk(BIOS_INFO, "TXT-STS: BIOS is ");
120
121 if (acm_status & ACMSTS_BIOS_TRUSTED)
122 printk(BIOS_INFO, "trusted\n");
123 else
124 printk(BIOS_INFO, "not trusted\n");
125}
126
127/* Returns true if secrets might be in memory */
128bool intel_txt_memory_has_secrets(void)
129{
130 bool ret;
131 if (!CONFIG(INTEL_TXT))
132 return false;
133
134 ret = (read8((void *)TXT_ESTS) & TXT_ESTS_WAKE_ERROR_STS) ||
135 (read64((void *)TXT_E2STS) & TXT_E2STS_SECRET_STS);
136
137 if (ret)
138 printk(BIOS_CRIT, "TXT-STS: Secrets in memory!\n");
139 return ret;
140}
141
142static struct acm_info_table *find_info_table(const void *ptr)
143{
144 const struct acm_header_v0 *acm_header = (struct acm_header_v0 *)ptr;
145
146 return (struct acm_info_table *)(ptr +
147 (acm_header->header_len + acm_header->scratch_size) * sizeof(uint32_t));
148}
149
150/**
151 * Validate that the provided ACM is useable on this platform.
152 */
153static int validate_acm(const void *ptr)
154{
155 const struct acm_header_v0 *acm_header = (struct acm_header_v0 *)ptr;
156 uint32_t max_size_acm_area = 0;
157
158 if (acm_header->module_type != CHIPSET_ACM)
159 return ACM_E_TYPE_NOT_MATCH;
160
161 /* Seems inconsistent across generations. */
162 if (acm_header->module_sub_type != 0 && acm_header->module_sub_type != 1)
163 return ACM_E_MODULE_SUB_TYPE_WRONG;
164
165 if (acm_header->module_vendor != INTEL_ACM_VENDOR)
166 return ACM_E_MODULE_VENDOR_NOT_INTEL;
167
John Zhao536e9652020-08-04 11:29:08 -0700168 if (acm_header->size == 0)
169 return ACM_E_SIZE_INCORRECT;
170
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100171 if (((acm_header->header_len + acm_header->scratch_size) * sizeof(uint32_t) +
172 sizeof(struct acm_info_table)) > (acm_header->size & 0xffffff) * sizeof(uint32_t)) {
173 return ACM_E_SIZE_INCORRECT;
174 }
175
176 if (!getsec_parameter(NULL, NULL, &max_size_acm_area, NULL, NULL, NULL))
177 return ACM_E_CANT_CALL_GETSEC;
178
179 /*
180 * Causes #GP if acm_header->size > processor internal authenticated
181 * code area capacity.
182 * SAFER MODE EXTENSIONS REFERENCE.
183 * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D
184 */
185 const size_t acm_len = 1UL << log2_ceil((acm_header->size & 0xffffff) << 2);
186 if (max_size_acm_area < acm_len) {
187 printk(BIOS_ERR, "TEE-TXT: BIOS ACM doesn't fit into AC execution region\n");
188 return ACM_E_NOT_FIT_INTO_CPU_ACM_MEM;
189 }
190
191 struct acm_info_table *info = find_info_table(ptr);
192 if (!info)
193 return ACM_E_NO_INFO_TABLE;
194 if (info->chipset_acm_type != BIOS)
195 return ACM_E_NOT_BIOS_ACM;
196
197 static const u8 acm_uuid[] = {
198 0xaa, 0x3a, 0xc0, 0x7f, 0xa7, 0x46, 0xdb, 0x18,
199 0x2e, 0xac, 0x69, 0x8f, 0x8d, 0x41, 0x7f, 0x5a,
200 };
201 if (memcmp(acm_uuid, info->uuid, sizeof(acm_uuid)) != 0)
202 return ACM_E_UUID_NOT_MATCH;
203
204 if ((acm_header->flags & ACM_FORMAT_FLAGS_DEBUG) ==
205 (read64((void *)TXT_VER_FSBIF) & TXT_VER_PRODUCTION_FUSED))
206 return ACM_E_PLATFORM_IS_NOT_PROD;
207
208 return 0;
209}
210
211/*
212 * Test all bits for TXT execution.
213 *
214 * @return 0 on success
215 */
216int intel_txt_run_bios_acm(const u8 input_params)
217{
218 struct cbfsf file;
219 void *acm_data;
220 struct region_device acm;
221 size_t acm_len;
222 int ret;
223
224 if (cbfs_boot_locate(&file, CONFIG_INTEL_TXT_CBFS_BIOS_ACM, NULL)) {
225 printk(BIOS_ERR, "TEE-TXT: Couldn't locate BIOS ACM in CBFS.\n");
226 return -1;
227 }
228
229 cbfs_file_data(&acm, &file);
230 acm_data = rdev_mmap_full(&acm);
231 acm_len = region_device_sz(&acm);
232 if (!acm_data || acm_len == 0) {
233 printk(BIOS_ERR, "TEE-TXT: Couldn't map BIOS ACM from CBFS.\n");
234 return -1;
235 }
236
237 /*
238 * CPU enforces only 4KiB alignment.
239 * Chapter A.1.1
240 * Intel TXT Software Development Guide (Document: 315168-015)
241 */
242 if (!IS_ALIGNED((uintptr_t)acm_data, 4096)) {
243 printk(BIOS_ERR, "TEE-TXT: BIOS ACM isn't mapped at page boundary.\n");
244 rdev_munmap(&acm, acm_data);
245 return -1;
246 }
247
248 /*
249 * Causes #GP if not multiple of 64.
250 * SAFER MODE EXTENSIONS REFERENCE.
251 * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D
252 */
253 if (!IS_ALIGNED(acm_len, 64)) {
254 printk(BIOS_ERR, "TEE-TXT: BIOS ACM size isn't multiple of 64.\n");
255 rdev_munmap(&acm, acm_data);
256 return -1;
257 }
258
259 /*
260 * The ACM should be aligned to it's size, but that's not possible, as
261 * some ACMs are not power of two. Use the next power of two for verification.
262 */
263 if (!IS_ALIGNED((uintptr_t)acm_data, (1UL << log2_ceil(acm_len)))) {
264 printk(BIOS_ERR, "TEE-TXT: BIOS ACM isn't aligned to its size.\n");
265 rdev_munmap(&acm, acm_data);
266 return -1;
267 }
268
269 if (CONFIG(INTEL_TXT_LOGGING))
270 txt_dump_acm_info(acm_data);
271
272 ret = validate_acm(acm_data);
273 if (ret < 0) {
274 printk(BIOS_ERR, "TEE-TXT: Validation of ACM failed with: %d\n", ret);
275 rdev_munmap(&acm, acm_data);
276 return ret;
277 }
278
279 /* Call into assembly which invokes the referenced ACM */
280 getsec_enteraccs(input_params, (uintptr_t)acm_data, acm_len);
281
282 rdev_munmap(&acm, acm_data);
283
284 const uint64_t acm_status = read64((void *)TXT_SPAD);
285 if (acm_status & ACMERROR_TXT_VALID) {
286 printk(BIOS_ERR, "TEE-TXT: FATAL ACM launch error !\n");
287 /*
288 * WARNING !
289 * To clear TXT.BIOSACM.ERRORCODE you must issue a cold reboot!
290 */
291 intel_txt_log_acm_error(read32((void *)TXT_BIOSACM_ERRORCODE));
292 return -1;
293 }
294 if (intel_txt_log_acm_error(read32((void *)TXT_BIOSACM_ERRORCODE)) != 1)
295 return -1;
296
297 return 0;
298}
299
300 /* Returns true if cond is not met */
301static bool check_precondition(const int cond)
302{
303 printk(BIOS_DEBUG, "%s\n", cond ? "true" : "false");
304 return !cond;
305}
306
307/*
308 * Test all bits that are required for Intel TXT.
309 * Enable SMX if available.
310 *
311 * @return 0 on success
312 */
313bool intel_txt_prepare_txt_env(void)
314{
315 bool failure = false;
316 uint32_t txt_feature_flags = 0;
317
318 unsigned int ecx = cpuid_ecx(1);
319
320 printk(BIOS_DEBUG, "TEE-TXT: CPU supports SMX: ");
321 failure |= check_precondition(ecx & CPUID_SMX);
322
323 printk(BIOS_DEBUG, "TEE-TXT: CPU supports VMX: ");
324 failure |= check_precondition(ecx & CPUID_VMX);
325
326 msr_t msr = rdmsr(IA32_FEATURE_CONTROL);
327 if (!(msr.lo & BIT(0))) {
328 printk(BIOS_ERR, "TEE-TXT: IA32_FEATURE_CONTROL is not locked\n");
Angel Pons1fc43aa2020-08-04 17:54:01 +0200329 txt_reset_platform();
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100330 }
331
332 printk(BIOS_DEBUG, "TEE-TXT: IA32_FEATURE_CONTROL\n");
333 printk(BIOS_DEBUG, " VMXON in SMX enable: ");
334 failure |= check_precondition(msr.lo & BIT(1));
335
336 printk(BIOS_DEBUG, " VMXON outside SMX enable: ");
337 failure |= check_precondition(msr.lo & FEATURE_ENABLE_VMX);
338
339 printk(BIOS_DEBUG, " register is locked: ");
340 failure |= check_precondition(msr.lo & BIT(0));
341
342 /* IA32_FEATURE_CONTROL enables getsec instructions */
343 printk(BIOS_DEBUG, " GETSEC (all instructions) is enabled: ");
344 failure |= check_precondition((msr.lo & 0xff00) == 0xff00);
345
346 /* Prevent crash and opt out early */
347 if (failure)
348 return true;
349
350 uint32_t eax = 0;
351 /*
352 * GetSec[CAPABILITIES]
353 * SAFER MODE EXTENSIONS REFERENCE.
354 * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D
355 * Must check BIT0 of TXT chipset has been detected by CPU.
356 */
357 if (!getsec_capabilities(&eax))
358 return true;
359
360 printk(BIOS_DEBUG, "TEE-TXT: GETSEC[CAPABILITIES] returned:\n");
361 printk(BIOS_DEBUG, " TXT capable chipset: %s\n", (eax & BIT(0)) ? "true" : "false");
362
363 printk(BIOS_DEBUG, " ENTERACCS available: %s\n", (eax & BIT(2)) ? "true" : "false");
364 printk(BIOS_DEBUG, " EXITAC available: %s\n", (eax & BIT(3)) ? "true" : "false");
365 printk(BIOS_DEBUG, " SENTER available: %s\n", (eax & BIT(4)) ? "true" : "false");
366 printk(BIOS_DEBUG, " SEXIT available: %s\n", (eax & BIT(5)) ? "true" : "false");
367 printk(BIOS_DEBUG, " PARAMETERS available: %s\n", (eax & BIT(6)) ? "true" : "false");
368
369 /*
370 * Causes #GP if function is not supported by getsec.
371 * SAFER MODE EXTENSIONS REFERENCE.
372 * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D
373 * Order Number: 325383-060US
374 */
375 if ((eax & 0x7d) != 0x7d)
376 failure = true;
377
378 const uint64_t status = read64((void *)TXT_SPAD);
379
380 if (status & ACMSTS_TXT_DISABLED) {
381 printk(BIOS_INFO, "TEE-TXT: TXT disabled by BIOS policy in FIT.\n");
382 failure = true;
383 }
384
385 /*
386 * Only the BSP must call getsec[ENTERACCS].
387 * SAFER MODE EXTENSIONS REFERENCE.
388 * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D
389 * Order Number: 325383-060US
390 */
391 if (!boot_cpu()) {
392 printk(BIOS_ERR, "TEE-TXT: BSP flag not set in APICBASE_MSR.\n");
393 failure = true;
394 }
395
396 /*
397 * There must be no MCEs pending.
398 * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D
399 * Order Number: 325383-060US
400 */
401 msr = rdmsr(IA32_MCG_STATUS);
402 if (msr.lo & 0x4) {
403 printk(BIOS_ERR, "TEE-TXT: IA32_MCG_STATUS.MCIP is set.\n");
404 failure = true;
405 }
406
407 if (!getsec_parameter(NULL, NULL, NULL, NULL, NULL, &txt_feature_flags)) {
408 return true;
409 } else {
410 printk(BIOS_DEBUG, "TEE-TXT: Machine Check Register: ");
411 if (txt_feature_flags & GETSEC_PARAMS_TXT_EXT_MACHINE_CHECK)
412 printk(BIOS_DEBUG, "preserved\n");
413 else
414 printk(BIOS_DEBUG, "must be clear\n");
415 }
416
417 if (!(txt_feature_flags & GETSEC_PARAMS_TXT_EXT_MACHINE_CHECK)) {
418 /*
419 * Make sure there are no uncorrectable MCE errors.
420 * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D
421 */
422 msr = rdmsr(IA32_MCG_CAP);
423 size_t max_mc_msr = msr.lo & MCA_BANKS_MASK;
424 for (size_t i = 0; i < max_mc_msr; i++) {
425 msr = rdmsr(IA32_MC0_STATUS + 4 * i);
426 if (!(msr.hi & MCA_STATUS_HI_UC))
427 continue;
428
429 printk(BIOS_ERR, "TEE-TXT: IA32_MC%zd_STATUS.UC is set.\n", i);
430 failure = true;
431 break;
432 }
433 }
434
435 /* Need to park all APs. */
436 if (CONFIG(PARALLEL_MP_AP_WORK))
437 mp_park_aps();
438
439 return failure;
440}