Commit 91fdabc67aebc2468ad362c02449f215e0971c68

Authored by Pierre Aubert
Committed by Pantelis Antoniou
1 parent 6b2221b008

eMMC: add support for operations in RPMB partition

This patch adds functions for read, write and authentication
key programming for the Replay Protected Memory Block partition
in the eMMC.

Acked-by: Pantelis Antoniou <panto@antoniou-consulting.com>
Signed-off-by: Pierre Aubert <p.aubert@staubli.com>

Showing 4 changed files with 334 additions and 1 deletions Side-by-side Diff

drivers/mmc/Makefile
... ... @@ -30,6 +30,7 @@
30 30 obj-$(CONFIG_EXYNOS_DWMMC) += exynos_dw_mmc.o
31 31 obj-$(CONFIG_ZYNQ_SDHCI) += zynq_sdhci.o
32 32 obj-$(CONFIG_SOCFPGA_DWMMC) += socfpga_dw_mmc.o
  33 +obj-$(CONFIG_SUPPORT_EMMC_RPMB) += rpmb.o
33 34 ifdef CONFIG_SPL_BUILD
34 35 obj-$(CONFIG_SPL_MMC_BOOT) += fsl_esdhc_spl.o
35 36 else
  1 +/*
  2 + * Copyright 2014, Staubli Faverges
  3 + * Pierre Aubert
  4 + *
  5 + * eMMC- Replay Protected Memory Block
  6 + * According to JEDEC Standard No. 84-A441
  7 + *
  8 + * SPDX-License-Identifier: GPL-2.0+
  9 + */
  10 +
  11 +#include <config.h>
  12 +#include <common.h>
  13 +#include <mmc.h>
  14 +#include <sha256.h>
  15 +#include "mmc_private.h"
  16 +
  17 +/* Request codes */
  18 +#define RPMB_REQ_KEY 1
  19 +#define RPMB_REQ_WCOUNTER 2
  20 +#define RPMB_REQ_WRITE_DATA 3
  21 +#define RPMB_REQ_READ_DATA 4
  22 +#define RPMB_REQ_STATUS 5
  23 +
  24 +/* Response code */
  25 +#define RPMB_RESP_KEY 0x0100
  26 +#define RPMB_RESP_WCOUNTER 0x0200
  27 +#define RPMB_RESP_WRITE_DATA 0x0300
  28 +#define RPMB_RESP_READ_DATA 0x0400
  29 +
  30 +/* Error codes */
  31 +#define RPMB_OK 0
  32 +#define RPMB_ERR_GENERAL 1
  33 +#define RPMB_ERR_AUTH 2
  34 +#define RPMB_ERR_COUNTER 3
  35 +#define RPMB_ERR_ADDRESS 4
  36 +#define RPMB_ERR_WRITE 5
  37 +#define RPMB_ERR_READ 6
  38 +#define RPMB_ERR_KEY 7
  39 +#define RPMB_ERR_CNT_EXPIRED 0x80
  40 +#define RPMB_ERR_MSK 0x7
  41 +
  42 +/* Sizes of RPMB data frame */
  43 +#define RPMB_SZ_STUFF 196
  44 +#define RPMB_SZ_MAC 32
  45 +#define RPMB_SZ_DATA 256
  46 +#define RPMB_SZ_NONCE 16
  47 +
  48 +#define SHA256_BLOCK_SIZE 64
  49 +
  50 +/* Error messages */
  51 +static const char * const rpmb_err_msg[] = {
  52 + "",
  53 + "General failure",
  54 + "Authentication failure",
  55 + "Counter failure",
  56 + "Address failure",
  57 + "Write failure",
  58 + "Read failure",
  59 + "Authentication key not yet programmed",
  60 +};
  61 +
  62 +
  63 +/* Structure of RPMB data frame. */
  64 +struct s_rpmb {
  65 + unsigned char stuff[RPMB_SZ_STUFF];
  66 + unsigned char mac[RPMB_SZ_MAC];
  67 + unsigned char data[RPMB_SZ_DATA];
  68 + unsigned char nonce[RPMB_SZ_NONCE];
  69 + unsigned long write_counter;
  70 + unsigned short address;
  71 + unsigned short block_count;
  72 + unsigned short result;
  73 + unsigned short request;
  74 +};
  75 +
  76 +static int mmc_set_blockcount(struct mmc *mmc, unsigned int blockcount,
  77 + bool is_rel_write)
  78 +{
  79 + struct mmc_cmd cmd = {0};
  80 +
  81 + cmd.cmdidx = MMC_CMD_SET_BLOCK_COUNT;
  82 + cmd.cmdarg = blockcount & 0x0000FFFF;
  83 + if (is_rel_write)
  84 + cmd.cmdarg |= 1 << 31;
  85 + cmd.resp_type = MMC_RSP_R1;
  86 +
  87 + return mmc_send_cmd(mmc, &cmd, NULL);
  88 +}
  89 +static int mmc_rpmb_request(struct mmc *mmc, const struct s_rpmb *s,
  90 + unsigned int count, bool is_rel_write)
  91 +{
  92 + struct mmc_cmd cmd = {0};
  93 + struct mmc_data data;
  94 + int ret;
  95 +
  96 + ret = mmc_set_blockcount(mmc, count, is_rel_write);
  97 + if (ret) {
  98 +#ifdef CONFIG_MMC_RPMB_TRACE
  99 + printf("%s:mmc_set_blockcount-> %d\n", __func__, ret);
  100 +#endif
  101 + return 1;
  102 + }
  103 +
  104 + cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK;
  105 + cmd.cmdarg = 0;
  106 + cmd.resp_type = MMC_RSP_R1b;
  107 +
  108 + data.src = (const char *)s;
  109 + data.blocks = 1;
  110 + data.blocksize = MMC_MAX_BLOCK_LEN;
  111 + data.flags = MMC_DATA_WRITE;
  112 +
  113 + ret = mmc_send_cmd(mmc, &cmd, &data);
  114 + if (ret) {
  115 +#ifdef CONFIG_MMC_RPMB_TRACE
  116 + printf("%s:mmc_send_cmd-> %d\n", __func__, ret);
  117 +#endif
  118 + return 1;
  119 + }
  120 + return 0;
  121 +}
  122 +static int mmc_rpmb_response(struct mmc *mmc, struct s_rpmb *s,
  123 + unsigned short expected)
  124 +{
  125 + struct mmc_cmd cmd = {0};
  126 + struct mmc_data data;
  127 + int ret;
  128 +
  129 + ret = mmc_set_blockcount(mmc, 1, false);
  130 + if (ret) {
  131 +#ifdef CONFIG_MMC_RPMB_TRACE
  132 + printf("%s:mmc_set_blockcount-> %d\n", __func__, ret);
  133 +#endif
  134 + return -1;
  135 + }
  136 + cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
  137 + cmd.cmdarg = 0;
  138 + cmd.resp_type = MMC_RSP_R1;
  139 +
  140 + data.dest = (char *)s;
  141 + data.blocks = 1;
  142 + data.blocksize = MMC_MAX_BLOCK_LEN;
  143 + data.flags = MMC_DATA_READ;
  144 +
  145 + ret = mmc_send_cmd(mmc, &cmd, &data);
  146 + if (ret) {
  147 +#ifdef CONFIG_MMC_RPMB_TRACE
  148 + printf("%s:mmc_send_cmd-> %d\n", __func__, ret);
  149 +#endif
  150 + return -1;
  151 + }
  152 + /* Check the response and the status */
  153 + if (be16_to_cpu(s->request) != expected) {
  154 +#ifdef CONFIG_MMC_RPMB_TRACE
  155 + printf("%s:response= %x\n", __func__,
  156 + be16_to_cpu(s->request));
  157 +#endif
  158 + return -1;
  159 + }
  160 + ret = be16_to_cpu(s->result);
  161 + if (ret) {
  162 + printf("%s %s\n", rpmb_err_msg[ret & RPMB_ERR_MSK],
  163 + (ret & RPMB_ERR_CNT_EXPIRED) ?
  164 + "Write counter has expired" : "");
  165 + }
  166 +
  167 + /* Return the status of the command */
  168 + return ret;
  169 +}
  170 +static int mmc_rpmb_status(struct mmc *mmc, unsigned short expected)
  171 +{
  172 + ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
  173 +
  174 + memset(rpmb_frame, 0, sizeof(struct s_rpmb));
  175 + rpmb_frame->request = cpu_to_be16(RPMB_REQ_STATUS);
  176 + if (mmc_rpmb_request(mmc, rpmb_frame, 1, false))
  177 + return -1;
  178 +
  179 + /* Read the result */
  180 + return mmc_rpmb_response(mmc, rpmb_frame, expected);
  181 +}
  182 +static void rpmb_hmac(unsigned char *key, unsigned char *buff, int len,
  183 + unsigned char *output)
  184 +{
  185 + sha256_context ctx;
  186 + int i;
  187 + unsigned char k_ipad[SHA256_BLOCK_SIZE];
  188 + unsigned char k_opad[SHA256_BLOCK_SIZE];
  189 +
  190 + sha256_starts(&ctx);
  191 +
  192 + /* According to RFC 4634, the HMAC transform looks like:
  193 + SHA(K XOR opad, SHA(K XOR ipad, text))
  194 +
  195 + where K is an n byte key.
  196 + ipad is the byte 0x36 repeated blocksize times
  197 + opad is the byte 0x5c repeated blocksize times
  198 + and text is the data being protected.
  199 + */
  200 +
  201 + for (i = 0; i < RPMB_SZ_MAC; i++) {
  202 + k_ipad[i] = key[i] ^ 0x36;
  203 + k_opad[i] = key[i] ^ 0x5c;
  204 + }
  205 + /* remaining pad bytes are '\0' XOR'd with ipad and opad values */
  206 + for ( ; i < SHA256_BLOCK_SIZE; i++) {
  207 + k_ipad[i] = 0x36;
  208 + k_opad[i] = 0x5c;
  209 + }
  210 + sha256_update(&ctx, k_ipad, SHA256_BLOCK_SIZE);
  211 + sha256_update(&ctx, buff, len);
  212 + sha256_finish(&ctx, output);
  213 +
  214 + /* Init context for second pass */
  215 + sha256_starts(&ctx);
  216 +
  217 + /* start with outer pad */
  218 + sha256_update(&ctx, k_opad, SHA256_BLOCK_SIZE);
  219 +
  220 + /* then results of 1st hash */
  221 + sha256_update(&ctx, output, RPMB_SZ_MAC);
  222 +
  223 + /* finish up 2nd pass */
  224 + sha256_finish(&ctx, output);
  225 +}
  226 +int mmc_rpmb_get_counter(struct mmc *mmc, unsigned long *pcounter)
  227 +{
  228 + int ret;
  229 + ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
  230 +
  231 + /* Fill the request */
  232 + memset(rpmb_frame, 0, sizeof(struct s_rpmb));
  233 + rpmb_frame->request = cpu_to_be16(RPMB_REQ_WCOUNTER);
  234 + if (mmc_rpmb_request(mmc, rpmb_frame, 1, false))
  235 + return -1;
  236 +
  237 + /* Read the result */
  238 + ret = mmc_rpmb_response(mmc, rpmb_frame, RPMB_RESP_WCOUNTER);
  239 + if (ret)
  240 + return ret;
  241 +
  242 + *pcounter = be32_to_cpu(rpmb_frame->write_counter);
  243 + return 0;
  244 +}
  245 +int mmc_rpmb_set_key(struct mmc *mmc, void *key)
  246 +{
  247 + ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
  248 + /* Fill the request */
  249 + memset(rpmb_frame, 0, sizeof(struct s_rpmb));
  250 + rpmb_frame->request = cpu_to_be16(RPMB_REQ_KEY);
  251 + memcpy(rpmb_frame->mac, key, RPMB_SZ_MAC);
  252 +
  253 + if (mmc_rpmb_request(mmc, rpmb_frame, 1, true))
  254 + return -1;
  255 +
  256 + /* read the operation status */
  257 + return mmc_rpmb_status(mmc, RPMB_RESP_KEY);
  258 +}
  259 +int mmc_rpmb_read(struct mmc *mmc, void *addr, unsigned short blk,
  260 + unsigned short cnt, unsigned char *key)
  261 +{
  262 + ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
  263 + int i;
  264 +
  265 + for (i = 0; i < cnt; i++) {
  266 + /* Fill the request */
  267 + memset(rpmb_frame, 0, sizeof(struct s_rpmb));
  268 + rpmb_frame->address = cpu_to_be16(blk + i);
  269 + rpmb_frame->request = cpu_to_be16(RPMB_REQ_READ_DATA);
  270 + if (mmc_rpmb_request(mmc, rpmb_frame, 1, false))
  271 + break;
  272 +
  273 + /* Read the result */
  274 + if (mmc_rpmb_response(mmc, rpmb_frame, RPMB_RESP_READ_DATA))
  275 + break;
  276 +
  277 + /* Check the HMAC if key is provided */
  278 + if (key) {
  279 + unsigned char ret_hmac[RPMB_SZ_MAC];
  280 +
  281 + rpmb_hmac(key, rpmb_frame->data, 284, ret_hmac);
  282 + if (memcmp(ret_hmac, rpmb_frame->mac, RPMB_SZ_MAC)) {
  283 + printf("MAC error on block #%d\n", i);
  284 + break;
  285 + }
  286 + }
  287 + /* Copy data */
  288 + memcpy(addr + i * RPMB_SZ_DATA, rpmb_frame->data, RPMB_SZ_DATA);
  289 + }
  290 + return i;
  291 +}
  292 +int mmc_rpmb_write(struct mmc *mmc, void *addr, unsigned short blk,
  293 + unsigned short cnt, unsigned char *key)
  294 +{
  295 + ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
  296 + unsigned long wcount;
  297 + int i;
  298 +
  299 + for (i = 0; i < cnt; i++) {
  300 + if (mmc_rpmb_get_counter(mmc, &wcount)) {
  301 + printf("Cannot read RPMB write counter\n");
  302 + break;
  303 + }
  304 +
  305 + /* Fill the request */
  306 + memset(rpmb_frame, 0, sizeof(struct s_rpmb));
  307 + memcpy(rpmb_frame->data, addr + i * RPMB_SZ_DATA, RPMB_SZ_DATA);
  308 + rpmb_frame->address = cpu_to_be16(blk + i);
  309 + rpmb_frame->block_count = cpu_to_be16(1);
  310 + rpmb_frame->write_counter = cpu_to_be32(wcount);
  311 + rpmb_frame->request = cpu_to_be16(RPMB_REQ_WRITE_DATA);
  312 + /* Computes HMAC */
  313 + rpmb_hmac(key, rpmb_frame->data, 284, rpmb_frame->mac);
  314 +
  315 + if (mmc_rpmb_request(mmc, rpmb_frame, 1, true))
  316 + break;
  317 +
  318 + /* Get status */
  319 + if (mmc_rpmb_status(mmc, RPMB_RESP_WRITE_DATA))
  320 + break;
  321 + }
  322 + return i;
  323 +}
