1 /*
2  * Copyright (c) 2023 Microchip Technology Inc.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT microchip_xec_symcr
8 
9 #include <errno.h>
10 #include <string.h>
11 #include <zephyr/kernel.h>
12 #include <zephyr/crypto/crypto.h>
13 #include <zephyr/drivers/clock_control.h>
14 #include <zephyr/drivers/clock_control/mchp_xec_clock_control.h>
15 #include <zephyr/sys/util.h>
16 #include <zephyr/logging/log.h>
17 LOG_MODULE_REGISTER(xec_symcr, CONFIG_CRYPTO_LOG_LEVEL);
18 
19 #include <soc.h>
20 
21 /* ROM API for Hash without using external files */
22 
23 enum mchp_rom_hash_alg_id {
24 	MCHP_ROM_HASH_ALG_NONE = 0,
25 	MCHP_ROM_HASH_ALG_SHA1,
26 	MCHP_ROM_HASH_ALG_SHA224,
27 	MCHP_ROM_HASH_ALG_SHA256,
28 	MCHP_ROM_HASH_ALG_SHA384,
29 	MCHP_ROM_HASH_ALG_SHA512,
30 	MCHP_ROM_HASH_ALG_SM3,
31 	MCHP_ROM_HASH_ALG_MAX
32 };
33 
34 #define MCHP_XEC_STRUCT_HASH_STATE_STRUCT_SIZE	8
35 #define MCHP_XEC_STRUCT_HASH_STRUCT_SIZE	240
36 
37 struct mchphashstate {
38 	uint32_t v[MCHP_XEC_STRUCT_HASH_STATE_STRUCT_SIZE / 4];
39 };
40 
41 struct mchphash {
42 	uint32_t v[MCHP_XEC_STRUCT_HASH_STRUCT_SIZE / 4];
43 };
44 
45 #define MCHP_XEC_ROM_API_BASE DT_REG_ADDR(DT_NODELABEL(rom_api))
46 #define MCHP_XEC_ROM_API_ADDR(n)						\
47 	(((uint32_t)(MCHP_XEC_ROM_API_BASE) + ((uint32_t)(n) * 4u)) | BIT(0))
48 
49 #define MCHP_XEC_ROM_HASH_CREATE_SHA224_ID 95
50 #define mchp_xec_rom_hash_create_sha224						\
51 	((int (*)(struct mchphash *)) MCHP_XEC_ROM_API_ADDR(MCHP_XEC_ROM_HASH_CREATE_SHA224_ID))
52 
53 #define MCHP_XEC_ROM_HASH_CREATE_SHA256_ID 96
54 #define mchp_xec_rom_hash_create_sha256						\
55 	((int (*)(struct mchphash *)) MCHP_XEC_ROM_API_ADDR(MCHP_XEC_ROM_HASH_CREATE_SHA256_ID))
56 
57 #define MCHP_XEC_ROM_HASH_CREATE_SHA384_ID 97
58 #define mchp_xec_rom_hash_create_sha384						\
59 	((int (*)(struct mchphash *)) MCHP_XEC_ROM_API_ADDR(MCHP_XEC_ROM_HASH_CREATE_SHA384_ID))
60 
61 #define MCHP_XEC_ROM_HASH_CREATE_SHA512_ID 98
62 #define mchp_xec_rom_hash_create_sha512						\
63 	((int (*)(struct mchphash *)) MCHP_XEC_ROM_API_ADDR(MCHP_XEC_ROM_HASH_CREATE_SHA512_ID))
64 
65 
66 #define MCHP_XEC_ROM_HASH_INIT_STATE_ID 100
67 #define mec172x_rom_hash_init_state						\
68 	((void (*)(struct mchphash *, struct mchphashstate *, char *))		\
69 		MCHP_XEC_ROM_API_ADDR(MCHP_XEC_ROM_HASH_INIT_STATE_ID))
70 
71 #define MCHP_XEC_ROM_HASH_RESUME_STATE_ID 101
72 #define mchp_xec_rom_hash_resume_state						\
73 	((void (*)(struct mchphash *, struct mchphashstate *))			\
74 		MCHP_XEC_ROM_API_ADDR(MCHP_XEC_ROM_HASH_RESUME_STATE_ID))
75 
76 #define MCHP_XEC_ROM_HASH_SAVE_STATE_ID 102
77 #define mchp_xec_rom_hash_save_state						\
78 	((int (*)(struct mchphash *)) MCHP_XEC_ROM_API_ADDR(MCHP_XEC_ROM_HASH_SAVE_STATE_ID))
79 
80 #define MCHP_XEC_ROM_HASH_FEED_ID 103
81 #define mchp_xec_rom_hash_feed							\
82 	((int (*)(struct mchphash *, const uint8_t *, size_t))			\
83 		MCHP_XEC_ROM_API_ADDR(MCHP_XEC_ROM_HASH_FEED_ID))
84 
85 #define MCHP_XEC_ROM_HASH_DIGEST_ID 104
86 #define mchp_xec_rom_hash_digest						\
87 	((int (*)(struct mchphash *, char *)) MCHP_XEC_ROM_API_ADDR(MCHP_XEC_ROM_HASH_DIGEST_ID))
88 
89 #define MCHP_XEC_ROM_HASH_WAIT_ID 105
90 #define mec172x_rom_hash_wait							\
91 	((int (*)(struct mchphash *)) MCHP_XEC_ROM_API_ADDR(MCHP_XEC_ROM_HASH_WAIT_ID))
92 
93 #define MCHP_XEC_ROM_AH_DMA_INIT_ID 144
94 #define mchp_xec_rom_ah_dma_init						\
95 	((int (*)(uint8_t)) MCHP_XEC_ROM_API_ADDR(MCHP_XEC_ROM_AH_DMA_INIT_ID))
96 
97 #define MCHP_ROM_AH_DMA_INIT_NO_RESET 0
98 #define MCHP_ROM_AH_DMA_INIT_WITH_RESET 1
99 
100 #define MCHP_XEC_SYMCR_CAPS_SUPPORT	\
101 	(CAP_RAW_KEY | CAP_SEPARATE_IO_BUFS | CAP_SYNC_OPS | CAP_NO_IV_PREFIX)
102 #define MCHP_XEC_SYMCR_MAX_SESSION	1
103 #define MCHP_XEC_STATE_BUF_SIZE 256
104 #define MCHP_XEC_BLOCK_BUF_SIZE 128
105 
106 struct xec_symcr_hash_session {
107 	struct mchphash mhctx;
108 	struct mchphashstate mhstate;
109 	enum hash_algo algo;
110 	enum mchp_rom_hash_alg_id rom_algo;
111 	bool open;
112 	size_t blksz;
113 	size_t blklen;
114 	uint8_t blockbuf[MCHP_XEC_BLOCK_BUF_SIZE] __aligned(4);
115 	uint8_t statebuf[MCHP_XEC_STATE_BUF_SIZE] __aligned(4);
116 };
117 
118 struct xec_symcr_config {
119 	uint32_t regbase;
120 	const struct device *clk_dev;
121 	struct mchp_xec_pcr_clk_ctrl clk_ctrl;
122 	uint8_t irq_num;
123 	uint8_t girq;
124 	uint8_t girq_pos;
125 	uint8_t rsvd1;
126 };
127 
128 struct xec_symcr_data {
129 	struct xec_symcr_hash_session hash_sessions[MCHP_XEC_SYMCR_MAX_SESSION];
130 };
131 
mchp_xec_get_unused_session_index(struct xec_symcr_data * data)132 static int mchp_xec_get_unused_session_index(struct xec_symcr_data *data)
133 {
134 	int i;
135 
136 	for (i = 0; i < MCHP_XEC_SYMCR_MAX_SESSION; i++) {
137 		if (!data->hash_sessions[i].open) {
138 			data->hash_sessions[i].open = true;
139 			return i;
140 		}
141 	}
142 
143 	return -EPERM;
144 }
145 
146 struct hash_alg_to_rom {
147 	enum hash_algo algo;
148 	enum mchp_rom_hash_alg_id rom_algo;
149 };
150 
151 const struct hash_alg_to_rom hash_alg_tbl[] = {
152 	{ CRYPTO_HASH_ALGO_SHA224, MCHP_ROM_HASH_ALG_SHA224 },
153 	{ CRYPTO_HASH_ALGO_SHA256, MCHP_ROM_HASH_ALG_SHA256 },
154 	{ CRYPTO_HASH_ALGO_SHA384, MCHP_ROM_HASH_ALG_SHA384 },
155 	{ CRYPTO_HASH_ALGO_SHA512, MCHP_ROM_HASH_ALG_SHA512 },
156 };
157 
lookup_hash_alg(enum hash_algo algo)158 static enum mchp_rom_hash_alg_id lookup_hash_alg(enum hash_algo algo)
159 {
160 	for (size_t n = 0; n < ARRAY_SIZE(hash_alg_tbl); n++) {
161 		if (hash_alg_tbl[n].algo == algo) {
162 			return hash_alg_tbl[n].rom_algo;
163 		}
164 	}
165 
166 	return MCHP_ROM_HASH_ALG_NONE;
167 }
168 
169 /* SHA-1, 224, and 256 use block size of 64 bytes
170  * SHA-384 and 512 use 128 bytes.
171  */
hash_block_size(enum hash_algo algo)172 static size_t hash_block_size(enum hash_algo algo)
173 {
174 	switch (algo) {
175 	case CRYPTO_HASH_ALGO_SHA384:
176 	case CRYPTO_HASH_ALGO_SHA512:
177 		return 128u;
178 	default:
179 		return 64u;
180 	}
181 }
182 
init_rom_hash_context(enum mchp_rom_hash_alg_id rom_algo,struct mchphash * c)183 static int init_rom_hash_context(enum mchp_rom_hash_alg_id rom_algo, struct mchphash *c)
184 {
185 	int ret = 0;
186 
187 	if (!c) {
188 		return -EINVAL;
189 	}
190 
191 	switch (rom_algo) {
192 	case MCHP_ROM_HASH_ALG_SHA224:
193 		ret = mchp_xec_rom_hash_create_sha224(c);
194 		break;
195 	case MCHP_ROM_HASH_ALG_SHA256:
196 		ret = mchp_xec_rom_hash_create_sha256(c);
197 		break;
198 	case MCHP_ROM_HASH_ALG_SHA384:
199 		ret = mchp_xec_rom_hash_create_sha384(c);
200 		break;
201 	case MCHP_ROM_HASH_ALG_SHA512:
202 		ret = mchp_xec_rom_hash_create_sha512(c);
203 		break;
204 	default:
205 		return -EINVAL;
206 	}
207 
208 	if (ret) { /* use zephyr return value */
209 		ret = -EIO;
210 	}
211 
212 	return ret;
213 }
214 
215 /* use zephyr return values */
mchp_xec_rom_hash_init_state_wrapper(struct mchphash * c,struct mchphashstate * h,uint8_t * dmamem)216 int mchp_xec_rom_hash_init_state_wrapper(struct mchphash *c, struct mchphashstate *h,
217 					 uint8_t *dmamem)
218 {
219 	if (!c || !h || !dmamem) {
220 		return -EINVAL;
221 	}
222 
223 	mec172x_rom_hash_init_state(c, h, (char *)dmamem);
224 
225 	return 0;
226 }
227 
mchp_xec_rom_hash_resume_state_wrapper(struct mchphash * c,struct mchphashstate * h)228 int mchp_xec_rom_hash_resume_state_wrapper(struct mchphash *c, struct mchphashstate *h)
229 {
230 	if (!c || !h) {
231 		return -EINVAL;
232 	}
233 
234 	mchp_xec_rom_hash_resume_state(c, h);
235 	return 0;
236 }
237 
mchp_xec_rom_hash_save_state_wrapper(struct mchphash * c)238 int mchp_xec_rom_hash_save_state_wrapper(struct mchphash *c)
239 {
240 	if (!c) {
241 		return -EINVAL;
242 	}
243 
244 	if (mchp_xec_rom_hash_save_state(c) != 0) {
245 		return -EIO;
246 	}
247 
248 	return 0;
249 }
250 
mchp_xec_rom_hash_feed_wrapper(struct mchphash * c,const uint8_t * msg,size_t sz)251 int mchp_xec_rom_hash_feed_wrapper(struct mchphash *c, const uint8_t *msg, size_t sz)
252 {
253 	if ((!c) || (!msg && sz)) {
254 		return -EINVAL;
255 	}
256 
257 	if (mchp_xec_rom_hash_feed(c, (const char *)msg, sz) != 0) {
258 		return -EIO;
259 	}
260 
261 	return 0;
262 }
263 
mchp_xec_rom_hash_digest_wrapper(struct mchphash * c,uint8_t * digest)264 int mchp_xec_rom_hash_digest_wrapper(struct mchphash *c, uint8_t *digest)
265 {
266 	if (!c || !digest) {
267 		return -EINVAL;
268 	}
269 
270 	if (mchp_xec_rom_hash_digest(c, (char *)digest)) {
271 		return -EIO;
272 	}
273 
274 	return 0;
275 }
276 
277 /* Wait for hardware to finish.
278  * returns 0 if hardware finished with no errors
279  * returns -EIO if hardware stopped due to error
280  * returns -EINVAL if parameter is bad, hardware may still be running!
281  */
mchp_xec_rom_hash_wait_wrapper(struct mchphash * c)282 int mchp_xec_rom_hash_wait_wrapper(struct mchphash *c)
283 {
284 	if (!c) {
285 		return -EINVAL;
286 	}
287 
288 	if (mec172x_rom_hash_wait(c) != 0) {
289 		return -EIO;
290 	}
291 
292 	return 0;
293 }
294 
295 /* Called by application for update(finish==false)
296  * and compute final hash digest(finish==true)
297  */
xec_symcr_do_hash(struct hash_ctx * ctx,struct hash_pkt * pkt,bool finish)298 static int xec_symcr_do_hash(struct hash_ctx *ctx, struct hash_pkt *pkt, bool finish)
299 {
300 	struct xec_symcr_hash_session *hs = NULL;
301 	struct mchphash *c = NULL;
302 	struct mchphashstate *cstate = NULL;
303 	size_t fill_len = 0, rem_len = 0;
304 	int ret = 0;
305 
306 	if (!ctx || !pkt) {
307 		return -EINVAL;
308 	}
309 
310 	hs = (struct xec_symcr_hash_session *)ctx->drv_sessn_state;
311 	c = &hs->mhctx;
312 	cstate = &hs->mhstate;
313 
314 	if (!hs->open) {
315 		LOG_ERR("Session not open");
316 		return -EIO;
317 	}
318 
319 	if (!finish && !pkt->in_len) {
320 		return 0; /* nothing to do */
321 	}
322 
323 	/* Not final digest computation and not enough data to run engine */
324 	if (!finish && ((hs->blklen + pkt->in_len) < hs->blksz)) {
325 		memcpy(&hs->blockbuf[hs->blklen], pkt->in_buf, pkt->in_len);
326 		hs->blklen += pkt->in_len;
327 		return 0;
328 	}
329 
330 	ret = init_rom_hash_context(hs->rom_algo, c);
331 	if (ret) {
332 		LOG_ERR("ROM context init error %d", ret);
333 		return ret;
334 	}
335 	ret = mchp_xec_rom_hash_resume_state_wrapper(c, cstate);
336 	if (ret) {
337 		LOG_ERR("Resume state error %d", ret);
338 		return ret;
339 	}
340 
341 	fill_len = pkt->in_len;
342 	rem_len = 0;
343 	if (!finish) {
344 		rem_len = pkt->in_len & (hs->blksz - 1u);
345 		fill_len = pkt->in_len & ~(hs->blksz - 1u);
346 		if (hs->blklen) {
347 			fill_len = ((hs->blklen + pkt->in_len) & ~(hs->blksz - 1u)) - hs->blklen;
348 			rem_len = pkt->in_len - fill_len;
349 		}
350 	}
351 
352 	if (hs->blklen) {
353 		ret = mchp_xec_rom_hash_feed_wrapper(c, (const uint8_t *)hs->blockbuf, hs->blklen);
354 		if (ret) {
355 			LOG_ERR("ROM hash feed error %d", ret);
356 			return ret;
357 		}
358 		hs->blklen = 0; /* consumed */
359 	}
360 
361 	ret = mchp_xec_rom_hash_feed_wrapper(c, (const uint8_t *)pkt->in_buf, fill_len);
362 	if (ret) {
363 		LOG_ERR("ROM hash feed error %d", ret);
364 		return ret;
365 	}
366 
367 	if (finish) {
368 		ret = mchp_xec_rom_hash_digest_wrapper(c, pkt->out_buf);
369 		if (ret) {
370 			LOG_ERR("ROM Hash final error %d", ret);
371 			return ret;
372 		}
373 	} else {
374 		ret = mchp_xec_rom_hash_save_state(c);
375 		if (ret) {
376 			LOG_ERR("ROM hash save state error %d", ret);
377 			return ret;
378 		}
379 	}
380 	ret = mchp_xec_rom_hash_wait_wrapper(c);
381 	if (ret) {
382 		LOG_ERR("ROM hash wait error %d", ret);
383 		return ret;
384 	}
385 	if (finish) {
386 		hs->blklen = 0;
387 	} else {
388 		memcpy(hs->blockbuf, &pkt->in_buf[fill_len], rem_len);
389 		hs->blklen = rem_len;
390 	}
391 
392 	return 0;
393 }
394 
xec_symcr_hash_session_begin(const struct device * dev,struct hash_ctx * ctx,enum hash_algo algo)395 static int xec_symcr_hash_session_begin(const struct device *dev, struct hash_ctx *ctx,
396 					enum hash_algo algo)
397 {
398 	struct xec_symcr_data *data = dev->data;
399 	struct xec_symcr_hash_session *hs = NULL;
400 	struct mchphash *c = NULL;
401 	struct mchphashstate *cstate = NULL;
402 	enum mchp_rom_hash_alg_id rom_algo = MCHP_ROM_HASH_ALG_NONE;
403 	int session_idx = 0;
404 	int ret = 0;
405 
406 	if (ctx->flags & ~(MCHP_XEC_SYMCR_CAPS_SUPPORT)) {
407 		LOG_ERR("Unsupported flag");
408 		return -EINVAL;
409 	}
410 
411 	rom_algo = lookup_hash_alg(algo);
412 	if (rom_algo == MCHP_ROM_HASH_ALG_NONE) {
413 		LOG_ERR("Unsupported algo %d", algo);
414 		return -EINVAL;
415 	}
416 
417 	session_idx = mchp_xec_get_unused_session_index(data);
418 	if (session_idx < 0) {
419 		LOG_ERR("No session available");
420 		return -ENOSPC;
421 	}
422 
423 	hs = &data->hash_sessions[session_idx];
424 
425 	hs->algo = algo;
426 	hs->rom_algo = rom_algo;
427 	hs->open = false;
428 	hs->blklen = 0;
429 	hs->blksz = hash_block_size(algo);
430 
431 	ctx->drv_sessn_state = hs;
432 	ctx->started = false;
433 	ctx->hash_hndlr = xec_symcr_do_hash;
434 
435 	/* reset HW at beginning of session */
436 	ret = mchp_xec_rom_ah_dma_init(MCHP_ROM_AH_DMA_INIT_WITH_RESET);
437 	if (ret) {
438 		LOG_ERR("ROM HW init error %d", ret);
439 		return -EIO;
440 	}
441 
442 	c = &hs->mhctx;
443 	cstate = &hs->mhstate;
444 
445 	ret = init_rom_hash_context(hs->rom_algo, c);
446 	if (ret) {
447 		LOG_ERR("ROM HW context init error %d", ret);
448 		return ret;
449 	}
450 
451 	ret = mchp_xec_rom_hash_init_state_wrapper(c, cstate, hs->statebuf);
452 	if (ret) {
453 		LOG_ERR("ROM HW init state error %d", ret);
454 	}
455 
456 	hs->open = true;
457 
458 	return ret;
459 }
460 
461 /*
462  * struct hash_ctx {
463  *	const struct device *device; this device driver's instance structure
464  *	void *drv_sessn_state; pointer to driver instance struct session state. Defined by driver
465  *	hash_op hash_hndlr; pointer to this driver function. App calls via pointer to do operations
466  *	bool started; true if multipart hash has been started
467  *	uint16_t flags; app populates this before calling hash_begin_session
468  * }
469  */
xec_symcr_hash_session_free(const struct device * dev,struct hash_ctx * ctx)470 static int xec_symcr_hash_session_free(const struct device *dev, struct hash_ctx *ctx)
471 {
472 	struct xec_symcr_hash_session *hs = NULL;
473 	int ret = 0;
474 
475 	ret = mchp_xec_rom_ah_dma_init(MCHP_ROM_AH_DMA_INIT_WITH_RESET);
476 	if (ret) {
477 		ret = -EIO;
478 		LOG_ERR("ROM HW reset error %d", ret);
479 	}
480 
481 	hs = (struct xec_symcr_hash_session *)ctx->drv_sessn_state;
482 
483 	memset(hs, 0, sizeof(struct xec_symcr_hash_session));
484 
485 	return ret;
486 }
487 
xec_symcr_query_hw_caps(const struct device * dev)488 static int xec_symcr_query_hw_caps(const struct device *dev)
489 {
490 	return MCHP_XEC_SYMCR_CAPS_SUPPORT;
491 }
492 
xec_symcr_init(const struct device * dev)493 static int xec_symcr_init(const struct device *dev)
494 {
495 	const struct xec_symcr_config *cfg = dev->config;
496 	int ret;
497 
498 	if (!device_is_ready(cfg->clk_dev)) {
499 		LOG_ERR("clock device not ready");
500 		return -ENODEV;
501 	}
502 
503 	ret = clock_control_on(cfg->clk_dev, (clock_control_subsys_t *)&cfg->clk_ctrl);
504 	if (ret < 0) {
505 		LOG_ERR("clock on error %d", ret);
506 		return ret;
507 	}
508 
509 	ret = mchp_xec_rom_ah_dma_init(MCHP_ROM_AH_DMA_INIT_WITH_RESET);
510 	if (ret) {
511 		ret = -EIO;
512 	}
513 
514 	return ret;
515 }
516 
517 static DEVICE_API(crypto, xec_symcr_api) = {
518 	.query_hw_caps = xec_symcr_query_hw_caps,
519 	.hash_begin_session = xec_symcr_hash_session_begin,
520 	.hash_free_session = xec_symcr_hash_session_free,
521 };
522 
523 #define XEC_SYMCR_PCR_INFO(i)						\
524 	MCHP_XEC_PCR_SCR_ENCODE(DT_INST_CLOCKS_CELL(i, regidx),		\
525 				DT_INST_CLOCKS_CELL(i, bitpos),		\
526 				DT_INST_CLOCKS_CELL(i, domain))
527 
528 #define XEC_SYMCR_INIT(inst)								\
529 											\
530 	static struct xec_symcr_data xec_symcr_data_##inst;				\
531 											\
532 	static const struct xec_symcr_config xec_symcr_cfg_##inst = {			\
533 		.regbase = DT_INST_REG_ADDR(inst),					\
534 		.clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(inst)),			\
535 		.clk_ctrl = {								\
536 			.pcr_info = XEC_SYMCR_PCR_INFO(inst),				\
537 		},									\
538 		.irq_num = DT_INST_IRQN(inst),						\
539 		.girq = DT_INST_PROP_BY_IDX(inst, girqs, 0),				\
540 		.girq_pos = DT_INST_PROP_BY_IDX(inst, girqs, 1),			\
541 	};										\
542 											\
543 	DEVICE_DT_INST_DEFINE(inst, &xec_symcr_init, NULL,				\
544 			      &xec_symcr_data_##inst, &xec_symcr_cfg_##inst,		\
545 			      POST_KERNEL, CONFIG_CRYPTO_INIT_PRIORITY,			\
546 			      &xec_symcr_api);
547 
548 DT_INST_FOREACH_STATUS_OKAY(XEC_SYMCR_INIT)
549