blob: 1887149475a009a36b30c1fe49c6073fddad00f4 [file] [log] [blame]
/*
* Copyright (c) 2020 The Fuchsia Authors
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common.h>
#include <blk.h>
#include <emmc_storage.h>
#include <emmc_partitions.h>
#include <mmc.h>
#include <part.h>
#include <u-boot/sha256.h>
#include <zircon_uboot/partition.h>
#include <zircon_uboot/util.h>
#define BLK_SIZE (512)
#define GPT_SIZE_LBA (33)
#define GPT_SIZE (GPT_SIZE_LBA * BLK_SIZE)
// `gpt_update_img_t` consists of primary + secondary GPT concatenated together.
typedef struct {
gpt_header primary_header;
uint8_t reserved_1[BLK_SIZE - sizeof(gpt_header)];
gpt_entry primary_entries[GPT_ENTRY_NUMBERS];
gpt_entry backup_entries[GPT_ENTRY_NUMBERS];
gpt_header backup_header;
uint8_t reserved_2[BLK_SIZE - sizeof(gpt_header)];
} __packed gpt_update_img_t;
static gpt_update_img_t gpt_update_img __aligned(ARCH_DMA_MINALIGN);
int gpt_update()
{
printf("GPT Update: checking for new GPT\n");
struct mmc *mmc = find_mmc_device(STORAGE_DEV_EMMC);
if (!mmc) {
fprintf(stderr, "GPT Update: No MMC device found\n");
return -1;
}
struct blk_desc *blk_desc = mmc_get_blk_desc(mmc);
if (!blk_desc) {
fprintf(stderr, "GPT Update: mmc_get_blk_desc failed\n");
return -1;
}
zircon_partition *migration_part = zircon_get_partition("migration");
if (!migration_part) {
fprintf(stderr, "GPT Update: partition not found\n");
return -1;
}
if (migration_part->read(migration_part, 0, &gpt_update_img,
sizeof(gpt_update_img))) {
fprintf(stderr, "GPT Update: read failed\n");
zircon_free_partition(migration_part);
return -1;
}
lbaint_t disk_size_lba = blk_desc->lba;
lbaint_t last_usable_lba = disk_size_lba - GPT_SIZE_LBA - 1;
lbaint_t primary_header_lba = 1;
lbaint_t backup_header_lba = disk_size_lba - 1;
if (validate_gpt_header(&gpt_update_img.primary_header,
primary_header_lba, last_usable_lba) ||
validate_gpt_entries(&gpt_update_img.primary_header,
gpt_update_img.primary_entries) ||
validate_gpt_header(&gpt_update_img.backup_header,
backup_header_lba, last_usable_lba) ||
validate_gpt_entries(&gpt_update_img.backup_header,
gpt_update_img.backup_entries)) {
fprintf(stderr, "GPT Update: GPT validation failed\n");
zircon_free_partition(migration_part);
return -1;
}
zircon_partition *gpt_primary_part =
zircon_get_partition("gpt_primary");
if (!gpt_primary_part) {
fprintf(stderr, "GPT Update: partition not found\n");
zircon_free_partition(migration_part);
return -1;
}
if (gpt_primary_part->write(gpt_primary_part, 0, &gpt_update_img,
GPT_SIZE)) {
fprintf(stderr, "GPT Update: primary write failed\n");
zircon_free_partition(migration_part);
zircon_free_partition(gpt_primary_part);
return -1;
}
zircon_free_partition(gpt_primary_part);
zircon_partition *gpt_backup_part = zircon_get_partition("gpt_backup");
if (!gpt_backup_part) {
fprintf(stderr, "GPT Update: partition not found\n");
zircon_free_partition(migration_part);
return -1;
}
if (gpt_backup_part->write(gpt_backup_part, 0,
&gpt_update_img.backup_entries, GPT_SIZE)) {
fprintf(stderr, "GPT Update: backup write failed\n");
zircon_free_partition(migration_part);
zircon_free_partition(gpt_backup_part);
return -1;
}
zircon_free_partition(gpt_backup_part);
int ret = migration_part->erase(migration_part);
zircon_free_partition(migration_part);
// reinitialize mmc to update the cached partition table.
mmc_device_init(mmc);
printf("GPT Update: update complete\n");
return ret;
}
/*
* Generate a default serial number of given size (including null terminator)
* based on the eMMC device info.
*/
int get_default_serial_number(char *sn, size_t size)
{
if ((sn == NULL) || !size) {
return -1;
}
// Get eMMC device info.
struct mmc *mmc = find_mmc_device(STORAGE_DEV_EMMC);
if (!mmc) {
printf("Cannot find eMMC dev.\n");
return -1;
}
// The eMMC CID contains a serial number. Hash it to get a default serial number for use
// in case a real one isn't available.
uint8_t hash[SHA256_DIGEST_SIZE];
sha256_csum_wd((const uint8_t *)mmc->cid, sizeof(mmc->cid), hash,
CHUNKSZ_SHA256);
int i = SHA256_DIGEST_SIZE - 1;
/* if |sn| is too small to fit all hash digest, calc how many can be stored */
if (size < (SHA256_DIGEST_SIZE * 2 + 1)) {
i = ((size - 1) / 2) - 1;
}
static const char hex[] = "0123456789ABCDEF";
int j = 0;
for (; i >= 0; i--) {
sn[j++] = hex[(hash[i] >> 4) & 0xF];
sn[j++] = hex[hash[i] & 0xF];
}
sn[size - 1] = '\0';
return 0;
}