blob: fa3ac2d9e37d43cd7bd1ca28df3563603bcad13f [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Pierre Aubert343cd9f2014-04-24 10:30:06 +02002/*
3 * Copyright 2014, Staubli Faverges
4 * Pierre Aubert
5 *
6 * eMMC- Replay Protected Memory Block
7 * According to JEDEC Standard No. 84-A441
Pierre Aubert343cd9f2014-04-24 10:30:06 +02008 */
9
10#include <config.h>
Simon Glass0f2af882020-05-10 11:40:05 -060011#include <log.h>
Simon Glass2dd337a2015-09-02 17:24:58 -060012#include <memalign.h>
Pierre Aubert343cd9f2014-04-24 10:30:06 +020013#include <mmc.h>
Bharat Kumar Reddy Gootya8e2e402019-11-22 15:13:09 -080014#include <sdhci.h>
Jeroen Hofsteebfe88fe2014-06-12 22:27:12 +020015#include <u-boot/sha256.h>
Pierre Aubert343cd9f2014-04-24 10:30:06 +020016#include "mmc_private.h"
17
18/* Request codes */
19#define RPMB_REQ_KEY 1
20#define RPMB_REQ_WCOUNTER 2
21#define RPMB_REQ_WRITE_DATA 3
22#define RPMB_REQ_READ_DATA 4
23#define RPMB_REQ_STATUS 5
24
25/* Response code */
26#define RPMB_RESP_KEY 0x0100
27#define RPMB_RESP_WCOUNTER 0x0200
28#define RPMB_RESP_WRITE_DATA 0x0300
29#define RPMB_RESP_READ_DATA 0x0400
30
31/* Error codes */
32#define RPMB_OK 0
33#define RPMB_ERR_GENERAL 1
34#define RPMB_ERR_AUTH 2
35#define RPMB_ERR_COUNTER 3
36#define RPMB_ERR_ADDRESS 4
37#define RPMB_ERR_WRITE 5
38#define RPMB_ERR_READ 6
39#define RPMB_ERR_KEY 7
40#define RPMB_ERR_CNT_EXPIRED 0x80
41#define RPMB_ERR_MSK 0x7
42
43/* Sizes of RPMB data frame */
44#define RPMB_SZ_STUFF 196
45#define RPMB_SZ_MAC 32
46#define RPMB_SZ_DATA 256
47#define RPMB_SZ_NONCE 16
48
49#define SHA256_BLOCK_SIZE 64
50
51/* Error messages */
52static const char * const rpmb_err_msg[] = {
53 "",
54 "General failure",
55 "Authentication failure",
56 "Counter failure",
57 "Address failure",
58 "Write failure",
59 "Read failure",
60 "Authentication key not yet programmed",
61};
62
Pierre Aubert343cd9f2014-04-24 10:30:06 +020063/* Structure of RPMB data frame. */
64struct 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];
Kever Yang9bfe3822017-06-08 09:20:04 +080069 unsigned int write_counter;
Pierre Aubert343cd9f2014-04-24 10:30:06 +020070 unsigned short address;
71 unsigned short block_count;
72 unsigned short result;
73 unsigned short request;
74};
75
76static 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}
89static 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;
Bharat Kumar Reddy Gootya8e2e402019-11-22 15:13:09 -080094 struct sdhci_host *host = mmc->priv;
Pierre Aubert343cd9f2014-04-24 10:30:06 +020095 int ret;
96
97 ret = mmc_set_blockcount(mmc, count, is_rel_write);
98 if (ret) {
99#ifdef CONFIG_MMC_RPMB_TRACE
100 printf("%s:mmc_set_blockcount-> %d\n", __func__, ret);
101#endif
102 return 1;
103 }
104
105 cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK;
106 cmd.cmdarg = 0;
Akio Hirayama7e40f412019-06-28 21:16:25 +0900107 cmd.resp_type = MMC_RSP_R1;
Pierre Aubert343cd9f2014-04-24 10:30:06 +0200108
Bharat Kumar Reddy Gootya8e2e402019-11-22 15:13:09 -0800109 if (host->quirks & SDHCI_QUIRK_BROKEN_R1B)
110 cmd.resp_type = MMC_RSP_R1;
111
Pierre Aubert343cd9f2014-04-24 10:30:06 +0200112 data.src = (const char *)s;
113 data.blocks = 1;
114 data.blocksize = MMC_MAX_BLOCK_LEN;
115 data.flags = MMC_DATA_WRITE;
116
117 ret = mmc_send_cmd(mmc, &cmd, &data);
118 if (ret) {
119#ifdef CONFIG_MMC_RPMB_TRACE
120 printf("%s:mmc_send_cmd-> %d\n", __func__, ret);
121#endif
122 return 1;
123 }
124 return 0;
125}
126static int mmc_rpmb_response(struct mmc *mmc, struct s_rpmb *s,
127 unsigned short expected)
128{
129 struct mmc_cmd cmd = {0};
130 struct mmc_data data;
131 int ret;
132
133 ret = mmc_set_blockcount(mmc, 1, false);
134 if (ret) {
135#ifdef CONFIG_MMC_RPMB_TRACE
136 printf("%s:mmc_set_blockcount-> %d\n", __func__, ret);
137#endif
138 return -1;
139 }
140 cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
141 cmd.cmdarg = 0;
142 cmd.resp_type = MMC_RSP_R1;
143
144 data.dest = (char *)s;
145 data.blocks = 1;
146 data.blocksize = MMC_MAX_BLOCK_LEN;
147 data.flags = MMC_DATA_READ;
148
149 ret = mmc_send_cmd(mmc, &cmd, &data);
150 if (ret) {
151#ifdef CONFIG_MMC_RPMB_TRACE
152 printf("%s:mmc_send_cmd-> %d\n", __func__, ret);
153#endif
154 return -1;
155 }
156 /* Check the response and the status */
157 if (be16_to_cpu(s->request) != expected) {
158#ifdef CONFIG_MMC_RPMB_TRACE
159 printf("%s:response= %x\n", __func__,
160 be16_to_cpu(s->request));
161#endif
162 return -1;
163 }
164 ret = be16_to_cpu(s->result);
165 if (ret) {
166 printf("%s %s\n", rpmb_err_msg[ret & RPMB_ERR_MSK],
167 (ret & RPMB_ERR_CNT_EXPIRED) ?
168 "Write counter has expired" : "");
169 }
170
171 /* Return the status of the command */
172 return ret;
173}
174static int mmc_rpmb_status(struct mmc *mmc, unsigned short expected)
175{
176 ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
177
178 memset(rpmb_frame, 0, sizeof(struct s_rpmb));
179 rpmb_frame->request = cpu_to_be16(RPMB_REQ_STATUS);
180 if (mmc_rpmb_request(mmc, rpmb_frame, 1, false))
181 return -1;
182
183 /* Read the result */
184 return mmc_rpmb_response(mmc, rpmb_frame, expected);
185}
186static void rpmb_hmac(unsigned char *key, unsigned char *buff, int len,
187 unsigned char *output)
188{
189 sha256_context ctx;
190 int i;
191 unsigned char k_ipad[SHA256_BLOCK_SIZE];
192 unsigned char k_opad[SHA256_BLOCK_SIZE];
193
194 sha256_starts(&ctx);
195
196 /* According to RFC 4634, the HMAC transform looks like:
197 SHA(K XOR opad, SHA(K XOR ipad, text))
198
199 where K is an n byte key.
200 ipad is the byte 0x36 repeated blocksize times
201 opad is the byte 0x5c repeated blocksize times
202 and text is the data being protected.
203 */
204
205 for (i = 0; i < RPMB_SZ_MAC; i++) {
206 k_ipad[i] = key[i] ^ 0x36;
207 k_opad[i] = key[i] ^ 0x5c;
208 }
209 /* remaining pad bytes are '\0' XOR'd with ipad and opad values */
210 for ( ; i < SHA256_BLOCK_SIZE; i++) {
211 k_ipad[i] = 0x36;
212 k_opad[i] = 0x5c;
213 }
214 sha256_update(&ctx, k_ipad, SHA256_BLOCK_SIZE);
215 sha256_update(&ctx, buff, len);
216 sha256_finish(&ctx, output);
217
218 /* Init context for second pass */
219 sha256_starts(&ctx);
220
221 /* start with outer pad */
222 sha256_update(&ctx, k_opad, SHA256_BLOCK_SIZE);
223
224 /* then results of 1st hash */
225 sha256_update(&ctx, output, RPMB_SZ_MAC);
226
227 /* finish up 2nd pass */
228 sha256_finish(&ctx, output);
229}
230int mmc_rpmb_get_counter(struct mmc *mmc, unsigned long *pcounter)
231{
232 int ret;
233 ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
234
235 /* Fill the request */
236 memset(rpmb_frame, 0, sizeof(struct s_rpmb));
237 rpmb_frame->request = cpu_to_be16(RPMB_REQ_WCOUNTER);
238 if (mmc_rpmb_request(mmc, rpmb_frame, 1, false))
239 return -1;
240
241 /* Read the result */
242 ret = mmc_rpmb_response(mmc, rpmb_frame, RPMB_RESP_WCOUNTER);
243 if (ret)
244 return ret;
245
246 *pcounter = be32_to_cpu(rpmb_frame->write_counter);
247 return 0;
248}
249int mmc_rpmb_set_key(struct mmc *mmc, void *key)
250{
251 ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
252 /* Fill the request */
253 memset(rpmb_frame, 0, sizeof(struct s_rpmb));
254 rpmb_frame->request = cpu_to_be16(RPMB_REQ_KEY);
255 memcpy(rpmb_frame->mac, key, RPMB_SZ_MAC);
256
257 if (mmc_rpmb_request(mmc, rpmb_frame, 1, true))
258 return -1;
259
260 /* read the operation status */
261 return mmc_rpmb_status(mmc, RPMB_RESP_KEY);
262}
263int mmc_rpmb_read(struct mmc *mmc, void *addr, unsigned short blk,
264 unsigned short cnt, unsigned char *key)
265{
266 ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
267 int i;
268
269 for (i = 0; i < cnt; i++) {
270 /* Fill the request */
271 memset(rpmb_frame, 0, sizeof(struct s_rpmb));
272 rpmb_frame->address = cpu_to_be16(blk + i);
273 rpmb_frame->request = cpu_to_be16(RPMB_REQ_READ_DATA);
274 if (mmc_rpmb_request(mmc, rpmb_frame, 1, false))
275 break;
276
277 /* Read the result */
278 if (mmc_rpmb_response(mmc, rpmb_frame, RPMB_RESP_READ_DATA))
279 break;
280
281 /* Check the HMAC if key is provided */
282 if (key) {
283 unsigned char ret_hmac[RPMB_SZ_MAC];
284
285 rpmb_hmac(key, rpmb_frame->data, 284, ret_hmac);
286 if (memcmp(ret_hmac, rpmb_frame->mac, RPMB_SZ_MAC)) {
287 printf("MAC error on block #%d\n", i);
288 break;
289 }
290 }
291 /* Copy data */
292 memcpy(addr + i * RPMB_SZ_DATA, rpmb_frame->data, RPMB_SZ_DATA);
293 }
294 return i;
295}
296int mmc_rpmb_write(struct mmc *mmc, void *addr, unsigned short blk,
297 unsigned short cnt, unsigned char *key)
298{
299 ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
300 unsigned long wcount;
301 int i;
302
303 for (i = 0; i < cnt; i++) {
304 if (mmc_rpmb_get_counter(mmc, &wcount)) {
305 printf("Cannot read RPMB write counter\n");
306 break;
307 }
308
309 /* Fill the request */
310 memset(rpmb_frame, 0, sizeof(struct s_rpmb));
311 memcpy(rpmb_frame->data, addr + i * RPMB_SZ_DATA, RPMB_SZ_DATA);
312 rpmb_frame->address = cpu_to_be16(blk + i);
313 rpmb_frame->block_count = cpu_to_be16(1);
314 rpmb_frame->write_counter = cpu_to_be32(wcount);
315 rpmb_frame->request = cpu_to_be16(RPMB_REQ_WRITE_DATA);
316 /* Computes HMAC */
317 rpmb_hmac(key, rpmb_frame->data, 284, rpmb_frame->mac);
318
319 if (mmc_rpmb_request(mmc, rpmb_frame, 1, true))
320 break;
321
322 /* Get status */
323 if (mmc_rpmb_status(mmc, RPMB_RESP_WRITE_DATA))
324 break;
325 }
326 return i;
327}
Jens Wiklanderd4898392018-09-25 16:40:08 +0200328
329static int send_write_mult_block(struct mmc *mmc, const struct s_rpmb *frm,
330 unsigned short cnt)
331{
332 struct mmc_cmd cmd = {
333 .cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK,
Akio Hirayama7e40f412019-06-28 21:16:25 +0900334 .resp_type = MMC_RSP_R1,
Jens Wiklanderd4898392018-09-25 16:40:08 +0200335 };
336 struct mmc_data data = {
337 .src = (const void *)frm,
338 .blocks = cnt,
339 .blocksize = sizeof(*frm),
340 .flags = MMC_DATA_WRITE,
341 };
342
343 return mmc_send_cmd(mmc, &cmd, &data);
344}
345
346static int send_read_mult_block(struct mmc *mmc, struct s_rpmb *frm,
347 unsigned short cnt)
348{
349 struct mmc_cmd cmd = {
350 .cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK,
351 .resp_type = MMC_RSP_R1,
352 };
353 struct mmc_data data = {
354 .dest = (void *)frm,
355 .blocks = cnt,
356 .blocksize = sizeof(*frm),
357 .flags = MMC_DATA_READ,
358 };
359
360 return mmc_send_cmd(mmc, &cmd, &data);
361}
362
363static int rpmb_route_write_req(struct mmc *mmc, struct s_rpmb *req,
364 unsigned short req_cnt, struct s_rpmb *rsp,
365 unsigned short rsp_cnt)
366{
367 int ret;
368
369 /*
370 * Send the write request.
371 */
372 ret = mmc_set_blockcount(mmc, req_cnt, true);
373 if (ret)
374 return ret;
375
376 ret = send_write_mult_block(mmc, req, req_cnt);
377 if (ret)
378 return ret;
379
380 /*
381 * Read the result of the request.
382 */
383 ret = mmc_set_blockcount(mmc, 1, false);
384 if (ret)
385 return ret;
386
387 memset(rsp, 0, sizeof(*rsp));
388 rsp->request = cpu_to_be16(RPMB_REQ_STATUS);
389 ret = send_write_mult_block(mmc, rsp, 1);
390 if (ret)
391 return ret;
392
393 ret = mmc_set_blockcount(mmc, 1, false);
394 if (ret)
395 return ret;
396
397 return send_read_mult_block(mmc, rsp, 1);
398}
399
400static int rpmb_route_read_req(struct mmc *mmc, struct s_rpmb *req,
401 unsigned short req_cnt, struct s_rpmb *rsp,
402 unsigned short rsp_cnt)
403{
404 int ret;
405
406 /*
407 * Send the read request.
408 */
409 ret = mmc_set_blockcount(mmc, 1, false);
410 if (ret)
411 return ret;
412
413 ret = send_write_mult_block(mmc, req, 1);
414 if (ret)
415 return ret;
416
417 /*
418 * Read the result of the request.
419 */
420
421 ret = mmc_set_blockcount(mmc, rsp_cnt, false);
422 if (ret)
423 return ret;
424
425 return send_read_mult_block(mmc, rsp, rsp_cnt);
426}
427
428static int rpmb_route_frames(struct mmc *mmc, struct s_rpmb *req,
429 unsigned short req_cnt, struct s_rpmb *rsp,
430 unsigned short rsp_cnt)
431{
432 unsigned short n;
433
434 /*
435 * If multiple request frames are provided, make sure that all are
436 * of the same type.
437 */
438 for (n = 1; n < req_cnt; n++)
439 if (req[n].request != req->request)
440 return -EINVAL;
441
442 switch (be16_to_cpu(req->request)) {
443 case RPMB_REQ_KEY:
444 if (req_cnt != 1 || rsp_cnt != 1)
445 return -EINVAL;
446 return rpmb_route_write_req(mmc, req, req_cnt, rsp, rsp_cnt);
447
448 case RPMB_REQ_WRITE_DATA:
449 if (!req_cnt || rsp_cnt != 1)
450 return -EINVAL;
451 return rpmb_route_write_req(mmc, req, req_cnt, rsp, rsp_cnt);
452
453 case RPMB_REQ_WCOUNTER:
454 if (req_cnt != 1 || rsp_cnt != 1)
455 return -EINVAL;
456 return rpmb_route_read_req(mmc, req, req_cnt, rsp, rsp_cnt);
457
458 case RPMB_REQ_READ_DATA:
459 if (req_cnt != 1 || !req_cnt)
460 return -EINVAL;
461 return rpmb_route_read_req(mmc, req, req_cnt, rsp, rsp_cnt);
462
463 default:
464 debug("Unsupported message type: %d\n",
465 be16_to_cpu(req->request));
466 return -EINVAL;
467 }
468}
469
470int mmc_rpmb_route_frames(struct mmc *mmc, void *req, unsigned long reqlen,
471 void *rsp, unsigned long rsplen)
472{
473 /*
474 * Whoever crafted the data supplied to this function knows how to
475 * format the PRMB frames and which response is expected. If
476 * there's some unexpected mismatch it's more helpful to report an
477 * error immediately than trying to guess what was the intention
478 * and possibly just delay an eventual error which will be harder
479 * to track down.
480 */
litchipid9cdc9f2021-06-15 08:53:06 +0000481 void *rpmb_data = NULL;
482 int ret;
Jens Wiklanderd4898392018-09-25 16:40:08 +0200483
484 if (reqlen % sizeof(struct s_rpmb) || rsplen % sizeof(struct s_rpmb))
485 return -EINVAL;
486
litchipid9cdc9f2021-06-15 08:53:06 +0000487 if (!IS_ALIGNED((uintptr_t)req, ARCH_DMA_MINALIGN)) {
488 /* Memory alignment is required by MMC driver */
489 rpmb_data = malloc(reqlen);
490 if (!rpmb_data)
491 return -ENOMEM;
492
493 memcpy(rpmb_data, req, reqlen);
494 req = rpmb_data;
495 }
496
497 ret = rpmb_route_frames(mmc, req, reqlen / sizeof(struct s_rpmb),
498 rsp, rsplen / sizeof(struct s_rpmb));
499 free(rpmb_data);
500 return ret;
Jens Wiklanderd4898392018-09-25 16:40:08 +0200501}