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 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 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 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 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 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 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 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 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 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 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 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 201 static int spl_get_lastboot(AvbABData *ab_data) 202 { 203 return ab_data->last_boot; 204 } 205 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 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 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 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 */ 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. */ 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 */ 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 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