10cc16201SJason Zhu // SPDX-License-Identifier: GPL-2.0 20cc16201SJason Zhu /* 30cc16201SJason Zhu * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd 40cc16201SJason Zhu */ 50cc16201SJason Zhu 60cc16201SJason Zhu #include <common.h> 70cc16201SJason Zhu #include <blk.h> 80cc16201SJason Zhu #include <spl_ab.h> 90cc16201SJason Zhu 100cc16201SJason Zhu int safe_memcmp(const void *s1, const void *s2, size_t n) 110cc16201SJason Zhu { 120cc16201SJason Zhu const unsigned char *us1 = s1; 130cc16201SJason Zhu const unsigned char *us2 = s2; 140cc16201SJason Zhu int result = 0; 150cc16201SJason Zhu 160cc16201SJason Zhu if (0 == n) 170cc16201SJason Zhu return 0; 180cc16201SJason Zhu 190cc16201SJason Zhu /* 200cc16201SJason Zhu * Code snippet without data-dependent branch due to Nate Lawson 210cc16201SJason Zhu * (nate@root.org) of Root Labs. 220cc16201SJason Zhu */ 230cc16201SJason Zhu while (n--) 240cc16201SJason Zhu result |= *us1++ ^ *us2++; 250cc16201SJason Zhu 260cc16201SJason Zhu return result != 0; 270cc16201SJason Zhu } 280cc16201SJason Zhu 290cc16201SJason Zhu static uint32_t htobe32(uint32_t in) 300cc16201SJason Zhu { 310cc16201SJason Zhu union { 320cc16201SJason Zhu uint32_t word; 330cc16201SJason Zhu uint8_t bytes[4]; 340cc16201SJason Zhu } ret; 350cc16201SJason Zhu 360cc16201SJason Zhu ret.bytes[0] = (in >> 24) & 0xff; 370cc16201SJason Zhu ret.bytes[1] = (in >> 16) & 0xff; 380cc16201SJason Zhu ret.bytes[2] = (in >> 8) & 0xff; 390cc16201SJason Zhu ret.bytes[3] = in & 0xff; 400cc16201SJason Zhu 410cc16201SJason Zhu return ret.word; 420cc16201SJason Zhu } 430cc16201SJason Zhu 440cc16201SJason Zhu static uint32_t be32toh(uint32_t in) 450cc16201SJason Zhu { 460cc16201SJason Zhu uint8_t *d = (uint8_t *)∈ 470cc16201SJason Zhu uint32_t ret; 480cc16201SJason Zhu 490cc16201SJason Zhu ret = ((uint32_t)d[0]) << 24; 500cc16201SJason Zhu ret |= ((uint32_t)d[1]) << 16; 510cc16201SJason Zhu ret |= ((uint32_t)d[2]) << 8; 520cc16201SJason Zhu ret |= ((uint32_t)d[3]); 530cc16201SJason Zhu 540cc16201SJason Zhu return ret; 550cc16201SJason Zhu } 560cc16201SJason Zhu 570cc16201SJason Zhu static bool spl_ab_data_verify_and_byteswap(const AvbABData *src, 580cc16201SJason Zhu AvbABData *dest) 590cc16201SJason Zhu { 600cc16201SJason Zhu /* Ensure magic is correct. */ 610cc16201SJason Zhu if (safe_memcmp(src->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN) != 0) { 620cc16201SJason Zhu printf("Magic is incorrect.\n"); 630cc16201SJason Zhu return false; 640cc16201SJason Zhu } 650cc16201SJason Zhu 660cc16201SJason Zhu memcpy(dest, src, sizeof(AvbABData)); 670cc16201SJason Zhu dest->crc32 = be32toh(dest->crc32); 680cc16201SJason Zhu 690cc16201SJason Zhu /* Ensure we don't attempt to access any fields if the major version 700cc16201SJason Zhu * is not supported. 710cc16201SJason Zhu */ 720cc16201SJason Zhu if (dest->version_major > AVB_AB_MAJOR_VERSION) { 730cc16201SJason Zhu printf("No support for given major version.\n"); 740cc16201SJason Zhu return false; 750cc16201SJason Zhu } 760cc16201SJason Zhu 770cc16201SJason Zhu /* Bail if CRC32 doesn't match. */ 780cc16201SJason Zhu if (dest->crc32 != 790cc16201SJason Zhu crc32(0, (const uint8_t *)dest, 800cc16201SJason Zhu sizeof(AvbABData) - sizeof(uint32_t))) { 810cc16201SJason Zhu printf("CRC32 does not match.\n"); 820cc16201SJason Zhu return false; 830cc16201SJason Zhu } 840cc16201SJason Zhu 850cc16201SJason Zhu return true; 860cc16201SJason Zhu } 870cc16201SJason Zhu 880cc16201SJason Zhu static void spl_ab_data_update_crc_and_byteswap(const AvbABData *src, 890cc16201SJason Zhu AvbABData *dest) 900cc16201SJason Zhu { 910cc16201SJason Zhu memcpy(dest, src, sizeof(AvbABData)); 920cc16201SJason Zhu dest->crc32 = htobe32(crc32(0, (const uint8_t *)dest, 930cc16201SJason Zhu sizeof(AvbABData) - sizeof(uint32_t))); 940cc16201SJason Zhu } 950cc16201SJason Zhu 960cc16201SJason Zhu static void spl_ab_data_init(AvbABData *data) 970cc16201SJason Zhu { 980cc16201SJason Zhu memset(data, '\0', sizeof(AvbABData)); 990cc16201SJason Zhu memcpy(data->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN); 1000cc16201SJason Zhu data->version_major = AVB_AB_MAJOR_VERSION; 1010cc16201SJason Zhu data->version_minor = AVB_AB_MINOR_VERSION; 1020cc16201SJason Zhu data->last_boot = 0; 1030cc16201SJason Zhu data->slots[0].priority = AVB_AB_MAX_PRIORITY; 1040cc16201SJason Zhu data->slots[0].tries_remaining = AVB_AB_MAX_TRIES_REMAINING; 1050cc16201SJason Zhu data->slots[0].successful_boot = 0; 1060cc16201SJason Zhu data->slots[1].priority = AVB_AB_MAX_PRIORITY - 1; 1070cc16201SJason Zhu data->slots[1].tries_remaining = AVB_AB_MAX_TRIES_REMAINING; 1080cc16201SJason Zhu data->slots[1].successful_boot = 0; 1090cc16201SJason Zhu } 1100cc16201SJason Zhu 1110cc16201SJason Zhu static int spl_read_ab_metadata(struct blk_desc *dev_desc, AvbABData *ab_data, 1120cc16201SJason Zhu char *partition) 1130cc16201SJason Zhu { 1140cc16201SJason Zhu disk_partition_t part_info; 1150cc16201SJason Zhu char temp[512]; 1160cc16201SJason Zhu int ret; 1170cc16201SJason Zhu 1180cc16201SJason Zhu if (!dev_desc || !partition || !ab_data) 1190cc16201SJason Zhu return -EFAULT; 1200cc16201SJason Zhu 1210cc16201SJason Zhu if (part_get_info_by_name(dev_desc, partition, &part_info) < 0) 1220cc16201SJason Zhu return -ENOENT; 1230cc16201SJason Zhu 1240cc16201SJason Zhu ret = blk_dread(dev_desc, part_info.start + AB_METADATA_OFFSET, 1, 1250cc16201SJason Zhu temp); 1260cc16201SJason Zhu if (ret != 1) 1270cc16201SJason Zhu return -ENODEV; 1280cc16201SJason Zhu 1290cc16201SJason Zhu if (sizeof(AvbABData) > 512) 1300cc16201SJason Zhu return -ENOMEM; 1310cc16201SJason Zhu 1320cc16201SJason Zhu memcpy(ab_data, temp, sizeof(AvbABData)); 1330cc16201SJason Zhu 1340cc16201SJason Zhu return 0; 1350cc16201SJason Zhu } 1360cc16201SJason Zhu 1370cc16201SJason Zhu static int spl_write_ab_metadata(struct blk_desc *dev_desc, AvbABData *ab_data, 1380cc16201SJason Zhu char *partition) 1390cc16201SJason Zhu { 1400cc16201SJason Zhu disk_partition_t part_info; 1410cc16201SJason Zhu char temp[512]; 1420cc16201SJason Zhu int ret; 1430cc16201SJason Zhu 1440cc16201SJason Zhu if (!dev_desc || !partition || !ab_data) 1450cc16201SJason Zhu return -EFAULT; 1460cc16201SJason Zhu 1470cc16201SJason Zhu if (sizeof(AvbABData) > 512) 1480cc16201SJason Zhu return -ENOMEM; 1490cc16201SJason Zhu 1500cc16201SJason Zhu memcpy(temp, ab_data, sizeof(AvbABData)); 1510cc16201SJason Zhu if (part_get_info_by_name(dev_desc, partition, &part_info) < 0) 1520cc16201SJason Zhu return -ENOENT; 1530cc16201SJason Zhu 1540cc16201SJason Zhu ret = blk_dwrite(dev_desc, part_info.start + AB_METADATA_OFFSET, 1, 1550cc16201SJason Zhu temp); 1560cc16201SJason Zhu if (ret != 1) 1570cc16201SJason Zhu return -ENODEV; 1580cc16201SJason Zhu 1590cc16201SJason Zhu return 0; 1600cc16201SJason Zhu } 1610cc16201SJason Zhu 1620cc16201SJason Zhu static int spl_ab_data_write(struct blk_desc *dev_desc, AvbABData *ab_data, 1630cc16201SJason Zhu char *partition) 1640cc16201SJason Zhu { 1650cc16201SJason Zhu AvbABData serialized; 1660cc16201SJason Zhu 1670cc16201SJason Zhu spl_ab_data_update_crc_and_byteswap(ab_data, &serialized); 1680cc16201SJason Zhu 1690cc16201SJason Zhu return spl_write_ab_metadata(dev_desc, &serialized, partition); 1700cc16201SJason Zhu } 1710cc16201SJason Zhu 1720cc16201SJason Zhu static int spl_ab_data_read(struct blk_desc *dev_desc, AvbABData *ab_data, 1730cc16201SJason Zhu char *partition) 1740cc16201SJason Zhu { 1750cc16201SJason Zhu int ret; 1760cc16201SJason Zhu AvbABData serialized; 1770cc16201SJason Zhu 1780cc16201SJason Zhu ret = spl_read_ab_metadata(dev_desc, &serialized, partition); 1790cc16201SJason Zhu if (ret) 1800cc16201SJason Zhu return ret; 1810cc16201SJason Zhu 1820cc16201SJason Zhu if (!spl_ab_data_verify_and_byteswap(&serialized, ab_data)) { 1830cc16201SJason Zhu printf("Error validating A/B metadata from disk. " 1840cc16201SJason Zhu "Resetting and writing new A/B metadata to disk.\n"); 1850cc16201SJason Zhu spl_ab_data_init(ab_data); 1860cc16201SJason Zhu spl_ab_data_write(dev_desc, ab_data, partition); 1870cc16201SJason Zhu } 1880cc16201SJason Zhu 1890cc16201SJason Zhu return 0; 1900cc16201SJason Zhu } 1910cc16201SJason Zhu 1920cc16201SJason Zhu static bool spl_slot_is_bootable(AvbABSlotData *slot) 1930cc16201SJason Zhu { 1940cc16201SJason Zhu return slot->priority > 0 && 1950cc16201SJason Zhu (slot->successful_boot || (slot->tries_remaining > 0)); 1960cc16201SJason Zhu } 1970cc16201SJason Zhu 1980cc16201SJason Zhu static int spl_get_lastboot(AvbABData *ab_data) 1990cc16201SJason Zhu { 2000cc16201SJason Zhu return ab_data->last_boot; 2010cc16201SJason Zhu } 2020cc16201SJason Zhu 2030cc16201SJason Zhu int spl_get_current_slot(struct blk_desc *dev_desc, char *partition, char *slot) 2040cc16201SJason Zhu { 2050cc16201SJason Zhu size_t slot_index_to_boot; 2060cc16201SJason Zhu AvbABData ab_data; 2070cc16201SJason Zhu int ret; 2080cc16201SJason Zhu 2090cc16201SJason Zhu ret = spl_ab_data_read(dev_desc, &ab_data, partition); 2100cc16201SJason Zhu if (ret) 2110cc16201SJason Zhu return ret; 2120cc16201SJason Zhu 2130cc16201SJason Zhu if (spl_slot_is_bootable(&ab_data.slots[0]) && 2140cc16201SJason Zhu spl_slot_is_bootable(&ab_data.slots[1])) { 2150cc16201SJason Zhu if (ab_data.slots[1].priority > ab_data.slots[0].priority) 2160cc16201SJason Zhu slot_index_to_boot = 1; 2170cc16201SJason Zhu else 2180cc16201SJason Zhu slot_index_to_boot = 0; 2190cc16201SJason Zhu } else if (spl_slot_is_bootable(&ab_data.slots[0])) { 2200cc16201SJason Zhu slot_index_to_boot = 0; 2210cc16201SJason Zhu } else if (spl_slot_is_bootable(&ab_data.slots[1])) { 2220cc16201SJason Zhu slot_index_to_boot = 1; 2230cc16201SJason Zhu } else { 2240cc16201SJason Zhu printf("No bootable slots found, use lastboot.\n"); 2250cc16201SJason Zhu if (spl_get_lastboot(&ab_data) == 0) { 2260cc16201SJason Zhu memcpy(slot, "_a", 2); 2270cc16201SJason Zhu goto out; 2280cc16201SJason Zhu } else if (spl_get_lastboot(&ab_data) == 1) { 2290cc16201SJason Zhu memcpy(slot, "_b", 2); 2300cc16201SJason Zhu goto out; 2310cc16201SJason Zhu } else { 2320cc16201SJason Zhu return -ENODEV; 2330cc16201SJason Zhu } 2340cc16201SJason Zhu } 2350cc16201SJason Zhu 2360cc16201SJason Zhu if (slot_index_to_boot == 0) 2370cc16201SJason Zhu memcpy(slot, "_a", 2); 2380cc16201SJason Zhu else if (slot_index_to_boot == 1) 2390cc16201SJason Zhu memcpy(slot, "_b", 2); 2400cc16201SJason Zhu 2410cc16201SJason Zhu out: 2420cc16201SJason Zhu return 0; 2430cc16201SJason Zhu } 2440cc16201SJason Zhu 245*1e33e3cbSJason Zhu int spl_ab_append_part_slot(struct blk_desc *dev_desc, 246*1e33e3cbSJason Zhu const char *part_name, 247*1e33e3cbSJason Zhu char *new_name) 2480cc16201SJason Zhu { 249*1e33e3cbSJason Zhu char slot_suffix[3] = {0}; 2500cc16201SJason Zhu 251*1e33e3cbSJason Zhu if (!strcmp(part_name, "misc")) { 252*1e33e3cbSJason Zhu strcat(new_name, part_name); 253*1e33e3cbSJason Zhu return 0; 254*1e33e3cbSJason Zhu } 2550cc16201SJason Zhu 256*1e33e3cbSJason Zhu if (spl_get_current_slot(dev_desc, "misc", slot_suffix)) { 257*1e33e3cbSJason Zhu printf("%s: failed to get slot suffix !\n", __func__); 258*1e33e3cbSJason Zhu return -1; 259*1e33e3cbSJason Zhu } 2600cc16201SJason Zhu 261*1e33e3cbSJason Zhu strcpy(new_name, part_name); 262*1e33e3cbSJason Zhu strcat(new_name, slot_suffix); 2630cc16201SJason Zhu 2640cc16201SJason Zhu return 0; 2650cc16201SJason Zhu } 266