Branch data Line data Source code
1 : : // SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
2 : : /* Copyright 2013-2018 IBM Corp. */
3 : :
4 : : #ifndef pr_fmt
5 : : #define pr_fmt(fmt) "TPMREL: " fmt
6 : : #endif
7 : :
8 : : #include <skiboot.h>
9 : : #include <device.h>
10 : :
11 : : #include "spira.h"
12 : : #include "hdata.h"
13 : : #include "hdif.h"
14 : :
15 : 0 : static void tpmrel_add_firmware_event_log(const struct HDIF_common_hdr *hdif_hdr)
16 : : {
17 : : const struct secureboot_tpm_info *stinfo;
18 : : struct dt_node *xscom, *node;
19 : : uint64_t addr;
20 : : int count, i;
21 : : unsigned int asize;
22 : :
23 : : /* Are the hdat values populated? */
24 : 0 : if (!HDIF_get_idata(hdif_hdr, TPMREL_IDATA_SECUREBOOT_TPM_INFO, &asize))
25 : 0 : return;
26 : 0 : if (asize < sizeof(struct HDIF_array_hdr)) {
27 : 0 : prlog(PR_ERR, "secureboot_tpm_info idata not populated\n");
28 : 0 : return;
29 : : }
30 : :
31 : 0 : count = HDIF_get_iarray_size(hdif_hdr, TPMREL_IDATA_SECUREBOOT_TPM_INFO);
32 : 0 : if (count > 1) {
33 : 0 : prlog(PR_ERR, "multiple TPM not supported, count=%d\n", count);
34 : 0 : return;
35 : : }
36 : :
37 : : /*
38 : : * There can be multiple secureboot_tpm_info entries with each entry
39 : : * corresponding to a master processor that has a tpm device.
40 : : * This looks for the tpm node that supposedly exists under the xscom
41 : : * node associated with the respective chip_id.
42 : : */
43 : 0 : for (i = 0; i < count; i++) {
44 : :
45 : 0 : stinfo = HDIF_get_iarray_item(hdif_hdr,
46 : : TPMREL_IDATA_SECUREBOOT_TPM_INFO,
47 : : i, NULL);
48 : :
49 : : /*
50 : : * If tpm is not present, hostboot creates an empty
51 : : * secureboot_tpm_info entry, but setting
52 : : * tpm_status=TPM_NOT_PRESENT
53 : : */
54 : 0 : if (stinfo->tpm_status == TPM_NOT_PRESENT)
55 : 0 : continue;
56 : :
57 : 0 : xscom = find_xscom_for_chip(be32_to_cpu(stinfo->chip_id));
58 : 0 : if (xscom) {
59 : 0 : dt_for_each_node(xscom, node) {
60 : 0 : if (dt_has_node_property(node, "label", "tpm"))
61 : 0 : break;
62 : : }
63 : :
64 : 0 : if (node) {
65 : 0 : addr = (uint64_t) stinfo +
66 : 0 : be32_to_cpu(stinfo->srtm_log_offset);
67 : 0 : dt_add_property_u64s(node, "linux,sml-base", addr);
68 : 0 : dt_add_property_cells(node, "linux,sml-size",
69 : : be32_to_cpu(stinfo->srtm_log_size));
70 : :
71 : 0 : if (stinfo->tpm_status == TPM_PRESENT_AND_NOT_FUNCTIONAL)
72 : 0 : dt_add_property_string(node, "status", "disabled");
73 : : } else {
74 : : /**
75 : : * @fwts-label HDATNoTpmForChipId
76 : : * @fwts-advice HDAT secureboot_tpm_info
77 : : * structure described a chip id, but no tpm
78 : : * node was found under that xscom chip id.
79 : : * This is most certainly a hostboot bug.
80 : : */
81 : 0 : prlog(PR_ERR, "TPM node not found for "
82 : : "chip_id=%d (HB bug)\n", stinfo->chip_id);
83 : 0 : continue;
84 : : }
85 : : } else {
86 : : /**
87 : : * @fwts-label HDATBadChipIdForTPM
88 : : * @fwts-advice HDAT secureboot_tpm_info structure
89 : : * described a chip id, but the xscom node for the
90 : : * chip_id was not found.
91 : : * This is most certainly a firmware bug.
92 : : */
93 : 0 : prlog(PR_ERR, "xscom node not found for chip_id=%d\n",
94 : : stinfo->chip_id);
95 : 0 : continue;
96 : : }
97 : : }
98 : : }
99 : :
100 : 0 : static struct dt_node *get_hb_reserved_memory(const char *label)
101 : : {
102 : : struct dt_node *node, *hb_reserved_mem;
103 : :
104 : 0 : hb_reserved_mem = dt_find_by_path(dt_root, "/ibm,hostboot/reserved-memory");
105 : 0 : if (!hb_reserved_mem) {
106 : 0 : prlog(PR_DEBUG, "/ibm,hostboot/reserved-memory node not found\n");
107 : 0 : return NULL;
108 : : }
109 : :
110 : 0 : dt_for_each_node(hb_reserved_mem, node) {
111 : : const char *prd_label;
112 : 0 : if (!dt_find_property(node, "ibm,prd-label"))
113 : 0 : continue;
114 : 0 : prd_label = dt_prop_get(node, "ibm,prd-label");
115 : 0 : if (!strcmp(prd_label, label))
116 : 0 : return node;
117 : : }
118 : 0 : return NULL;
119 : : }
120 : :
121 : : static struct {
122 : : uint32_t type;
123 : : const char *compat;
124 : : } cvc_services[] = {
125 : : { TPMREL_HV_SHA512, "ibm,cvc-sha512" },
126 : : { TPMREL_HV_VERIFY, "ibm,cvc-verify" },
127 : : };
128 : :
129 : 0 : static const char* cvc_service_map_compat(uint32_t type) {
130 : : int i;
131 : 0 : for (i = 0; i < ARRAY_SIZE(cvc_services); i++) {
132 : 0 : if (cvc_services[i].type == type)
133 : 0 : return cvc_services[i].compat;
134 : : }
135 : 0 : return NULL;
136 : : }
137 : :
138 : 0 : static void tpmrel_cvc_init(struct HDIF_common_hdr *hdif_hdr)
139 : : {
140 : : struct dt_node *cvc_reserved_mem, *node, *parent;
141 : : int count, i;
142 : : unsigned int asize;
143 : :
144 : : /* Are the hdat values populated? */
145 : 0 : if (!HDIF_get_idata(hdif_hdr, TPMREL_IDATA_HASH_VERIF_OFFSETS, &asize))
146 : 0 : return;
147 : 0 : if (asize < sizeof(struct HDIF_array_hdr)) {
148 : 0 : prlog(PR_ERR, "hash_and_verification idata not populated\n");
149 : 0 : return;
150 : : }
151 : :
152 : 0 : node = dt_find_by_path(dt_root, "/ibm,secureboot");
153 : 0 : if (!node)
154 : 0 : return;
155 : :
156 : 0 : cvc_reserved_mem = get_hb_reserved_memory("secure-crypt-algo-code");
157 : 0 : if (!cvc_reserved_mem) {
158 : : /* Fallback to old style ibm,prd-label */
159 : 0 : cvc_reserved_mem = get_hb_reserved_memory("ibm,secure-crypt-algo-code");
160 : 0 : if (!cvc_reserved_mem) {
161 : 0 : prlog(PR_ERR, "CVC reserved memory not found\n");
162 : 0 : return;
163 : : }
164 : : }
165 : :
166 : 0 : parent = dt_new(node, "ibm,cvc");
167 : 0 : assert(parent);
168 : 0 : dt_add_property_cells(parent, "#address-cells", 1);
169 : 0 : dt_add_property_cells(parent, "#size-cells", 0);
170 : 0 : dt_add_property_strings(parent, "compatible", "ibm,container-verification-code");
171 : 0 : dt_add_property_cells(parent, "memory-region", cvc_reserved_mem->phandle);
172 : :
173 : : /*
174 : : * Initialize each service provided by the container verification code
175 : : */
176 : 0 : count = HDIF_get_iarray_size(hdif_hdr, TPMREL_IDATA_HASH_VERIF_OFFSETS);
177 : 0 : if (count <= 0 ) {
178 : 0 : prlog(PR_ERR, "no CVC service found\n");
179 : 0 : return;
180 : : }
181 : :
182 : 0 : for (i = 0; i < count; i++) {
183 : : const struct hash_and_verification *hv;
184 : : uint32_t type, offset, version;
185 : : const char *compat;
186 : :
187 : 0 : hv = HDIF_get_iarray_item(hdif_hdr,
188 : : TPMREL_IDATA_HASH_VERIF_OFFSETS,
189 : : i, NULL);
190 : 0 : type = be32_to_cpu(hv->type);
191 : 0 : offset = be32_to_cpu(hv->offset);
192 : 0 : version = be32_to_cpu(hv->version);
193 : :
194 : 0 : compat = cvc_service_map_compat(type);
195 : :
196 : 0 : if (!compat) {
197 : 0 : prlog(PR_WARNING, "CVC service type 0x%x unknown\n", type);
198 : 0 : continue;
199 : : }
200 : :
201 : 0 : node = dt_new_addr(parent, "ibm,cvc-service", offset);
202 : 0 : dt_add_property_strings(node, "compatible", compat);
203 : 0 : dt_add_property_cells(node, "reg", offset);
204 : 0 : dt_add_property_cells(node, "version", version);
205 : : }
206 : : }
207 : :
208 : 0 : void node_stb_parse(void)
209 : : {
210 : : struct HDIF_common_hdr *hdif_hdr;
211 : :
212 : 0 : hdif_hdr = get_hdif(&spiras->ntuples.node_stb_data, STB_HDIF_SIG);
213 : 0 : if (!hdif_hdr) {
214 : 0 : prlog(PR_DEBUG, "TPMREL data not found\n");
215 : 0 : return;
216 : : }
217 : :
218 : 0 : tpmrel_add_firmware_event_log(hdif_hdr);
219 : 0 : tpmrel_cvc_init(hdif_hdr);
220 : : }
|