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 ret = spl_ab_data_read(dev_desc, &ab_data, partition); 211 if (ret) 212 return ret; 213 214 if (spl_slot_is_bootable(&ab_data.slots[0]) && 215 spl_slot_is_bootable(&ab_data.slots[1])) { 216 if (ab_data.slots[1].priority > ab_data.slots[0].priority) 217 slot_index_to_boot = 1; 218 else 219 slot_index_to_boot = 0; 220 } else if (spl_slot_is_bootable(&ab_data.slots[0])) { 221 slot_index_to_boot = 0; 222 } else if (spl_slot_is_bootable(&ab_data.slots[1])) { 223 slot_index_to_boot = 1; 224 } else { 225 printf("No bootable slots found, use lastboot.\n"); 226 if (spl_get_lastboot(&ab_data) == 0) { 227 memcpy(slot, "_a", 2); 228 goto out; 229 } else if (spl_get_lastboot(&ab_data) == 1) { 230 memcpy(slot, "_b", 2); 231 goto out; 232 } else { 233 return -ENODEV; 234 } 235 } 236 237 if (slot_index_to_boot == 0) 238 memcpy(slot, "_a", 2); 239 else if (slot_index_to_boot == 1) 240 memcpy(slot, "_b", 2); 241 242 if (last_slot_index != slot_index_to_boot) { 243 last_slot_index = slot_index_to_boot; 244 printf("SPL: A/B-slot: %s, successful: %d, tries-remain: %d\n", 245 slot, 246 ab_data.slots[slot_index_to_boot].successful_boot, 247 ab_data.slots[slot_index_to_boot].tries_remaining); 248 } 249 250 out: 251 return 0; 252 } 253 254 int spl_ab_append_part_slot(struct blk_desc *dev_desc, 255 const char *part_name, 256 char *new_name) 257 { 258 char slot_suffix[3] = {0}; 259 260 if (!strcmp(part_name, "misc")) { 261 strcat(new_name, part_name); 262 return 0; 263 } 264 265 if (spl_get_current_slot(dev_desc, "misc", slot_suffix)) { 266 printf("No misc partition\n"); 267 strcat(new_name, part_name); 268 return 0; 269 } 270 271 strcpy(new_name, part_name); 272 strcat(new_name, slot_suffix); 273 274 return 0; 275 } 276 277 static int spl_save_metadata_if_changed(struct blk_desc *dev_desc, 278 AvbABData *ab_data, 279 AvbABData *ab_data_orig) 280 { 281 if (safe_memcmp(ab_data, ab_data_orig, sizeof(AvbABData))) 282 return spl_ab_data_write(dev_desc, ab_data, "misc"); 283 284 return 0; 285 } 286 287 /* If verify fail in a/b system, then decrease 1. */ 288 int spl_ab_decrease_tries(struct blk_desc *dev_desc) 289 { 290 AvbABData ab_data, ab_data_orig; 291 size_t slot_index = 0; 292 char slot_suffix[3] = {0}; 293 int ret = -1; 294 295 ret = spl_get_current_slot(dev_desc, "misc", slot_suffix); 296 if (ret) 297 goto out; 298 299 if (!strncmp(slot_suffix, "_a", 2)) 300 slot_index = 0; 301 else if (!strncmp(slot_suffix, "_b", 2)) 302 slot_index = 1; 303 else 304 slot_index = 0; 305 306 ret = spl_ab_data_read(dev_desc, &ab_data, "misc"); 307 if (ret) 308 goto out; 309 310 memcpy(&ab_data_orig, &ab_data, sizeof(AvbABData)); 311 312 /* ... and decrement tries remaining, if applicable. */ 313 if (!ab_data.slots[slot_index].successful_boot && 314 ab_data.slots[slot_index].tries_remaining > 0) 315 ab_data.slots[slot_index].tries_remaining -= 1; 316 317 ret = spl_save_metadata_if_changed(dev_desc, &ab_data, &ab_data_orig); 318 319 out: 320 return ret; 321 } 322 323 /* 324 * If boot A/B system fail, tries-remaining decrease 1 325 * and do reset automatically if still bootable. 326 */ 327 int spl_ab_decrease_reset(struct blk_desc *dev_desc) 328 { 329 AvbABData ab_data; 330 int ret; 331 332 ret = spl_ab_data_read(dev_desc, &ab_data, "misc"); 333 if (ret) 334 return ret; 335 336 /* If current device cannot boot, return and try other devices. */ 337 if (!spl_slot_is_bootable(&ab_data.slots[0]) && 338 !spl_slot_is_bootable(&ab_data.slots[1])) { 339 printf("A/B: no bootable slot\n"); 340 return -ENODEV; 341 } 342 343 /* If current device still can boot, decrease and do reset. */ 344 ret = spl_ab_decrease_tries(dev_desc); 345 if (ret) 346 return ret; 347 348 printf("A/B: slot boot fail, do reset\n"); 349 do_reset(NULL, 0, 0, NULL); 350 351 /* 352 * Only do_reset() fail will arrive here, return a 353 * negative number, then enter maskrom in the caller. 354 */ 355 return -EINVAL; 356 } 357