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 size_t slot_index_to_boot; 206 AvbABData ab_data; 207 int ret; 208 209 ret = spl_ab_data_read(dev_desc, &ab_data, partition); 210 if (ret) 211 return ret; 212 213 if (spl_slot_is_bootable(&ab_data.slots[0]) && 214 spl_slot_is_bootable(&ab_data.slots[1])) { 215 if (ab_data.slots[1].priority > ab_data.slots[0].priority) 216 slot_index_to_boot = 1; 217 else 218 slot_index_to_boot = 0; 219 } else if (spl_slot_is_bootable(&ab_data.slots[0])) { 220 slot_index_to_boot = 0; 221 } else if (spl_slot_is_bootable(&ab_data.slots[1])) { 222 slot_index_to_boot = 1; 223 } else { 224 printf("No bootable slots found, use lastboot.\n"); 225 if (spl_get_lastboot(&ab_data) == 0) { 226 memcpy(slot, "_a", 2); 227 goto out; 228 } else if (spl_get_lastboot(&ab_data) == 1) { 229 memcpy(slot, "_b", 2); 230 goto out; 231 } else { 232 return -ENODEV; 233 } 234 } 235 236 if (slot_index_to_boot == 0) 237 memcpy(slot, "_a", 2); 238 else if (slot_index_to_boot == 1) 239 memcpy(slot, "_b", 2); 240 241 out: 242 return 0; 243 } 244 245 int spl_get_partitions_sector(struct blk_desc *dev_desc, char *partition, 246 u32 *sectors) 247 { 248 disk_partition_t part_info; 249 char part[10] = {0}; 250 char slot[3] = {0}; 251 252 if (!partition || !sectors) 253 return -EFAULT; 254 255 spl_get_current_slot(dev_desc, "misc", slot); 256 if (strlen(partition) > 8) 257 return -ENOMEM; 258 259 strcat(part, partition); 260 strcat(part, slot); 261 if (part_get_info_by_name(dev_desc, part, &part_info) < 0) 262 return -ENODEV; 263 264 *sectors = part_info.start; 265 266 return 0; 267 } 268