diff options
author | Tom Rini <trini@konsulko.com> | 2022-12-04 10:01:48 -0500 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2022-12-04 10:01:48 -0500 |
commit | d2c5607edde2544e059fa871927877213f6bd532 (patch) | |
tree | e57d7db3425ccc950a1b0d5f3d4332eb7be84d54 | |
parent | a32f6341ccf2ea69f64fe87b9d07fd87325a2056 (diff) | |
parent | 30124c2bb96decd737963c043b26407791859faf (diff) | |
download | u-boot-WIP/04Dec2022.zip u-boot-WIP/04Dec2022.tar.gz u-boot-WIP/04Dec2022.tar.bz2 |
Merge tag 'efi-2023-01-rc3' of https://source.denx.de/u-boot/custodians/u-boot-efiWIP/04Dec2022
Pull request for efi-2023-01-rc3
Documentation:
* describe DM firmware needed for j721e_evm
* describe management of UEFI security data base with eficonfig
UEFI:
* code clean-up for eficonfig command
* fix handling of DHCP aknowledge
* correct EFI memory type used for U-Boot code
* unit test for FatToStr() truncation
* add an EFI binary to print boot hart ID
Other:
* improve parameter checks in console functions
* fix variable initialization in blk_get_device_part_str
-rw-r--r-- | cmd/eficonfig.c | 146 | ||||
-rw-r--r-- | cmd/efidebug.c | 25 | ||||
-rw-r--r-- | common/console.c | 10 | ||||
-rw-r--r-- | disk/part.c | 23 | ||||
-rw-r--r-- | doc/board/microchip/mpfs_icicle.rst | 4 | ||||
-rw-r--r-- | doc/board/ti/j721e_evm.rst | 30 | ||||
-rw-r--r-- | doc/usage/cmd/eficonfig.rst | 90 | ||||
-rw-r--r-- | include/efi_loader.h | 1 | ||||
-rw-r--r-- | lib/efi_loader/Makefile | 6 | ||||
-rw-r--r-- | lib/efi_loader/boothart.c | 335 | ||||
-rw-r--r-- | lib/efi_loader/efi_helper.c | 33 | ||||
-rw-r--r-- | lib/efi_loader/efi_memory.c | 4 | ||||
-rw-r--r-- | lib/efi_loader/efi_net.c | 13 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_unicode_collation.c | 2 | ||||
-rw-r--r-- | net/bootp.c | 2 |
15 files changed, 600 insertions, 124 deletions
diff --git a/cmd/eficonfig.c b/cmd/eficonfig.c index 97d3559..394ae67 100644 --- a/cmd/eficonfig.c +++ b/cmd/eficonfig.c @@ -452,8 +452,7 @@ struct efi_device_path *eficonfig_create_device_path(struct efi_device_path *dp_ struct efi_device_path *dp; struct efi_device_path_file_path *fp; - fp_size = sizeof(struct efi_device_path) + - ((u16_strlen(current_path) + 1) * sizeof(u16)); + fp_size = sizeof(struct efi_device_path) + u16_strsize(current_path); buf = calloc(1, fp_size + sizeof(END)); if (!buf) return NULL; @@ -488,7 +487,7 @@ static efi_status_t eficonfig_file_selected(void *data) if (!info) return EFI_INVALID_PARAMETER; - if (!strcmp(info->file_name, "..")) { + if (!strcmp(info->file_name, "..\\")) { struct eficonfig_filepath_info *iter; struct list_head *pos, *n; int is_last; @@ -1684,7 +1683,8 @@ static efi_status_t eficonfig_show_boot_selection(unsigned int *selected) u32 i; u16 *bootorder; efi_status_t ret; - efi_uintn_t num, size; + u16 *var_name16 = NULL, *p; + efi_uintn_t num, size, buf_size; struct efimenu *efi_menu; struct list_head *pos, *n; struct eficonfig_entry *entry; @@ -1708,14 +1708,43 @@ static efi_status_t eficonfig_show_boot_selection(unsigned int *selected) } /* list the remaining load option not included in the BootOrder */ - for (i = 0; i <= 0xFFFF; i++) { - /* If the index is included in the BootOrder, skip it */ - if (search_bootorder(bootorder, num, i, NULL)) - continue; + buf_size = 128; + var_name16 = malloc(buf_size); + if (!var_name16) + return EFI_OUT_OF_RESOURCES; - ret = eficonfig_add_boot_selection_entry(efi_menu, i, selected); - if (ret != EFI_SUCCESS) - goto out; + var_name16[0] = 0; + for (;;) { + int index; + efi_guid_t guid; + + size = buf_size; + ret = efi_get_next_variable_name_int(&size, var_name16, &guid); + if (ret == EFI_NOT_FOUND) + break; + if (ret == EFI_BUFFER_TOO_SMALL) { + buf_size = size; + p = realloc(var_name16, buf_size); + if (!p) { + free(var_name16); + return EFI_OUT_OF_RESOURCES; + } + var_name16 = p; + ret = efi_get_next_variable_name_int(&size, var_name16, &guid); + } + if (ret != EFI_SUCCESS) { + free(var_name16); + return ret; + } + if (efi_varname_is_load_option(var_name16, &index)) { + /* If the index is included in the BootOrder, skip it */ + if (search_bootorder(bootorder, num, index, NULL)) + continue; + + ret = eficonfig_add_boot_selection_entry(efi_menu, index, selected); + if (ret != EFI_SUCCESS) + goto out; + } if (efi_menu->count >= EFICONFIG_ENTRY_NUM_MAX - 1) break; @@ -1733,6 +1762,8 @@ out: } eficonfig_destroy(efi_menu); + free(var_name16); + return ret; } @@ -1995,6 +2026,8 @@ static efi_status_t eficonfig_create_change_boot_order_entry(struct efimenu *efi u32 i; char *title; efi_status_t ret; + u16 *var_name16 = NULL, *p; + efi_uintn_t size, buf_size; /* list the load option in the order of BootOrder variable */ for (i = 0; i < num; i++) { @@ -2007,17 +2040,45 @@ static efi_status_t eficonfig_create_change_boot_order_entry(struct efimenu *efi } /* list the remaining load option not included in the BootOrder */ - for (i = 0; i < 0xFFFF; i++) { + buf_size = 128; + var_name16 = malloc(buf_size); + if (!var_name16) + return EFI_OUT_OF_RESOURCES; + + var_name16[0] = 0; + for (;;) { + int index; + efi_guid_t guid; + if (efi_menu->count >= EFICONFIG_ENTRY_NUM_MAX - 2) break; - /* If the index is included in the BootOrder, skip it */ - if (search_bootorder(bootorder, num, i, NULL)) - continue; - - ret = eficonfig_add_change_boot_order_entry(efi_menu, i, false); + size = buf_size; + ret = efi_get_next_variable_name_int(&size, var_name16, &guid); + if (ret == EFI_NOT_FOUND) + break; + if (ret == EFI_BUFFER_TOO_SMALL) { + buf_size = size; + p = realloc(var_name16, buf_size); + if (!p) { + ret = EFI_OUT_OF_RESOURCES; + goto out; + } + var_name16 = p; + ret = efi_get_next_variable_name_int(&size, var_name16, &guid); + } if (ret != EFI_SUCCESS) goto out; + + if (efi_varname_is_load_option(var_name16, &index)) { + /* If the index is included in the BootOrder, skip it */ + if (search_bootorder(bootorder, num, index, NULL)) + continue; + + ret = eficonfig_add_change_boot_order_entry(efi_menu, index, false); + if (ret != EFI_SUCCESS) + goto out; + } } /* add "Save" and "Quit" entries */ @@ -2036,9 +2097,9 @@ static efi_status_t eficonfig_create_change_boot_order_entry(struct efimenu *efi goto out; efi_menu->active = 0; - - return EFI_SUCCESS; out: + free(var_name16); + return ret; } @@ -2271,17 +2332,48 @@ out: efi_status_t eficonfig_delete_invalid_boot_option(struct eficonfig_media_boot_option *opt, efi_status_t count) { - u32 i, j; + u32 i; efi_uintn_t size; void *load_option; struct efi_load_option lo; + u16 *var_name16 = NULL, *p; u16 varname[] = u"Boot####"; efi_status_t ret = EFI_SUCCESS; + efi_uintn_t varname_size, buf_size; - for (i = 0; i <= 0xFFFF; i++) { + buf_size = 128; + var_name16 = malloc(buf_size); + if (!var_name16) + return EFI_OUT_OF_RESOURCES; + + var_name16[0] = 0; + for (;;) { + int index; + efi_guid_t guid; efi_uintn_t tmp; - efi_create_indexed_name(varname, sizeof(varname), "Boot", i); + varname_size = buf_size; + ret = efi_get_next_variable_name_int(&varname_size, var_name16, &guid); + if (ret == EFI_NOT_FOUND) + break; + if (ret == EFI_BUFFER_TOO_SMALL) { + buf_size = varname_size; + p = realloc(var_name16, buf_size); + if (!p) { + free(var_name16); + return EFI_OUT_OF_RESOURCES; + } + var_name16 = p; + ret = efi_get_next_variable_name_int(&varname_size, var_name16, &guid); + } + if (ret != EFI_SUCCESS) { + free(var_name16); + return ret; + } + if (!efi_varname_is_load_option(var_name16, &index)) + continue; + + efi_create_indexed_name(varname, sizeof(varname), "Boot", index); load_option = efi_get_var(varname, &efi_global_variable_guid, &size); if (!load_option) continue; @@ -2293,15 +2385,15 @@ efi_status_t eficonfig_delete_invalid_boot_option(struct eficonfig_media_boot_op if (size >= sizeof(efi_guid_bootmenu_auto_generated)) { if (guidcmp(lo.optional_data, &efi_guid_bootmenu_auto_generated) == 0) { - for (j = 0; j < count; j++) { - if (opt[j].size == tmp && - memcmp(opt[j].lo, load_option, tmp) == 0) { - opt[j].exist = true; + for (i = 0; i < count; i++) { + if (opt[i].size == tmp && + memcmp(opt[i].lo, load_option, tmp) == 0) { + opt[i].exist = true; break; } } - if (j == count) { + if (i == count) { ret = delete_boot_option(i); if (ret != EFI_SUCCESS) { free(load_option); diff --git a/cmd/efidebug.c b/cmd/efidebug.c index ef239bb..569003a 100644 --- a/cmd/efidebug.c +++ b/cmd/efidebug.c @@ -600,7 +600,7 @@ static int do_efi_show_memmap(struct cmd_tbl *cmdtp, int flag, ret = efi_get_memory_map(&map_size, memmap, NULL, NULL, NULL); if (ret == EFI_BUFFER_TOO_SMALL) { map_size += sizeof(struct efi_mem_desc); /* for my own */ - ret = efi_allocate_pool(EFI_LOADER_DATA, map_size, + ret = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, map_size, (void *)&memmap); if (ret != EFI_SUCCESS) return CMD_RET_FAILURE; @@ -1010,17 +1010,6 @@ static void show_efi_boot_opt(u16 *varname16) } } -static int u16_tohex(u16 c) -{ - if (c >= '0' && c <= '9') - return c - '0'; - if (c >= 'A' && c <= 'F') - return c - 'A' + 10; - - /* not hexadecimal */ - return -1; -} - /** * show_efi_boot_dump() - dump all UEFI load options * @@ -1041,7 +1030,6 @@ static int do_efi_boot_dump(struct cmd_tbl *cmdtp, int flag, u16 *var_name16, *p; efi_uintn_t buf_size, size; efi_guid_t guid; - int id, i, digit; efi_status_t ret; if (argc > 1) @@ -1074,16 +1062,7 @@ static int do_efi_boot_dump(struct cmd_tbl *cmdtp, int flag, return CMD_RET_FAILURE; } - if (memcmp(var_name16, u"Boot", 8)) - continue; - - for (id = 0, i = 0; i < 4; i++) { - digit = u16_tohex(var_name16[4 + i]); - if (digit < 0) - break; - id = (id << 4) + digit; - } - if (i == 4 && !var_name16[8]) + if (efi_varname_is_load_option(var_name16, NULL)) show_efi_boot_opt(var_name16); } diff --git a/common/console.c b/common/console.c index 0c9bf66..10ab361 100644 --- a/common/console.c +++ b/common/console.c @@ -497,7 +497,7 @@ int serial_printf(const char *fmt, ...) int fgetc(int file) { - if (file < MAX_FILES) { + if ((unsigned int)file < MAX_FILES) { /* * Effectively poll for input wherever it may be available. */ @@ -530,7 +530,7 @@ int fgetc(int file) int ftstc(int file) { - if (file < MAX_FILES) + if ((unsigned int)file < MAX_FILES) return console_tstc(file); return -1; @@ -538,20 +538,20 @@ int ftstc(int file) void fputc(int file, const char c) { - if (file < MAX_FILES) + if ((unsigned int)file < MAX_FILES) console_putc(file, c); } void fputs(int file, const char *s) { - if (file < MAX_FILES) + if ((unsigned int)file < MAX_FILES) console_puts(file, s); } #ifdef CONFIG_CONSOLE_FLUSH_SUPPORT void fflush(int file) { - if (file < MAX_FILES) + if ((unsigned int)file < MAX_FILES) console_flush(file); } #endif diff --git a/disk/part.c b/disk/part.c index 2eb30eb..5ee60a7 100644 --- a/disk/part.c +++ b/disk/part.c @@ -433,25 +433,17 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str, int part; struct disk_partition tmpinfo; + *dev_desc = NULL; + memset(info, 0, sizeof(*info)); + #if IS_ENABLED(CONFIG_SANDBOX) || IS_ENABLED(CONFIG_SEMIHOSTING) /* * Special-case a pseudo block device "hostfs", to allow access to the * host's own filesystem. */ - if (0 == strcmp(ifname, "hostfs")) { - *dev_desc = NULL; - info->start = 0; - info->size = 0; - info->blksz = 0; - info->bootable = 0; + if (!strcmp(ifname, "hostfs")) { strcpy((char *)info->type, BOOT_PART_TYPE); strcpy((char *)info->name, "Host filesystem"); -#if CONFIG_IS_ENABLED(PARTITION_UUIDS) - info->uuid[0] = 0; -#endif -#ifdef CONFIG_PARTITION_TYPE_GUID - info->type_guid[0] = 0; -#endif return 0; } @@ -462,19 +454,14 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str, * Special-case ubi, ubi goes through a mtd, rather than through * a regular block device. */ - if (0 == strcmp(ifname, "ubi")) { + if (!strcmp(ifname, "ubi")) { if (!ubifs_is_mounted()) { printf("UBIFS not mounted, use ubifsmount to mount volume first!\n"); return -EINVAL; } - *dev_desc = NULL; - memset(info, 0, sizeof(*info)); strcpy((char *)info->type, BOOT_PART_TYPE); strcpy((char *)info->name, "UBI"); -#if CONFIG_IS_ENABLED(PARTITION_UUIDS) - info->uuid[0] = 0; -#endif return 0; } #endif diff --git a/doc/board/microchip/mpfs_icicle.rst b/doc/board/microchip/mpfs_icicle.rst index a4b10c6..09c2c6a 100644 --- a/doc/board/microchip/mpfs_icicle.rst +++ b/doc/board/microchip/mpfs_icicle.rst @@ -209,7 +209,7 @@ GUID type ~~~~~~~~~ The HSS always picks up HSS payload from a GPT partition with -GIUD type "21686148-6449-6E6F-744E-656564454649" or sector '0' of the eMMC if no +GUID type "21686148-6449-6E6F-744E-656564454649" or sector '0' of the eMMC if no GPT partition. Booting @@ -460,7 +460,7 @@ GUID type ~~~~~~~~~ The HSS always picks up the HSS payload from a GPT partition with -GIUD type "21686148-6449-6E6F-744E-656564454649" or sector '0' of the eMMC if no +GUID type "21686148-6449-6E6F-744E-656564454649" or sector '0' of the eMMC if no GPT partition. Sample boot log from MPFS Icicle Kit diff --git a/doc/board/ti/j721e_evm.rst b/doc/board/ti/j721e_evm.rst index 44dc316..ad70f15 100644 --- a/doc/board/ti/j721e_evm.rst +++ b/doc/board/ti/j721e_evm.rst @@ -142,7 +142,11 @@ Sources: Tree: https://github.com/OP-TEE/optee_os.git Branch: master -4. U-Boot: +4. DM Firmware: + Tree: git://git.ti.com/processor-firmware/ti-linux-firmware.git + Branch: ti-linux-firmware + +5. U-Boot: Tree: https://source.denx.de/u-boot/u-boot Branch: master @@ -150,37 +154,37 @@ Build procedure: ---------------- 1. SYSFW: -.. code-block:: text +.. code-block:: bash - $ make CROSS_COMPILE=arm-linux-gnueabihf- + make CROSS_COMPILE=arm-linux-gnueabihf- SOC=j721e 2. ATF: -.. code-block:: text +.. code-block:: bash - $ make CROSS_COMPILE=aarch64-linux-gnu- ARCH=aarch64 PLAT=k3 TARGET_BOARD=generic SPD=opteed + make CROSS_COMPILE=aarch64-linux-gnu- ARCH=aarch64 PLAT=k3 TARGET_BOARD=generic SPD=opteed 3. OPTEE: -.. code-block:: text +.. code-block:: bash - $ make PLATFORM=k3-j721e CFG_ARM64_core=y + make PLATFORM=k3-j721e CFG_ARM64_core=y 4. U-Boot: * 4.1 R5: -.. code-block:: text +.. code-block:: bash - $ make CROSS_COMPILE=arm-linux-gnueabihf- j721e_evm_r5_defconfig O=/tmp/r5 - $ make CROSS_COMPILE=arm-linux-gnueabihf- O=/tmp/r5 + make CROSS_COMPILE=arm-linux-gnueabihf- j721e_evm_r5_defconfig O=build/r5 + make CROSS_COMPILE=arm-linux-gnueabihf- O=build/r5 * 4.2 A72: -.. code-block:: text +.. code-block:: bash - $ make CROSS_COMPILE=aarch64-linux-gnu- j721e_evm_a72_defconfig O=/tmp/a72 - $ make CROSS_COMPILE=aarch64-linux-gnu- ATF=<path to ATF dir>/build/k3/generic/release/bl31.bin TEE=<path to OPTEE OS dir>/out/arm-plat-k3/core/tee-pager_v2.bin DM=<path to DM firmware image> O=/tmp/a72 + make CROSS_COMPILE=aarch64-linux-gnu- j721e_evm_a72_defconfig O=build/a72 + make CROSS_COMPILE=aarch64-linux-gnu- ATF=<ATF dir>/build/k3/generic/release/bl31.bin TEE=<OPTEE OS dir>/out/arm-plat-k3/core/tee-pager_v2.bin DM=<DM firmware>/ti-dm/j721e/ipc_echo_testb_mcu1_0_release_strip.xer5f O=build/a72 Target Images -------------- diff --git a/doc/usage/cmd/eficonfig.rst b/doc/usage/cmd/eficonfig.rst index 340ebc8..30eb72b 100644 --- a/doc/usage/cmd/eficonfig.rst +++ b/doc/usage/cmd/eficonfig.rst @@ -13,49 +13,43 @@ Synopsis Description ----------- -The "eficonfig" command uses U-Boot menu interface and provides -a menu-driven UEFI variable maintenance feature. -The "eficonfig" has the following menu entries. +The "eficonfig" command uses the U-Boot menu interface to provide a +menu-driven UEFI variable maintenance feature. These are the top level menu +entries: Add Boot Option - Add new UEFI Boot Option. - User can edit description, file path, and optional_data. + Add a new UEFI Boot Option. + The user can edit description, file path, and optional_data. + The new boot opiton is appended to the boot order in the *BootOrder* + variable. The user may want to update the boot order using the + *Change Boot Order* menu entry. Edit Boot Option - Edit the existing UEFI Boot Option - User can edit description, file path, and optional_data. + Edit an existing UEFI Boot Option. + The User can edit description, file path, and optional_data. Change Boot Order - Change the order of UEFI BootOrder variable. + Change the boot order updating the UEFI BootOrder variable. Delete Boot Option - Delete the UEFI Boot Option + Delete a UEFI Boot Option -Configuration -------------- +Secure Boot Configuration + Edit the UEFI Secure Boot Configuration -The "eficonfig" command is enabled by:: +How to boot the system with a newly added UEFI Boot Option +'''''''''''''''''''''''''''''''''''''''''''''''''''''''''' - CONFIG_CMD_EFICONFIG=y - -If CONFIG_BOOTMENU_DISABLE_UBOOT_CONSOLE is enabled, user can not enter -U-Boot console. In this case, bootmenu can be used to invoke "eficonfig":: - - CONFIG_USE_PREBOOT=y - CONFIG_PREBOOT="setenv bootmenu_0 UEFI Maintenance Menu=eficonfig" +The "eficonfig" command is used to set the UEFI boot options which are stored +in the UEFI variable Boot#### where #### is a hexadecimal number. -How to boot the system with newly added UEFI Boot Option -'''''''''''''''''''''''''''''''''''''''''''''''''''''''' +The command *bootefi bootmgr* can be used to boot by trying in sequence all +boot options selected by the variable *BootOrder*. -"eficonfig" command is responsible for configuring the UEFI variables, -not directly handle the system boot. -The new Boot Option added by "eficonfig" is appended at the last entry -of UEFI BootOrder variable, user may want to change the boot order -through "Change Boot Order". If the bootmenu is enabled, CONFIG_BOOTMENU_DISABLE_UBOOT_CONSOLE is enabled, and "eficonfig" is configured as preboot command, the newly added Boot Options -are enumerated in the bootmenu when user exits from the eficonfig menu. -User may select the entry in the bootmenu to boot the system, or follow +are enumerated in the bootmenu when the user exits from the eficonfig menu. +The user may select the entry in the bootmenu to boot the system, or follow the U-Boot configuration the system already has. Auto boot with the UEFI Boot Option @@ -66,6 +60,44 @@ add "bootefi bootmgr" entry as a default or first bootmenu entry:: CONFIG_PREBOOT="setenv bootmenu_0 UEFI Boot Manager=bootefi bootmgr; setenv bootmenu_1 UEFI Maintenance Menu=eficonfig" +UEFI Secure Boot Configuration +'''''''''''''''''''''''''''''' + +The user can enroll the variables PK, KEK, db and dbx by selecting a file. +The "eficonfig" command only accepts signed EFI Signature List(s) with an +authenticated header, typically a ".auth" file. + +To clear the PK, KEK, db and dbx, the user needs to enroll a null value +signed by PK or KEK. + +Configuration +------------- + +The "eficonfig" command is enabled by:: + + CONFIG_CMD_EFICONFIG=y + +If CONFIG_BOOTMENU_DISABLE_UBOOT_CONSOLE is enabled, the user can not enter +U-Boot console. In this case, the bootmenu can be used to invoke "eficonfig":: + + CONFIG_USE_PREBOOT=y + CONFIG_PREBOOT="setenv bootmenu_0 UEFI Maintenance Menu=eficonfig" + +The only way U-Boot can currently store EFI variables on a tamper +resistant medium is via OP-TEE. The Kconfig option that enables that is:: + + CONFIG_EFI_MM_COMM_TEE=y. + +It enables storing EFI variables on the RPMB partition of an eMMC device. + +The UEFI Secure Boot Configuration menu entry is only available if the following +options are enabled:: + + CONFIG_EFI_SECURE_BOOT=y + CONFIG_EFI_MM_COMM_TEE=y + See also -------- -* :doc:`bootmenu<bootmenu>` provides a simple mechanism for creating menus with different boot items + +* :doc:`bootmenu<bootmenu>` provides a simple mechanism for creating menus with + different boot items diff --git a/include/efi_loader.h b/include/efi_loader.h index 0c6c95b..0899e29 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -707,6 +707,7 @@ int algo_to_len(const char *algo); int efi_link_dev(efi_handle_t handle, struct udevice *dev); int efi_unlink_dev(efi_handle_t handle); +bool efi_varname_is_load_option(u16 *var_name16, int *index); /** * efi_size_in_pages() - convert size in bytes to size in pages diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 8738757..13a35ea 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -12,6 +12,8 @@ ccflags-y += -DHOST_ARCH="$(HOST_ARCH)" CFLAGS_efi_boottime.o += \ -DFW_VERSION="0x$(VERSION)" \ -DFW_PATCHLEVEL="0x$(PATCHLEVEL)" +CFLAGS_boothart.o := $(CFLAGS_EFI) -Os -ffreestanding +CFLAGS_REMOVE_boothart.o := $(CFLAGS_NON_EFI) CFLAGS_helloworld.o := $(CFLAGS_EFI) -Os -ffreestanding CFLAGS_REMOVE_helloworld.o := $(CFLAGS_NON_EFI) CFLAGS_dtbdump.o := $(CFLAGS_EFI) -Os -ffreestanding @@ -19,6 +21,10 @@ CFLAGS_REMOVE_dtbdump.o := $(CFLAGS_NON_EFI) CFLAGS_initrddump.o := $(CFLAGS_EFI) -Os -ffreestanding CFLAGS_REMOVE_initrddump.o := $(CFLAGS_NON_EFI) +ifdef CONFIG_RISCV +always += boothart.efi +endif + ifneq ($(CONFIG_CMD_BOOTEFI_HELLO_COMPILE),) always += helloworld.efi targets += helloworld.o diff --git a/lib/efi_loader/boothart.c b/lib/efi_loader/boothart.c new file mode 100644 index 0000000..df176ee --- /dev/null +++ b/lib/efi_loader/boothart.c @@ -0,0 +1,335 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Check RISC-V boot hart ID + * + * Copyright 2022, Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * This test program reads the boot HART ID both from the device-tree from the + * RISCV_EFI_BOOT_PROTOCOL and writes both values to the console. + */ + +#include <efi_api.h> +#include <efi_riscv.h> +#include <linux/libfdt.h> + +static const efi_guid_t riscv_efi_boot_protocol_guid = + RISCV_EFI_BOOT_PROTOCOL_GUID; +static const efi_guid_t fdt_guid = EFI_FDT_GUID; + +static struct efi_system_table *systable; +static struct efi_boot_services *boottime; +static struct efi_simple_text_output_protocol *con_out; +static const char *fdt; + +/** + * Print an unsigned 32bit value as decimal number to an u16 string + * + * @value: value to be printed + * @buf: pointer to buffer address + */ +static void uint2dec(u32 value, u16 *buf) +{ + u16 *pos = buf; + int i; + u16 c; + u64 f; + + /* + * Increment by .5 and multiply with + * (2 << 60) / 1,000,000,000 = 0x44B82FA0.9B5A52CC + * to move the first digit to bit 60-63. + */ + f = 0x225C17D0; + f += (0x9B5A52DULL * value) >> 28; + f += 0x44B82FA0ULL * value; + + for (i = 0; i < 10; ++i) { + /* Write current digit */ + c = f >> 60; + if (c || pos != buf) + *pos++ = c + '0'; + /* Eliminate current digit */ + f &= 0xfffffffffffffff; + /* Get next digit */ + f *= 0xaULL; + } + if (pos == buf) + *pos++ = '0'; + *pos = 0; +} + +/** + * f2h() - convert FDT value to host endianness. + * + * UEFI code is always low endian. The FDT is big endian. + * + * @val: FDT value + * Return: converted value + */ +static uint32_t f2h(fdt32_t val) +{ + char *buf = (char *)&val; + char i; + + /* Swap the bytes */ + i = buf[0]; buf[0] = buf[3]; buf[3] = i; + i = buf[1]; buf[1] = buf[2]; buf[2] = i; + + return val; +} + +/** + * memcomp() - compare two memory buffers + * + * s1: first buffer + * s2: second buffer + * n: size of buffers + * Return: 0 if both buffers have the same content + */ +static int memcomp(const void *s1, const void *s2, size_t n) +{ + const char *pos1 = s1, *pos2 = s2; + + for (size_t count = 0; count < n ; ++pos1, ++pos2, --count) { + if (*pos1 != *pos2) + return *pos1 - *pos2; + } + return 0; +} + +/** + * strcomp() - compare to strings + * + * @buf1: first string + * @buf2: second string + * Return: 0 if both strings are the same + */ +static int strcomp(const char *buf1, const char *buf2) +{ + for (; *buf1 || *buf2; ++buf1, ++buf2) { + if (*buf1 != *buf2) + return *buf1 - *buf2; + } + return 0; +} + +/** + * get_property() - return value of a property of an FDT node + * + * A property of the root node or one of its direct children can be + * retrieved. + * + * @property name of the property + * @node name of the node or NULL for root node + * Return: value of the property + */ +static char *get_property(const char *property, const char *node) +{ + struct fdt_header *header = (struct fdt_header *)fdt; + const fdt32_t *end; + const fdt32_t *pos; + const char *strings; + size_t level = 0; + const char *nodelabel = NULL; + + if (!header) { + con_out->output_string(con_out, u"Missing device tree\r\n"); + return NULL; + } + + if (f2h(header->magic) != FDT_MAGIC) { + con_out->output_string(con_out, u"Wrong device tree magic\r\n"); + return NULL; + } + + pos = (fdt32_t *)(fdt + f2h(header->off_dt_struct)); + end = &pos[f2h(header->totalsize) >> 2]; + strings = fdt + f2h(header->off_dt_strings); + + for (; pos < end;) { + switch (f2h(pos[0])) { + case FDT_BEGIN_NODE: { + const char *c = (char *)&pos[1]; + size_t i; + + if (level == 1) + nodelabel = c; + ++level; + for (i = 0; c[i]; ++i) + ; + pos = &pos[2 + (i >> 2)]; + break; + } + case FDT_PROP: { + struct fdt_property *prop = (struct fdt_property *)pos; + const char *label = &strings[f2h(prop->nameoff)]; + efi_status_t ret; + + /* Check if this is the property to be returned */ + if (!strcomp(property, label) && + ((level == 1 && !node) || + (level == 2 && node && + !strcomp(node, nodelabel)))) { + char *str; + efi_uintn_t len = f2h(prop->len); + + if (!len) + return NULL; + /* + * The string might not be 0 terminated. + * It is safer to make a copy. + */ + ret = boottime->allocate_pool( + EFI_LOADER_DATA, len + 1, + (void **)&str); + if (ret != EFI_SUCCESS) { + con_out->output_string( + con_out, + u"AllocatePool failed\r\n"); + return NULL; + } + boottime->copy_mem(str, &pos[3], len); + str[len] = 0; + + return str; + } + + pos = &pos[3 + ((f2h(prop->len) + 3) >> 2)]; + break; + } + case FDT_NOP: + ++pos; + break; + case FDT_END_NODE: + --level; + ++pos; + break; + case FDT_END: + return NULL; + default: + con_out->output_string( + con_out, u"Invalid device tree token\r\n"); + return NULL; + } + } + con_out->output_string( + con_out, u"Missing FDT_END token\r\n"); + return NULL; +} + +/** + * get_config_table() - get configuration table + * + * @guid: table GUID + * Return: pointer to table or NULL + */ +static void *get_config_table(const efi_guid_t *guid) +{ + size_t i; + + for (i = 0; i < systable->nr_tables; i++) { + if (!memcomp(guid, &systable->tables[i].guid, 16)) + return systable->tables[i].table; + } + return NULL; +} + +/** + * fdt_get_hart() - get hart ID via RISC-V device-tree + * + * @hartid: boot hart ID + * Return: status code + */ +static efi_status_t fdt_get_hart(efi_uintn_t *hartid) +{ + char *str; + + fdt = get_config_table(&fdt_guid); + if (!fdt) { + con_out->output_string(con_out, u"Missing device tree\r\n"); + return EFI_NOT_FOUND; + } + + str = get_property("boot-hartid", "chosen"); + if (!str) { + con_out->output_string(con_out, + u"/chosen/boot-hartid missing\r\n"); + return EFI_NOT_FOUND; + } + *hartid = f2h(*(fdt32_t *)str); + boottime->free_pool(str); + + return EFI_SUCCESS; +} + +/** + * prot_get_hart() - get hart ID via RISC-V Boot Protocol + * + * @hartid: boot hart ID + * Return: status code + */ +static efi_status_t prot_get_hart(efi_uintn_t *hartid) +{ + efi_status_t ret; + struct riscv_efi_boot_protocol *prot; + + /* Get RISC-V boot protocol */ + ret = boottime->locate_protocol(&riscv_efi_boot_protocol_guid, NULL, + (void **)&prot); + if (ret != EFI_SUCCESS) { + con_out->output_string( + con_out, u"RISC-V Boot Protocol not available\r\n"); + return ret; + } + + /* Get boot hart ID from EFI protocol */ + ret = prot->get_boot_hartid(prot, hartid); + if (ret != EFI_SUCCESS) + con_out->output_string(con_out, + u"Could not retrieve boot hart ID\r\n"); + return ret; +} + +/** + * efi_main() - entry point of the EFI application. + * + * @handle: handle of the loaded image + * @systab: system table + * Return: status code + */ +efi_status_t EFIAPI efi_main(efi_handle_t handle, + struct efi_system_table *systab) +{ + efi_status_t ret; + efi_uintn_t hartid; + u16 buf[16]; + + systable = systab; + boottime = systable->boottime; + con_out = systable->con_out; + + con_out->output_string(con_out, + u"\r\nBoot hart ID\r\n------------\r\n\r\n"); + + ret = fdt_get_hart(&hartid); + if (ret == EFI_SUCCESS) { + con_out->output_string(con_out, u"Device-tree: "); + uint2dec(hartid, buf); + con_out->output_string(con_out, buf); + con_out->output_string(con_out, u"\r\n"); + } + + ret = prot_get_hart(&hartid); + if (ret == EFI_SUCCESS) { + con_out->output_string(con_out, u"RISCV_EFI_BOOT_PROTOCOL: "); + uint2dec(hartid, buf); + con_out->output_string(con_out, buf); + con_out->output_string(con_out, u"\r\n"); + } + + con_out->output_string(con_out, u"\r\n"); + boottime->exit(handle, EFI_SUCCESS, 0, NULL); + + /* We should never arrive here */ + return EFI_SUCCESS; +} diff --git a/lib/efi_loader/efi_helper.c b/lib/efi_loader/efi_helper.c index c71e87d..788cb9f 100644 --- a/lib/efi_loader/efi_helper.c +++ b/lib/efi_loader/efi_helper.c @@ -190,3 +190,36 @@ int efi_unlink_dev(efi_handle_t handle) return 0; } + +static int u16_tohex(u16 c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + + /* not hexadecimal */ + return -1; +} + +bool efi_varname_is_load_option(u16 *var_name16, int *index) +{ + int id, i, digit; + + if (memcmp(var_name16, u"Boot", 8)) + return false; + + for (id = 0, i = 0; i < 4; i++) { + digit = u16_tohex(var_name16[4 + i]); + if (digit < 0) + break; + id = (id << 4) + digit; + } + if (i == 4 && !var_name16[8]) { + if (index) + *index = id; + return true; + } + + return false; +} diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index a17b426..8d347f1 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -823,7 +823,7 @@ static void add_u_boot_and_runtime(void) uboot_stack_size) & ~EFI_PAGE_MASK; uboot_pages = ((uintptr_t)map_sysmem(gd->ram_top - 1, 0) - uboot_start + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT; - efi_add_memory_map_pg(uboot_start, uboot_pages, EFI_LOADER_DATA, + efi_add_memory_map_pg(uboot_start, uboot_pages, EFI_BOOT_SERVICES_CODE, false); #if defined(__aarch64__) @@ -857,7 +857,7 @@ int efi_memory_init(void) /* Request a 32bit 64MB bounce buffer region */ uint64_t efi_bounce_buffer_addr = 0xffffffff; - if (efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, EFI_LOADER_DATA, + if (efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, EFI_BOOT_SERVICES_DATA, (64 * 1024 * 1024) >> EFI_PAGE_SHIFT, &efi_bounce_buffer_addr) != EFI_SUCCESS) return -1; diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c index 69276b2..96a5bcc 100644 --- a/lib/efi_loader/efi_net.c +++ b/lib/efi_loader/efi_net.c @@ -30,6 +30,7 @@ static uchar **receive_buffer; static size_t *receive_lengths; static int rx_packet_idx; static int rx_packet_num; +static struct efi_net_obj *netobj; /* * The notification function of this event is called in every timer cycle @@ -660,10 +661,16 @@ void efi_net_set_dhcp_ack(void *pkt, int len) { int maxsize = sizeof(*dhcp_ack); - if (!dhcp_ack) + if (!dhcp_ack) { dhcp_ack = malloc(maxsize); - + if (!dhcp_ack) + return; + } + memset(dhcp_ack, 0, maxsize); memcpy(dhcp_ack, pkt, min(len, maxsize)); + + if (netobj) + netobj->pxe_mode.dhcp_ack = *dhcp_ack; } /** @@ -853,7 +860,6 @@ static efi_status_t EFIAPI efi_pxe_base_code_set_packets( */ efi_status_t efi_net_register(void) { - struct efi_net_obj *netobj = NULL; efi_status_t r; int i; @@ -982,6 +988,7 @@ failure_to_add_protocol: return r; out_of_resources: free(netobj); + netobj = NULL; free(transmit_buffer); if (receive_buffer) for (i = 0; i < ETH_PACKETS_BATCH_RECV; i++) diff --git a/lib/efi_selftest/efi_selftest_unicode_collation.c b/lib/efi_selftest/efi_selftest_unicode_collation.c index 11050a3..32c99ca 100644 --- a/lib/efi_selftest/efi_selftest_unicode_collation.c +++ b/lib/efi_selftest/efi_selftest_unicode_collation.c @@ -178,7 +178,7 @@ static int test_fat_to_str(void) boottime->set_mem(str, sizeof(str), 0); unicode_collation_protocol->fat_to_str(unicode_collation_protocol, 6, - "U-BOOT", str); + "U-BOOT!", str); if (efi_st_strcmp_16_8(str, "U-BOOT")) { efi_st_error("fat_to_str returned \"%ps\"\n", str); return EFI_ST_FAILURE; diff --git a/net/bootp.c b/net/bootp.c index 6c01e38..7ac0093 100644 --- a/net/bootp.c +++ b/net/bootp.c @@ -1078,7 +1078,7 @@ static void dhcp_handler(uchar *pkt, unsigned dest, struct in_addr sip, #endif /* CONFIG_SYS_BOOTFILE_PREFIX */ dhcp_packet_process_options(bp); if (CONFIG_IS_ENABLED(EFI_LOADER) && - CONFIG_IS_ENABLED(NET_DEVICES)) + CONFIG_IS_ENABLED(NETDEVICES)) efi_net_set_dhcp_ack(pkt, len); #if defined(CONFIG_SERVERIP_FROM_PROXYDHCP) |