1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd
4 */
5
6 #include <common.h>
7 #include <android_image.h>
8 #include <fdt_support.h>
9 #include <blk.h>
10 #include <malloc.h>
11 #include <spl_ab.h>
12
safe_memcmp(const void * s1,const void * s2,size_t n)13 int safe_memcmp(const void *s1, const void *s2, size_t n)
14 {
15 const unsigned char *us1 = s1;
16 const unsigned char *us2 = s2;
17 int result = 0;
18
19 if (0 == n)
20 return 0;
21
22 /*
23 * Code snippet without data-dependent branch due to Nate Lawson
24 * (nate@root.org) of Root Labs.
25 */
26 while (n--)
27 result |= *us1++ ^ *us2++;
28
29 return result != 0;
30 }
31
htobe32(uint32_t in)32 static uint32_t htobe32(uint32_t in)
33 {
34 union {
35 uint32_t word;
36 uint8_t bytes[4];
37 } ret;
38
39 ret.bytes[0] = (in >> 24) & 0xff;
40 ret.bytes[1] = (in >> 16) & 0xff;
41 ret.bytes[2] = (in >> 8) & 0xff;
42 ret.bytes[3] = in & 0xff;
43
44 return ret.word;
45 }
46
be32toh(uint32_t in)47 static uint32_t be32toh(uint32_t in)
48 {
49 uint8_t *d = (uint8_t *)∈
50 uint32_t ret;
51
52 ret = ((uint32_t)d[0]) << 24;
53 ret |= ((uint32_t)d[1]) << 16;
54 ret |= ((uint32_t)d[2]) << 8;
55 ret |= ((uint32_t)d[3]);
56
57 return ret;
58 }
59
spl_ab_data_verify_and_byteswap(const AvbABData * src,AvbABData * dest)60 static bool spl_ab_data_verify_and_byteswap(const AvbABData *src,
61 AvbABData *dest)
62 {
63 /* Ensure magic is correct. */
64 if (safe_memcmp(src->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN) != 0) {
65 printf("Magic is incorrect.\n");
66 return false;
67 }
68
69 memcpy(dest, src, sizeof(AvbABData));
70 dest->crc32 = be32toh(dest->crc32);
71
72 /* Ensure we don't attempt to access any fields if the major version
73 * is not supported.
74 */
75 if (dest->version_major > AVB_AB_MAJOR_VERSION) {
76 printf("No support for given major version.\n");
77 return false;
78 }
79
80 /* Bail if CRC32 doesn't match. */
81 if (dest->crc32 !=
82 crc32(0, (const uint8_t *)dest,
83 sizeof(AvbABData) - sizeof(uint32_t))) {
84 printf("CRC32 does not match.\n");
85 return false;
86 }
87
88 return true;
89 }
90
spl_ab_data_update_crc_and_byteswap(const AvbABData * src,AvbABData * dest)91 static void spl_ab_data_update_crc_and_byteswap(const AvbABData *src,
92 AvbABData *dest)
93 {
94 memcpy(dest, src, sizeof(AvbABData));
95 dest->crc32 = htobe32(crc32(0, (const uint8_t *)dest,
96 sizeof(AvbABData) - sizeof(uint32_t)));
97 }
98
spl_ab_data_init(AvbABData * data)99 static void spl_ab_data_init(AvbABData *data)
100 {
101 memset(data, '\0', sizeof(AvbABData));
102 memcpy(data->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN);
103 data->version_major = AVB_AB_MAJOR_VERSION;
104 data->version_minor = AVB_AB_MINOR_VERSION;
105 data->last_boot = 0;
106 data->slots[0].priority = AVB_AB_MAX_PRIORITY;
107 data->slots[0].tries_remaining = AVB_AB_MAX_TRIES_REMAINING;
108 data->slots[0].successful_boot = 0;
109 data->slots[1].priority = AVB_AB_MAX_PRIORITY - 1;
110 data->slots[1].tries_remaining = AVB_AB_MAX_TRIES_REMAINING;
111 data->slots[1].successful_boot = 0;
112 }
113
spl_read_ab_metadata(struct blk_desc * dev_desc,AvbABData * ab_data,char * partition)114 static int spl_read_ab_metadata(struct blk_desc *dev_desc, AvbABData *ab_data,
115 char *partition)
116 {
117 disk_partition_t part_info;
118 char temp[512];
119 int ret;
120
121 if (!dev_desc || !partition || !ab_data)
122 return -EFAULT;
123
124 if (part_get_info_by_name(dev_desc, partition, &part_info) < 0)
125 return -ENOENT;
126
127 ret = blk_dread(dev_desc, part_info.start + AB_METADATA_OFFSET, 1,
128 temp);
129 if (ret != 1)
130 return -ENODEV;
131
132 if (sizeof(AvbABData) > 512)
133 return -ENOMEM;
134
135 memcpy(ab_data, temp, sizeof(AvbABData));
136
137 return 0;
138 }
139
spl_write_ab_metadata(struct blk_desc * dev_desc,AvbABData * ab_data,char * partition)140 static int spl_write_ab_metadata(struct blk_desc *dev_desc, AvbABData *ab_data,
141 char *partition)
142 {
143 disk_partition_t part_info;
144 char temp[512];
145 int ret;
146
147 if (!dev_desc || !partition || !ab_data)
148 return -EFAULT;
149
150 if (sizeof(AvbABData) > 512)
151 return -ENOMEM;
152
153 memcpy(temp, ab_data, sizeof(AvbABData));
154 if (part_get_info_by_name(dev_desc, partition, &part_info) < 0)
155 return -ENOENT;
156
157 ret = blk_dwrite(dev_desc, part_info.start + AB_METADATA_OFFSET, 1,
158 temp);
159 if (ret != 1)
160 return -ENODEV;
161
162 return 0;
163 }
164
spl_ab_data_write(struct blk_desc * dev_desc,AvbABData * ab_data,char * partition)165 static int spl_ab_data_write(struct blk_desc *dev_desc, AvbABData *ab_data,
166 char *partition)
167 {
168 AvbABData serialized;
169
170 spl_ab_data_update_crc_and_byteswap(ab_data, &serialized);
171
172 return spl_write_ab_metadata(dev_desc, &serialized, partition);
173 }
174
spl_ab_data_read(struct blk_desc * dev_desc,AvbABData * ab_data,char * partition)175 static int spl_ab_data_read(struct blk_desc *dev_desc, AvbABData *ab_data,
176 char *partition)
177 {
178 int ret;
179 AvbABData serialized;
180
181 ret = spl_read_ab_metadata(dev_desc, &serialized, partition);
182 if (ret)
183 return ret;
184
185 if (!spl_ab_data_verify_and_byteswap(&serialized, ab_data)) {
186 printf("Error validating A/B metadata from disk. "
187 "Resetting and writing new A/B metadata to disk.\n");
188 spl_ab_data_init(ab_data);
189 spl_ab_data_write(dev_desc, ab_data, partition);
190 }
191
192 return 0;
193 }
194
spl_slot_is_bootable(AvbABSlotData * slot)195 static bool spl_slot_is_bootable(AvbABSlotData *slot)
196 {
197 return slot->priority > 0 &&
198 (slot->successful_boot || (slot->tries_remaining > 0));
199 }
200
spl_get_lastboot(AvbABData * ab_data)201 static int spl_get_lastboot(AvbABData *ab_data)
202 {
203 return ab_data->last_boot;
204 }
205
spl_get_current_slot(struct blk_desc * dev_desc,char * partition,char * slot)206 int spl_get_current_slot(struct blk_desc *dev_desc, char *partition, char *slot)
207 {
208 static int last_slot_index = -1;
209 size_t slot_index_to_boot;
210 AvbABData ab_data;
211 int ret;
212
213 /*
214 * 1. Call spl_ab_decrease_tries() before load kernel to be compatible with
215 * the case when storage is eMMC, because preload image will occupy eMMC.
216 *
217 * 2. (For solving Boundary problem) Need to record slot_suffix before ab_decrease,
218 * otherwise when boot kernel, it will use the result after decrease.
219 *
220 * 3. For example, current slot_suffix is _a, tries-remaining is 1. Without
221 * recording slot_suffix before decrease, after decrease, slot_suffix is _b,
222 * tries-remaining is 7. SPL will parse boot_b instead of boot_a that expected.
223 */
224 #ifdef CONFIG_SPL_KERNEL_BOOT
225 if (last_slot_index == 0) {
226 memcpy(slot, "_a", 2);
227 return 0;
228 } else if (last_slot_index == 1) {
229 memcpy(slot, "_b", 2);
230 return 0;
231 }
232 #endif
233
234 ret = spl_ab_data_read(dev_desc, &ab_data, partition);
235 if (ret)
236 return ret;
237
238 if (spl_slot_is_bootable(&ab_data.slots[0]) &&
239 spl_slot_is_bootable(&ab_data.slots[1])) {
240 if (ab_data.slots[1].priority > ab_data.slots[0].priority)
241 slot_index_to_boot = 1;
242 else
243 slot_index_to_boot = 0;
244 } else if (spl_slot_is_bootable(&ab_data.slots[0])) {
245 slot_index_to_boot = 0;
246 } else if (spl_slot_is_bootable(&ab_data.slots[1])) {
247 slot_index_to_boot = 1;
248 } else {
249 printf("No bootable slots found, use lastboot.\n");
250 if (spl_get_lastboot(&ab_data) == 0) {
251 memcpy(slot, "_a", 2);
252 goto out;
253 } else if (spl_get_lastboot(&ab_data) == 1) {
254 memcpy(slot, "_b", 2);
255 goto out;
256 } else {
257 return -ENODEV;
258 }
259 }
260
261 if (slot_index_to_boot == 0)
262 memcpy(slot, "_a", 2);
263 else if (slot_index_to_boot == 1)
264 memcpy(slot, "_b", 2);
265
266 if (last_slot_index != slot_index_to_boot) {
267 last_slot_index = slot_index_to_boot;
268 printf("SPL: A/B-slot: %s, successful: %d, tries-remain: %d\n",
269 slot,
270 ab_data.slots[slot_index_to_boot].successful_boot,
271 ab_data.slots[slot_index_to_boot].tries_remaining);
272 }
273
274 out:
275 return 0;
276 }
277
spl_ab_append_part_slot(struct blk_desc * dev_desc,const char * part_name,char * new_name)278 int spl_ab_append_part_slot(struct blk_desc *dev_desc,
279 const char *part_name,
280 char *new_name)
281 {
282 char slot_suffix[3] = {0};
283
284 if (!strcmp(part_name, "misc")) {
285 strcat(new_name, part_name);
286 return 0;
287 }
288
289 if (spl_get_current_slot(dev_desc, "misc", slot_suffix)) {
290 printf("No misc partition\n");
291 strcat(new_name, part_name);
292 return 0;
293 }
294
295 strcpy(new_name, part_name);
296 strcat(new_name, slot_suffix);
297
298 return 0;
299 }
300
spl_save_metadata_if_changed(struct blk_desc * dev_desc,AvbABData * ab_data,AvbABData * ab_data_orig)301 static int spl_save_metadata_if_changed(struct blk_desc *dev_desc,
302 AvbABData *ab_data,
303 AvbABData *ab_data_orig)
304 {
305 if (safe_memcmp(ab_data, ab_data_orig, sizeof(AvbABData)))
306 return spl_ab_data_write(dev_desc, ab_data, "misc");
307
308 return 0;
309 }
310
spl_slot_set_unbootable(AvbABSlotData * slot)311 static void spl_slot_set_unbootable(AvbABSlotData* slot)
312 {
313 slot->priority = 0;
314 slot->tries_remaining = 0;
315 slot->successful_boot = 0;
316 }
317
318 /* Ensure all unbootable and/or illegal states are marked as the
319 * canonical 'unbootable' state, e.g. priority=0, tries_remaining=0,
320 * and successful_boot=0.
321 */
spl_slot_normalize(AvbABSlotData * slot)322 static void spl_slot_normalize(AvbABSlotData* slot)
323 {
324 if (slot->priority > 0) {
325 if (slot->tries_remaining == 0 && !slot->successful_boot) {
326 /* We've exhausted all tries -> unbootable. */
327 spl_slot_set_unbootable(slot);
328 }
329 if (slot->tries_remaining > 0 && slot->successful_boot) {
330 /* Illegal state - avb_ab_mark_slot_successful() and so on
331 * will clear tries_remaining when setting successful_boot.
332 */
333 spl_slot_set_unbootable(slot);
334 }
335 } else {
336 spl_slot_set_unbootable(slot);
337 }
338 }
339
340 /* If verify fail in a/b system, then decrease 1. */
spl_ab_decrease_tries(struct blk_desc * dev_desc)341 int spl_ab_decrease_tries(struct blk_desc *dev_desc)
342 {
343 AvbABData ab_data, ab_data_orig;
344 size_t slot_index = 0;
345 char slot_suffix[3] = {0};
346 int ret = -1;
347
348 ret = spl_get_current_slot(dev_desc, "misc", slot_suffix);
349 if (ret)
350 goto out;
351
352 if (!strncmp(slot_suffix, "_a", 2))
353 slot_index = 0;
354 else if (!strncmp(slot_suffix, "_b", 2))
355 slot_index = 1;
356 else
357 slot_index = 0;
358
359 ret = spl_ab_data_read(dev_desc, &ab_data, "misc");
360 if (ret)
361 goto out;
362
363 memcpy(&ab_data_orig, &ab_data, sizeof(AvbABData));
364
365 /* Ensure data is normalized, e.g. illegal states will be marked as
366 * unbootable and all unbootable states are represented with
367 * (priority=0, tries_remaining=0, successful_boot=0).
368 */
369 spl_slot_normalize(&ab_data.slots[0]);
370 spl_slot_normalize(&ab_data.slots[1]);
371
372 /* ... and decrement tries remaining, if applicable. */
373 if (!ab_data.slots[slot_index].successful_boot &&
374 ab_data.slots[slot_index].tries_remaining > 0)
375 ab_data.slots[slot_index].tries_remaining -= 1;
376
377 ret = spl_save_metadata_if_changed(dev_desc, &ab_data, &ab_data_orig);
378
379 out:
380 return ret;
381 }
382
383 /*
384 * If boot A/B system fail, tries-remaining decrease 1
385 * and do reset automatically if still bootable.
386 */
spl_ab_decrease_reset(struct blk_desc * dev_desc)387 int spl_ab_decrease_reset(struct blk_desc *dev_desc)
388 {
389 AvbABData ab_data;
390 int ret;
391
392 ret = spl_ab_data_read(dev_desc, &ab_data, "misc");
393 if (ret)
394 return ret;
395
396 /* If current device cannot boot, return and try other devices. */
397 if (!spl_slot_is_bootable(&ab_data.slots[0]) &&
398 !spl_slot_is_bootable(&ab_data.slots[1])) {
399 printf("A/B: no bootable slot\n");
400 return -ENODEV;
401 }
402
403 /* If current device still can boot, decrease and do reset. */
404 ret = spl_ab_decrease_tries(dev_desc);
405 if (ret)
406 return ret;
407
408 printf("A/B: slot boot fail, do reset\n");
409 do_reset(NULL, 0, 0, NULL);
410
411 /*
412 * Only do_reset() fail will arrive here, return a
413 * negative number, then enter maskrom in the caller.
414 */
415 return -EINVAL;
416 }
417
spl_ab_bootargs_append_slot(void * fdt,char * slot)418 int spl_ab_bootargs_append_slot(void *fdt, char *slot)
419 {
420 char *str;
421 int len, ret = 0;
422
423 if (!slot)
424 return 0;
425
426 len = strlen(ANDROID_ARG_SLOT_SUFFIX) + strlen(slot) + 1;
427 str = malloc(len);
428 if (!str)
429 return -ENOMEM;
430
431 snprintf(str, len, "%s%s", ANDROID_ARG_SLOT_SUFFIX, slot);
432 ret = fdt_bootargs_append(fdt, str);
433 if (ret)
434 printf("Append slot info to bootargs fail");
435
436 free(str);
437
438 return ret;
439 }
440