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