1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <console/console.h>
4 #include <cpu/x86/smm.h>
5 #include <device/mmio.h>
9 #include "txt_getsec.h"
10 #include "txt_register.h"
12 const char *intel_txt_processor_error_type(uint8_t type
)
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",
23 [12] = "Machine check event",
25 [14] = "AC memory corruption",
26 [15] = "Illegal voltage/bus ratio",
29 return type
< ARRAY_SIZE(names
) && names
[type
] ? names
[type
] : "Unknown";
33 * Logs microcode or SINIT ACM errors.
34 * Does not log SBIOS ACM errors.
36 static void log_txt_error(const char *phase
)
38 const uint64_t txt_error
= read64p(TXT_ERROR
);
40 if (txt_error
& ACMERROR_TXT_VALID
) {
41 printk(BIOS_ERR
, "%s: Error occurred\n", phase
);
43 if (txt_error
& ACMERROR_TXT_EXTERNAL
)
44 printk(BIOS_ERR
, " Caused by: External\n");
46 printk(BIOS_ERR
, " Caused by: Processor\n");
48 printk(BIOS_ERR
, " Type: %s\n",
49 intel_txt_processor_error_type(txt_error
& TXT_ERROR_MASK
));
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.
58 void intel_txt_log_bios_acm_error(void)
60 uint32_t bios_acm_error
;
64 printk(BIOS_INFO
, "TEE-TXT: State of ACM and ucode update:\n");
66 bios_acm_error
= read32p(TXT_BIOSACM_ERRORCODE
);
67 acm_status
= read64p(TXT_SPAD
);
68 txt_error
= read64p(TXT_ERROR
);
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");
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");
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
));
92 * Dump information about the provided ACM.
94 void txt_dump_acm_info(const struct acm_header_v0
*acm_header
)
96 const struct acm_info_table
*info
= NULL
;
100 printk(BIOS_INFO
, "ACM @ %p\n", acm_header
);
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;
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
);
109 printk(BIOS_INFO
, " ACM: Binary Info\n");
110 if (acm_header
->module_type
== CHIPSET_ACM
)
111 printk(BIOS_INFO
, " Type: Chipset ACM\n");
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");
118 printk(BIOS_INFO
, " Header: v%u.%u\n", acm_header
->header_version
[0],
119 acm_header
->header_version
[1]);
121 printk(BIOS_INFO
, " Chipset: %x\n", acm_header
->chipset_id
);
122 printk(BIOS_INFO
, " Size: %zu\n", acm_size
);
124 switch (acm_header
->flags
) {
125 case ACM_FORMAT_FLAGS_PW
:
126 printk(BIOS_INFO
, " Flags: PW signed (Production Worthy)\n");
128 case ACM_FORMAT_FLAGS_NPW
:
129 printk(BIOS_INFO
, " Flags: NPW signed (Non Production Worthy)\n");
131 case ACM_FORMAT_FLAGS_DEBUG
:
132 printk(BIOS_INFO
, " Flags: Debug signed\n");
136 if (acm_header
->module_vendor
== INTEL_ACM_VENDOR
)
137 printk(BIOS_INFO
, " Vendor: Intel Corporation\n");
139 printk(BIOS_INFO
, " Date: %x\n", acm_header
->date
);
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");
146 case ACM_FORMAT_SIZE_128KB
:
147 printk(BIOS_INFO
, " Size: 128KB\n");
148 printk(BIOS_INFO
, " CBnT: no\n");
150 case ACM_FORMAT_SIZE_256KB
:
151 printk(BIOS_INFO
, " Size: 256KB\n");
152 printk(BIOS_INFO
, " CBnT: yes\n");
155 printk(BIOS_INFO
, " Size: 0x%08x\n", acm_header
->size
);
160 printk(BIOS_INFO
, " TXT SVN: %u\n", acm_header
->txt_svn
);
161 printk(BIOS_INFO
, " SE SVN: %u\n", acm_header
->se_svn
);
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
);
175 * Dump information about the chipset's TXT capabilities.
177 void txt_dump_chipset_info(void)
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))));
184 printk(BIOS_INFO
, "\n");
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");
191 void txt_dump_regions(void)
193 struct txt_biosdataregion
*bdr
= NULL
;
198 smm_region(&tseg_base
, &tseg_size
);
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));
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
));
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",
220 printk(BIOS_DEBUG
, "TEE-TXT: BiosDataRegion.lcp_pd_base 0x%llx\n",
225 void txt_dump_getsec_parameters(void)
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
;
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");
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",
246 printk(BIOS_DEBUG
, " External memory types supported during AC mode: %08x\n",
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");
255 printk(BIOS_DEBUG
, "BIOS\n");
257 printk(BIOS_DEBUG
, "\tMachine Check Register: ");
258 if (txt_feature_flags
& GETSEC_PARAMS_TXT_EXT_MACHINE_CHECK
) {
259 printk(BIOS_DEBUG
, "preserved\n");
261 printk(BIOS_DEBUG
, "must be clear\n");