1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7 #include <android_ab.h> 8 9 #include <android_bootloader_message.h> 10 #include <common.h> 11 #include <malloc.h> 12 #include <u-boot/crc.h> 13 #include <boot_rkimg.h> 14 15 /** android_boot_control_compute_crc - Compute the CRC-32 of the bootloader 16 * control struct. Only the bytes up to the crc32_le field are considered for 17 * the CRC-32 calculation. 18 */ 19 static uint32_t android_boot_control_compute_crc( 20 struct android_bootloader_control *abc) 21 { 22 return crc32(0, (void *)abc, offsetof(typeof(*abc), crc32_le)); 23 } 24 25 /** android_boot_control_default - Initialize android_bootloader_control to the 26 * default value which allows to boot all slots in order from the first one. 27 * This value should be used when the bootloader message is corrupted, but not 28 * when a valid message indicates that all slots are unbootable. 29 */ 30 void android_boot_control_default(struct android_bootloader_control *abc) 31 { 32 int i; 33 const struct android_slot_metadata metadata = { 34 .priority = 15, 35 .tries_remaining = 7, 36 .successful_boot = 0, 37 .verity_corrupted = 0, 38 .reserved = 0 39 }; 40 memcpy(abc->slot_suffix, "a\0\0\0", 4); 41 abc->magic = ANDROID_BOOT_CTRL_MAGIC; 42 abc->version = ANDROID_BOOT_CTRL_VERSION; 43 abc->nb_slot = ARRAY_SIZE(abc->slot_info); 44 memset(abc->reserved0, 0, sizeof(abc->reserved0)); 45 for (i = 0; i < abc->nb_slot; ++i) { 46 abc->slot_info[i] = metadata; 47 } 48 memset(abc->reserved1, 0, sizeof(abc->reserved1)); 49 abc->crc32_le = android_boot_control_compute_crc(abc); 50 } 51 52 /** android_boot_control_create_from_disk 53 * Load the boot_control struct from disk into newly allocated memory. This 54 * function allocates and returns an integer number of disk blocks, based on the 55 * block size of the passed device to help performing a read-modify-write 56 * operation on the boot_control struct. The boot_control struct offset (2 KiB) 57 * must be a multiple of the device block size, for simplicity. 58 * @dev_desc: device where to read the boot_control struct from. 59 * @part_info: partition in 'dev_desc' where to read from, normally the "misc" 60 * partition should be used. 61 */ 62 static void *android_boot_control_create_from_disk( 63 struct blk_desc *dev_desc, 64 const disk_partition_t *part_info) 65 { 66 ulong abc_offset, abc_blocks; 67 void *buf; 68 69 abc_offset = offsetof(struct android_bootloader_message_ab, 70 slot_suffix); 71 if (abc_offset % part_info->blksz) { 72 printf("ANDROID: Boot control block not block aligned.\n"); 73 return NULL; 74 } 75 abc_offset /= part_info->blksz; 76 77 abc_blocks = DIV_ROUND_UP(sizeof(struct android_bootloader_control), 78 part_info->blksz); 79 if (abc_offset + abc_blocks > part_info->size) { 80 printf("ANDROID: boot control partition too small. Need at" 81 " least %lu blocks but have %lu blocks.\n", 82 abc_offset + abc_blocks, part_info->size); 83 return NULL; 84 } 85 buf = malloc(abc_blocks * part_info->blksz); 86 if (!buf) 87 return NULL; 88 89 if (blk_dread(dev_desc, part_info->start + abc_offset, abc_blocks, 90 buf) != abc_blocks) { 91 printf("ANDROID: Could not read from boot control partition\n"); 92 free(buf); 93 return NULL; 94 } 95 debug("ANDROID: Loaded ABC, %lu blocks.\n", abc_blocks); 96 return buf; 97 } 98 99 /** android_boot_control_store 100 * Store the loaded boot_control block back to the same location it was read 101 * from with android_boot_control_create_from_misc(). 102 * 103 * @abc_data_block: pointer to the boot_control struct and the extra bytes after 104 * it up to the nearest block boundary. 105 * @dev_desc: device where we should write the boot_control struct. 106 * @part_info: partition on the 'dev_desc' where to write. 107 * @return 0 on success and -1 on error. 108 */ 109 static int android_boot_control_store(void *abc_data_block, 110 struct blk_desc *dev_desc, 111 const disk_partition_t *part_info) 112 { 113 ulong abc_offset, abc_blocks; 114 115 abc_offset = offsetof(struct android_bootloader_message_ab, 116 slot_suffix) / part_info->blksz; 117 abc_blocks = DIV_ROUND_UP(sizeof(struct android_bootloader_control), 118 part_info->blksz); 119 if (blk_dwrite(dev_desc, part_info->start + abc_offset, abc_blocks, 120 abc_data_block) != abc_blocks) { 121 printf("ANDROID: Could not write back the misc partition\n"); 122 return -1; 123 } 124 return 0; 125 } 126 127 /** android_boot_compare_slots - compares two slots returning which slot is 128 * should we boot from among the two. 129 * @a: The first bootable slot metadata 130 * @b: The second bootable slot metadata 131 * @return negative if the slot "a" is better, positive of the slot "b" is 132 * better or 0 if they are equally good. 133 */ 134 static int android_ab_compare_slots(const struct android_slot_metadata *a, 135 const struct android_slot_metadata *b) 136 { 137 /* Higher priority is better */ 138 if (a->priority != b->priority) 139 return b->priority - a->priority; 140 141 /* Higher successful_boot value is better, in case of same priority. */ 142 if (a->successful_boot != b->successful_boot) 143 return b->successful_boot - a->successful_boot; 144 145 /* Higher tries_remaining is better to ensure round-robin. */ 146 if (a->tries_remaining != b->tries_remaining) 147 return b->tries_remaining - a->tries_remaining; 148 149 return 0; 150 } 151 152 int android_ab_select(struct blk_desc *dev_desc, disk_partition_t *part_info) 153 { 154 struct android_bootloader_control *abc; 155 u32 crc32_le; 156 int slot, i; 157 bool store_needed = false; 158 char slot_suffix[4]; 159 160 abc = android_boot_control_create_from_disk(dev_desc, part_info); 161 if (!abc) { 162 /* This condition represents an actual problem with the code 163 * or the board setup, like an invalid partition information. 164 * Signal a repair mode and do not try to boot from either 165 * slot. 166 */ 167 return -1; 168 } 169 170 crc32_le = android_boot_control_compute_crc(abc); 171 if (abc->crc32_le != crc32_le) { 172 printf("ANDROID: Invalid CRC-32 (expected %.8x, found %.8x), " 173 "re-initializing A/B metadata.\n", 174 crc32_le, abc->crc32_le); 175 android_boot_control_default(abc); 176 store_needed = true; 177 } 178 179 if (abc->magic != ANDROID_BOOT_CTRL_MAGIC) { 180 printf("ANDROID: Unknown A/B metadata: %.8x\n", abc->magic); 181 free(abc); 182 return -1; 183 } 184 185 if (abc->version > ANDROID_BOOT_CTRL_VERSION) { 186 printf("ANDROID: Unsupported A/B metadata version: %.8x\n", 187 abc->version); 188 free(abc); 189 return -1; 190 } 191 192 /* At this point a valid boot control metadata is stored in abc, 193 * followed by other reserved data in the same block. 194 * We select a with the higher priority slot that 195 * - is not marked as corrupted and 196 * - either has tries_remaining > 0 or successful_boot is true. 197 * If the slot selected has a false successful_boot, we also decrement 198 * the tries_remaining until it eventually becomes unbootable because 199 * tries_remaining reaches 0. This mechanism produces a bootloader 200 * induced rollback, typically right after a failed update. 201 */ 202 203 /* Safety check: limit the number of slots. */ 204 if (abc->nb_slot > ARRAY_SIZE(abc->slot_info)) { 205 abc->nb_slot = ARRAY_SIZE(abc->slot_info); 206 store_needed = true; 207 } 208 209 slot = -1; 210 for (i = 0; i < abc->nb_slot; ++i) { 211 if (abc->slot_info[i].verity_corrupted || 212 !abc->slot_info[i].tries_remaining) { 213 debug("ANDROID: unbootable slot %d tries: %d, " 214 "corrupt: %d\n", 215 i, 216 abc->slot_info[i].tries_remaining, 217 abc->slot_info[i].verity_corrupted); 218 continue; 219 } 220 debug("ANDROID: bootable slot %d pri: %d, tries: %d, " 221 "corrupt: %d, successful: %d\n", 222 i, 223 abc->slot_info[i].priority, 224 abc->slot_info[i].tries_remaining, 225 abc->slot_info[i].verity_corrupted, 226 abc->slot_info[i].successful_boot); 227 228 if (slot < 0 || 229 android_ab_compare_slots(&abc->slot_info[i], 230 &abc->slot_info[slot]) < 0) { 231 slot = i; 232 } 233 } 234 235 if (slot >= 0 && !abc->slot_info[slot].successful_boot) { 236 printf("ANDROID: Attempting slot %c, tries remaining %d\n", 237 ANDROID_BOOT_SLOT_NAME(slot), 238 abc->slot_info[slot].tries_remaining); 239 abc->slot_info[slot].tries_remaining--; 240 store_needed = true; 241 } 242 243 if (slot >= 0) { 244 /* Legacy user-space requires this field to be set in the BCB. 245 * Newer releases load this the slot suffix from the command 246 * line or the device tree. 247 */ 248 memset(slot_suffix, 0, sizeof(slot_suffix)); 249 slot_suffix[0] = ANDROID_BOOT_SLOT_NAME(slot); 250 if (memcmp(abc->slot_suffix, slot_suffix, 251 sizeof(slot_suffix))) { 252 memcpy(abc->slot_suffix, slot_suffix, 253 sizeof(slot_suffix)); 254 store_needed = true; 255 } 256 } 257 258 if (store_needed) { 259 abc->crc32_le = android_boot_control_compute_crc(abc); 260 android_boot_control_store(abc, dev_desc, part_info); 261 } 262 free(abc); 263 264 if (slot < 0) 265 return -1; 266 return slot; 267 } 268 269 int read_misc_virtual_ab_message(struct misc_virtual_ab_message *message) 270 { 271 struct blk_desc *dev_desc; 272 disk_partition_t part_info; 273 u32 bcb_offset = (ANDROID_VIRTUAL_AB_METADATA_OFFSET_IN_MISC >> 9); 274 int cnt, ret; 275 276 if (!message) { 277 debug("%s: message is NULL!\n", __func__); 278 return -1; 279 } 280 281 dev_desc = rockchip_get_bootdev(); 282 if (!dev_desc) { 283 debug("%s: dev_desc is NULL!\n", __func__); 284 return -1; 285 } 286 287 ret = part_get_info_by_name(dev_desc, PART_MISC, &part_info); 288 if (ret < 0) { 289 debug("%s: Could not found misc partition\n", 290 __func__); 291 return -1; 292 } 293 294 cnt = DIV_ROUND_UP(sizeof(struct misc_virtual_ab_message), dev_desc->blksz); 295 if (blk_dread(dev_desc, part_info.start + bcb_offset, cnt, message) != cnt) { 296 debug("%s: could not read from misc partition\n", __func__); 297 return -1; 298 } 299 300 return 0; 301 } 302 303 int write_misc_virtual_ab_message(struct misc_virtual_ab_message *message) 304 { 305 struct blk_desc *dev_desc; 306 disk_partition_t part_info; 307 u32 bcb_offset = (ANDROID_VIRTUAL_AB_METADATA_OFFSET_IN_MISC >> 9); 308 int cnt, ret; 309 310 if (!message) { 311 debug("%s: message is NULL!\n", __func__); 312 return -1; 313 } 314 315 dev_desc = rockchip_get_bootdev(); 316 if (!dev_desc) { 317 debug("%s: dev_desc is NULL!\n", __func__); 318 return -1; 319 } 320 321 ret = part_get_info_by_name(dev_desc, PART_MISC, &part_info); 322 if (ret < 0) { 323 debug("%s: Could not found misc partition\n", 324 __func__); 325 return -1; 326 } 327 328 cnt = DIV_ROUND_UP(sizeof(struct misc_virtual_ab_message), dev_desc->blksz); 329 ret = blk_dwrite(dev_desc, part_info.start + bcb_offset, cnt, message); 330 if (ret != cnt) 331 debug("%s: blk_dwrite write failed, ret=%d\n", __func__, ret); 332 333 return 0; 334 } 335