Commit 4853ad3e13e21462a86e09caee4ea27ae68e764b
Committed by
Tom Rini
1 parent
6d89902d7a
Exists in
smarc_8mq_lf_v2020.04
and in
12 other branches
mmc: rpmb: add mmc_rpmb_route_frames()
Adds mmc_rpmb_route_frames() to route RPMB data frames from/to an external entity. Tested-by: Igor Opaniuk <igor.opaniuk@linaro.org> Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org> Reviewed-by: Simon Glass <sjg@chromium.org>
Showing 2 changed files with 179 additions and 0 deletions Side-by-side Diff
drivers/mmc/rpmb.c
... | ... | @@ -321,4 +321,164 @@ |
321 | 321 | } |
322 | 322 | return i; |
323 | 323 | } |
324 | + | |
325 | +static int send_write_mult_block(struct mmc *mmc, const struct s_rpmb *frm, | |
326 | + unsigned short cnt) | |
327 | +{ | |
328 | + struct mmc_cmd cmd = { | |
329 | + .cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK, | |
330 | + .resp_type = MMC_RSP_R1b, | |
331 | + }; | |
332 | + struct mmc_data data = { | |
333 | + .src = (const void *)frm, | |
334 | + .blocks = cnt, | |
335 | + .blocksize = sizeof(*frm), | |
336 | + .flags = MMC_DATA_WRITE, | |
337 | + }; | |
338 | + | |
339 | + return mmc_send_cmd(mmc, &cmd, &data); | |
340 | +} | |
341 | + | |
342 | +static int send_read_mult_block(struct mmc *mmc, struct s_rpmb *frm, | |
343 | + unsigned short cnt) | |
344 | +{ | |
345 | + struct mmc_cmd cmd = { | |
346 | + .cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK, | |
347 | + .resp_type = MMC_RSP_R1, | |
348 | + }; | |
349 | + struct mmc_data data = { | |
350 | + .dest = (void *)frm, | |
351 | + .blocks = cnt, | |
352 | + .blocksize = sizeof(*frm), | |
353 | + .flags = MMC_DATA_READ, | |
354 | + }; | |
355 | + | |
356 | + return mmc_send_cmd(mmc, &cmd, &data); | |
357 | +} | |
358 | + | |
359 | +static int rpmb_route_write_req(struct mmc *mmc, struct s_rpmb *req, | |
360 | + unsigned short req_cnt, struct s_rpmb *rsp, | |
361 | + unsigned short rsp_cnt) | |
362 | +{ | |
363 | + int ret; | |
364 | + | |
365 | + /* | |
366 | + * Send the write request. | |
367 | + */ | |
368 | + ret = mmc_set_blockcount(mmc, req_cnt, true); | |
369 | + if (ret) | |
370 | + return ret; | |
371 | + | |
372 | + ret = send_write_mult_block(mmc, req, req_cnt); | |
373 | + if (ret) | |
374 | + return ret; | |
375 | + | |
376 | + /* | |
377 | + * Read the result of the request. | |
378 | + */ | |
379 | + ret = mmc_set_blockcount(mmc, 1, false); | |
380 | + if (ret) | |
381 | + return ret; | |
382 | + | |
383 | + memset(rsp, 0, sizeof(*rsp)); | |
384 | + rsp->request = cpu_to_be16(RPMB_REQ_STATUS); | |
385 | + ret = send_write_mult_block(mmc, rsp, 1); | |
386 | + if (ret) | |
387 | + return ret; | |
388 | + | |
389 | + ret = mmc_set_blockcount(mmc, 1, false); | |
390 | + if (ret) | |
391 | + return ret; | |
392 | + | |
393 | + return send_read_mult_block(mmc, rsp, 1); | |
394 | +} | |
395 | + | |
396 | +static int rpmb_route_read_req(struct mmc *mmc, struct s_rpmb *req, | |
397 | + unsigned short req_cnt, struct s_rpmb *rsp, | |
398 | + unsigned short rsp_cnt) | |
399 | +{ | |
400 | + int ret; | |
401 | + | |
402 | + /* | |
403 | + * Send the read request. | |
404 | + */ | |
405 | + ret = mmc_set_blockcount(mmc, 1, false); | |
406 | + if (ret) | |
407 | + return ret; | |
408 | + | |
409 | + ret = send_write_mult_block(mmc, req, 1); | |
410 | + if (ret) | |
411 | + return ret; | |
412 | + | |
413 | + /* | |
414 | + * Read the result of the request. | |
415 | + */ | |
416 | + | |
417 | + ret = mmc_set_blockcount(mmc, rsp_cnt, false); | |
418 | + if (ret) | |
419 | + return ret; | |
420 | + | |
421 | + return send_read_mult_block(mmc, rsp, rsp_cnt); | |
422 | +} | |
423 | + | |
424 | +static int rpmb_route_frames(struct mmc *mmc, struct s_rpmb *req, | |
425 | + unsigned short req_cnt, struct s_rpmb *rsp, | |
426 | + unsigned short rsp_cnt) | |
427 | +{ | |
428 | + unsigned short n; | |
429 | + | |
430 | + /* | |
431 | + * If multiple request frames are provided, make sure that all are | |
432 | + * of the same type. | |
433 | + */ | |
434 | + for (n = 1; n < req_cnt; n++) | |
435 | + if (req[n].request != req->request) | |
436 | + return -EINVAL; | |
437 | + | |
438 | + switch (be16_to_cpu(req->request)) { | |
439 | + case RPMB_REQ_KEY: | |
440 | + if (req_cnt != 1 || rsp_cnt != 1) | |
441 | + return -EINVAL; | |
442 | + return rpmb_route_write_req(mmc, req, req_cnt, rsp, rsp_cnt); | |
443 | + | |
444 | + case RPMB_REQ_WRITE_DATA: | |
445 | + if (!req_cnt || rsp_cnt != 1) | |
446 | + return -EINVAL; | |
447 | + return rpmb_route_write_req(mmc, req, req_cnt, rsp, rsp_cnt); | |
448 | + | |
449 | + case RPMB_REQ_WCOUNTER: | |
450 | + if (req_cnt != 1 || rsp_cnt != 1) | |
451 | + return -EINVAL; | |
452 | + return rpmb_route_read_req(mmc, req, req_cnt, rsp, rsp_cnt); | |
453 | + | |
454 | + case RPMB_REQ_READ_DATA: | |
455 | + if (req_cnt != 1 || !req_cnt) | |
456 | + return -EINVAL; | |
457 | + return rpmb_route_read_req(mmc, req, req_cnt, rsp, rsp_cnt); | |
458 | + | |
459 | + default: | |
460 | + debug("Unsupported message type: %d\n", | |
461 | + be16_to_cpu(req->request)); | |
462 | + return -EINVAL; | |
463 | + } | |
464 | +} | |
465 | + | |
466 | +int mmc_rpmb_route_frames(struct mmc *mmc, void *req, unsigned long reqlen, | |
467 | + void *rsp, unsigned long rsplen) | |
468 | +{ | |
469 | + /* | |
470 | + * Whoever crafted the data supplied to this function knows how to | |
471 | + * format the PRMB frames and which response is expected. If | |
472 | + * there's some unexpected mismatch it's more helpful to report an | |
473 | + * error immediately than trying to guess what was the intention | |
474 | + * and possibly just delay an eventual error which will be harder | |
475 | + * to track down. | |
476 | + */ | |
477 | + | |
478 | + if (reqlen % sizeof(struct s_rpmb) || rsplen % sizeof(struct s_rpmb)) | |
479 | + return -EINVAL; | |
480 | + | |
481 | + return rpmb_route_frames(mmc, req, reqlen / sizeof(struct s_rpmb), | |
482 | + rsp, rsplen / sizeof(struct s_rpmb)); | |
483 | +} |
include/mmc.h
... | ... | @@ -759,6 +759,25 @@ |
759 | 759 | unsigned short cnt, unsigned char *key); |
760 | 760 | int mmc_rpmb_write(struct mmc *mmc, void *addr, unsigned short blk, |
761 | 761 | unsigned short cnt, unsigned char *key); |
762 | + | |
763 | +/** | |
764 | + * mmc_rpmb_route_frames() - route RPMB data frames | |
765 | + * @mmc Pointer to a MMC device struct | |
766 | + * @req Request data frames | |
767 | + * @reqlen Length of data frames in bytes | |
768 | + * @rsp Supplied buffer for response data frames | |
769 | + * @rsplen Length of supplied buffer for response data frames | |
770 | + * | |
771 | + * The RPMB data frames are routed to/from some external entity, for | |
772 | + * example a Trusted Exectuion Environment in an arm TrustZone protected | |
773 | + * secure world. It's expected that it's the external entity who is in | |
774 | + * control of the RPMB key. | |
775 | + * | |
776 | + * Returns 0 on success, < 0 on error. | |
777 | + */ | |
778 | +int mmc_rpmb_route_frames(struct mmc *mmc, void *req, unsigned long reqlen, | |
779 | + void *rsp, unsigned long rsplen); | |
780 | + | |
762 | 781 | #ifdef CONFIG_CMD_BKOPS_ENABLE |
763 | 782 | int mmc_set_bkops_enable(struct mmc *mmc); |
764 | 783 | #endif |