blob: 7d8dcf7979b46da48da69f210350d203ff724834 [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 <arch/mmio.h>
Angel Pons52082be2020-10-05 12:34:29 +02004#include <console/console.h>
Angel Pons11334722020-10-05 16:34:03 +02005#include <cpu/x86/smm.h>
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +01006#include <string.h>
Angel Pons52082be2020-10-05 12:34:29 +02007#include <types.h>
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +01008
9#include "txt.h"
10#include "txt_register.h"
11
12/**
13 * Logs microcode or SINIT ACM errors.
14 * Does not log SBIOS ACM errors.
15 */
16static void log_txt_error(const char *phase)
17{
18 const uint64_t txt_error = read64((void *)TXT_ERROR);
19
20 if (txt_error & ACMERROR_TXT_VALID) {
21 printk(BIOS_ERR, "%s: Error occurred\n", phase);
22
23 if (txt_error & ACMERROR_TXT_EXTERNAL)
24 printk(BIOS_ERR, " Caused by: External\n");
25 else
26 printk(BIOS_ERR, " Caused by: Processor\n");
27
28 printk(BIOS_ERR, " Type: ");
29
30 switch (txt_error & TXT_ERROR_MASK) {
31 case 0:
32 printk(BIOS_ERR, "Legacy Shutdown\n");
33 break;
34 case 5:
35 printk(BIOS_ERR, "Load memory type error in ACM area\n");
36 break;
37 case 6:
38 printk(BIOS_ERR, "Unrecognized ACM format\n");
39 break;
40 case 7:
41 printk(BIOS_ERR, "Failure to authenticate\n");
42 break;
43 case 8:
44 printk(BIOS_ERR, "Invalid ACM format\n");
45 break;
46 case 9:
47 printk(BIOS_ERR, "Unexpected Snoop hit\n");
48 break;
49 case 10:
50 printk(BIOS_ERR, "Invalid event\n");
51 break;
52 case 11:
53 printk(BIOS_ERR, "Invalid MLE\n");
54 break;
55 case 12:
56 printk(BIOS_ERR, "Machine check event\n");
57 break;
58 case 13:
59 printk(BIOS_ERR, "VMXAbort\n");
60 break;
61 case 14:
62 printk(BIOS_ERR, "AC memory corruption\n");
63 break;
64 case 15:
65 printk(BIOS_ERR, "Illegal voltage/bus ratio\n");
66 break;
67 default:
68 printk(BIOS_ERR, "unknown\n");
69 break;
70 }
71 }
72}
73
74/**
75 * Dump useful informaation about the BIOS ACM state.
76 * Should run right after console_init() in romstage.
77 * Resets the platform if TXT reset is active and MLE cannot be established.
78 **/
79void intel_txt_log_bios_acm_error(void)
80{
81 uint32_t bios_acm_error;
82 uint64_t acm_status;
83 uint64_t txt_error;
84
85 printk(BIOS_INFO, "TEE-TXT: State of ACM and ucode update:\n");
86
87 bios_acm_error = read32((void *)TXT_BIOSACM_ERRORCODE);
88 acm_status = read64((void *)TXT_SPAD);
89 txt_error = read64((void *)TXT_ERROR);
90
91 /* Errors by BIOS ACM or FIT */
92 if ((txt_error & ACMERROR_TXT_VALID) &&
93 (acm_status & ACMERROR_TXT_VALID)) {
94 intel_txt_log_acm_error(read32((void *)TXT_BIOSACM_ERRORCODE));
95 log_txt_error("FIT MICROCODE");
96 }
97 /* Errors by SINIT */
98 if ((txt_error & ACMERROR_TXT_VALID) &&
99 !(acm_status & ACMERROR_TXT_VALID)) {
100 intel_txt_log_acm_error(txt_error);
101 log_txt_error("SINIT");
102 }
103
104 /* Check for fatal ACM error and TXT reset */
105 uint8_t error = read8((void *)TXT_ESTS);
106 if (error & TXT_ESTS_TXT_RESET_STS) {
107 printk(BIOS_CRIT, "TXT-STS: Intel TXT reset detected\n");
108 intel_txt_log_acm_error(read32((void *)TXT_ERROR));
109 }
110}
111
112/**
113 * Dump information about the provided ACM.
114 */
115void txt_dump_acm_info(const struct acm_header_v0 *acm_header)
116{
117 const struct acm_info_table *info = NULL;
118 if (!acm_header)
119 return;
120
121 printk(BIOS_INFO, "ACM @ %p\n", acm_header);
122
123 const size_t acm_size = (acm_header->size & 0xffffff) << 2;
124 const size_t info_off = (acm_header->header_len + acm_header->scratch_size) * 4;
125
126 if (acm_size > (info_off + sizeof(struct acm_info_table)))
127 info = (const struct acm_info_table *)
128 ((const unsigned char *)acm_header + info_off);
129
130 printk(BIOS_INFO, " ACM: Binary Info\n");
131 if (acm_header->module_type == CHIPSET_ACM)
132 printk(BIOS_INFO, " Type: Chipset ACM\n");
133
134 if (acm_header->module_sub_type == 0)
135 printk(BIOS_INFO, " Subtype: undefined\n");
136 else if (acm_header->module_sub_type == 1)
137 printk(BIOS_INFO, " Subtype: Run at reset\n");
138
139 printk(BIOS_INFO, " Header: v%u.%u\n", acm_header->header_version[0],
140 acm_header->header_version[1]);
141
Christian Walter6e536bc2020-09-30 13:42:35 +0200142 printk(BIOS_INFO, " Chipset: %x\n", acm_header->chipset_id);
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100143 printk(BIOS_INFO, " Size: %zu\n", acm_size);
144
145 switch (acm_header->flags) {
146 case ACM_FORMAT_FLAGS_PW:
147 printk(BIOS_INFO, " Flags: PW signed (Production Worthy)\n");
148 break;
149 case ACM_FORMAT_FLAGS_NPW:
150 printk(BIOS_INFO, " Flags: NPW signed (Non Production Worthy)\n");
151 break;
152 case ACM_FORMAT_FLAGS_DEBUG:
153 printk(BIOS_INFO, " Flags: Debug signed\n");
154 break;
155 }
156
157 if (acm_header->module_vendor == INTEL_ACM_VENDOR)
158 printk(BIOS_INFO, " Vendor: Intel Corporation\n");
159
160 printk(BIOS_INFO, " Date: %x\n", acm_header->date);
161
162 switch (acm_header->size) {
163 case ACM_FORMAT_SIZE_64KB:
164 printk(BIOS_INFO, " Size: 64KB\n");
165 printk(BIOS_INFO, " CBnT: no\n");
166 break;
167 case ACM_FORMAT_SIZE_128KB:
168 printk(BIOS_INFO, " Size: 128KB\n");
169 printk(BIOS_INFO, " CBnT: no\n");
170 break;
171 case ACM_FORMAT_SIZE_256KB:
172 printk(BIOS_INFO, " Size: 256KB\n");
173 printk(BIOS_INFO, " CBnT: yes\n");
174 break;
175 default:
176 printk(BIOS_INFO, " Size: 0x%08x\n", acm_header->size);
177
178 break;
179 }
180
181 printk(BIOS_INFO, " TXT SVN: %u\n", acm_header->txt_svn);
182 printk(BIOS_INFO, " SE SVN: %u\n", acm_header->se_svn);
183
184 if (!info)
185 return;
186 printk(BIOS_INFO, " Table info:\n");
187 printk(BIOS_INFO, " UUID: ");
188 for (size_t i = 0; i < sizeof(info->uuid); i++)
189 printk(BIOS_INFO, "%02X ", info->uuid[i]);
190 printk(BIOS_INFO, "\n");
191 printk(BIOS_INFO, " Chipset acm type: 0x%x\n", info->chipset_acm_type);
192 printk(BIOS_INFO, " Capabilities: 0x%x\n", info->capabilities);
193}
194
195/**
196 * Dump information about the chipset's TXT capabilities.
197 */
198void txt_dump_chipset_info(void)
199{
200 printk(BIOS_INFO, "TEE-TXT: Chipset Key Hash 0x");
201 for (int i = 0; i < TXT_ACM_KEY_HASH_LEN; i++) {
202 printk(BIOS_INFO, "%llx", read64((void *)TXT_ACM_KEY_HASH +
203 (i * sizeof(uint64_t))));
204 }
205 printk(BIOS_INFO, "\n");
206
207 printk(BIOS_INFO, "TEE-TXT: DIDVID 0x%x\n", read32((void *)TXT_DIDVID));
208 printk(BIOS_INFO, "TEE-TXT: production fused chipset: %s\n",
209 (read64((void *)TXT_VER_FSBIF) & TXT_VER_PRODUCTION_FUSED) ? "true" : "false");
210}
211
212void txt_dump_regions(void)
213{
214 struct txt_biosdataregion *bdr = NULL;
Angel Pons11334722020-10-05 16:34:03 +0200215
216 uintptr_t tseg_base;
217 size_t tseg_size;
218
219 smm_region(&tseg_base, &tseg_size);
220
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100221 uint64_t reg64;
222
223 reg64 = read64((void *)TXT_HEAP_BASE);
224 if ((reg64 != 0 && reg64 != ~0UL) &&
225 (read64((void *)(uintptr_t)reg64) >= (sizeof(*bdr) + sizeof(uint64_t))))
226 bdr = (void *)((uintptr_t)reg64 + sizeof(uint64_t));
227
Angel Pons11334722020-10-05 16:34:03 +0200228 printk(BIOS_DEBUG, "TEE-TXT: TSEG 0x%lx, size %zu MiB\n", tseg_base, tseg_size / MiB);
Philipp Deppenwiese5f9f7762018-11-20 14:22:15 +0100229 printk(BIOS_DEBUG, "TEE-TXT: TXT.HEAP.BASE 0x%llx\n", read64((void *)TXT_HEAP_BASE));
230 printk(BIOS_DEBUG, "TEE-TXT: TXT.HEAP.SIZE 0x%llx\n", read64((void *)TXT_HEAP_SIZE));
231 printk(BIOS_DEBUG, "TEE-TXT: TXT.SINIT.BASE 0x%llx\n", read64((void *)TXT_SINIT_BASE));
232 printk(BIOS_DEBUG, "TEE-TXT: TXT.SINIT.SIZE 0x%llx\n", read64((void *)TXT_SINIT_SIZE));
233 printk(BIOS_DEBUG, "TEE-TXT: TXT.MSEG.BASE 0x%llx\n", read64((void *)TXT_MSEG_BASE));
234 printk(BIOS_DEBUG, "TEE-TXT: TXT.MSEG.SIZE 0x%llx\n", read64((void *)TXT_MSEG_SIZE));
235
236 if (bdr) {
237 printk(BIOS_DEBUG, "TEE-TXT: BiosDataRegion.bios_sinit_size 0x%x\n",
238 bdr->bios_sinit_size);
239 printk(BIOS_DEBUG, "TEE-TXT: BiosDataRegion.lcp_pd_size 0x%llx\n",
240 bdr->lcp_pd_size);
241 printk(BIOS_DEBUG, "TEE-TXT: BiosDataRegion.lcp_pd_base 0x%llx\n",
242 bdr->lcp_pd_base);
243 }
244}