| /* SPDX-License-Identifier: GPL-2.0-only */ |
| |
| #include <console/console.h> |
| #include <cpu/x86/msr.h> |
| #include <cpu/intel/msr.h> |
| #include <device/mmio.h> |
| #include <stdint.h> |
| #include <security/intel/txt/txt.h> |
| |
| #include "cbnt.h" |
| |
| #define LOG(...) printk(BIOS_INFO, "CBnT: " __VA_ARGS__) |
| |
| union sacm_info { |
| struct { |
| uint64_t nem_enabled : 1; |
| uint64_t tpm_type : 2; |
| uint64_t tpm_success : 1; |
| uint64_t facb : 1; |
| uint64_t measured_boot : 1; |
| uint64_t verified_boot : 1; |
| uint64_t revoked : 1; |
| uint64_t : 24; |
| uint64_t btg_cap : 1; |
| uint64_t : 1; |
| uint64_t txt_cap : 1; |
| uint64_t : 29; |
| }; |
| msr_t msr; |
| uint64_t raw; |
| }; |
| |
| _Static_assert(sizeof(union sacm_info) == sizeof(uint64_t), "Wrong size of sacm_info"); |
| |
| static const char *const tpm_type[] = { |
| "No TPM", |
| "TPM 1.2", |
| "TPM 2.0", |
| "PTT", |
| }; |
| |
| union cbnt_bootstatus { |
| struct { |
| uint64_t : 59; |
| uint64_t bios_trusted : 1; |
| uint64_t txt_dis_pol : 1; |
| uint64_t btg_startup_err : 1; |
| uint64_t txt_err : 1; |
| uint64_t type7 : 1; |
| }; |
| uint64_t raw; |
| }; |
| _Static_assert(sizeof(union cbnt_bootstatus) == sizeof(uint64_t), |
| "Wrong size of cbnt_bootstatus"); |
| |
| union cbnt_errorcode { |
| struct { |
| uint32_t type : 15; |
| uint32_t : 15; |
| uint32_t external : 1; |
| uint32_t valid : 1; |
| } microcode; |
| struct { |
| uint32_t ac_type : 4; |
| uint32_t class : 6; |
| uint32_t major : 5; |
| uint32_t minor_invalid : 1; |
| uint32_t minor : 9; |
| uint32_t : 5; |
| uint32_t external : 1; |
| uint32_t valid : 1; |
| } sinit; |
| uint32_t raw; |
| }; |
| |
| _Static_assert(sizeof(union cbnt_errorcode) == sizeof(uint32_t), |
| "Wrong size of cbnt_errorcode"); |
| |
| union cbnt_biosacm_errorcode { |
| struct { |
| uint32_t ac_type : 4; |
| uint32_t class : 6; |
| uint32_t major : 5; |
| uint32_t minor_invalid : 1; |
| uint32_t minor : 12; |
| uint32_t : 2; |
| uint32_t external : 1; |
| uint32_t valid : 1; |
| } txt; |
| struct { |
| uint32_t ac_type : 4; |
| uint32_t class : 6; |
| uint32_t error : 5; |
| uint32_t acm_started : 1; |
| uint32_t km_id : 4; |
| uint32_t bp : 5; |
| uint32_t : 6; |
| uint32_t valid : 1; |
| } btg; |
| uint32_t raw; |
| }; |
| _Static_assert(sizeof(union cbnt_biosacm_errorcode) == sizeof(uint32_t), |
| "Wrong size of cbnt_biosacm_errorcode"); |
| |
| |
| static const char *decode_err_type(uint8_t type) |
| { |
| switch (type) { |
| case 0: |
| return "BIOS ACM Error"; |
| case 1: |
| return "SINIT ACM Error"; |
| case 3: |
| return "Boot Guard Error"; |
| default: |
| return "Reserved"; |
| } |
| } |
| |
| void intel_cbnt_log_registers(void) |
| { |
| const union sacm_info acm_info = { .msr = rdmsr(MSR_BOOT_GUARD_SACM_INFO) }; |
| LOG("SACM INFO MSR (0x13A) raw: 0x%016llx\n", acm_info.raw); |
| LOG(" NEM status: %u\n", acm_info.nem_enabled); |
| LOG(" TPM type: %s\n", tpm_type[acm_info.tpm_type]); |
| LOG(" TPM success: %u\n", acm_info.tpm_success); |
| LOG(" FACB: %u\n", acm_info.facb); |
| LOG(" measured boot: %u\n", acm_info.measured_boot); |
| LOG(" verified boot: %u\n", acm_info.verified_boot); |
| LOG(" revoked: %u\n", acm_info.revoked); |
| LOG(" BtG capable: %u\n", acm_info.btg_cap); |
| LOG(" TXT capable: %u\n", acm_info.txt_cap); |
| |
| const union cbnt_bootstatus btsts = { |
| .raw = read64p(CBNT_BOOTSTATUS), |
| }; |
| LOG("BOOTSTATUS (0xA0) raw: 0x%016llx\n", btsts.raw); |
| LOG(" Bios trusted: %u\n", btsts.bios_trusted); |
| LOG(" TXT disabled by policy: %u\n", btsts.txt_dis_pol); |
| LOG(" Bootguard startup error: %u\n", btsts.btg_startup_err); |
| LOG(" TXT ucode or ACM error: %u\n", btsts.txt_err); |
| LOG(" TXT measurement type 7: %u\n", btsts.type7); |
| |
| const union cbnt_errorcode err = { |
| .raw = read32p(CBNT_ERRORCODE), |
| }; |
| LOG("ERRORCODE (0x30) raw: 0x%08x\n", err.raw); |
| /* It looks like the hardware does not set the txt error bit properly */ |
| const bool txt_err_valid = btsts.txt_err || true; |
| if (txt_err_valid && !btsts.txt_dis_pol) { |
| if (err.microcode.valid && !err.microcode.external) { |
| LOG("ERRORCODE is ucode error\n"); |
| LOG(" type: %s\n", |
| intel_txt_processor_error_type(err.microcode.type)); |
| } else if (err.sinit.valid && err.sinit.external) { |
| LOG("ERRORCODE is SINIT error\n"); |
| const char *type = decode_err_type(err.sinit.ac_type); |
| LOG(" AC Module Type: %s\n", type); |
| LOG(" class: 0x%x\n", err.sinit.class); |
| LOG(" major: 0x%x\n", err.sinit.major); |
| if (!err.sinit.minor_invalid) |
| LOG(" minor: 0x%x\n", err.sinit.minor); |
| } |
| } else if (txt_err_valid && btsts.txt_dis_pol) { |
| LOG("TXT disabled in Policy\n"); |
| } |
| |
| const union cbnt_biosacm_errorcode biosacm_err = { |
| .raw = read32p(CBNT_BIOSACM_ERRORCODE), |
| }; |
| LOG("BIOSACM_ERRORCODE (0x328) raw: 0x%08x\n", biosacm_err.raw); |
| if (txt_err_valid && biosacm_err.txt.valid) { |
| LOG("BIOSACM_ERRORCODE: TXT ucode or ACM error\n"); |
| const char *type = decode_err_type(biosacm_err.txt.ac_type); |
| LOG(" AC Module Type: %s\n", type); |
| LOG(" class: 0x%x\n", biosacm_err.txt.class); |
| LOG(" major: 0x%x\n", biosacm_err.txt.major); |
| if (!biosacm_err.txt.minor_invalid) |
| LOG(" minor: 0x%x\n", biosacm_err.txt.minor); |
| LOG(" External: 0x%x\n", biosacm_err.txt.external); |
| } |
| |
| if (btsts.btg_startup_err && biosacm_err.btg.valid) { |
| LOG("BIOSACM_ERRORCODE: Bootguard error\n"); |
| const char *type = decode_err_type(biosacm_err.btg.ac_type); |
| LOG(" AC Module Type: %s\n", type); |
| LOG(" class: 0x%x\n", biosacm_err.btg.class); |
| LOG(" error: 0x%x\n", biosacm_err.btg.error); |
| LOG(" ACM started: %u\n", biosacm_err.btg.acm_started); |
| LOG(" KMID: 0x%x\n", biosacm_err.btg.km_id); |
| LOG(" BootPolicies: 0x%x\n", biosacm_err.btg.bp); |
| } |
| } |