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