#include <vsprintf.h>
#include <errno.h>
#include <dm.h>
+#include <fuse.h>
+#include <mach/efuse.h>
#include <spi_flash.h>
#include <spi.h>
#include <nand.h>
+#include <scsi.h>
#include <usb.h>
#include <fs.h>
#include <mmc.h>
u8 checksum; /* 0x1F */
};
+/*
+ * Header for the optional headers, version 1 (Armada 370/XP/375/38x/39x)
+ */
+struct a38x_opt_hdr_v1 {
+ u8 headertype;
+ u8 headersz_msb;
+ u16 headersz_lsb;
+ u8 data[0];
+};
+#define A38X_OPT_HDR_V1_SECURE_TYPE 0x1
+
struct a38x_boot_mode {
unsigned int id;
const char *name;
#ifdef CONFIG_BLK
struct blk_desc *blk_desc;
#endif
+#ifdef CONFIG_SUPPORT_EMMC_BOOT
+ u8 part;
+ u8 orig_part;
+#endif
+
mmc = find_mmc_device(mmc_dev_num);
if (!mmc) {
printf("No SD/MMC/eMMC card found\n");
return err;
}
+#ifdef CONFIG_BLK
+ blk_desc = mmc_get_blk_desc(mmc);
+ if (!blk_desc) {
+ printf("Error - failed to obtain block descriptor\n");
+ return -ENODEV;
+ }
+#endif
+
+#ifdef CONFIG_SUPPORT_EMMC_BOOT
+#ifdef CONFIG_BLK
+ orig_part = blk_desc->hwpart;
+#else
+ orig_part = mmc->block_dev.hwpart;
+#endif
+
+ part = (mmc->part_config >> 3) & PART_ACCESS_MASK;
+
+ if (part == 7)
+ part = 0;
+
+#ifdef CONFIG_BLK
+ err = blk_dselect_hwpart(blk_desc, part);
+#else
+ err = mmc_switch_part(mmc, part);
+#endif
+
+ if (err) {
+ printf("Error - MMC partition switch failed\n");
+ return err;
+ }
+#endif
+
/* SD reserves LBA-0 for MBR and boots from LBA-1,
* MMC/eMMC boots from LBA-0
*/
if (image_size % mmc->write_bl_len)
blk_count += 1;
- blk_desc = mmc_get_blk_desc(mmc);
- if (!blk_desc) {
- printf("Error - failed to obtain block descriptor\n");
- return -ENODEV;
- }
blk_written = blk_dwrite(blk_desc, start_lba, blk_count,
(void *)get_load_addr());
#else
start_lba, blk_count,
(void *)get_load_addr());
#endif /* CONFIG_BLK */
+
+#ifdef CONFIG_SUPPORT_EMMC_BOOT
+#ifdef CONFIG_BLK
+ err = blk_dselect_hwpart(blk_desc, orig_part);
+#else
+ err = mmc_switch_part(mmc, orig_part);
+#endif
+ if (err)
+ printf("Error - MMC failed to switch back to original partition\n");
+#endif
+
if (blk_written != blk_count) {
printf("Error - written %#lx blocks\n", blk_written);
return -ENOSPC;
}
#endif /* CONFIG_DM_MMC */
+/********************************************************************
+ * SATA services
+ ********************************************************************/
+#if defined(CONFIG_SCSI) && defined(CONFIG_BLK)
+static int sata_burn_image(size_t image_size)
+{
+#if defined(CONFIG_ARMADA_3700) || defined(CONFIG_ARMADA_32BIT)
+ lbaint_t start_lba;
+ lbaint_t blk_count;
+ ulong blk_written;
+ struct blk_desc *blk_desc;
+#ifdef CONFIG_ARMADA_3700
+ struct disk_partition info;
+ int part;
+#endif
+
+ scsi_scan(false);
+
+ blk_desc = blk_get_devnum_by_uclass_id(UCLASS_SCSI, 0);
+ if (!blk_desc)
+ return -ENODEV;
+
+#ifdef CONFIG_ARMADA_3700
+ /*
+ * 64-bit Armada 3700 BootROM loads SATA firmware from
+ * GPT 'Marvell Armada 3700 Boot partition' or from
+ * MBR 'M' (0x4d) partition.
+ */
+ switch (blk_desc->part_type) {
+ case PART_TYPE_DOS:
+ for (part = 1; part <= 4; part++) {
+ info.sys_ind = 0;
+ if (part_get_info(blk_desc, part, &info))
+ continue;
+ if (info.sys_ind == 'M')
+ break;
+ }
+ if (part > 4) {
+ printf("Error - cannot find MBR 'M' (0x4d) partition on SATA disk\n");
+ return -ENODEV;
+ }
+ start_lba = info.start;
+ break;
+ case PART_TYPE_EFI:
+ for (part = 1; part <= 64; part++) {
+ info.type_guid[0] = 0;
+ if (part_get_info(blk_desc, part, &info))
+ continue;
+ /* Check for GPT type GUID of 'Marvell Armada 3700 Boot partition' */
+ if (strcmp(info.type_guid, "6828311A-BA55-42A4-BCDE-A89BB5EDECAE") == 0)
+ break;
+ }
+ if (part > 64) {
+ printf("Error - cannot find GPT 'Marvell Armada 3700 Boot partition' on SATA disk\n");
+ return -ENODEV;
+ }
+ start_lba = info.start;
+ break;
+ default:
+ printf("Error - no partitions on SATA disk\n");
+ return -ENODEV;
+ }
+#else
+ /* 32-bit Armada BootROM loads SATA firmware from the sector 1. */
+ start_lba = 1;
+#endif
+
+ blk_count = image_size / blk_desc->blksz;
+ if (image_size % blk_desc->blksz)
+ blk_count += 1;
+
+ blk_written = blk_dwrite(blk_desc, start_lba, blk_count,
+ (void *)get_load_addr());
+
+ if (blk_written != blk_count) {
+ printf("Error - written %#lx blocks\n", blk_written);
+ return -ENOSPC;
+ }
+
+ printf("Done!\n");
+ return 0;
+#else
+ return -ENODEV;
+#endif
+}
+
+static size_t sata_read_file(const char *file_name)
+{
+ loff_t act_read = 0;
+ struct udevice *dev;
+ int rc;
+
+ /* try to recognize storage devices immediately */
+ scsi_scan(false);
+
+ /* Try to recognize storage devices immediately */
+ blk_first_device(UCLASS_SCSI, &dev);
+ if (!dev) {
+ printf("Error: SATA device not found\n");
+ return 0;
+ }
+
+ /* Always load from scsi 0 */
+ if (fs_set_blk_dev("scsi", "0", FS_TYPE_ANY)) {
+ printf("Error: SATA 0 not found\n");
+ return 0;
+ }
+
+ /* Perfrom file read */
+ rc = fs_read(file_name, get_load_addr(), 0, 0, &act_read);
+ if (rc)
+ return 0;
+
+ return act_read;
+}
+
+static int is_sata_active(void)
+{
+ return 1;
+}
+#else /* CONFIG_SCSI */
+static int sata_burn_image(size_t image_size)
+{
+ return -ENODEV;
+}
+
+static size_t sata_read_file(const char *file_name)
+{
+ return 0;
+}
+
+static int is_sata_active(void)
+{
+ return 0;
+}
+#endif /* CONFIG_SCSI */
+
/********************************************************************
* SPI services
********************************************************************/
BUBT_DEV_NET = 0,
BUBT_DEV_USB,
BUBT_DEV_MMC,
+ BUBT_DEV_SATA,
BUBT_DEV_SPI,
BUBT_DEV_NAND,
BUBT_MAX_DEV
};
-struct bubt_dev bubt_devs[BUBT_MAX_DEV] = {
+static struct bubt_dev bubt_devs[BUBT_MAX_DEV] = {
{"tftp", tftp_read_file, NULL, is_tftp_active},
{"usb", usb_read_file, NULL, is_usb_active},
{"mmc", mmc_read_file, mmc_burn_image, is_mmc_active},
+ {"sata", sata_read_file, sata_burn_image, is_sata_active},
{"spi", NULL, spi_burn_image, is_spi_active},
{"nand", NULL, nand_burn_image, is_nand_active},
};
}
#if defined(CONFIG_ARMADA_8K)
-u32 do_checksum32(u32 *start, int32_t len)
+static u32 do_checksum32(u32 *start, int32_t len)
{
u32 sum = 0;
u32 *startp = start;
{
struct mvebu_image_header *hdr =
(struct mvebu_image_header *)get_load_addr();
- u32 header_len = hdr->prolog_size;
u32 checksum;
- u32 checksum_ref = hdr->prolog_checksum;
+ u32 checksum_ref;
/*
* For now compare checksum, and magic. Later we can
return -ENOEXEC;
}
- /* The checksum value is discarded from checksum calculation */
- hdr->prolog_checksum = 0;
+ checksum_ref = hdr->prolog_checksum;
+ checksum = do_checksum32((u32 *)hdr, hdr->prolog_size);
+ checksum -= hdr->prolog_checksum;
+ if (checksum != checksum_ref) {
+ printf("Error: Bad Prolog checksum. 0x%x != 0x%x\n",
+ checksum, checksum_ref);
+ return -ENOEXEC;
+ }
- checksum = do_checksum32((u32 *)hdr, header_len);
+ checksum_ref = hdr->boot_image_checksum;
+ checksum = do_checksum32((u32 *)((u8 *)hdr + hdr->prolog_size), hdr->boot_image_size);
if (checksum != checksum_ref) {
printf("Error: Bad Image checksum. 0x%x != 0x%x\n",
checksum, checksum_ref);
return -ENOEXEC;
}
- /* Restore the checksum before writing */
- hdr->prolog_checksum = checksum_ref;
printf("Image checksum...OK!\n");
return 0;
return csum;
}
+static uint32_t image_checksum32(const void *start, size_t len)
+{
+ u32 csum = 0;
+ const u32 *p = start;
+
+ while (len) {
+ csum += *p;
+ ++p;
+ len -= sizeof(u32);
+ }
+
+ return csum;
+}
+
static int check_image_header(void)
{
u8 checksum;
+ u32 checksum32, exp_checksum32;
+ u32 offset, size;
const struct a38x_main_hdr_v1 *hdr =
(struct a38x_main_hdr_v1 *)get_load_addr();
- const size_t image_size = a38x_header_size(hdr);
+ const size_t hdr_size = a38x_header_size(hdr);
- if (!image_size)
+ if (!hdr_size)
return -ENOEXEC;
- checksum = image_checksum8(hdr, image_size);
+ checksum = image_checksum8(hdr, hdr_size);
checksum -= hdr->checksum;
if (checksum != hdr->checksum) {
- printf("Error: Bad A38x image checksum. 0x%x != 0x%x\n",
+ printf("Error: Bad A38x image header checksum. 0x%x != 0x%x\n",
checksum, hdr->checksum);
return -ENOEXEC;
}
+ offset = le32_to_cpu(hdr->srcaddr);
+ size = le32_to_cpu(hdr->blocksize);
+
+ if (hdr->blockid == 0x78) /* SATA id */
+ offset *= 512;
+
+ if (offset % 4 != 0 || size < 4 || size % 4 != 0) {
+ printf("Error: Bad A38x image blocksize.\n");
+ return -ENOEXEC;
+ }
+
+ checksum32 = image_checksum32((u8 *)hdr + offset, size - 4);
+ exp_checksum32 = *(u32 *)((u8 *)hdr + offset + size - 4);
+ if (checksum32 != exp_checksum32) {
+ printf("Error: Bad A38x image data checksum. 0x%08x != 0x%08x\n",
+ checksum32, exp_checksum32);
+ return -ENOEXEC;
+ }
+
printf("Image checksum...OK!\n");
return 0;
}
+
+#if defined(CONFIG_ARMADA_38X)
+static int a38x_image_is_secure(const struct a38x_main_hdr_v1 *hdr)
+{
+ const size_t hdr_size = a38x_header_size(hdr);
+ struct a38x_opt_hdr_v1 *ohdr;
+ u32 ohdr_size;
+
+ if (hdr->version != 1)
+ return 0;
+
+ if (!hdr->ext)
+ return 0;
+
+ ohdr = (struct a38x_opt_hdr_v1 *)(hdr + 1);
+ do {
+ if (ohdr->headertype == A38X_OPT_HDR_V1_SECURE_TYPE)
+ return 1;
+
+ ohdr_size = (ohdr->headersz_msb << 16) | le16_to_cpu(ohdr->headersz_lsb);
+
+ if (!*((u8 *)ohdr + ohdr_size - 4))
+ break;
+
+ ohdr = (struct a38x_opt_hdr_v1 *)((u8 *)ohdr + ohdr_size);
+ if ((u8 *)ohdr >= (u8 *)hdr + hdr_size)
+ break;
+ } while (1);
+
+ return 0;
+}
+#endif
#else /* Not ARMADA? */
static int check_image_header(void)
{
}
#endif
+#if defined(CONFIG_ARMADA_3700) || defined(CONFIG_ARMADA_38X)
+static u64 fuse_read_u64(u32 bank)
+{
+ u32 val[2];
+ int ret;
+
+ ret = fuse_read(bank, 0, &val[0]);
+ if (ret < 0)
+ return -1;
+
+ ret = fuse_read(bank, 1, &val[1]);
+ if (ret < 0)
+ return -1;
+
+ return ((u64)val[1] << 32) | val[0];
+}
+#endif
+
+#if defined(CONFIG_ARMADA_3700)
+static inline u8 maj3(u8 val)
+{
+ /* return majority vote of 3 bits */
+ return ((val & 0x7) == 3 || (val & 0x7) > 4) ? 1 : 0;
+}
+#endif
+
static int bubt_check_boot_mode(const struct bubt_dev *dst)
{
#if defined(CONFIG_ARMADA_3700) || defined(CONFIG_ARMADA_32BIT)
int mode;
+#if defined(CONFIG_ARMADA_3700) || defined(CONFIG_ARMADA_38X)
+ int secure_mode;
+#endif
#if defined(CONFIG_ARMADA_3700)
const struct tim_boot_flash_sign *boot_modes = tim_boot_flash_signs;
const struct common_tim_data *hdr =
(struct common_tim_data *)get_load_addr();
u32 id = hdr->boot_flash_sign;
+ int is_secure = hdr->trusted != 0;
+ u64 otp_secure_bits = fuse_read_u64(1);
+ int otp_secure_boot = ((maj3(otp_secure_bits >> 0) << 0) |
+ (maj3(otp_secure_bits >> 4) << 1)) == 2;
+ unsigned int otp_boot_device = (maj3(otp_secure_bits >> 48) << 0) |
+ (maj3(otp_secure_bits >> 52) << 1) |
+ (maj3(otp_secure_bits >> 56) << 2) |
+ (maj3(otp_secure_bits >> 60) << 3);
#elif defined(CONFIG_ARMADA_32BIT)
const struct a38x_boot_mode *boot_modes = a38x_boot_modes;
const struct a38x_main_hdr_v1 *hdr =
(struct a38x_main_hdr_v1 *)get_load_addr();
u32 id = hdr->blockid;
+#if defined(CONFIG_ARMADA_38X)
+ int is_secure = a38x_image_is_secure(hdr);
+ u64 otp_secure_bits = fuse_read_u64(EFUSE_LINE_SECURE_BOOT);
+ int otp_secure_boot = otp_secure_bits & 0x1;
+ unsigned int otp_boot_device = (otp_secure_bits >> 8) & 0x7;
+#endif
#endif
for (mode = 0; boot_modes[mode].name; mode++) {
return -ENOEXEC;
}
- if (strcmp(boot_modes[mode].name, dst->name) == 0)
- return 0;
+ if (strcmp(boot_modes[mode].name, dst->name) != 0) {
+ printf("Error: image meant to be booted from \"%s\", not \"%s\"!\n",
+ boot_modes[mode].name, dst->name);
+ return -ENOEXEC;
+ }
- printf("Error: image meant to be booted from \"%s\", not \"%s\"!\n",
- boot_modes[mode].name, dst->name);
- return -ENOEXEC;
-#else
- return 0;
+#if defined(CONFIG_ARMADA_38X) || defined(CONFIG_ARMADA_3700)
+ if (otp_secure_bits == (u64)-1) {
+ printf("Error: cannot read OTP secure bits\n");
+ return -ENOEXEC;
+ } else {
+ if (otp_secure_boot && !is_secure) {
+ printf("Error: secure boot is enabled in OTP but image does not have secure boot header!\n");
+ return -ENOEXEC;
+ } else if (!otp_secure_boot && is_secure) {
+#if defined(CONFIG_ARMADA_3700)
+ /*
+ * Armada 3700 BootROM rejects trusted image when secure boot is not enabled.
+ * Armada 385 BootROM accepts image with secure boot header also when secure boot is not enabled.
+ */
+ printf("Error: secure boot is disabled in OTP but image has secure boot header!\n");
+ return -ENOEXEC;
#endif
+ } else if (otp_boot_device && otp_boot_device != id) {
+ for (secure_mode = 0; boot_modes[secure_mode].name; secure_mode++) {
+ if (boot_modes[secure_mode].id == otp_boot_device)
+ break;
+ }
+ printf("Error: boot source is set to \"%s\" in OTP but image is for \"%s\"!\n",
+ boot_modes[secure_mode].name ?: "unknown", dst->name);
+ return -ENOEXEC;
+ }
+ }
+#endif
+#endif
+ return 0;
}
static int bubt_verify(const struct bubt_dev *dst)
return 1;
}
-struct bubt_dev *find_bubt_dev(char *dev_name)
+static struct bubt_dev *find_bubt_dev(char *dev_name)
{
int dev;
#define DEFAULT_BUBT_DST "nand"
#elif defined(CONFIG_MVEBU_MMC_BOOT)
#define DEFAULT_BUBT_DST "mmc"
+#elif defined(CONFIG_MVEBU_SATA_BOOT)
+#define DEFAULT_BUBT_DST "sata"
#else
#define DEFAULT_BUBT_DST "error"
#endif
#endif /* DEFAULT_BUBT_DST */
-int do_bubt_cmd(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+static int do_bubt_cmd(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
{
struct bubt_dev *src, *dst;
size_t image_size;
"Burn a u-boot image to flash",
"[file-name] [destination [source]]\n"
"\t-file-name The image file name to burn. Default = " CONFIG_MVEBU_UBOOT_DFLT_NAME "\n"
- "\t-destination Flash to burn to [spi, nand, mmc]. Default = " DEFAULT_BUBT_DST "\n"
- "\t-source The source to load image from [tftp, usb, mmc]. Default = " DEFAULT_BUBT_SRC "\n"
+ "\t-destination Flash to burn to [spi, nand, mmc, sata]. Default = " DEFAULT_BUBT_DST "\n"
+ "\t-source The source to load image from [tftp, usb, mmc, sata]. Default = " DEFAULT_BUBT_SRC "\n"
"Examples:\n"
"\tbubt - Burn flash-image.bin from tftp to active boot device\n"
"\tbubt flash-image-new.bin nand - Burn flash-image-new.bin from tftp to NAND flash\n"