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