Commit 4853ad3e13e21462a86e09caee4ea27ae68e764b

Authored by Jens Wiklander
Committed by Tom Rini
1 parent 6d89902d7a

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

... ... @@ -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 +}
... ... @@ -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