... ... @@ -71,6 +71,7 @@
71 71 #define MMC_CMD_SET_BLOCKLEN 16
72 72 #define MMC_CMD_READ_SINGLE_BLOCK 17
73 73 #define MMC_CMD_READ_MULTIPLE_BLOCK 18
  74 +#define MMC_CMD_SET_BLOCK_COUNT 23
74 75 #define MMC_CMD_WRITE_SINGLE_BLOCK 24
75 76 #define MMC_CMD_WRITE_MULTIPLE_BLOCK 25
76 77 #define MMC_CMD_ERASE_GROUP_START 35
... ... @@ -227,6 +228,7 @@
227 228 * boot partitions (2), general purpose partitions (4) in MMC v4.4.
228 229 */
229 230 #define MMC_NUM_BOOT_PARTITION 2
  231 +#define MMC_PART_RPMB 3 /* RPMB partition number */
230 232  
231 233 struct mmc_cid {
232 234 unsigned long psn;
... ... @@ -338,7 +340,13 @@
338 340 int mmc_set_boot_bus_width(struct mmc *mmc, u8 width, u8 reset, u8 mode);
339 341 /* Function to modify the RST_n_FUNCTION field of EXT_CSD */
340 342 int mmc_set_rst_n_function(struct mmc *mmc, u8 enable);
341   -
  343 +/* Functions to read / write the RPMB partition */
  344 +int mmc_rpmb_set_key(struct mmc *mmc, void *key);
  345 +int mmc_rpmb_get_counter(struct mmc *mmc, unsigned long *counter);
  346 +int mmc_rpmb_read(struct mmc *mmc, void *addr, unsigned short blk,
  347 + unsigned short cnt, unsigned char *key);
  348 +int mmc_rpmb_write(struct mmc *mmc, void *addr, unsigned short blk,
  349 + unsigned short cnt, unsigned char *key);
342 350 /**
343 351 * Start device initialization and return immediately; it does not block on
344 352 * polling OCR (operation condition register) status. Then you should call
... ... @@ -35,6 +35,7 @@
35 35 obj-$(CONFIG_PHYSMEM) += physmem.o
36 36 obj-y += qsort.o
37 37 obj-$(CONFIG_SHA1) += sha1.o
  38 +obj-$(CONFIG_SUPPORT_EMMC_RPMB) += sha256.o
38 39 obj-$(CONFIG_SHA256) += sha256.o
39 40 obj-y += strmhz.o
40 41 obj-$(CONFIG_TPM) += tpm.o