1 /* Copyright 2013-2017 IBM Corp.
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * 	http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12  * implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef pr_fmt
18 #define pr_fmt(fmt) "STB: " fmt
19 #endif
20 
21 #include <skiboot.h>
22 #include <string.h>
23 #include <opal-api.h>
24 #include <chip.h>
25 #include <xscom.h>
26 #include <inttypes.h>
27 #include "secureboot.h"
28 #include "cvc.h"
29 #include "mbedtls/sha512.h"
30 
31 /*
32  * Assembly interfaces to call into the Container Verification Code.
33  * func_ptr: CVC base address + offset
34  */
35 ROM_response __cvc_verify_v1(void *func_ptr, ROM_container_raw *container,
36 			     ROM_hw_params *params);
37 void __cvc_sha512_v1(void *func_ptr, const uint8_t *data, size_t len,
38 		     uint8_t *digest);
39 
40 struct container_verification_code {
41 	uint64_t start_addr;
42 	uint64_t end_addr;
43 	struct list_head service_list;
44 };
45 
46 static struct container_verification_code *cvc = NULL;
47 static bool softrom = false;
48 static void *secure_rom_mem = NULL;
49 
50 static struct dt_node *cvc_resv_mem = NULL;
51 static struct dt_node *cvc_node = NULL;
52 
53 struct cvc_service {
54 	int id;
55 	uint64_t addr;    /* base_addr + offset */
56 	uint32_t version;
57 	struct list_node link;
58 };
59 
60 static struct {
61 	enum cvc_service_id id;
62 	const char *name;
63 } cvc_service_map[] = {
64 	{ CVC_SHA512_SERVICE, "sha512" },
65 	{ CVC_VERIFY_SERVICE, "verify" },
66 };
67 
cvc_find_service(enum cvc_service_id id)68 static struct cvc_service *cvc_find_service(enum cvc_service_id id)
69 {
70 	struct cvc_service *service;
71 	if (!cvc)
72 		return NULL;
73 
74 	list_for_each(&cvc->service_list, service, link) {
75 		if (service->id == id)
76 			return service;
77 	}
78 	return NULL;
79 }
80 
cvc_service_map_name(enum cvc_service_id id)81 static const char *cvc_service_map_name(enum cvc_service_id id)
82 {
83 	int i;
84 
85 	for (i = 0; i < ARRAY_SIZE(cvc_service_map); i++) {
86 		if (cvc_service_map[i].id == id)
87 			return cvc_service_map[i].name;
88 	}
89 	return NULL;
90 }
91 
cvc_register(uint64_t start_addr,uint64_t end_addr)92 static void cvc_register(uint64_t start_addr, uint64_t end_addr)
93 {
94 	if (cvc)
95 		return;
96 
97 	cvc = malloc(sizeof(struct container_verification_code));
98 	assert(cvc);
99 	cvc->start_addr = start_addr;
100 	cvc->end_addr = end_addr;
101 	list_head_init(&cvc->service_list);
102 	prlog(PR_INFO, "Found CVC @ %" PRIx64 "-%" PRIx64 "\n",
103 	      start_addr, end_addr);
104 }
105 
cvc_service_register(uint32_t id,uint32_t offset,uint32_t version)106 static void cvc_service_register(uint32_t id, uint32_t offset, uint32_t version)
107 {
108 	struct cvc_service *service;
109 	const char *name;
110 
111 	if (!cvc)
112 		return;
113 
114 	/* Service already registered? */
115 	if (cvc_find_service(id))
116 		return;
117 
118 	if (cvc->start_addr + offset > cvc->end_addr) {
119 		prlog(PR_WARNING, "CVC service @ %x out of range, "
120 		      "id=%d\n", offset, id);
121 		return;
122 	}
123 
124 	name = cvc_service_map_name(id);
125 	if (!name) {
126 		prlog(PR_ERR, "CVC service %d not supported\n", id);
127 		return;
128 	}
129 
130 	service = malloc(sizeof(struct cvc_service));
131 	assert(service);
132 	service->id = id;
133 	service->version = version;
134 	service->addr = cvc->start_addr + offset;
135 	list_add_tail(&cvc->service_list, &service->link);
136 	prlog(PR_INFO, "Found CVC-%s @ %" PRIx64 ", version=%d\n",
137 	      name, service->addr, service->version);
138 }
139 
cvc_reserved_mem_init(struct dt_node * parent)140 static int cvc_reserved_mem_init(struct dt_node *parent) {
141 	struct dt_node *node, *service;
142 	struct dt_node *reserved_mem;
143 	uint32_t phandle;
144 	uint64_t addr, size;
145 
146 	reserved_mem = dt_find_by_path(dt_root, "/ibm,hostboot/reserved-memory");
147 	if (!reserved_mem) {
148 		prlog(PR_ERR, "/ibm,hostboot/reserved-memory not found\n");
149 		return -1;
150 	}
151 
152 	/*
153 	 * The container verification code is stored in a hostboot reserved
154 	 * memory which is pointed by the property
155 	 * /ibm,secureboot/ibm,container-verification-code/memory-region
156 	 */
157 	dt_for_each_child(parent, node) {
158 		if (dt_node_is_compatible(node, "ibm,container-verification-code")) {
159 			phandle = dt_prop_get_u32(node, "memory-region");
160 			cvc_resv_mem = dt_find_by_phandle(reserved_mem, phandle);
161 			cvc_node = node;
162 			break;
163 		}
164 	}
165 	if (!cvc_resv_mem) {
166 		prlog(PR_ERR, "CVC not found in /ibm,hostboot/reserved-memory\n");
167 		return -1;
168 	}
169 	addr = dt_get_address(cvc_resv_mem, 0, &size);
170 	cvc_register(addr, addr + size-1);
171 
172 	/*
173 	 *  Each child of the CVC node describes a CVC service
174 	 */
175 	dt_for_each_child(node, service) {
176 		uint32_t version, offset;
177 
178 		version = dt_prop_get_u32(service, "version");
179 		offset = dt_prop_get_u32(service, "reg");
180 
181 		if (dt_node_is_compatible(service, "ibm,cvc-sha512"))
182 			cvc_service_register(CVC_SHA512_SERVICE, offset, version);
183 		else if (dt_node_is_compatible(service, "ibm,cvc-verify"))
184 			cvc_service_register(CVC_VERIFY_SERVICE, offset, version);
185 		else
186 			prlog(PR_DEBUG, "unknown %s\n", service->name);
187 	}
188 
189 	return 0;
190 }
191 
192 #define SECURE_ROM_MEMORY_SIZE		(16 * 1024)
193 #define SECURE_ROM_XSCOM_ADDRESS	0x02020017
194 
195 #define SECURE_ROM_SHA512_OFFSET	0x20
196 #define SECURE_ROM_VERIFY_OFFSET	0x30
197 
cvc_secure_rom_init(void)198 static int cvc_secure_rom_init(void) {
199 	const uint32_t reg_addr = SECURE_ROM_XSCOM_ADDRESS;
200 	uint64_t reg_data;
201 	struct proc_chip *chip;
202 
203 	if (!secure_rom_mem) {
204 		secure_rom_mem = malloc(SECURE_ROM_MEMORY_SIZE);
205 		assert(secure_rom_mem);
206 	}
207 	/*
208 	 * The logic that contains the ROM within the processor is implemented
209 	 * in a way that it only responds to CI (cache inhibited) operations.
210 	 * Due to performance issues we copy the verification code from the
211 	 * secure ROM to RAM. We use memcpy_from_ci() to do that.
212 	 */
213 	chip = next_chip(NULL);
214 	xscom_read(chip->id, reg_addr, &reg_data);
215 	memcpy_from_ci(secure_rom_mem, (void*) reg_data,
216 		       SECURE_ROM_MEMORY_SIZE);
217 	cvc_register((uint64_t)secure_rom_mem,
218 		     (uint64_t)secure_rom_mem + SECURE_ROM_MEMORY_SIZE-1);
219 	cvc_service_register(CVC_SHA512_SERVICE, SECURE_ROM_SHA512_OFFSET, 1);
220 	cvc_service_register(CVC_VERIFY_SERVICE, SECURE_ROM_VERIFY_OFFSET, 1);
221 	return 0;
222 }
223 
cvc_update_reserved_memory_phandle(void)224 void cvc_update_reserved_memory_phandle(void) {
225 	struct dt_node *reserved_mem;
226 
227 	if (!cvc_resv_mem || !cvc_node)
228 		return;
229 
230 	/*
231 	 * The linux documentation, reserved-memory.txt, says that memory-region
232 	 * is a phandle that pairs to a children of /reserved-memory
233 	 */
234 	reserved_mem = dt_find_by_path(dt_root, "/reserved-memory");
235 	if (!reserved_mem) {
236 		prlog(PR_ERR, "/reserved-memory not found\n");
237 		return;
238 	}
239 	cvc_resv_mem = dt_find_by_name(reserved_mem, cvc_resv_mem->name);
240 	if (cvc_resv_mem) {
241 		dt_check_del_prop(cvc_node, "memory-region");
242 		dt_add_property_cells(cvc_node, "memory-region", cvc_resv_mem->phandle);
243 	} else {
244 		prlog(PR_WARNING, "CVC not found in /reserved-memory\n");
245 		return;
246 	}
247 
248 	cvc_resv_mem = NULL;
249 	cvc_node = NULL;
250 }
251 
cvc_init(void)252 int cvc_init(void)
253 {
254 	struct dt_node *node;
255 	int version;
256 	int rc = 0;
257 
258 	if (cvc)
259 		return 0;
260 
261 	node = dt_find_by_path(dt_root, "/ibm,secureboot");
262 	if (!node)
263 		return -1;
264 
265 	if (!secureboot_is_compatible(node, &version, NULL)) {
266 		/**
267 		 * @fwts-label CVCNotCompatible
268 		 * @fwts-advice Compatible CVC driver not found. Probably,
269 		 * hostboot/mambo/skiboot has updated the
270 		 * /ibm,secureboot/compatible without adding a driver that
271 		 * supports it.
272 		 */
273 		prlog(PR_ERR, "%s FAILED, /ibm,secureboot not compatible.\n",
274 		     __func__);
275 		return -1;
276 	}
277 
278 	/* Only in P8 the CVC is stored in a secure ROM */
279 	if (version == IBM_SECUREBOOT_V1 &&
280 	    proc_gen == proc_gen_p8) {
281 		rc = cvc_secure_rom_init();
282 	} else if (version == IBM_SECUREBOOT_SOFTROM) {
283 		softrom = true;
284 	} else if (version == IBM_SECUREBOOT_V2) {
285 		rc = cvc_reserved_mem_init(node);
286 	} else {
287 		prlog(PR_ERR, "%s FAILED. /ibm,secureboot not supported\n",
288 		      __func__);
289 		return -1;
290 	}
291 	return rc;
292 }
293 
call_cvc_sha512(const uint8_t * data,size_t data_len,uint8_t * digest,size_t digest_size)294 int call_cvc_sha512(const uint8_t *data, size_t data_len, uint8_t *digest,
295 		   size_t digest_size)
296 {
297 	struct cvc_service *service;
298 
299 	if (!data || !digest || digest_size < SHA512_DIGEST_LENGTH)
300 		return OPAL_PARAMETER;
301 
302 	if (data_len <= 0)
303 		return OPAL_SUCCESS;
304 
305 	memset(digest, 0, SHA512_DIGEST_LENGTH);
306 	if (softrom) {
307 		mbedtls_sha512_context ctx;
308 		mbedtls_sha512_init(&ctx);
309 		mbedtls_sha512_starts(&ctx, 0); // SHA512 = 0
310 		mbedtls_sha512_update(&ctx, data, data_len);
311 		mbedtls_sha512_finish(&ctx, digest);
312 		mbedtls_sha512_free(&ctx);
313 		return OPAL_SUCCESS;
314 	}
315 
316 	service = cvc_find_service(CVC_SHA512_SERVICE);
317 
318 	if (!service)
319 		return OPAL_UNSUPPORTED;
320 
321 	if (service->version == 1)
322 		__cvc_sha512_v1((void*) service->addr, data, data_len, digest);
323 	else
324 		return OPAL_UNSUPPORTED;
325 
326 	return OPAL_SUCCESS;
327 }
328 
call_cvc_verify(void * container,size_t len,const void * hw_key_hash,size_t hw_key_hash_size,uint64_t * log)329 int call_cvc_verify(void *container, size_t len, const void *hw_key_hash,
330 		    size_t hw_key_hash_size, uint64_t *log)
331 {
332 	ROM_hw_params hw_params;
333 	ROM_response rc;
334 	struct cvc_service *service;
335 
336 	if (!container || len < SECURE_BOOT_HEADERS_SIZE ||
337 	    !hw_key_hash || hw_key_hash_size <= 0)
338 		return OPAL_PARAMETER;
339 
340 	if (softrom)
341 		return OPAL_UNSUPPORTED;
342 
343 	service = cvc_find_service(CVC_VERIFY_SERVICE);
344 
345 	if (!service)
346 		return OPAL_UNSUPPORTED;
347 
348 	memset(&hw_params, 0, sizeof(ROM_hw_params));
349 	memcpy(&hw_params.hw_key_hash, hw_key_hash, hw_key_hash_size);
350 
351 	if (service->version == 1)
352 		rc = __cvc_verify_v1((void*) service->addr,
353 				   (ROM_container_raw*) container,
354 				   &hw_params);
355 	else
356 		return OPAL_UNSUPPORTED;
357 
358 	if (log)
359 		*log = hw_params.log;
360 
361 	if (rc != ROM_DONE)
362 		return OPAL_PARTIAL;
363 
364 	return OPAL_SUCCESS;
365 }
366