aboutsummaryrefslogtreecommitdiffstats
path: root/roms/skiboot/hdata/tpmrel.c
diff options
context:
space:
mode:
Diffstat (limited to 'roms/skiboot/hdata/tpmrel.c')
-rw-r--r--roms/skiboot/hdata/tpmrel.c220
1 files changed, 220 insertions, 0 deletions
diff --git a/roms/skiboot/hdata/tpmrel.c b/roms/skiboot/hdata/tpmrel.c
new file mode 100644
index 000000000..4be3f81c4
--- /dev/null
+++ b/roms/skiboot/hdata/tpmrel.c
@@ -0,0 +1,220 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/* Copyright 2013-2018 IBM Corp. */
+
+#ifndef pr_fmt
+#define pr_fmt(fmt) "TPMREL: " fmt
+#endif
+
+#include <skiboot.h>
+#include <device.h>
+
+#include "spira.h"
+#include "hdata.h"
+#include "hdif.h"
+
+static void tpmrel_add_firmware_event_log(const struct HDIF_common_hdr *hdif_hdr)
+{
+ const struct secureboot_tpm_info *stinfo;
+ struct dt_node *xscom, *node;
+ uint64_t addr;
+ int count, i;
+ unsigned int asize;
+
+ /* Are the hdat values populated? */
+ if (!HDIF_get_idata(hdif_hdr, TPMREL_IDATA_SECUREBOOT_TPM_INFO, &asize))
+ return;
+ if (asize < sizeof(struct HDIF_array_hdr)) {
+ prlog(PR_ERR, "secureboot_tpm_info idata not populated\n");
+ return;
+ }
+
+ count = HDIF_get_iarray_size(hdif_hdr, TPMREL_IDATA_SECUREBOOT_TPM_INFO);
+ if (count > 1) {
+ prlog(PR_ERR, "multiple TPM not supported, count=%d\n", count);
+ return;
+ }
+
+ /*
+ * There can be multiple secureboot_tpm_info entries with each entry
+ * corresponding to a master processor that has a tpm device.
+ * This looks for the tpm node that supposedly exists under the xscom
+ * node associated with the respective chip_id.
+ */
+ for (i = 0; i < count; i++) {
+
+ stinfo = HDIF_get_iarray_item(hdif_hdr,
+ TPMREL_IDATA_SECUREBOOT_TPM_INFO,
+ i, NULL);
+
+ /*
+ * If tpm is not present, hostboot creates an empty
+ * secureboot_tpm_info entry, but setting
+ * tpm_status=TPM_NOT_PRESENT
+ */
+ if (stinfo->tpm_status == TPM_NOT_PRESENT)
+ continue;
+
+ xscom = find_xscom_for_chip(be32_to_cpu(stinfo->chip_id));
+ if (xscom) {
+ dt_for_each_node(xscom, node) {
+ if (dt_has_node_property(node, "label", "tpm"))
+ break;
+ }
+
+ if (node) {
+ addr = (uint64_t) stinfo +
+ be32_to_cpu(stinfo->srtm_log_offset);
+ dt_add_property_u64s(node, "linux,sml-base", addr);
+ dt_add_property_cells(node, "linux,sml-size",
+ be32_to_cpu(stinfo->srtm_log_size));
+
+ if (stinfo->tpm_status == TPM_PRESENT_AND_NOT_FUNCTIONAL)
+ dt_add_property_string(node, "status", "disabled");
+ } else {
+ /**
+ * @fwts-label HDATNoTpmForChipId
+ * @fwts-advice HDAT secureboot_tpm_info
+ * structure described a chip id, but no tpm
+ * node was found under that xscom chip id.
+ * This is most certainly a hostboot bug.
+ */
+ prlog(PR_ERR, "TPM node not found for "
+ "chip_id=%d (HB bug)\n", stinfo->chip_id);
+ continue;
+ }
+ } else {
+ /**
+ * @fwts-label HDATBadChipIdForTPM
+ * @fwts-advice HDAT secureboot_tpm_info structure
+ * described a chip id, but the xscom node for the
+ * chip_id was not found.
+ * This is most certainly a firmware bug.
+ */
+ prlog(PR_ERR, "xscom node not found for chip_id=%d\n",
+ stinfo->chip_id);
+ continue;
+ }
+ }
+}
+
+static struct dt_node *get_hb_reserved_memory(const char *label)
+{
+ struct dt_node *node, *hb_reserved_mem;
+
+ hb_reserved_mem = dt_find_by_path(dt_root, "/ibm,hostboot/reserved-memory");
+ if (!hb_reserved_mem) {
+ prlog(PR_DEBUG, "/ibm,hostboot/reserved-memory node not found\n");
+ return NULL;
+ }
+
+ dt_for_each_node(hb_reserved_mem, node) {
+ const char *prd_label;
+ if (!dt_find_property(node, "ibm,prd-label"))
+ continue;
+ prd_label = dt_prop_get(node, "ibm,prd-label");
+ if (!strcmp(prd_label, label))
+ return node;
+ }
+ return NULL;
+}
+
+static struct {
+ uint32_t type;
+ const char *compat;
+} cvc_services[] = {
+ { TPMREL_HV_SHA512, "ibm,cvc-sha512" },
+ { TPMREL_HV_VERIFY, "ibm,cvc-verify" },
+};
+
+static const char* cvc_service_map_compat(uint32_t type) {
+ int i;
+ for (i = 0; i < ARRAY_SIZE(cvc_services); i++) {
+ if (cvc_services[i].type == type)
+ return cvc_services[i].compat;
+ }
+ return NULL;
+}
+
+static void tpmrel_cvc_init(struct HDIF_common_hdr *hdif_hdr)
+{
+ struct dt_node *cvc_reserved_mem, *node, *parent;
+ int count, i;
+ unsigned int asize;
+
+ /* Are the hdat values populated? */
+ if (!HDIF_get_idata(hdif_hdr, TPMREL_IDATA_HASH_VERIF_OFFSETS, &asize))
+ return;
+ if (asize < sizeof(struct HDIF_array_hdr)) {
+ prlog(PR_ERR, "hash_and_verification idata not populated\n");
+ return;
+ }
+
+ node = dt_find_by_path(dt_root, "/ibm,secureboot");
+ if (!node)
+ return;
+
+ cvc_reserved_mem = get_hb_reserved_memory("secure-crypt-algo-code");
+ if (!cvc_reserved_mem) {
+ /* Fallback to old style ibm,prd-label */
+ cvc_reserved_mem = get_hb_reserved_memory("ibm,secure-crypt-algo-code");
+ if (!cvc_reserved_mem) {
+ prlog(PR_ERR, "CVC reserved memory not found\n");
+ return;
+ }
+ }
+
+ parent = dt_new(node, "ibm,cvc");
+ assert(parent);
+ dt_add_property_cells(parent, "#address-cells", 1);
+ dt_add_property_cells(parent, "#size-cells", 0);
+ dt_add_property_strings(parent, "compatible", "ibm,container-verification-code");
+ dt_add_property_cells(parent, "memory-region", cvc_reserved_mem->phandle);
+
+ /*
+ * Initialize each service provided by the container verification code
+ */
+ count = HDIF_get_iarray_size(hdif_hdr, TPMREL_IDATA_HASH_VERIF_OFFSETS);
+ if (count <= 0 ) {
+ prlog(PR_ERR, "no CVC service found\n");
+ return;
+ }
+
+ for (i = 0; i < count; i++) {
+ const struct hash_and_verification *hv;
+ uint32_t type, offset, version;
+ const char *compat;
+
+ hv = HDIF_get_iarray_item(hdif_hdr,
+ TPMREL_IDATA_HASH_VERIF_OFFSETS,
+ i, NULL);
+ type = be32_to_cpu(hv->type);
+ offset = be32_to_cpu(hv->offset);
+ version = be32_to_cpu(hv->version);
+
+ compat = cvc_service_map_compat(type);
+
+ if (!compat) {
+ prlog(PR_WARNING, "CVC service type 0x%x unknown\n", type);
+ continue;
+ }
+
+ node = dt_new_addr(parent, "ibm,cvc-service", offset);
+ dt_add_property_strings(node, "compatible", compat);
+ dt_add_property_cells(node, "reg", offset);
+ dt_add_property_cells(node, "version", version);
+ }
+}
+
+void node_stb_parse(void)
+{
+ struct HDIF_common_hdr *hdif_hdr;
+
+ hdif_hdr = get_hdif(&spira.ntuples.node_stb_data, STB_HDIF_SIG);
+ if (!hdif_hdr) {
+ prlog(PR_DEBUG, "TPMREL data not found\n");
+ return;
+ }
+
+ tpmrel_add_firmware_event_log(hdif_hdr);
+ tpmrel_cvc_init(hdif_hdr);
+}