security/intel/cbnt: Add logging

This decodes and logs the CBnT status and error registers.

Change-Id: I8b57132bedbd944b9861ab0e2e0d14723cb61635
Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/54093
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
diff --git a/src/security/intel/cbnt/Kconfig b/src/security/intel/cbnt/Kconfig
index 9d48490..d16e685 100644
--- a/src/security/intel/cbnt/Kconfig
+++ b/src/security/intel/cbnt/Kconfig
@@ -17,6 +17,12 @@
 
 if INTEL_CBNT_SUPPORT
 
+config INTEL_CBNT_LOGGING
+	bool "Enable verbose CBnT logging"
+	help
+	  Print more CBnT related debug output.
+	  Use in pre-production environments only!
+
 config INTEL_CBNT_GENERATE_KM
 	bool "Generate Key Manifest (KM)"
 	default y
diff --git a/src/security/intel/cbnt/Makefile.inc b/src/security/intel/cbnt/Makefile.inc
index 9ade1cd..cc18b20 100644
--- a/src/security/intel/cbnt/Makefile.inc
+++ b/src/security/intel/cbnt/Makefile.inc
@@ -1,5 +1,6 @@
 ifeq ($(CONFIG_INTEL_CBNT_SUPPORT),y)
 
+all-y += logging.c
 ramstage-y += cmos.c
 
 # As specified in Intel Trusted Execution Technology and Boot Guard Server BIOS
diff --git a/src/security/intel/cbnt/cbnt.h b/src/security/intel/cbnt/cbnt.h
new file mode 100644
index 0000000..08011f5
--- /dev/null
+++ b/src/security/intel/cbnt/cbnt.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef SECURITY_INTEL_CBNT_H_
+#define SECURITY_INTEL_CBNT_H_
+
+#include <security/intel/txt/txt_register.h>
+
+#define CBNT_BASE_ADDRESS TXT_PUBLIC_SPACE
+
+#define CBNT_ERRORCODE (CBNT_BASE_ADDRESS + 0x30)
+#define CBNT_BOOTSTATUS (CBNT_BASE_ADDRESS + 0xa0)
+#define CBNT_BIOSACM_ERRORCODE (CBNT_BASE_ADDRESS + 0x328)
+
+void intel_cbnt_log_registers(void);
+
+#endif
diff --git a/src/security/intel/cbnt/logging.c b/src/security/intel/cbnt/logging.c
new file mode 100644
index 0000000..8e02202
--- /dev/null
+++ b/src/security/intel/cbnt/logging.c
@@ -0,0 +1,193 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <arch/mmio.h>
+#include <console/console.h>
+#include <cpu/x86/msr.h>
+#include <cpu/intel/msr.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:              %ul\n", acm_info.nem_enabled);
+	LOG("  TPM type:                %s\n", tpm_type[acm_info.tpm_type]);
+	LOG("  TPM succes:              %ul\n", acm_info.tpm_success);
+	LOG("  FACB:                    %ul\n", acm_info.facb);
+	LOG("  measured boot:           %ul\n", acm_info.measured_boot);
+	LOG("  verified boot:           %ul\n", acm_info.verified_boot);
+	LOG("  revoked:                 %ul\n", acm_info.revoked);
+	LOG("  BtG capable:             %ul\n", acm_info.btg_cap);
+	LOG("  TXT capable:             %ul\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:            %ul\n", btsts.bios_trusted);
+	LOG("  TXT disabled by policy:  %ul\n", btsts.txt_dis_pol);
+	LOG("  Bootguard startup error: %ul\n", btsts.btg_startup_err);
+	LOG("  TXT ucode or ACM error:  %ul\n", btsts.txt_err);
+	LOG("  TXT measurement type 7:  %ul\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);
+	}
+}