1*0cc16201SJason Zhu // SPDX-License-Identifier: GPL-2.0 2*0cc16201SJason Zhu /* 3*0cc16201SJason Zhu * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd 4*0cc16201SJason Zhu */ 5*0cc16201SJason Zhu 6*0cc16201SJason Zhu #include <common.h> 7*0cc16201SJason Zhu #include <blk.h> 8*0cc16201SJason Zhu #include <spl_ab.h> 9*0cc16201SJason Zhu 10*0cc16201SJason Zhu int safe_memcmp(const void *s1, const void *s2, size_t n) 11*0cc16201SJason Zhu { 12*0cc16201SJason Zhu const unsigned char *us1 = s1; 13*0cc16201SJason Zhu const unsigned char *us2 = s2; 14*0cc16201SJason Zhu int result = 0; 15*0cc16201SJason Zhu 16*0cc16201SJason Zhu if (0 == n) 17*0cc16201SJason Zhu return 0; 18*0cc16201SJason Zhu 19*0cc16201SJason Zhu /* 20*0cc16201SJason Zhu * Code snippet without data-dependent branch due to Nate Lawson 21*0cc16201SJason Zhu * (nate@root.org) of Root Labs. 22*0cc16201SJason Zhu */ 23*0cc16201SJason Zhu while (n--) 24*0cc16201SJason Zhu result |= *us1++ ^ *us2++; 25*0cc16201SJason Zhu 26*0cc16201SJason Zhu return result != 0; 27*0cc16201SJason Zhu } 28*0cc16201SJason Zhu 29*0cc16201SJason Zhu static uint32_t htobe32(uint32_t in) 30*0cc16201SJason Zhu { 31*0cc16201SJason Zhu union { 32*0cc16201SJason Zhu uint32_t word; 33*0cc16201SJason Zhu uint8_t bytes[4]; 34*0cc16201SJason Zhu } ret; 35*0cc16201SJason Zhu 36*0cc16201SJason Zhu ret.bytes[0] = (in >> 24) & 0xff; 37*0cc16201SJason Zhu ret.bytes[1] = (in >> 16) & 0xff; 38*0cc16201SJason Zhu ret.bytes[2] = (in >> 8) & 0xff; 39*0cc16201SJason Zhu ret.bytes[3] = in & 0xff; 40*0cc16201SJason Zhu 41*0cc16201SJason Zhu return ret.word; 42*0cc16201SJason Zhu } 43*0cc16201SJason Zhu 44*0cc16201SJason Zhu static uint32_t be32toh(uint32_t in) 45*0cc16201SJason Zhu { 46*0cc16201SJason Zhu uint8_t *d = (uint8_t *)∈ 47*0cc16201SJason Zhu uint32_t ret; 48*0cc16201SJason Zhu 49*0cc16201SJason Zhu ret = ((uint32_t)d[0]) << 24; 50*0cc16201SJason Zhu ret |= ((uint32_t)d[1]) << 16; 51*0cc16201SJason Zhu ret |= ((uint32_t)d[2]) << 8; 52*0cc16201SJason Zhu ret |= ((uint32_t)d[3]); 53*0cc16201SJason Zhu 54*0cc16201SJason Zhu return ret; 55*0cc16201SJason Zhu } 56*0cc16201SJason Zhu 57*0cc16201SJason Zhu static bool spl_ab_data_verify_and_byteswap(const AvbABData *src, 58*0cc16201SJason Zhu AvbABData *dest) 59*0cc16201SJason Zhu { 60*0cc16201SJason Zhu /* Ensure magic is correct. */ 61*0cc16201SJason Zhu if (safe_memcmp(src->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN) != 0) { 62*0cc16201SJason Zhu printf("Magic is incorrect.\n"); 63*0cc16201SJason Zhu return false; 64*0cc16201SJason Zhu } 65*0cc16201SJason Zhu 66*0cc16201SJason Zhu memcpy(dest, src, sizeof(AvbABData)); 67*0cc16201SJason Zhu dest->crc32 = be32toh(dest->crc32); 68*0cc16201SJason Zhu 69*0cc16201SJason Zhu /* Ensure we don't attempt to access any fields if the major version 70*0cc16201SJason Zhu * is not supported. 71*0cc16201SJason Zhu */ 72*0cc16201SJason Zhu if (dest->version_major > AVB_AB_MAJOR_VERSION) { 73*0cc16201SJason Zhu printf("No support for given major version.\n"); 74*0cc16201SJason Zhu return false; 75*0cc16201SJason Zhu } 76*0cc16201SJason Zhu 77*0cc16201SJason Zhu /* Bail if CRC32 doesn't match. */ 78*0cc16201SJason Zhu if (dest->crc32 != 79*0cc16201SJason Zhu crc32(0, (const uint8_t *)dest, 80*0cc16201SJason Zhu sizeof(AvbABData) - sizeof(uint32_t))) { 81*0cc16201SJason Zhu printf("CRC32 does not match.\n"); 82*0cc16201SJason Zhu return false; 83*0cc16201SJason Zhu } 84*0cc16201SJason Zhu 85*0cc16201SJason Zhu return true; 86*0cc16201SJason Zhu } 87*0cc16201SJason Zhu 88*0cc16201SJason Zhu static void spl_ab_data_update_crc_and_byteswap(const AvbABData *src, 89*0cc16201SJason Zhu AvbABData *dest) 90*0cc16201SJason Zhu { 91*0cc16201SJason Zhu memcpy(dest, src, sizeof(AvbABData)); 92*0cc16201SJason Zhu dest->crc32 = htobe32(crc32(0, (const uint8_t *)dest, 93*0cc16201SJason Zhu sizeof(AvbABData) - sizeof(uint32_t))); 94*0cc16201SJason Zhu } 95*0cc16201SJason Zhu 96*0cc16201SJason Zhu static void spl_ab_data_init(AvbABData *data) 97*0cc16201SJason Zhu { 98*0cc16201SJason Zhu memset(data, '\0', sizeof(AvbABData)); 99*0cc16201SJason Zhu memcpy(data->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN); 100*0cc16201SJason Zhu data->version_major = AVB_AB_MAJOR_VERSION; 101*0cc16201SJason Zhu data->version_minor = AVB_AB_MINOR_VERSION; 102*0cc16201SJason Zhu data->last_boot = 0; 103*0cc16201SJason Zhu data->slots[0].priority = AVB_AB_MAX_PRIORITY; 104*0cc16201SJason Zhu data->slots[0].tries_remaining = AVB_AB_MAX_TRIES_REMAINING; 105*0cc16201SJason Zhu data->slots[0].successful_boot = 0; 106*0cc16201SJason Zhu data->slots[1].priority = AVB_AB_MAX_PRIORITY - 1; 107*0cc16201SJason Zhu data->slots[1].tries_remaining = AVB_AB_MAX_TRIES_REMAINING; 108*0cc16201SJason Zhu data->slots[1].successful_boot = 0; 109*0cc16201SJason Zhu } 110*0cc16201SJason Zhu 111*0cc16201SJason Zhu static int spl_read_ab_metadata(struct blk_desc *dev_desc, AvbABData *ab_data, 112*0cc16201SJason Zhu char *partition) 113*0cc16201SJason Zhu { 114*0cc16201SJason Zhu disk_partition_t part_info; 115*0cc16201SJason Zhu char temp[512]; 116*0cc16201SJason Zhu int ret; 117*0cc16201SJason Zhu 118*0cc16201SJason Zhu if (!dev_desc || !partition || !ab_data) 119*0cc16201SJason Zhu return -EFAULT; 120*0cc16201SJason Zhu 121*0cc16201SJason Zhu if (part_get_info_by_name(dev_desc, partition, &part_info) < 0) 122*0cc16201SJason Zhu return -ENOENT; 123*0cc16201SJason Zhu 124*0cc16201SJason Zhu ret = blk_dread(dev_desc, part_info.start + AB_METADATA_OFFSET, 1, 125*0cc16201SJason Zhu temp); 126*0cc16201SJason Zhu if (ret != 1) 127*0cc16201SJason Zhu return -ENODEV; 128*0cc16201SJason Zhu 129*0cc16201SJason Zhu if (sizeof(AvbABData) > 512) 130*0cc16201SJason Zhu return -ENOMEM; 131*0cc16201SJason Zhu 132*0cc16201SJason Zhu memcpy(ab_data, temp, sizeof(AvbABData)); 133*0cc16201SJason Zhu 134*0cc16201SJason Zhu return 0; 135*0cc16201SJason Zhu } 136*0cc16201SJason Zhu 137*0cc16201SJason Zhu static int spl_write_ab_metadata(struct blk_desc *dev_desc, AvbABData *ab_data, 138*0cc16201SJason Zhu char *partition) 139*0cc16201SJason Zhu { 140*0cc16201SJason Zhu disk_partition_t part_info; 141*0cc16201SJason Zhu char temp[512]; 142*0cc16201SJason Zhu int ret; 143*0cc16201SJason Zhu 144*0cc16201SJason Zhu if (!dev_desc || !partition || !ab_data) 145*0cc16201SJason Zhu return -EFAULT; 146*0cc16201SJason Zhu 147*0cc16201SJason Zhu if (sizeof(AvbABData) > 512) 148*0cc16201SJason Zhu return -ENOMEM; 149*0cc16201SJason Zhu 150*0cc16201SJason Zhu memcpy(temp, ab_data, sizeof(AvbABData)); 151*0cc16201SJason Zhu if (part_get_info_by_name(dev_desc, partition, &part_info) < 0) 152*0cc16201SJason Zhu return -ENOENT; 153*0cc16201SJason Zhu 154*0cc16201SJason Zhu ret = blk_dwrite(dev_desc, part_info.start + AB_METADATA_OFFSET, 1, 155*0cc16201SJason Zhu temp); 156*0cc16201SJason Zhu if (ret != 1) 157*0cc16201SJason Zhu return -ENODEV; 158*0cc16201SJason Zhu 159*0cc16201SJason Zhu return 0; 160*0cc16201SJason Zhu } 161*0cc16201SJason Zhu 162*0cc16201SJason Zhu static int spl_ab_data_write(struct blk_desc *dev_desc, AvbABData *ab_data, 163*0cc16201SJason Zhu char *partition) 164*0cc16201SJason Zhu { 165*0cc16201SJason Zhu AvbABData serialized; 166*0cc16201SJason Zhu 167*0cc16201SJason Zhu spl_ab_data_update_crc_and_byteswap(ab_data, &serialized); 168*0cc16201SJason Zhu 169*0cc16201SJason Zhu return spl_write_ab_metadata(dev_desc, &serialized, partition); 170*0cc16201SJason Zhu } 171*0cc16201SJason Zhu 172*0cc16201SJason Zhu static int spl_ab_data_read(struct blk_desc *dev_desc, AvbABData *ab_data, 173*0cc16201SJason Zhu char *partition) 174*0cc16201SJason Zhu { 175*0cc16201SJason Zhu int ret; 176*0cc16201SJason Zhu AvbABData serialized; 177*0cc16201SJason Zhu 178*0cc16201SJason Zhu ret = spl_read_ab_metadata(dev_desc, &serialized, partition); 179*0cc16201SJason Zhu if (ret) 180*0cc16201SJason Zhu return ret; 181*0cc16201SJason Zhu 182*0cc16201SJason Zhu if (!spl_ab_data_verify_and_byteswap(&serialized, ab_data)) { 183*0cc16201SJason Zhu printf("Error validating A/B metadata from disk. " 184*0cc16201SJason Zhu "Resetting and writing new A/B metadata to disk.\n"); 185*0cc16201SJason Zhu spl_ab_data_init(ab_data); 186*0cc16201SJason Zhu spl_ab_data_write(dev_desc, ab_data, partition); 187*0cc16201SJason Zhu } 188*0cc16201SJason Zhu 189*0cc16201SJason Zhu return 0; 190*0cc16201SJason Zhu } 191*0cc16201SJason Zhu 192*0cc16201SJason Zhu static bool spl_slot_is_bootable(AvbABSlotData *slot) 193*0cc16201SJason Zhu { 194*0cc16201SJason Zhu return slot->priority > 0 && 195*0cc16201SJason Zhu (slot->successful_boot || (slot->tries_remaining > 0)); 196*0cc16201SJason Zhu } 197*0cc16201SJason Zhu 198*0cc16201SJason Zhu static int spl_get_lastboot(AvbABData *ab_data) 199*0cc16201SJason Zhu { 200*0cc16201SJason Zhu return ab_data->last_boot; 201*0cc16201SJason Zhu } 202*0cc16201SJason Zhu 203*0cc16201SJason Zhu int spl_get_current_slot(struct blk_desc *dev_desc, char *partition, char *slot) 204*0cc16201SJason Zhu { 205*0cc16201SJason Zhu size_t slot_index_to_boot; 206*0cc16201SJason Zhu AvbABData ab_data; 207*0cc16201SJason Zhu int ret; 208*0cc16201SJason Zhu 209*0cc16201SJason Zhu ret = spl_ab_data_read(dev_desc, &ab_data, partition); 210*0cc16201SJason Zhu if (ret) 211*0cc16201SJason Zhu return ret; 212*0cc16201SJason Zhu 213*0cc16201SJason Zhu if (spl_slot_is_bootable(&ab_data.slots[0]) && 214*0cc16201SJason Zhu spl_slot_is_bootable(&ab_data.slots[1])) { 215*0cc16201SJason Zhu if (ab_data.slots[1].priority > ab_data.slots[0].priority) 216*0cc16201SJason Zhu slot_index_to_boot = 1; 217*0cc16201SJason Zhu else 218*0cc16201SJason Zhu slot_index_to_boot = 0; 219*0cc16201SJason Zhu } else if (spl_slot_is_bootable(&ab_data.slots[0])) { 220*0cc16201SJason Zhu slot_index_to_boot = 0; 221*0cc16201SJason Zhu } else if (spl_slot_is_bootable(&ab_data.slots[1])) { 222*0cc16201SJason Zhu slot_index_to_boot = 1; 223*0cc16201SJason Zhu } else { 224*0cc16201SJason Zhu printf("No bootable slots found, use lastboot.\n"); 225*0cc16201SJason Zhu if (spl_get_lastboot(&ab_data) == 0) { 226*0cc16201SJason Zhu memcpy(slot, "_a", 2); 227*0cc16201SJason Zhu goto out; 228*0cc16201SJason Zhu } else if (spl_get_lastboot(&ab_data) == 1) { 229*0cc16201SJason Zhu memcpy(slot, "_b", 2); 230*0cc16201SJason Zhu goto out; 231*0cc16201SJason Zhu } else { 232*0cc16201SJason Zhu return -ENODEV; 233*0cc16201SJason Zhu } 234*0cc16201SJason Zhu } 235*0cc16201SJason Zhu 236*0cc16201SJason Zhu if (slot_index_to_boot == 0) 237*0cc16201SJason Zhu memcpy(slot, "_a", 2); 238*0cc16201SJason Zhu else if (slot_index_to_boot == 1) 239*0cc16201SJason Zhu memcpy(slot, "_b", 2); 240*0cc16201SJason Zhu 241*0cc16201SJason Zhu out: 242*0cc16201SJason Zhu return 0; 243*0cc16201SJason Zhu } 244*0cc16201SJason Zhu 245*0cc16201SJason Zhu int spl_get_partitions_sector(struct blk_desc *dev_desc, char *partition, 246*0cc16201SJason Zhu u32 *sectors) 247*0cc16201SJason Zhu { 248*0cc16201SJason Zhu disk_partition_t part_info; 249*0cc16201SJason Zhu char part[10] = {0}; 250*0cc16201SJason Zhu char slot[3] = {0}; 251*0cc16201SJason Zhu 252*0cc16201SJason Zhu if (!partition || !sectors) 253*0cc16201SJason Zhu return -EFAULT; 254*0cc16201SJason Zhu 255*0cc16201SJason Zhu spl_get_current_slot(dev_desc, "misc", slot); 256*0cc16201SJason Zhu if (strlen(partition) > 8) 257*0cc16201SJason Zhu return -ENOMEM; 258*0cc16201SJason Zhu 259*0cc16201SJason Zhu strcat(part, partition); 260*0cc16201SJason Zhu strcat(part, slot); 261*0cc16201SJason Zhu if (part_get_info_by_name(dev_desc, part, &part_info) < 0) 262*0cc16201SJason Zhu return -ENODEV; 263*0cc16201SJason Zhu 264*0cc16201SJason Zhu *sectors = part_info.start; 265*0cc16201SJason Zhu 266*0cc16201SJason Zhu return 0; 267*0cc16201SJason Zhu } 268