aboutsummaryrefslogtreecommitdiff
path: root/boot
diff options
context:
space:
mode:
Diffstat (limited to 'boot')
-rw-r--r--boot/Kconfig124
-rw-r--r--boot/Makefile7
-rw-r--r--boot/bootm.c33
-rw-r--r--boot/bootretry.c4
-rw-r--r--boot/image-pre-load.c416
5 files changed, 575 insertions, 9 deletions
diff --git a/boot/Kconfig b/boot/Kconfig
index b83a4e8..394b26f 100644
--- a/boot/Kconfig
+++ b/boot/Kconfig
@@ -370,6 +370,31 @@ config SYS_TEXT_BASE
help
The address in memory that U-Boot will be running from, initially.
+config HAVE_SYS_MONITOR_BASE
+ bool
+ depends on ARC || MIPS || M68K || NIOS2 || PPC || XTENSA || X86 \
+ || FLASH_PIC32 || ENV_IS_IN_FLASH || MTD_NOR_FLASH
+ depends on !EFI_APP
+ default y
+
+config SYS_MONITOR_BASE
+ depends on HAVE_SYS_MONITOR_BASE
+ hex "Physical start address of boot monitor code"
+ default SYS_TEXT_BASE
+ help
+ The physical start address of boot monitor code (which is the same as
+ CONFIG_SYS_TEXT_BASE when linking) and the same as CONFIG_SYS_FLASH_BASE
+ when booting from flash.
+
+config SPL_SYS_MONITOR_BASE
+ depends on MPC85xx && SPL && HAVE_SYS_MONITOR_BASE
+ hex "Physical start address of SPL monitor code"
+ default SPL_TEXT_BASE
+
+config TPL_SYS_MONITOR_BASE
+ depends on MPC85xx && TPL && HAVE_SYS_MONITOR_BASE
+ hex "Physical start address of TPL monitor code"
+
config DYNAMIC_SYS_CLK_FREQ
bool "Determine CPU clock frequency at run-time"
help
@@ -423,6 +448,20 @@ config RAMBOOT_PBL
Some SoCs use PBL to load RCW and/or pre-initialization instructions.
For more details refer to doc/README.pblimage
+choice
+ prompt "Freescale PBL load location"
+ depends on RAMBOOT_PBL || ((TARGET_P1010RDB_PA || TARGET_P1010RDB_PB \
+ || TARGET_P1020RDB_PC || TARGET_P1020RDB_PD || TARGET_P2020RDB) \
+ && !CMD_NAND)
+
+config SDCARD
+ bool "Freescale PBL is found on SD card"
+
+config SPIFLASH
+ bool "Freescale PBL is found on SPI flash"
+
+endchoice
+
config SYS_FSL_PBL_PBI
string "PBI(pre-boot instructions) commands for the PBL image"
depends on RAMBOOT_PBL
@@ -991,6 +1030,91 @@ config AUTOBOOT_MENU_SHOW
environmnent variable (if enabled) and before handling the boot delay.
See README.bootmenu for more details.
+config BOOT_RETRY
+ bool "Boot retry feature"
+ help
+ Allow for having the U-Boot command prompt time out and attempt
+ to boot again. If the environment variable "bootretry" is found then
+ its value is used, otherwise the retry timeout is
+ CONFIG_BOOT_RETRY_TIME. CONFIG_BOOT_RETRY_MIN is optional and
+ defaults to CONFIG_BOOT_RETRY_TIME. All times are in seconds.
+
+config BOOT_RETRY_TIME
+ int "Timeout in seconds before attempting to boot again"
+ depends on BOOT_RETRY
+ help
+ Time in seconds before the U-Boot prompt will timeout and boot will
+ be attempted again.
+
+config BOOT_RETRY_MIN
+ int "Minimum timeout in seconds for 'bootretry'"
+ depends on BOOT_RETRY
+ default BOOT_RETRY_TIME
+ help
+ The minimum time in seconds that "bootretry" can be set to.
+
+config RESET_TO_RETRY
+ bool "Reset the board to retry autoboot"
+ depends on BOOT_RETRY
+ help
+ After the countdown timed out, the board will be reset to restart
+ again.
+
+endmenu
+
+menu "Image support"
+
+config IMAGE_PRE_LOAD
+ bool "Image pre-load support"
+ help
+ Enable an image pre-load stage in the SPL.
+ This pre-load stage allows to do some manipulation
+ or check (for example signature check) on an image
+ before launching it.
+
+config SPL_IMAGE_PRE_LOAD
+ bool "Image pre-load support within SPL"
+ depends on SPL && IMAGE_PRE_LOAD
+ help
+ Enable an image pre-load stage in the SPL.
+ This pre-load stage allows to do some manipulation
+ or check (for example signature check) on an image
+ before launching it.
+
+config IMAGE_PRE_LOAD_SIG
+ bool "Image pre-load signature support"
+ depends on IMAGE_PRE_LOAD
+ select FIT_SIGNATURE
+ select RSA
+ select RSA_VERIFY_WITH_PKEY
+ help
+ Enable signature check support in the pre-load stage.
+ For this feature a very simple header is added before
+ the image with few fields:
+ - a magic
+ - the image size
+ - the signature
+ All other information (header size, type of signature,
+ ...) are provided in the node /image/pre-load/sig of
+ u-boot.
+
+config SPL_IMAGE_PRE_LOAD_SIG
+ bool "Image pre-load signature support witin SPL"
+ depends on SPL_IMAGE_PRE_LOAD && IMAGE_PRE_LOAD_SIG
+ select SPL_FIT_SIGNATURE
+ select SPL_RSA
+ select SPL_RSA_VERIFY_WITH_PKEY
+ help
+ Enable signature check support in the pre-load stage in the SPL.
+ For this feature a very simple header is added before
+ the image with few fields:
+ - a magic
+ - the image size
+ - the signature
+ All other information (header size, type of signature,
+ ...) are provided in the node /image/pre-load/sig of
+ u-boot.
+
endmenu
config USE_BOOTARGS
diff --git a/boot/Makefile b/boot/Makefile
index 2938c3f..1b99e6e 100644
--- a/boot/Makefile
+++ b/boot/Makefile
@@ -5,11 +5,7 @@
ifndef CONFIG_SPL_BUILD
-# This option is not just y/n - it can have a numeric value
-ifdef CONFIG_BOOT_RETRY_TIME
-obj-y += bootretry.o
-endif
-
+obj-$(CONFIG_BOOT_RETRY) += bootretry.o
obj-$(CONFIG_CMD_BOOTM) += bootm.o bootm_os.o
obj-$(CONFIG_CMD_BOOTZ) += bootm.o bootm_os.o
obj-$(CONFIG_CMD_BOOTI) += bootm.o bootm_os.o
@@ -26,6 +22,7 @@ obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += image-fdt.o
obj-$(CONFIG_$(SPL_TPL_)FIT_SIGNATURE) += fdt_region.o
obj-$(CONFIG_$(SPL_TPL_)FIT) += image-fit.o
obj-$(CONFIG_$(SPL_)MULTI_DTB_FIT) += boot_fit.o common_fit.o
+obj-$(CONFIG_$(SPL_TPL_)IMAGE_PRE_LOAD) += image-pre-load.o
obj-$(CONFIG_$(SPL_TPL_)IMAGE_SIGN_INFO) += image-sig.o
obj-$(CONFIG_$(SPL_TPL_)FIT_SIGNATURE) += image-fit-sig.o
obj-$(CONFIG_$(SPL_TPL_)FIT_CIPHER) += image-cipher.o
diff --git a/boot/bootm.c b/boot/bootm.c
index 00c00ae..714406a 100644
--- a/boot/bootm.c
+++ b/boot/bootm.c
@@ -87,6 +87,33 @@ static int bootm_start(struct cmd_tbl *cmdtp, int flag, int argc,
return 0;
}
+static ulong bootm_data_addr(int argc, char *const argv[])
+{
+ ulong addr;
+
+ if (argc > 0)
+ addr = simple_strtoul(argv[0], NULL, 16);
+ else
+ addr = image_load_addr;
+
+ return addr;
+}
+
+static int bootm_pre_load(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ ulong data_addr = bootm_data_addr(argc, argv);
+ int ret = 0;
+
+ if (CONFIG_IS_ENABLED(CMD_BOOTM_PRE_LOAD))
+ ret = image_pre_load(data_addr);
+
+ if (ret)
+ ret = CMD_RET_FAILURE;
+
+ return ret;
+}
+
static int bootm_find_os(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
@@ -677,6 +704,9 @@ int do_bootm_states(struct cmd_tbl *cmdtp, int flag, int argc,
if (states & BOOTM_STATE_START)
ret = bootm_start(cmdtp, flag, argc, argv);
+ if (!ret && (states & BOOTM_STATE_PRE_LOAD))
+ ret = bootm_pre_load(cmdtp, flag, argc, argv);
+
if (!ret && (states & BOOTM_STATE_FINDOS))
ret = bootm_find_os(cmdtp, flag, argc, argv);
@@ -866,6 +896,9 @@ static const void *boot_get_kernel(struct cmd_tbl *cmdtp, int flag, int argc,
&fit_uname_config,
&fit_uname_kernel);
+ if (CONFIG_IS_ENABLED(CMD_BOOTM_PRE_LOAD))
+ img_addr += image_load_offset;
+
bootstage_mark(BOOTSTAGE_ID_CHECK_MAGIC);
/* check image type, for FIT images get FIT kernel node */
diff --git a/boot/bootretry.c b/boot/bootretry.c
index dac891f..2bc9c68 100644
--- a/boot/bootretry.c
+++ b/boot/bootretry.c
@@ -12,10 +12,6 @@
#include <time.h>
#include <watchdog.h>
-#ifndef CONFIG_BOOT_RETRY_MIN
-#define CONFIG_BOOT_RETRY_MIN CONFIG_BOOT_RETRY_TIME
-#endif
-
static uint64_t endtime; /* must be set, default is instant timeout */
static int retry_time = -1; /* -1 so can call readline before main_loop */
diff --git a/boot/image-pre-load.c b/boot/image-pre-load.c
new file mode 100644
index 0000000..78d8906
--- /dev/null
+++ b/boot/image-pre-load.c
@@ -0,0 +1,416 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2021 Philippe Reynes <philippe.reynes@softathome.com>
+ */
+
+#include <common.h>
+#include <asm/global_data.h>
+DECLARE_GLOBAL_DATA_PTR;
+#include <image.h>
+#include <mapmem.h>
+
+#include <u-boot/sha256.h>
+
+#define IMAGE_PRE_LOAD_SIG_MAGIC 0x55425348
+#define IMAGE_PRE_LOAD_SIG_OFFSET_MAGIC 0
+#define IMAGE_PRE_LOAD_SIG_OFFSET_IMG_LEN 4
+#define IMAGE_PRE_LOAD_SIG_OFFSET_SIG 8
+
+#define IMAGE_PRE_LOAD_PATH "/image/pre-load/sig"
+#define IMAGE_PRE_LOAD_PROP_ALGO_NAME "algo-name"
+#define IMAGE_PRE_LOAD_PROP_PADDING_NAME "padding-name"
+#define IMAGE_PRE_LOAD_PROP_SIG_SIZE "signature-size"
+#define IMAGE_PRE_LOAD_PROP_PUBLIC_KEY "public-key"
+#define IMAGE_PRE_LOAD_PROP_MANDATORY "mandatory"
+
+#ifndef CONFIG_SYS_BOOTM_LEN
+/* use 8MByte as default max gunzip size */
+#define CONFIG_SYS_BOOTM_LEN 0x800000
+#endif
+
+/*
+ * Information in the device-tree about the signature in the header
+ */
+struct image_sig_info {
+ char *algo_name; /* Name of the algo (eg: sha256,rsa2048) */
+ char *padding_name; /* Name of the padding */
+ u8 *key; /* Public signature key */
+ int key_len; /* Length of the public key */
+ u32 sig_size; /* size of the signature (in the header) */
+ int mandatory; /* Set if the signature is mandatory */
+
+ struct image_sign_info sig_info; /* Signature info */
+};
+
+/*
+ * Header of the signature header
+ */
+struct sig_header_s {
+ u32 magic;
+ u32 version;
+ u32 header_size;
+ u32 image_size;
+ u32 offset_img_sig;
+ u32 flags;
+ u32 reserved0;
+ u32 reserved1;
+ u8 sha256_img_sig[SHA256_SUM_LEN];
+};
+
+#define SIG_HEADER_LEN (sizeof(struct sig_header_s))
+
+/*
+ * Offset of the image
+ *
+ * This value is used to skip the header before really launching the image
+ */
+ulong image_load_offset;
+
+/*
+ * This function gathers information about the signature check
+ * that could be done before launching the image.
+ *
+ * return:
+ * < 0 => an error has occurred
+ * 0 => OK
+ * 1 => no setup
+ */
+static int image_pre_load_sig_setup(struct image_sig_info *info)
+{
+ const void *algo_name, *padding_name, *key, *mandatory;
+ const u32 *sig_size;
+ int key_len;
+ int node, ret = 0;
+
+ if (!info) {
+ log_err("ERROR: info is NULL for image pre-load sig check\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ memset(info, 0, sizeof(*info));
+
+ node = fdt_path_offset(gd_fdt_blob(), IMAGE_PRE_LOAD_PATH);
+ if (node < 0) {
+ log_info("INFO: no info for image pre-load sig check\n");
+ ret = 1;
+ goto out;
+ }
+
+ algo_name = fdt_getprop(gd_fdt_blob(), node,
+ IMAGE_PRE_LOAD_PROP_ALGO_NAME, NULL);
+ if (!algo_name) {
+ printf("ERROR: no algo_name for image pre-load sig check\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ padding_name = fdt_getprop(gd_fdt_blob(), node,
+ IMAGE_PRE_LOAD_PROP_PADDING_NAME, NULL);
+ if (!padding_name) {
+ log_info("INFO: no padding_name provided, so using pkcs-1.5\n");
+ padding_name = "pkcs-1.5";
+ }
+
+ sig_size = fdt_getprop(gd_fdt_blob(), node,
+ IMAGE_PRE_LOAD_PROP_SIG_SIZE, NULL);
+ if (!sig_size) {
+ log_err("ERROR: no signature-size for image pre-load sig check\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ key = fdt_getprop(gd_fdt_blob(), node,
+ IMAGE_PRE_LOAD_PROP_PUBLIC_KEY, &key_len);
+ if (!key) {
+ log_err("ERROR: no key for image pre-load sig check\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ info->algo_name = (char *)algo_name;
+ info->padding_name = (char *)padding_name;
+ info->key = (uint8_t *)key;
+ info->key_len = key_len;
+ info->sig_size = fdt32_to_cpu(*sig_size);
+
+ mandatory = fdt_getprop(gd_fdt_blob(), node,
+ IMAGE_PRE_LOAD_PROP_MANDATORY, NULL);
+ if (mandatory && !strcmp((char *)mandatory, "yes"))
+ info->mandatory = 1;
+
+ /* Compute signature information */
+ info->sig_info.name = info->algo_name;
+ info->sig_info.padding = image_get_padding_algo(info->padding_name);
+ info->sig_info.checksum = image_get_checksum_algo(info->sig_info.name);
+ info->sig_info.crypto = image_get_crypto_algo(info->sig_info.name);
+ info->sig_info.key = info->key;
+ info->sig_info.keylen = info->key_len;
+
+ out:
+ return ret;
+}
+
+static int image_pre_load_sig_get_magic(ulong addr, u32 *magic)
+{
+ struct sig_header_s *sig_header;
+ int ret = 0;
+
+ sig_header = (struct sig_header_s *)map_sysmem(addr, SIG_HEADER_LEN);
+ if (!sig_header) {
+ log_err("ERROR: can't map first header\n");
+ ret = -EFAULT;
+ goto out;
+ }
+
+ *magic = fdt32_to_cpu(sig_header->magic);
+
+ unmap_sysmem(sig_header);
+
+ out:
+ return ret;
+}
+
+static int image_pre_load_sig_get_header_size(ulong addr, u32 *header_size)
+{
+ struct sig_header_s *sig_header;
+ int ret = 0;
+
+ sig_header = (struct sig_header_s *)map_sysmem(addr, SIG_HEADER_LEN);
+ if (!sig_header) {
+ log_err("ERROR: can't map first header\n");
+ ret = -EFAULT;
+ goto out;
+ }
+
+ *header_size = fdt32_to_cpu(sig_header->header_size);
+
+ unmap_sysmem(sig_header);
+
+ out:
+ return ret;
+}
+
+/*
+ * return:
+ * < 0 => no magic and magic mandatory (or error when reading magic)
+ * 0 => magic found
+ * 1 => magic NOT found
+ */
+static int image_pre_load_sig_check_magic(struct image_sig_info *info, ulong addr)
+{
+ u32 magic;
+ int ret = 1;
+
+ ret = image_pre_load_sig_get_magic(addr, &magic);
+ if (ret < 0)
+ goto out;
+
+ if (magic != IMAGE_PRE_LOAD_SIG_MAGIC) {
+ if (info->mandatory) {
+ log_err("ERROR: signature is mandatory\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ ret = 1;
+ goto out;
+ }
+
+ ret = 0; /* magic found */
+
+ out:
+ return ret;
+}
+
+static int image_pre_load_sig_check_header_sig(struct image_sig_info *info, ulong addr)
+{
+ void *header;
+ struct image_region reg;
+ u32 sig_len;
+ u8 *sig;
+ int ret = 0;
+
+ /* Only map header of the header and its signature */
+ header = (void *)map_sysmem(addr, SIG_HEADER_LEN + info->sig_size);
+ if (!header) {
+ log_err("ERROR: can't map header\n");
+ ret = -EFAULT;
+ goto out;
+ }
+
+ reg.data = header;
+ reg.size = SIG_HEADER_LEN;
+
+ sig = (uint8_t *)header + SIG_HEADER_LEN;
+ sig_len = info->sig_size;
+
+ ret = info->sig_info.crypto->verify(&info->sig_info, &reg, 1, sig, sig_len);
+ if (ret) {
+ log_err("ERROR: header signature check has failed (err=%d)\n", ret);
+ ret = -EINVAL;
+ goto out_unmap;
+ }
+
+ out_unmap:
+ unmap_sysmem(header);
+
+ out:
+ return ret;
+}
+
+static int image_pre_load_sig_check_img_sig_sha256(struct image_sig_info *info, ulong addr)
+{
+ struct sig_header_s *sig_header;
+ u32 header_size, offset_img_sig;
+ void *header;
+ u8 sha256_img_sig[SHA256_SUM_LEN];
+ int ret = 0;
+
+ sig_header = (struct sig_header_s *)map_sysmem(addr, SIG_HEADER_LEN);
+ if (!sig_header) {
+ log_err("ERROR: can't map first header\n");
+ ret = -EFAULT;
+ goto out;
+ }
+
+ header_size = fdt32_to_cpu(sig_header->header_size);
+ offset_img_sig = fdt32_to_cpu(sig_header->offset_img_sig);
+
+ header = (void *)map_sysmem(addr, header_size);
+ if (!header) {
+ log_err("ERROR: can't map header\n");
+ ret = -EFAULT;
+ goto out_sig_header;
+ }
+
+ sha256_csum_wd(header + offset_img_sig, info->sig_size,
+ sha256_img_sig, CHUNKSZ_SHA256);
+
+ ret = memcmp(sig_header->sha256_img_sig, sha256_img_sig, SHA256_SUM_LEN);
+ if (ret) {
+ log_err("ERROR: sha256 of image signature is invalid\n");
+ ret = -EFAULT;
+ goto out_header;
+ }
+
+ out_header:
+ unmap_sysmem(header);
+ out_sig_header:
+ unmap_sysmem(sig_header);
+ out:
+ return ret;
+}
+
+static int image_pre_load_sig_check_img_sig(struct image_sig_info *info, ulong addr)
+{
+ struct sig_header_s *sig_header;
+ u32 header_size, image_size, offset_img_sig;
+ void *image;
+ struct image_region reg;
+ u32 sig_len;
+ u8 *sig;
+ int ret = 0;
+
+ sig_header = (struct sig_header_s *)map_sysmem(addr, SIG_HEADER_LEN);
+ if (!sig_header) {
+ log_err("ERROR: can't map first header\n");
+ ret = -EFAULT;
+ goto out;
+ }
+
+ header_size = fdt32_to_cpu(sig_header->header_size);
+ image_size = fdt32_to_cpu(sig_header->image_size);
+ offset_img_sig = fdt32_to_cpu(sig_header->offset_img_sig);
+
+ unmap_sysmem(sig_header);
+
+ image = (void *)map_sysmem(addr, header_size + image_size);
+ if (!image) {
+ log_err("ERROR: can't map full image\n");
+ ret = -EFAULT;
+ goto out;
+ }
+
+ reg.data = image + header_size;
+ reg.size = image_size;
+
+ sig = (uint8_t *)image + offset_img_sig;
+ sig_len = info->sig_size;
+
+ ret = info->sig_info.crypto->verify(&info->sig_info, &reg, 1, sig, sig_len);
+ if (ret) {
+ log_err("ERROR: signature check has failed (err=%d)\n", ret);
+ ret = -EINVAL;
+ goto out_unmap_image;
+ }
+
+ log_info("INFO: signature check has succeed\n");
+
+ out_unmap_image:
+ unmap_sysmem(image);
+
+ out:
+ return ret;
+}
+
+int image_pre_load_sig(ulong addr)
+{
+ struct image_sig_info info;
+ int ret;
+
+ ret = image_pre_load_sig_setup(&info);
+ if (ret < 0)
+ goto out;
+ if (ret > 0) {
+ ret = 0;
+ goto out;
+ }
+
+ ret = image_pre_load_sig_check_magic(&info, addr);
+ if (ret < 0)
+ goto out;
+ if (ret > 0) {
+ ret = 0;
+ goto out;
+ }
+
+ /* Check the signature of the signature header */
+ ret = image_pre_load_sig_check_header_sig(&info, addr);
+ if (ret < 0)
+ goto out;
+
+ /* Check sha256 of the image signature */
+ ret = image_pre_load_sig_check_img_sig_sha256(&info, addr);
+ if (ret < 0)
+ goto out;
+
+ /* Check the image signature */
+ ret = image_pre_load_sig_check_img_sig(&info, addr);
+ if (!ret) {
+ u32 header_size;
+
+ ret = image_pre_load_sig_get_header_size(addr, &header_size);
+ if (ret) {
+ log_err("%s: can't get header size\n", __func__);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ image_load_offset += header_size;
+ }
+
+ out:
+ return ret;
+}
+
+int image_pre_load(ulong addr)
+{
+ int ret = 0;
+
+ image_load_offset = 0;
+
+ if (CONFIG_IS_ENABLED(IMAGE_PRE_LOAD_SIG))
+ ret = image_pre_load_sig(addr);
+
+ return ret;
+}