]> git.ipfire.org Git - people/ms/u-boot.git/blame - drivers/mmc/rpmb.c
Merge git://git.denx.de/u-boot-mmc
[people/ms/u-boot.git] / drivers / mmc / rpmb.c
CommitLineData
91fdabc6
PA
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>
cf92e05c 13#include <memalign.h>
91fdabc6 14#include <mmc.h>
2b9912e6 15#include <u-boot/sha256.h>
91fdabc6
PA
16#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
63
64/* Structure of RPMB data frame. */
65struct s_rpmb {
66 unsigned char stuff[RPMB_SZ_STUFF];
67 unsigned char mac[RPMB_SZ_MAC];
68 unsigned char data[RPMB_SZ_DATA];
69 unsigned char nonce[RPMB_SZ_NONCE];
343749c4 70 unsigned int write_counter;
91fdabc6
PA
71 unsigned short address;
72 unsigned short block_count;
73 unsigned short result;
74 unsigned short request;
75};
76
77static int mmc_set_blockcount(struct mmc *mmc, unsigned int blockcount,
78 bool is_rel_write)
79{
80 struct mmc_cmd cmd = {0};
81
82 cmd.cmdidx = MMC_CMD_SET_BLOCK_COUNT;
83 cmd.cmdarg = blockcount & 0x0000FFFF;
84 if (is_rel_write)
85 cmd.cmdarg |= 1 << 31;
86 cmd.resp_type = MMC_RSP_R1;
87
88 return mmc_send_cmd(mmc, &cmd, NULL);
89}
90static int mmc_rpmb_request(struct mmc *mmc, const struct s_rpmb *s,
91 unsigned int count, bool is_rel_write)
92{
93 struct mmc_cmd cmd = {0};
94 struct mmc_data data;
95 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;
107 cmd.resp_type = MMC_RSP_R1b;
108
109 data.src = (const char *)s;
110 data.blocks = 1;
111 data.blocksize = MMC_MAX_BLOCK_LEN;
112 data.flags = MMC_DATA_WRITE;
113
114 ret = mmc_send_cmd(mmc, &cmd, &data);
115 if (ret) {
116#ifdef CONFIG_MMC_RPMB_TRACE
117 printf("%s:mmc_send_cmd-> %d\n", __func__, ret);
118#endif
119 return 1;
120 }
121 return 0;
122}
123static int mmc_rpmb_response(struct mmc *mmc, struct s_rpmb *s,
124 unsigned short expected)
125{
126 struct mmc_cmd cmd = {0};
127 struct mmc_data data;
128 int ret;
129
130 ret = mmc_set_blockcount(mmc, 1, false);
131 if (ret) {
132#ifdef CONFIG_MMC_RPMB_TRACE
133 printf("%s:mmc_set_blockcount-> %d\n", __func__, ret);
134#endif
135 return -1;
136 }
137 cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
138 cmd.cmdarg = 0;
139 cmd.resp_type = MMC_RSP_R1;
140
141 data.dest = (char *)s;
142 data.blocks = 1;
143 data.blocksize = MMC_MAX_BLOCK_LEN;
144 data.flags = MMC_DATA_READ;
145
146 ret = mmc_send_cmd(mmc, &cmd, &data);
147 if (ret) {
148#ifdef CONFIG_MMC_RPMB_TRACE
149 printf("%s:mmc_send_cmd-> %d\n", __func__, ret);
150#endif
151 return -1;
152 }
153 /* Check the response and the status */
154 if (be16_to_cpu(s->request) != expected) {
155#ifdef CONFIG_MMC_RPMB_TRACE
156 printf("%s:response= %x\n", __func__,
157 be16_to_cpu(s->request));
158#endif
159 return -1;
160 }
161 ret = be16_to_cpu(s->result);
162 if (ret) {
163 printf("%s %s\n", rpmb_err_msg[ret & RPMB_ERR_MSK],
164 (ret & RPMB_ERR_CNT_EXPIRED) ?
165 "Write counter has expired" : "");
166 }
167
168 /* Return the status of the command */
169 return ret;
170}
171static int mmc_rpmb_status(struct mmc *mmc, unsigned short expected)
172{
173 ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
174
175 memset(rpmb_frame, 0, sizeof(struct s_rpmb));
176 rpmb_frame->request = cpu_to_be16(RPMB_REQ_STATUS);
177 if (mmc_rpmb_request(mmc, rpmb_frame, 1, false))
178 return -1;
179
180 /* Read the result */
181 return mmc_rpmb_response(mmc, rpmb_frame, expected);
182}
183static void rpmb_hmac(unsigned char *key, unsigned char *buff, int len,
184 unsigned char *output)
185{
186 sha256_context ctx;
187 int i;
188 unsigned char k_ipad[SHA256_BLOCK_SIZE];
189 unsigned char k_opad[SHA256_BLOCK_SIZE];
190
191 sha256_starts(&ctx);
192
193 /* According to RFC 4634, the HMAC transform looks like:
194 SHA(K XOR opad, SHA(K XOR ipad, text))
195
196 where K is an n byte key.
197 ipad is the byte 0x36 repeated blocksize times
198 opad is the byte 0x5c repeated blocksize times
199 and text is the data being protected.
200 */
201
202 for (i = 0; i < RPMB_SZ_MAC; i++) {
203 k_ipad[i] = key[i] ^ 0x36;
204 k_opad[i] = key[i] ^ 0x5c;
205 }
206 /* remaining pad bytes are '\0' XOR'd with ipad and opad values */
207 for ( ; i < SHA256_BLOCK_SIZE; i++) {
208 k_ipad[i] = 0x36;
209 k_opad[i] = 0x5c;
210 }
211 sha256_update(&ctx, k_ipad, SHA256_BLOCK_SIZE);
212 sha256_update(&ctx, buff, len);
213 sha256_finish(&ctx, output);
214
215 /* Init context for second pass */
216 sha256_starts(&ctx);
217
218 /* start with outer pad */
219 sha256_update(&ctx, k_opad, SHA256_BLOCK_SIZE);
220
221 /* then results of 1st hash */
222 sha256_update(&ctx, output, RPMB_SZ_MAC);
223
224 /* finish up 2nd pass */
225 sha256_finish(&ctx, output);
226}
227int mmc_rpmb_get_counter(struct mmc *mmc, unsigned long *pcounter)
228{
229 int ret;
230 ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
231
232 /* Fill the request */
233 memset(rpmb_frame, 0, sizeof(struct s_rpmb));
234 rpmb_frame->request = cpu_to_be16(RPMB_REQ_WCOUNTER);
235 if (mmc_rpmb_request(mmc, rpmb_frame, 1, false))
236 return -1;
237
238 /* Read the result */
239 ret = mmc_rpmb_response(mmc, rpmb_frame, RPMB_RESP_WCOUNTER);
240 if (ret)
241 return ret;
242
243 *pcounter = be32_to_cpu(rpmb_frame->write_counter);
244 return 0;
245}
246int mmc_rpmb_set_key(struct mmc *mmc, void *key)
247{
248 ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
249 /* Fill the request */
250 memset(rpmb_frame, 0, sizeof(struct s_rpmb));
251 rpmb_frame->request = cpu_to_be16(RPMB_REQ_KEY);
252 memcpy(rpmb_frame->mac, key, RPMB_SZ_MAC);
253
254 if (mmc_rpmb_request(mmc, rpmb_frame, 1, true))
255 return -1;
256
257 /* read the operation status */
258 return mmc_rpmb_status(mmc, RPMB_RESP_KEY);
259}
260int mmc_rpmb_read(struct mmc *mmc, void *addr, unsigned short blk,
261 unsigned short cnt, unsigned char *key)
262{
263 ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
264 int i;
265
266 for (i = 0; i < cnt; i++) {
267 /* Fill the request */
268 memset(rpmb_frame, 0, sizeof(struct s_rpmb));
269 rpmb_frame->address = cpu_to_be16(blk + i);
270 rpmb_frame->request = cpu_to_be16(RPMB_REQ_READ_DATA);
271 if (mmc_rpmb_request(mmc, rpmb_frame, 1, false))
272 break;
273
274 /* Read the result */
275 if (mmc_rpmb_response(mmc, rpmb_frame, RPMB_RESP_READ_DATA))
276 break;
277
278 /* Check the HMAC if key is provided */
279 if (key) {
280 unsigned char ret_hmac[RPMB_SZ_MAC];
281
282 rpmb_hmac(key, rpmb_frame->data, 284, ret_hmac);
283 if (memcmp(ret_hmac, rpmb_frame->mac, RPMB_SZ_MAC)) {
284 printf("MAC error on block #%d\n", i);
285 break;
286 }
287 }
288 /* Copy data */
289 memcpy(addr + i * RPMB_SZ_DATA, rpmb_frame->data, RPMB_SZ_DATA);
290 }
291 return i;
292}
293int mmc_rpmb_write(struct mmc *mmc, void *addr, unsigned short blk,
294 unsigned short cnt, unsigned char *key)
295{
296 ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
297 unsigned long wcount;
298 int i;
299
300 for (i = 0; i < cnt; i++) {
301 if (mmc_rpmb_get_counter(mmc, &wcount)) {
302 printf("Cannot read RPMB write counter\n");
303 break;
304 }
305
306 /* Fill the request */
307 memset(rpmb_frame, 0, sizeof(struct s_rpmb));
308 memcpy(rpmb_frame->data, addr + i * RPMB_SZ_DATA, RPMB_SZ_DATA);
309 rpmb_frame->address = cpu_to_be16(blk + i);
310 rpmb_frame->block_count = cpu_to_be16(1);
311 rpmb_frame->write_counter = cpu_to_be32(wcount);
312 rpmb_frame->request = cpu_to_be16(RPMB_REQ_WRITE_DATA);
313 /* Computes HMAC */
314 rpmb_hmac(key, rpmb_frame->data, 284, rpmb_frame->mac);
315
316 if (mmc_rpmb_request(mmc, rpmb_frame, 1, true))
317 break;
318
319 /* Get status */
320 if (mmc_rpmb_status(mmc, RPMB_RESP_WRITE_DATA))
321 break;
322 }
323 return i;
324}