diff options
| -rw-r--r-- | board/sandbox/capsule_pub_esl_good.esl | bin | 831 -> 0 bytes | |||
| -rw-r--r-- | board/sunxi/board.c | 2 | ||||
| -rw-r--r-- | configs/sandbox_defconfig | 2 | ||||
| -rw-r--r-- | configs/sandbox_flattree_defconfig | 2 | ||||
| -rw-r--r-- | doc/develop/uefi/uefi.rst | 8 | ||||
| -rw-r--r-- | doc/sphinx/requirements.txt | 4 | ||||
| -rw-r--r-- | doc/usage/cmd/bootelf.rst | 61 | ||||
| -rw-r--r-- | doc/usage/cmd/itest.rst | 2 | ||||
| -rw-r--r-- | doc/usage/index.rst | 1 | ||||
| -rw-r--r-- | drivers/rtc/goldfish_rtc.c | 4 | ||||
| -rw-r--r-- | env/Kconfig | 2 | ||||
| -rw-r--r-- | lib/efi_loader/Kconfig | 12 | ||||
| -rw-r--r-- | lib/efi_loader/dtbdump.c | 261 | ||||
| -rw-r--r-- | scripts/Makefile.lib | 24 | ||||
| -rw-r--r-- | test/py/tests/test_efi_capsule/test_capsule_firmware_raw.py | 21 | 
15 files changed, 375 insertions, 31 deletions
| diff --git a/board/sandbox/capsule_pub_esl_good.esl b/board/sandbox/capsule_pub_esl_good.eslBinary files differ deleted file mode 100644 index f8cc272309b..00000000000 --- a/board/sandbox/capsule_pub_esl_good.esl +++ /dev/null diff --git a/board/sunxi/board.c b/board/sunxi/board.c index ed86f1df5dc..b9d47f5e870 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -515,7 +515,7 @@ int board_mmc_init(struct bd_info *bis)  	return 0;  } -#if CONFIG_MMC_SUNXI_SLOT_EXTRA != -1 +#ifdef CONFIG_SYS_MMC_ENV_DEV  int mmc_get_env_dev(void)  {  	switch (sunxi_get_boot_device()) { diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index da8c1976d7b..e2db66d4a25 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -353,7 +353,7 @@ CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y  CONFIG_EFI_CAPSULE_ON_DISK=y  CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y  CONFIG_EFI_CAPSULE_AUTHENTICATE=y -CONFIG_EFI_CAPSULE_ESL_FILE="board/sandbox/capsule_pub_esl_good.esl" +CONFIG_EFI_CAPSULE_CRT_FILE="board/sandbox/capsule_pub_key_good.crt"  CONFIG_EFI_SECURE_BOOT=y  CONFIG_TEST_FDTDEC=y  CONFIG_UNIT_TEST=y diff --git a/configs/sandbox_flattree_defconfig b/configs/sandbox_flattree_defconfig index 6bf8874e722..049a606613e 100644 --- a/configs/sandbox_flattree_defconfig +++ b/configs/sandbox_flattree_defconfig @@ -227,7 +227,7 @@ CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y  CONFIG_EFI_CAPSULE_ON_DISK=y  CONFIG_EFI_CAPSULE_FIRMWARE_FIT=y  CONFIG_EFI_CAPSULE_AUTHENTICATE=y -CONFIG_EFI_CAPSULE_ESL_FILE="board/sandbox/capsule_pub_esl_good.esl" +CONFIG_EFI_CAPSULE_CRT_FILE="board/sandbox/capsule_pub_key_good.crt"  CONFIG_UNIT_TEST=y  CONFIG_UT_TIME=y  CONFIG_UT_DM=y diff --git a/doc/develop/uefi/uefi.rst b/doc/develop/uefi/uefi.rst index 88596f312c0..d450b12bf80 100644 --- a/doc/develop/uefi/uefi.rst +++ b/doc/develop/uefi/uefi.rst @@ -580,10 +580,10 @@ and used by the steps highlighted below.      }  You can perform step-4 through the Kconfig symbol -CONFIG_EFI_CAPSULE_ESL_FILE. This symbol points to the esl file -generated in step-2. Once the symbol has been populated with the path -to the esl file, it will automatically get embedded into the -platform's dtb as part of U-Boot build. +CONFIG_EFI_CAPSULE_CRT_FILE. This symbol points to the signing key +generated in step-2. As part of U-Boot build, the ESL certificate file will +be generated from the signing key and automatically get embedded into the +platform's dtb.  Anti-rollback Protection  ************************ diff --git a/doc/sphinx/requirements.txt b/doc/sphinx/requirements.txt index 306b05a995e..40dde599916 100644 --- a/doc/sphinx/requirements.txt +++ b/doc/sphinx/requirements.txt @@ -1,6 +1,6 @@  alabaster==0.7.16  Babel==2.15.0 -certifi==2024.6.2 +certifi==2024.7.4  charset-normalizer==3.3.2  docutils==0.20.1  idna==3.7 @@ -22,4 +22,4 @@ sphinxcontrib-jquery==4.1  sphinxcontrib-jsmath==1.0.1  sphinxcontrib-qthelp==1.0.7  sphinxcontrib-serializinghtml==1.1.10 -urllib3==2.2.1 +urllib3==2.2.2 diff --git a/doc/usage/cmd/bootelf.rst b/doc/usage/cmd/bootelf.rst new file mode 100644 index 00000000000..705524c594a --- /dev/null +++ b/doc/usage/cmd/bootelf.rst @@ -0,0 +1,61 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later +.. Copyright 2024, Maxim Moskalets <maximmosk4@gmail.com> + +.. index:: +   single: bootelf (command) + +bootelf command +=============== + +Synopsis +-------- + +:: + +    bootelf [-p|-s] [-d <fdt_addr>] [<image_addr> [<arg>]...] + +Description +----------- + +The *bootelf* command is used to launch a ELF binary at *image_addr*. If +*image_addr* is not specified, the bootelf command will try to find image in +*image_load_addr* variable (*CONFIG\_SYS\_LOAD\_ADDR* by default). + +Args after *image_addr* will be passed to application in common *argc*, *argv* +format. + +A command sequence to run a ELF image using FDT might look like + +:: + +    load mmc 0:1 ${loadaddr} /kernel.elf +    load mmc 0:1 ${fdt_addr_r} /soc-board.dtb +    bootelf -d ${fdt_addr_r} ${loadaddr} ${loadaddr} + +image_addr +    Address of the ELF binary. + +fdt_addr +    Address of the device-tree. This argument in only needed if bootable +    application uses FDT that requires additional setup (like /memory node). + +arg +    Any text arguments for bootable application. This is usually the address +    of the device-tree. + +Flags: + +-p +    Load ELF image via program headers. + +-s +    Load ELF image via section headers. + +-d +    Setup FDT by address. + +Configuration +------------- + +The bootelf command is only available if CONFIG_CMD_ELF=y. FDT setup by flag -d +need CONFIG_CMD_ELF_FDT_SETUP=y. diff --git a/doc/usage/cmd/itest.rst b/doc/usage/cmd/itest.rst index 9c307fb4bf4..adcad05b2d4 100644 --- a/doc/usage/cmd/itest.rst +++ b/doc/usage/cmd/itest.rst @@ -58,7 +58,7 @@ op      ======== ======================  Examples -======== +--------  The itest command sets the result variable $? to true (0) or false (1): diff --git a/doc/usage/index.rst b/doc/usage/index.rst index 2f211f748ab..49b354e6ffd 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -33,6 +33,7 @@ Shell commands     cmd/bootd     cmd/bootdev     cmd/bootefi +   cmd/bootelf     cmd/bootflow     cmd/booti     cmd/bootm diff --git a/drivers/rtc/goldfish_rtc.c b/drivers/rtc/goldfish_rtc.c index 3231eb0daf8..e63a2766c76 100644 --- a/drivers/rtc/goldfish_rtc.c +++ b/drivers/rtc/goldfish_rtc.c @@ -2,7 +2,9 @@  /*   * Copyright 2023, Heinrich Schuchardt <heinrich.schuchardt@canonical.com>   * - * This driver emulates a real time clock based on timer ticks. + * This driver supports the Google Goldfish virtual platform RTC device. + * The device is provided by the RISC-V virt machine in QEMU. It exposes + * a 64-bit nanosecond timer via two memory-mapped 32-bit registers.   */  #include <div64.h> diff --git a/env/Kconfig b/env/Kconfig index 451bab45ea7..031cf58186a 100644 --- a/env/Kconfig +++ b/env/Kconfig @@ -655,7 +655,7 @@ config SYS_RELOC_GD_ENV_ADDR  config SYS_MMC_ENV_DEV  	int "mmc device number" -	depends on ENV_IS_IN_MMC || ENV_IS_IN_FAT || \ +	depends on ENV_IS_IN_MMC || ENV_IS_IN_FAT || ENV_IS_IN_EXT4 || \  		CMD_MVEBU_BUBT || FMAN_ENET || QE || PHY_CORTINA  	default 0  	help diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index ee71f417147..2fb24d7af9a 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -298,13 +298,15 @@ config EFI_CAPSULE_MAX  	  Select the max capsule index value used for capsule report  	  variables. This value is used to create CapsuleMax variable. -config EFI_CAPSULE_ESL_FILE -	string "Path to the EFI Signature List File" +config EFI_CAPSULE_CRT_FILE +	string "Path to the EFI capsule public key certificate"  	depends on EFI_CAPSULE_AUTHENTICATE  	help -	  Provides the path to the EFI Signature List file which will -	  be embedded in the platform's device tree and used for -	  capsule authentication at the time of capsule update. +	  Provides the path to the EFI capsule public key certificate that +	  corresponds to the capsule signing key. This certificate will be used +	  to generate the EFI capsule ESL (signature list file) that gets +	  embedded in the platform's device tree and used for capsule +	  authentication at the time of capsule update.  config EFI_DEVICE_PATH_TO_TEXT  	bool "Device path to text protocol" diff --git a/lib/efi_loader/dtbdump.c b/lib/efi_loader/dtbdump.c index 5f39cf22da7..9f1d8fb82cb 100644 --- a/lib/efi_loader/dtbdump.c +++ b/lib/efi_loader/dtbdump.c @@ -41,6 +41,53 @@ static void print(u16 *string)  }  /** + * print_char() - print character + * + * 0x00 is replaced by '", "'. + * + * @c:	- character + */ +static void print_char(unsigned char c) +{ +	u16 out[2] = u"?"; + +	if (!c) { +		print(u"\", \""); +		return; +	} + +	if (c > 0x1f && c < 0x80) +		out[0] = c; + +	print(out); +} + +/** + * print_hex_digit() - print hexadecimal digit + * + * @digit:	digit to print + */ +static void print_hex_digit(unsigned char digit) +{ +	if (digit < 10) +		digit += '0'; +	else +		digit += 'a' - 10; +	print_char(digit); +} + +/** + * printx() - print hexadecimal byte + * + * @val:	value to print + */ +static void printx(unsigned char val) +{ +	print_hex_digit(val >> 4); +	print_hex_digit(val & 0xf); +} + +/**   * error() - print error string   *   * @string:	error text @@ -227,6 +274,7 @@ bool starts_with(u16 *string, u16 *keyword)   */  void do_help(void)  { +	error(u"dump       - print device-tree\r\n");  	error(u"load <dtb> - load device-tree from file\r\n");  	error(u"save <dtb> - save device-tree to file\r\n");  	error(u"exit       - exit the shell\r\n"); @@ -490,6 +538,217 @@ efi_status_t do_save(u16 *filename)  }  /** + * indent() - print a number of tabstops + * + * @level:	indentation level + */ +static void indent(u32 level) +{ +	for (; level; --level) +		print(u"\t"); +} + +/** + * is_string_value() - determine if property is a string + * + * If a property is a string, an x-string, or a u32 cannot be deducted + * from the device-tree. Therefore a heuristic is used. + * + * @str:	pointer to device-tree property + * @len:	length of the device-tree property + * Return:	1 for string, 0 otherwise + */ +static int is_string_value(const unsigned char *str, u32 len) +{ +	int nonzero_flag = 0; + +	/* Zero length or not ending with 0x00 */ +	if (!len || str[len - 1]) +		return 0; + +	for (u32 i = 0; i < len; ++i) { +		if (!str[i]) { +			/* Zero length string or two consecutive 0x00 */ +			if (!nonzero_flag) +				return 0; + +			nonzero_flag = 0; + +			continue; +		} +		/* Non-printable */ +		if (str[i] < 0x20 || str[i] >= 0x80) +			return 0; + +		nonzero_flag = 1; +	} + +	return 1; +} + +/** + * print_property() - print device-tree property + * + * If a property is a string, an x-string, or a u32 cannot be deducted + * from the device-tree. Therefore a heuristic is used. + * + * @str:	property value + * @len:	length of property value + */ +static void print_property(const unsigned char *val, u32 len) +{ +	if (is_string_value(val, len)) { +		/* string */ +		print(u"\""); +		for (int i = 0; i < len - 1; ++i) +			print_char(val[i]); +		print(u"\""); +	} else if (len & 0x3) { +		/* byte string */ +		print(u"["); +		for (int i = 0; i < len; ++i) { +			if (i) +				print(u" "); +			printx(val[i]); +		} +		print(u"]\""); +	} else { +		/* cell list */ +		print(u"<"); +		for (u32 i = 0; i < len; ++i) { +			if ((i & 0x3) == 0) { +				if (i > 0) +					print(u" "); +				print(u"0x"); +			} +			printx(val[i]); +		} +		print(u">"); +	} +} + +/** + * print_mem_res_block() - print memory reservation block + * + * @rsvblk:	memory reservation block + */ +static void print_mem_res_block(const struct fdt_reserve_entry *rsvblk) +{ +	for (; rsvblk->address || rsvblk->size; ++rsvblk) { +		const unsigned char *val; + +		print(u"/memreserve/ 0x"); +		val = (const unsigned char *)&rsvblk->address; +		for (u32 i = 0; i < sizeof(u64); ++i) +			printx(val[i]); +		print(u" 0x"); +		val = (const unsigned char *)&rsvblk->size; +		for (u32 i = 0; i < sizeof(u64); ++i) +			printx(val[i]); +		print(u";\r\n"); +	} +} + +/** + * do_dump() - print device-tree + */ +static efi_status_t do_dump(void) +{ +	const unsigned char *fdt; +	struct fdt_header *header; +	const u32 *end; +	const u32 *pos; +	const char *strings; +	u32 level = 0; + +	fdt = get_dtb(systable); +	if (!fdt) { +		error(u"DTB not found\r\n"); +		return EFI_NOT_FOUND; +	} + +	header = (struct fdt_header *)fdt; +	if (f2h(header->magic) != FDT_MAGIC) { +		error(u"Wrong device tree magic\r\n"); +		error(u"Not a device-tree\r\n"); +		return EFI_LOAD_ERROR; +	} + +	pos = (u32 *)(fdt + f2h(header->off_dt_struct)); +	end = &pos[f2h(header->totalsize) >> 2]; +	strings = fdt + f2h(header->off_dt_strings); + +	print(u"/dts-v1/;\r\n"); + +	print_mem_res_block((const struct fdt_reserve_entry *) +			    (fdt + f2h(header->off_mem_rsvmap))); + +	print(u"/"); +	for (; pos < end;) { +		switch (f2h(pos[0])) { +		case FDT_BEGIN_NODE: { +			const char *c = (char *)&pos[1]; +			size_t i; + +			indent(level); +			for (i = 0; c[i]; ++i) +				print_char(c[i]); +			print(u" {\n\r"); + +			++level; +			pos = &pos[2 + (i >> 2)]; +			break; +		} +		case FDT_PROP: { +			struct fdt_property *prop = (struct fdt_property *)pos; +			const unsigned char *label = &strings[f2h(prop->nameoff)]; +			u32 len = f2h(prop->len); +			const unsigned char *str = (unsigned char *)&pos[3]; + +			indent(level); +			for (int i = 0; label[i]; ++i) +				print_char(label[i]); + +			if (len) { +				print(u" = "); +				print_property(str, len); +			} +			print(u";\r\n"); + +			pos = &pos[3 + ((f2h(prop->len) + 3) >> 2)]; +			break; +		} +		case FDT_NOP: +			++pos; +			break; +		case FDT_END_NODE: +			if (!level) { +				error(u"Extraneous end node\r\n"); +				return EFI_LOAD_ERROR; +			} + +			--level; +			indent(level); +			print(u"};\n\r"); +			++pos; +			break; +		case FDT_END: +			if (level) { +				error(u"Missing end node\r\n"); +				return EFI_LOAD_ERROR; +			} +			return EFI_SUCCESS; +		default: +			error(u"Invalid device tree token\r\n"); +			return EFI_LOAD_ERROR; +		} +	} +	error(u"Overrun\r\n"); + +	return EFI_LOAD_ERROR; +} + +/**   * efi_main() - entry point of the EFI application.   *   * @handle:	handle of the loaded image @@ -524,6 +783,8 @@ efi_status_t EFIAPI efi_main(efi_handle_t image_handle,  		pos = skip_whitespace(command);  		if (starts_with(pos, u"exit"))  			break; +		else if (starts_with(pos, u"dump")) +			do_dump();  		else if (starts_with(pos, u"load "))  			do_load(pos + 5);  		else if (starts_with(pos, u"save ")) diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 3e68d5aa803..f66a65d1c1f 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -342,21 +342,27 @@ cmd_dtc = mkdir -p $(dir ${dtc-tmp}) ; \  		; \  	sed "s:$(pre-tmp):$(<):" $(depfile).pre.tmp $(depfile).dtc.tmp > $(depfile) +capsule_esl_input_file=$(srctree)/lib/efi_loader/capsule_esl.dtsi.in +capsule_crt_file=$(subst $(quote),,$(CONFIG_EFI_CAPSULE_CRT_FILE)) +capsule_esl_dtsi=.capsule_esl.dtsi +  quiet_cmd_capsule_esl_gen = CAPSULE_ESL_GEN $@ -cmd_capsule_esl_gen = \ -	$(shell sed "s:ESL_BIN_FILE:$(capsule_esl_path):" $(capsule_esl_input_file) > $@) +cmd_capsule_esl_gen = cert-to-efi-sig-list $< $@ -$(obj)/.capsule_esl.dtsi: FORCE -ifeq ($(CONFIG_EFI_CAPSULE_ESL_FILE),"") -	$(error "CONFIG_EFI_CAPSULE_ESL_FILE is empty, EFI capsule authentication \ +$(obj)/capsule_esl_file: $(capsule_crt_file) FORCE +ifeq ($(CONFIG_EFI_CAPSULE_CRT_FILE),"") +	$(error "CONFIG_EFI_CAPSULE_CRT_FILE is empty, EFI capsule authentication \  	public key must be specified when CONFIG_EFI_CAPSULE_AUTHENTICATE is enabled")  else -	$(call cmd_capsule_esl_gen) +	$(call cmd,capsule_esl_gen)  endif -capsule_esl_input_file=$(srctree)/lib/efi_loader/capsule_esl.dtsi.in -capsule_esl_dtsi = .capsule_esl.dtsi -capsule_esl_path=$(abspath $(srctree)/$(subst $(quote),,$(CONFIG_EFI_CAPSULE_ESL_FILE))) +quiet_cmd_capsule_dtsi_gen = CAPSULE_DTSI_GEN $@ +cmd_capsule_dtsi_gen = \ +	$(shell sed "s:ESL_BIN_FILE:$(abspath $<):" $(capsule_esl_input_file) > $@) + +$(obj)/$(capsule_esl_dtsi): $(obj)/capsule_esl_file FORCE +	$(call cmd,capsule_dtsi_gen)  dtsi_include_list_deps := $(addprefix $(u_boot_dtsi_loc),$(subst $(quote),,$(dtsi_include_list))) diff --git a/test/py/tests/test_efi_capsule/test_capsule_firmware_raw.py b/test/py/tests/test_efi_capsule/test_capsule_firmware_raw.py index a5b5c8a3853..f3a2dff5c2c 100644 --- a/test/py/tests/test_efi_capsule/test_capsule_firmware_raw.py +++ b/test/py/tests/test_efi_capsule/test_capsule_firmware_raw.py @@ -76,7 +76,7 @@ class TestEfiCapsuleFirmwareRaw:              self, u_boot_config, u_boot_console, efi_capsule_data):          """ Test Case 2          Update U-Boot and U-Boot environment on SPI Flash but with OsIndications unset -        No update should happen +        No update should happen unless CONFIG_EFI_IGNORE_OSINDICATIONS is set          0x100000-0x150000: U-Boot binary (but dummy)          0x150000-0x200000: U-Boot environment (but dummy)          """ @@ -91,16 +91,27 @@ class TestEfiCapsuleFirmwareRaw:          # reboot          u_boot_console.restart_uboot() +        ignore_os_indications = u_boot_config.buildconfig.get( +            'config_efi_ignore_osindications') +        need_reboot = True if ignore_os_indications else False + +        capsule_auth = u_boot_config.buildconfig.get( +            'config_efi_capsule_authenticate') +          capsule_early = u_boot_config.buildconfig.get(              'config_efi_capsule_on_disk_early')          with u_boot_console.log.section('Test Case 2-b, after reboot'):              if not capsule_early: -                exec_manual_update(u_boot_console, disk_img, capsule_files, False) +                exec_manual_update(u_boot_console, disk_img, capsule_files, need_reboot) -            check_file_exist(u_boot_console, disk_img, capsule_files) +            if not ignore_os_indications: +                check_file_exist(u_boot_console, disk_img, capsule_files) -            verify_content(u_boot_console, '100000', 'u-boot:Old') -            verify_content(u_boot_console, '150000', 'u-boot-env:Old') +            expected = 'u-boot:New' if (ignore_os_indications and not capsule_auth) else 'u-boot:Old' +            verify_content(u_boot_console, '100000', expected) + +            expected = 'u-boot-env:New' if (ignore_os_indications and not capsule_auth) else 'u-boot-env:Old' +            verify_content(u_boot_console, '150000', expected)      def test_efi_capsule_fw3(              self, u_boot_config, u_boot_console, efi_capsule_data): | 
