xref: /aosp_15_r20/external/coreboot/src/security/intel/txt/logging.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <console/console.h>
4 #include <cpu/x86/smm.h>
5 #include <device/mmio.h>
6 #include <types.h>
7 
8 #include "txt.h"
9 #include "txt_getsec.h"
10 #include "txt_register.h"
11 
intel_txt_processor_error_type(uint8_t type)12 const char *intel_txt_processor_error_type(uint8_t type)
13 {
14 	static const char *const names[] = {
15 		[0]  = "Legacy Shutdown",
16 		[5]  = "Load memory type error in ACM area",
17 		[6]  = "Unrecognized ACM format",
18 		[7]  = "Failure to authenticate",
19 		[8]  = "Invalid ACM format",
20 		[9]  = "Unexpected Snoop hit",
21 		[10] = "Invalid event",
22 		[11] = "Invalid MLE",
23 		[12] = "Machine check event",
24 		[13] = "VMXAbort",
25 		[14] = "AC memory corruption",
26 		[15] = "Illegal voltage/bus ratio",
27 	};
28 
29 	return type < ARRAY_SIZE(names) && names[type] ? names[type] : "Unknown";
30 }
31 
32 /**
33  * Logs microcode or SINIT ACM errors.
34  * Does not log SBIOS ACM errors.
35  */
log_txt_error(const char * phase)36 static void log_txt_error(const char *phase)
37 {
38 	const uint64_t txt_error = read64p(TXT_ERROR);
39 
40 	if (txt_error & ACMERROR_TXT_VALID) {
41 		printk(BIOS_ERR, "%s: Error occurred\n", phase);
42 
43 		if (txt_error & ACMERROR_TXT_EXTERNAL)
44 			printk(BIOS_ERR, " Caused by: External\n");
45 		else
46 			printk(BIOS_ERR, " Caused by: Processor\n");
47 
48 		printk(BIOS_ERR, " Type: %s\n",
49 		       intel_txt_processor_error_type(txt_error & TXT_ERROR_MASK));
50 	}
51 }
52 
53 /**
54  * Dump useful informaation about the BIOS ACM state.
55  * Should run right after console_init() in romstage.
56  * Resets the platform if TXT reset is active and MLE cannot be established.
57  **/
intel_txt_log_bios_acm_error(void)58 void intel_txt_log_bios_acm_error(void)
59 {
60 	uint32_t bios_acm_error;
61 	uint64_t acm_status;
62 	uint64_t txt_error;
63 
64 	printk(BIOS_INFO, "TEE-TXT: State of ACM and ucode update:\n");
65 
66 	bios_acm_error = read32p(TXT_BIOSACM_ERRORCODE);
67 	acm_status = read64p(TXT_SPAD);
68 	txt_error = read64p(TXT_ERROR);
69 
70 	/* Errors by BIOS ACM or FIT */
71 	if ((txt_error & ACMERROR_TXT_VALID) &&
72 	    (acm_status & ACMERROR_TXT_VALID)) {
73 		intel_txt_log_acm_error(bios_acm_error);
74 		log_txt_error("FIT MICROCODE");
75 	}
76 	/* Errors by SINIT */
77 	if ((txt_error & ACMERROR_TXT_VALID) &&
78 	    !(acm_status & ACMERROR_TXT_VALID)) {
79 		intel_txt_log_acm_error(txt_error);
80 		log_txt_error("SINIT");
81 	}
82 
83 	/* Check for fatal ACM error and TXT reset */
84 	uint8_t error = read8p(TXT_ESTS);
85 	if (error & TXT_ESTS_TXT_RESET_STS) {
86 		printk(BIOS_CRIT, "TXT-STS: Intel TXT reset detected\n");
87 		intel_txt_log_acm_error(read32p(TXT_ERROR));
88 	}
89 }
90 
91 /**
92  * Dump information about the provided ACM.
93  */
txt_dump_acm_info(const struct acm_header_v0 * acm_header)94 void txt_dump_acm_info(const struct acm_header_v0 *acm_header)
95 {
96 	const struct acm_info_table *info = NULL;
97 	if (!acm_header)
98 		return;
99 
100 	printk(BIOS_INFO, "ACM @ %p\n", acm_header);
101 
102 	const size_t acm_size = (acm_header->size & 0xffffff) << 2;
103 	const size_t info_off = (acm_header->header_len + acm_header->scratch_size) * 4;
104 
105 	if (acm_size > (info_off + sizeof(struct acm_info_table)))
106 		info = (const struct acm_info_table *)
107 			((const unsigned char *)acm_header + info_off);
108 
109 	printk(BIOS_INFO, " ACM:      Binary Info\n");
110 	if (acm_header->module_type == CHIPSET_ACM)
111 		printk(BIOS_INFO, " Type:     Chipset ACM\n");
112 
113 	if (acm_header->module_sub_type == 0)
114 		printk(BIOS_INFO, " Subtype:  undefined\n");
115 	else if (acm_header->module_sub_type == 1)
116 		printk(BIOS_INFO, " Subtype:  Run at reset\n");
117 
118 	printk(BIOS_INFO, " Header:   v%u.%u\n", acm_header->header_version[0],
119 	       acm_header->header_version[1]);
120 
121 	printk(BIOS_INFO, " Chipset:  %x\n", acm_header->chipset_id);
122 	printk(BIOS_INFO, " Size:     %zu\n", acm_size);
123 
124 	switch (acm_header->flags) {
125 	case ACM_FORMAT_FLAGS_PW:
126 		printk(BIOS_INFO, " Flags:    PW signed (Production Worthy)\n");
127 		break;
128 	case ACM_FORMAT_FLAGS_NPW:
129 		printk(BIOS_INFO, " Flags:    NPW signed (Non Production Worthy)\n");
130 		break;
131 	case ACM_FORMAT_FLAGS_DEBUG:
132 		printk(BIOS_INFO, " Flags:    Debug signed\n");
133 		break;
134 	}
135 
136 	if (acm_header->module_vendor == INTEL_ACM_VENDOR)
137 		printk(BIOS_INFO, " Vendor:   Intel Corporation\n");
138 
139 	printk(BIOS_INFO, " Date:     %x\n", acm_header->date);
140 
141 	switch (acm_header->size) {
142 	case ACM_FORMAT_SIZE_64KB:
143 			printk(BIOS_INFO, " Size:     64KB\n");
144 			printk(BIOS_INFO, " CBnT:     no\n");
145 		break;
146 	case ACM_FORMAT_SIZE_128KB:
147 			printk(BIOS_INFO, " Size:     128KB\n");
148 			printk(BIOS_INFO, " CBnT:     no\n");
149 		break;
150 	case ACM_FORMAT_SIZE_256KB:
151 			printk(BIOS_INFO, " Size:     256KB\n");
152 			printk(BIOS_INFO, " CBnT:     yes\n");
153 		break;
154 	default:
155 			printk(BIOS_INFO, " Size:     0x%08x\n", acm_header->size);
156 
157 		break;
158 	}
159 
160 	printk(BIOS_INFO, " TXT SVN:  %u\n", acm_header->txt_svn);
161 	printk(BIOS_INFO, " SE SVN:   %u\n", acm_header->se_svn);
162 
163 	if (!info)
164 		return;
165 	printk(BIOS_INFO, " Table info:\n");
166 	printk(BIOS_INFO, "  UUID: ");
167 	for (size_t i = 0; i < sizeof(info->uuid); i++)
168 		printk(BIOS_INFO, "%02X ", info->uuid[i]);
169 	printk(BIOS_INFO, "\n");
170 	printk(BIOS_INFO, "  Chipset acm type: 0x%x\n", info->chipset_acm_type);
171 	printk(BIOS_INFO, "  Capabilities: 0x%x\n", info->capabilities);
172 }
173 
174 /**
175  * Dump information about the chipset's TXT capabilities.
176  */
txt_dump_chipset_info(void)177 void txt_dump_chipset_info(void)
178 {
179 	printk(BIOS_INFO, "TEE-TXT: Chipset Key Hash 0x");
180 	for (int i = 0; i < TXT_ACM_KEY_HASH_LEN; i++) {
181 		printk(BIOS_INFO, "%llx", read64p(TXT_ACM_KEY_HASH +
182 		       (i * sizeof(uint64_t))));
183 	}
184 	printk(BIOS_INFO, "\n");
185 
186 	printk(BIOS_INFO, "TEE-TXT: DIDVID 0x%x\n", read32p(TXT_DIDVID));
187 	printk(BIOS_INFO, "TEE-TXT: production fused chipset: %s\n",
188 	       intel_txt_chipset_is_production_fused() ? "true" : "false");
189 }
190 
txt_dump_regions(void)191 void txt_dump_regions(void)
192 {
193 	struct txt_biosdataregion *bdr = NULL;
194 
195 	uintptr_t tseg_base;
196 	size_t tseg_size;
197 
198 	smm_region(&tseg_base, &tseg_size);
199 
200 	uint64_t reg64;
201 
202 	reg64 = read64p(TXT_HEAP_BASE);
203 	if ((reg64 != 0 && reg64 != ~0UL) &&
204 	    (read64p((uintptr_t)reg64) >= (sizeof(*bdr) + sizeof(uint64_t))))
205 		bdr = (void *)((uintptr_t)reg64 + sizeof(uint64_t));
206 
207 	printk(BIOS_DEBUG, "TEE-TXT: TSEG 0x%lx, size %zu MiB\n", tseg_base, tseg_size / MiB);
208 	printk(BIOS_DEBUG, "TEE-TXT: TXT.HEAP.BASE  0x%llx\n", read64p(TXT_HEAP_BASE));
209 	printk(BIOS_DEBUG, "TEE-TXT: TXT.HEAP.SIZE  0x%llx\n", read64p(TXT_HEAP_SIZE));
210 	printk(BIOS_DEBUG, "TEE-TXT: TXT.SINIT.BASE 0x%llx\n", read64p(TXT_SINIT_BASE));
211 	printk(BIOS_DEBUG, "TEE-TXT: TXT.SINIT.SIZE 0x%llx\n", read64p(TXT_SINIT_SIZE));
212 	printk(BIOS_DEBUG, "TEE-TXT: TXT.MSEG.BASE  0x%llx\n", read64p(TXT_MSEG_BASE));
213 	printk(BIOS_DEBUG, "TEE-TXT: TXT.MSEG.SIZE  0x%llx\n", read64p(TXT_MSEG_SIZE));
214 
215 	if (bdr) {
216 		printk(BIOS_DEBUG, "TEE-TXT: BiosDataRegion.bios_sinit_size 0x%x\n",
217 		       bdr->bios_sinit_size);
218 		printk(BIOS_DEBUG, "TEE-TXT: BiosDataRegion.lcp_pd_size 0x%llx\n",
219 		       bdr->lcp_pd_size);
220 		printk(BIOS_DEBUG, "TEE-TXT: BiosDataRegion.lcp_pd_base 0x%llx\n",
221 		       bdr->lcp_pd_base);
222 	}
223 }
224 
txt_dump_getsec_parameters(void)225 void txt_dump_getsec_parameters(void)
226 {
227 	uint32_t version_mask;
228 	uint32_t version_numbers_supported;
229 	uint32_t max_size_acm_area;
230 	uint32_t memory_type_mask;
231 	uint32_t senter_function_disable;
232 	uint32_t txt_feature_flags;
233 
234 	if (!getsec_parameter(&version_mask, &version_numbers_supported,
235 			      &max_size_acm_area, &memory_type_mask,
236 			      &senter_function_disable, &txt_feature_flags)) {
237 		printk(BIOS_WARNING, "Could not obtain GETSEC parameters\n");
238 		return;
239 	}
240 	printk(BIOS_DEBUG, "TEE-TXT: GETSEC[PARAMETERS] returned:\n");
241 	printk(BIOS_DEBUG, " ACM Version comparison mask: %08x\n", version_mask);
242 	printk(BIOS_DEBUG, " ACM Version numbers supported: %08x\n",
243 		version_numbers_supported);
244 	printk(BIOS_DEBUG, " Max size of authenticated code execution area: %08x\n",
245 		max_size_acm_area);
246 	printk(BIOS_DEBUG, " External memory types supported during AC mode: %08x\n",
247 		memory_type_mask);
248 	printk(BIOS_DEBUG, " Selective SENTER functionality control: %02x\n",
249 		(senter_function_disable >> 8) & 0x7f);
250 	printk(BIOS_DEBUG, " Feature Extensions Flags: %08x\n", txt_feature_flags);
251 	printk(BIOS_DEBUG, "\tS-CRTM Capability rooted in: ");
252 	if (txt_feature_flags & GETSEC_PARAMS_TXT_EXT_CRTM_SUPPORT) {
253 		printk(BIOS_DEBUG, "processor\n");
254 	} else {
255 		printk(BIOS_DEBUG, "BIOS\n");
256 	}
257 	printk(BIOS_DEBUG, "\tMachine Check Register: ");
258 	if (txt_feature_flags & GETSEC_PARAMS_TXT_EXT_MACHINE_CHECK) {
259 		printk(BIOS_DEBUG, "preserved\n");
260 	} else {
261 		printk(BIOS_DEBUG, "must be clear\n");
262 	}
263 }
264