[PATCH 00/22] efi: Tidy up some commands and provide a keyboard driver

From: Simon Glass <sjg@chromium.org> This series collect various odds and ends to make the ARM EFI app show a menu that looks reasonable, including truetype fonts and a new keyboard driver, selectable by setting stdin to 'efi-kbd'. Some highlights: - fix some bugs in addr_find and part_find and adds docs / tests - reset pager when clearing the console - use at least 1G of memory with EFI since the app allocates 512M - allow NEON registers so floating point can work (truetype) - show the global_data flags with bdinfo Simon Glass (22): bdinfo: Show the flags script: Use a minimum of 1G of memory for EFI console: Reset the pager when clearing the console doc: Fix up the booti examples efi: Avoid a memory leak in efi_bind_block() on error path efi: Drop config.h test: Drop an unwanted blank line in dm_test_video_box() test: Allow creating disks with a different Ubuntu version cmd: part_find: Correct radix and calls cmd: sandbox: efi: Enable part_find for sandbox and EFI app cmd: Refactor part_find() into separate functions doc: test: Add docs and test for part_find cmd: Update addr_find to use a simple lmb allocation cmd: Update addr_find to ignore the devicetree doc: test: Add docs and test for addr_find boot: Tidy up positioning in bootflow_menu_new() expo: Allow manual positioning of menu items Revert "ARM: Prevent the compiler from using NEON registers" efi: Enable truetype in the ARM app efi: arm: Drop setting of fdt_addr efi: Move key decoding into a shared file efi: app: Provide a keyboard driver arch/arm/config.mk | 1 - arch/arm/dts/efi-arm_app.dts | 4 + board/efi/efi-arm_app/efi-arm_app.env | 1 - boot/bootflow_menu.c | 8 +- boot/scene.c | 14 +++ cmd/Kconfig | 5 +- cmd/addr_find.c | 23 ++-- cmd/bdinfo.c | 1 + cmd/part_find.c | 154 ++++++++++++++--------- common/console.c | 1 + configs/efi-arm_app64_defconfig | 1 + doc/usage/cmd/addr_find.rst | 63 ++++++++++ doc/usage/cmd/booti.rst | 4 +- doc/usage/cmd/part_find.rst | 119 ++++++++++++++++++ doc/usage/index.rst | 2 + drivers/input/Kconfig | 14 +++ drivers/input/Makefile | 2 + drivers/input/efi_keyb.c | 173 ++++++++++++++++++++++++++ drivers/net/efi_net.c | 1 - drivers/serial/serial_efi.c | 15 +-- drivers/tpm/tpm2_efi.c | 1 - include/efi.h | 32 +++++ include/expo.h | 27 +++- lib/efi/Makefile | 1 + lib/efi/input.c | 40 ++++++ lib/efi_client/efi_app_init.c | 4 +- scripts/build-efi | 2 +- test/cmd/Makefile | 2 + test/cmd/addr_find.c | 27 ++++ test/cmd/bdinfo.c | 1 + test/cmd/part_find.c | 42 +++++++ test/dm/video.c | 1 - test/py/img/ubuntu.py | 8 +- 33 files changed, 683 insertions(+), 111 deletions(-) create mode 100644 doc/usage/cmd/addr_find.rst create mode 100644 doc/usage/cmd/part_find.rst create mode 100644 drivers/input/efi_keyb.c create mode 100644 lib/efi/input.c create mode 100644 test/cmd/addr_find.c create mode 100644 test/cmd/part_find.c -- 2.43.0 base-commit: 271239736374b0ed1e90311ac07f2346ff858414 branch: api

From: Simon Glass <sjg@chromium.org> The flags contain lots of little pieces of information. Print them out with the bdinfo command, so the user can look them up if needed. Signed-off-by: Simon Glass <sjg@chromium.org> --- cmd/bdinfo.c | 1 + test/cmd/bdinfo.c | 1 + 2 files changed, 2 insertions(+) diff --git a/cmd/bdinfo.c b/cmd/bdinfo.c index a70a1c59f51..69d9c3cfe4d 100644 --- a/cmd/bdinfo.c +++ b/cmd/bdinfo.c @@ -138,6 +138,7 @@ static int bdinfo_print_all(struct bd_info *bd) #if CONFIG_IS_ENABLED(MULTI_DTB_FIT) lprint_num_l("multi_dtb_fit", (ulong)gd->multi_dtb_fit); #endif + lprint_num_l("flags", gd->flags); if (IS_ENABLED(CONFIG_LMB) && gd->fdt_blob) { lmb_dump_all_force(); if (IS_ENABLED(CONFIG_OF_REAL)) diff --git a/test/cmd/bdinfo.c b/test/cmd/bdinfo.c index 03d9846de10..6b4cfa96e4d 100644 --- a/test/cmd/bdinfo.c +++ b/test/cmd/bdinfo.c @@ -191,6 +191,7 @@ static int bdinfo_test_all(struct unit_test_state *uts) #if CONFIG_IS_ENABLED(MULTI_DTB_FIT) ut_assertok(test_num_l(uts, "multi_dtb_fit", (ulong)gd->multi_dtb_fit)); #endif + ut_assertok(test_num_l(uts, "flags", gd->flags)); if (IS_ENABLED(CONFIG_LMB) && gd->fdt_blob) { ut_assertok(lmb_test_dump_all(uts)); -- 2.43.0

From: Simon Glass <sjg@chromium.org> Since the U-Boot app now requests 512MB (to fit the ramdisk, etc.) and Tianocore uses some as well, the current 512MB is not enough. Double it. Signed-off-by: Simon Glass <sjg@chromium.org> --- scripts/build-efi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build-efi b/scripts/build-efi index 27446295b2d..21c2b656530 100755 --- a/scripts/build-efi +++ b/scripts/build-efi @@ -127,7 +127,7 @@ class BuildEfi: mem = '4G' extra.extend(['-smp', '4']) else: - mem = '512' + mem = '1G' if self.args.debug: extra.extend(['-s', '-S']) -- 2.43.0

From: Simon Glass <sjg@chromium.org> When the console is cleared we have a fresh screen so we can reset the pager. Signed-off-by: Simon Glass <sjg@chromium.org> --- common/console.c | 1 + 1 file changed, 1 insertion(+) diff --git a/common/console.c b/common/console.c index 561a859dc1e..c033d72486a 100644 --- a/common/console.c +++ b/common/console.c @@ -1108,6 +1108,7 @@ int console_clear(void) if (ret) return ret; } + pager_reset(gd_pager()); return 0; } -- 2.43.0

From: Simon Glass <sjg@chromium.org> The command has been updated but the docs was left behind. Fix it. Signed-off-by: Simon Glass <sjg@chromium.org> Fixes: 7f9e630a9ea ("boot: Drop hex prefix from the booti image-mov..") --- doc/usage/cmd/booti.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/usage/cmd/booti.rst b/doc/usage/cmd/booti.rst index 313efb83cc6..a4264853f89 100644 --- a/doc/usage/cmd/booti.rst +++ b/doc/usage/cmd/booti.rst @@ -58,7 +58,7 @@ This is the boot log of an Odroid C2 board: => load mmc 0:1 $ramdisk_addr_r initrd.img-5.10.0-3-arm64 27421776 bytes read in 1209 ms (21.6 MiB/s) => booti $kernel_addr_r $ramdisk_addr_r:$filesize $fdt_addr_r - Moving Image from 0x8080000 to 0x8200000, end=9c60000 + Moving Image from 8080000 to 8200000, end 9c60000 ## Flattened Device Tree blob at 08008000 Booting using the fdt blob at 0x8008000 Loading Ramdisk to 7a52a000, end 7bf50c50 ... OK @@ -87,7 +87,7 @@ Here is the boot log for the compressed kernel: 27421776 bytes read in 1181 ms (22.1 MiB/s) => booti $kernel_addr_r $ramdisk_addr_r:$filesize $fdt_addr_r Uncompressing Kernel Image - Moving Image from 0x8080000 to 0x8200000, end=9c60000 + Moving Image from 8080000 to 8200000, end 9c60000 ## Flattened Device Tree blob at 08008000 Booting using the fdt blob at 0x8008000 Loading Ramdisk to 7a52a000, end 7bf50c50 ... OK -- 2.43.0

From: Simon Glass <sjg@chromium.org> Free the memory used if an error occurs. Suggested-by: Ilias Apalodimas <ilias.apalodimas@linaro.org> Signed-off-by: Simon Glass <sjg@chromium.org> --- lib/efi_client/efi_app_init.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/efi_client/efi_app_init.c b/lib/efi_client/efi_app_init.c index b5421dc5a91..462c9db61e9 100644 --- a/lib/efi_client/efi_app_init.c +++ b/lib/efi_client/efi_app_init.c @@ -60,8 +60,10 @@ int efi_bind_block(efi_handle_t handle, struct efi_block_io *blkio, plat->handle = handle; plat->blkio = blkio; plat->device_path = malloc(device_path_len); - if (!plat->device_path) + if (!plat->device_path) { + free(plat); return log_msg_ret("path", -ENOMEM); + } memcpy(plat->device_path, device_path, device_path_len); snprintf(name, sizeof(name), "efi_media_%x", -- 2.43.0

From: Simon Glass <sjg@chromium.org> We don't need to include this file anymore, so drop it. Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/net/efi_net.c | 1 - drivers/tpm/tpm2_efi.c | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/net/efi_net.c b/drivers/net/efi_net.c index 370056040f3..abc69058437 100644 --- a/drivers/net/efi_net.c +++ b/drivers/net/efi_net.c @@ -4,7 +4,6 @@ * */ -#include <config.h> #include <dm.h> #include <efi.h> #include <efi_api.h> diff --git a/drivers/tpm/tpm2_efi.c b/drivers/tpm/tpm2_efi.c index 2eb144891d8..c6e7db762b5 100644 --- a/drivers/tpm/tpm2_efi.c +++ b/drivers/tpm/tpm2_efi.c @@ -4,7 +4,6 @@ * */ -#include <config.h> #include <dm.h> #include <efi.h> #include <efi_api.h> -- 2.43.0

From: Simon Glass <sjg@chromium.org> This test has a blank line which separates one part of the test from another. Drop it. Signed-off-by: Simon Glass <sjg@chromium.org> --- test/dm/video.c | 1 - 1 file changed, 1 deletion(-) diff --git a/test/dm/video.c b/test/dm/video.c index bb88c17e272..702e9854005 100644 --- a/test/dm/video.c +++ b/test/dm/video.c @@ -950,7 +950,6 @@ static int dm_test_video_box(struct unit_test_state *uts) video_index_to_colour(priv, VID_GREEN), true); video_draw_box(dev, 350, 250, 400, 300, 0, video_index_to_colour(priv, VID_YELLOW), true); - ut_asserteq(175, video_compress_fb(uts, dev, false)); return 0; -- 2.43.0

From: Simon Glass <sjg@chromium.org> Add a way to specify the (fake) Ubuntu release being used, so that we can (later) add more tests for this case. Signed-off-by: Simon Glass <sjg@chromium.org> --- test/py/img/ubuntu.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/py/img/ubuntu.py b/test/py/img/ubuntu.py index 06e8251c05b..1247ec134d5 100644 --- a/test/py/img/ubuntu.py +++ b/test/py/img/ubuntu.py @@ -6,7 +6,7 @@ from img.common import setup_extlinux_image -def setup_ubuntu_image(config, log, devnum, basename): +def setup_ubuntu_image(config, log, devnum, basename, version='24.04.1 LTS'): """Create a 20MB Ubuntu disk image with a single FAT partition Args: @@ -32,16 +32,16 @@ timeout 50 label l0 - menu label Ubuntu 24.04.1 LTS 6.8.0-53-generic + menu label Ubuntu %s 6.8.0-53-generic linux /boot/%s initrd /boot/%s append root=/dev/disk/by-uuid/bcfdda4a-8249-4f40-9f0f-7c1a76b6cbe8 ro earlycon label l0r - menu label Ubuntu 24.04.1 LTS 6.8.0-53-generic (rescue target) + menu label Ubuntu %s 6.8.0-53-generic (rescue target) linux /boot/%s initrd /boot/%s -''' % (vmlinux, initrd, vmlinux, initrd) +''' % ((version, vmlinux, initrd) * 2) setup_extlinux_image(config, log, devnum, basename, vmlinux, initrd, dtbdir, script) -- 2.43.0

From: Simon Glass <sjg@chromium.org> Recent work removed the if_type member. Update the code to use the new method for obtaining the interface type. Use hex so that large partition numbers (>=10) work correctly. Signed-off-by: Simon Glass <sjg@chromium.org> --- cmd/part_find.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/part_find.c b/cmd/part_find.c index c39fce21e40..68b66569204 100644 --- a/cmd/part_find.c +++ b/cmd/part_find.c @@ -107,7 +107,7 @@ static int part_find(int argc, char *const argv[]) &loader_part_no)) { char env[256]; - ret = snprintf(env, sizeof(env), "%s %d:%d", blk_get_if_type_name(desc->if_type), desc->devnum, loader_part_no); + ret = snprintf(env, sizeof(env), "%s %x:%x", blk_get_if_type_name(desc->if_type), desc->devnum, loader_part_no); if (ret < 0 || ret == sizeof(env)) return CMD_RET_FAILURE; if (env_set("target_part", env)) @@ -123,7 +123,7 @@ static int part_find(int argc, char *const argv[]) break; if (strcasecmp(argv[1], info.type_guid) == 0) { char env[256]; - ret = snprintf(env, sizeof(env), "%s %d:%d", blk_get_if_type_name(desc->if_type), desc->devnum, i); + ret = snprintf(env, sizeof(env), "%s %x:%x", blk_get_uclass_name(desc->uclass_id), desc->devnum, i); if (ret < 0 || ret == sizeof(env)) return CMD_RET_FAILURE; env_set("target_part", env); -- 2.43.0

From: Simon Glass <sjg@chromium.org> Enable this command for sandbox and the EFI app. Signed-off-by: Simon Glass <sjg@chromium.org> --- cmd/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/Kconfig b/cmd/Kconfig index af79770b4c6..44e1b60c592 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1539,6 +1539,7 @@ config CMD_PART config CMD_PART_FIND bool "part_find" depends on PARTITIONS + default y if SANDBOX || EFI_APP select HAVE_BLOCK_DEVICE select PARTITION_UUIDS select PARTITION_TYPE_GUID -- 2.43.0

From: Simon Glass <sjg@chromium.org> This function uses #ifdefs and ends up with a very large indent, Split it into two separate functions, one for the EFI app and one for other builds. Drop the use of config.h while we are here. Signed-off-by: Simon Glass <sjg@chromium.org> --- cmd/part_find.c | 154 +++++++++++++++++++++++++++++------------------- 1 file changed, 94 insertions(+), 60 deletions(-) diff --git a/cmd/part_find.c b/cmd/part_find.c index 68b66569204..f3ce5b417a8 100644 --- a/cmd/part_find.c +++ b/cmd/part_find.c @@ -5,12 +5,10 @@ */ #include <blk.h> -#include <config.h> #include <command.h> #include <dm.h> #include <env.h> #include <part.h> -#if defined(CONFIG_EFI_CLIENT) || defined(CONFIG_EFI_APP) #include <efi.h> #include <efi_api.h> @@ -47,21 +45,86 @@ static bool partition_is_on_device(const struct efi_device_path *device, } return false; } -#endif + +/** + * part_self_find() - Check if a device contains the loaded-image path + * + * @udev: Block device to check + * @loaded_image_path: EFI path of the loaded image + * Return 0 if found, -ENOENT if not, other -ve value on error + */ +static int part_self_find(struct udevice *udev, + struct efi_device_path *loaded_image_path) +{ + struct blk_desc *desc = dev_get_uclass_plat(udev); + + if (desc->uclass_id == UCLASS_EFI_MEDIA) { + struct efi_media_plat *plat = dev_get_plat(udev->parent); + u32 loader_part_no; + + if (partition_is_on_device(plat->device_path, loaded_image_path, + &loader_part_no)) { + char env[256]; + int ret; + + ret = snprintf(env, sizeof(env), "%s %x:%x", + blk_get_uclass_name(desc->uclass_id), + desc->devnum, loader_part_no); + if (ret < 0 || ret == sizeof(env)) + return -ENOSPC; + if (env_set("target_part", env)) + return -ENOMEM; + return 0; + } + } + + return -ENOENT; +} + +/** + * part_blk_find() - Check if a device contains a partition with a type uuid + * + * @udev: Block device to check + * @uuid: UUID to search for (in string form) + * Return 0 if found, -ENOENT if not, other -ve value on error + */ +static int part_blk_find(struct udevice *udev, const char *uuid) +{ + struct blk_desc *desc = dev_get_uclass_plat(udev); + int i; + + for (i = 1; i <= MAX_SEARCH_PARTITIONS; i++) { + struct disk_partition info; + int ret; + + ret = part_get_info(desc, i, &info); + if (ret) + break; + if (strcasecmp(uuid, info.type_guid) == 0) { + char env[256]; + + ret = snprintf(env, sizeof(env), "%s %x:%x", + blk_get_uclass_name(desc->uclass_id), + desc->devnum, i); + if (ret < 0 || ret == sizeof(env)) + return -ENOSPC; + debug("Setting target_part to %s\n", env); + if (env_set("target_part", env)) + return -ENOMEM; + return 0; + } + } + + return -ENOENT; +} static int part_find(int argc, char *const argv[]) { -#if defined(CONFIG_EFI_CLIENT) || defined(CONFIG_EFI_APP) efi_guid_t efi_devpath_guid = EFI_DEVICE_PATH_PROTOCOL_GUID; struct efi_device_path *loaded_image_path = NULL; - struct efi_boot_services *boot = efi_get_boot(); - struct efi_priv *priv = efi_get_priv(); bool part_self = false; -#endif struct driver *d = ll_entry_start(struct driver, driver); const int n_ents = ll_entry_count(struct driver, driver); - struct disk_partition info; - struct blk_desc *desc; struct driver *entry; struct udevice *udev; struct uclass *uc; @@ -70,16 +133,20 @@ static int part_find(int argc, char *const argv[]) if (argc != 2) return CMD_RET_USAGE; -#if defined(CONFIG_EFI_CLIENT) || defined(CONFIG_EFI_APP) - part_self = !strncmp(argv[1], "self", 6); - if (part_self) { - ret = boot->handle_protocol(priv->loaded_image->device_handle, - &efi_devpath_guid, - (void **)&loaded_image_path); - if (ret) - log_warning("failed to get device path for loaded image (ret=%d)", ret); + if (IS_ENABLED(CONFIG_EFI_CLIENT)) { + struct efi_boot_services *boot = efi_get_boot(); + struct efi_priv *priv = efi_get_priv(); + + part_self = !strncmp(argv[1], "self", 6); + if (part_self) { + ret = boot->handle_protocol(priv->loaded_image->device_handle, + &efi_devpath_guid, + (void **)&loaded_image_path); + if (ret) + log_warning("failed to get device path for loaded image (ret=%d)", + ret); + } } -#endif ret = uclass_get(UCLASS_BLK, &uc); if (ret) { @@ -90,50 +157,17 @@ static int part_find(int argc, char *const argv[]) if (entry->id != UCLASS_BLK) continue; uclass_foreach_dev(udev, uc) { - int i; - if (udev->driver != entry) continue; - desc = dev_get_uclass_plat(udev); -#if defined(CONFIG_EFI_CLIENT) || defined(CONFIG_EFI_APP) - if (part_self) { - if (desc->if_type == IF_TYPE_EFI_MEDIA) { - struct efi_media_plat *plat = - dev_get_plat(udev->parent); - __u32 loader_part_no; - - if (partition_is_on_device(plat->device_path, - loaded_image_path, - &loader_part_no)) { - char env[256]; - - ret = snprintf(env, sizeof(env), "%s %x:%x", blk_get_if_type_name(desc->if_type), desc->devnum, loader_part_no); - if (ret < 0 || ret == sizeof(env)) - return CMD_RET_FAILURE; - if (env_set("target_part", env)) - return CMD_RET_FAILURE; - return CMD_RET_SUCCESS; - } - } - } else { -#endif - for (i = 1; i <= MAX_SEARCH_PARTITIONS; i++) { - ret = part_get_info(desc, i, &info); - if (ret) - break; - if (strcasecmp(argv[1], info.type_guid) == 0) { - char env[256]; - ret = snprintf(env, sizeof(env), "%s %x:%x", blk_get_uclass_name(desc->uclass_id), desc->devnum, i); - if (ret < 0 || ret == sizeof(env)) - return CMD_RET_FAILURE; - env_set("target_part", env); - debug("Setting target_part to %s\n", env); - return CMD_RET_SUCCESS; - } - } -#if defined(CONFIG_EFI_CLIENT) || defined(CONFIG_EFI_APP) - } -#endif + + if (IS_ENABLED(CONFIG_EFI_CLIENT) && part_self) + ret = part_self_find(udev, loaded_image_path); + else + ret = part_blk_find(udev, argv[1]); + if (!ret) + return 0; + if (ret != -ENOENT) + break; } } -- 2.43.0

From: Simon Glass <sjg@chromium.org> Add some documentation and a test for this new command. Signed-off-by: Simon Glass <sjg@chromium.org> --- doc/usage/cmd/part_find.rst | 119 ++++++++++++++++++++++++++++++++++++ doc/usage/index.rst | 1 + test/cmd/Makefile | 1 + test/cmd/part_find.c | 42 +++++++++++++ 4 files changed, 163 insertions(+) create mode 100644 doc/usage/cmd/part_find.rst create mode 100644 test/cmd/part_find.c diff --git a/doc/usage/cmd/part_find.rst b/doc/usage/cmd/part_find.rst new file mode 100644 index 00000000000..fd5bd6578d5 --- /dev/null +++ b/doc/usage/cmd/part_find.rst @@ -0,0 +1,119 @@ +.. SPDX-License-Identifier: GPL-2.0+: + +.. index:: + single: part_find (command) + +part_find command +================= + +Synopsis +-------- + +:: + + part_find <uuid> + part_find self + +Description +----------- + +The `part_find` command is used to find a partition with a given type GUID. When +it finds one, it sets the target_part environment variable to the corresponding +``interface dev:part`` string. + +uuid + Universally Unique Identifier (UUID) to search, expressed as a string + +self + This is only permitted in the EFI app. It indicates that the required + partition is the one from which the app was started. + +Example +------- + +This shows searching for an EFI system partition and looking at the files on +that partition:: + + => host bind 1 mmc5.img + => part list host 0 + + Partition Map for host device 0 -- Partition Type: EFI + + Part Start LBA End LBA Name + Attributes + Type GUID + Partition GUID + 1 0x0000202f 0x0000282e "" + attrs: 0x0000000000000000 + type: ebd0a0a2-b9e5-4433-87c0-68b6b72699c7 + (data) + guid: 6b1e51e3-427c-9f45-a947-e467b7216356 + 2 0x0000002d 0x0000082c "" + attrs: 0x0000000000000000 + type: fe3a2a5d-4f32-41a7-b725-accc3285a309 + (cros-kern) + guid: dece619f-4876-e140-a6c9-8c208a0c9099 + 3 0x0000202e 0x0000202e "" + attrs: 0x0000000000000000 + type: 3cb8e202-3b7e-47dd-8a3c-7ff2a13cfcec + (cros-root) + guid: 078cee87-a195-ae4c-a974-8ba3a3d783b3 + 4 0x0000082d 0x0000102c "" + attrs: 0x0000000000000000 + type: fe3a2a5d-4f32-41a7-b725-accc3285a309 + (cros-kern) + guid: 08d2f20f-d941-fc43-96f6-948931289d71 + 5 0x0000202d 0x0000202d "" + attrs: 0x0000000000000000 + type: 3cb8e202-3b7e-47dd-8a3c-7ff2a13cfcec + (cros-root) + guid: 0b23ba00-a11c-ed4e-8b49-5e8738899569 + 6 0x00000029 0x00000029 "" + attrs: 0x0000000000000000 + type: fe3a2a5d-4f32-41a7-b725-accc3285a309 + (cros-kern) + guid: 6d8158a8-f82d-0d4d-8983-a3ada4eb9b73 + 7 0x0000002a 0x0000002a "" + attrs: 0x0000000000000000 + type: 3cb8e202-3b7e-47dd-8a3c-7ff2a13cfcec + (cros-root) + guid: 76e8f9b0-7db7-3844-8f18-21de93485211 + 8 0x0000102d 0x0000182c "" + attrs: 0x0000000000000000 + type: ebd0a0a2-b9e5-4433-87c0-68b6b72699c7 + (data) + guid: 071dfd2d-173c-f64b-9474-3318665e1d24 + 9 0x0000002b 0x0000002b "" + attrs: 0x0000000000000000 + type: 2e0a753d-9e48-43b0-8337-b15192cb1b5e + (cros-rsrv) + guid: b9d078c3-bafa-cd48-b771-a0aaa18d5008 + 10 0x0000002c 0x0000002c "" + attrs: 0x0000000000000000 + type: 2e0a753d-9e48-43b0-8337-b15192cb1b5e + (cros-rsrv) + guid: 7b0c0234-1a29-0c4f-bceb-40fae8f7b27c + 11 0x00000028 0x00000028 "" + attrs: 0x0000000000000000 + type: cab6e88e-abf3-4102-a07a-d4bb9be3c1d3 + (cros-fw) + guid: aced715d-cd1f-394a-9e3e-24b54a7b1472 + 12 0x0000182d 0x0000202c "" + attrs: 0x0000000000000000 + type: c12a7328-f81f-11d2-ba4b-00a0c93ec93b + (system) + guid: e1672afd-75ee-d74e-be95-8726b12b5e74 + => part_find c12a7328-f81f-11d2-ba4b-00a0c93ec93b + => print target_part + target_part=host 0:c + => ls $target_part + EFI/ + + 0 file(s), 1 dir(s) + + +Return value +------------ + +The return value $? is set to 0 (true) if the command succeeds. If no partition +could be found, the return value $? is set to 1 (false). diff --git a/doc/usage/index.rst b/doc/usage/index.rst index eeda632b1a0..4d6b2f5227a 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -100,6 +100,7 @@ Shell commands cmd/mv cmd/panic cmd/part + cmd/part_find cmd/pause cmd/pinmux cmd/printenv diff --git a/test/cmd/Makefile b/test/cmd/Makefile index 5fe6ac7bb3e..773b3d7569b 100644 --- a/test/cmd/Makefile +++ b/test/cmd/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_CMD_MEMINFO) += meminfo.o endif obj-$(CONFIG_CMD_MEMORY) += mem_copy.o obj-$(CONFIG_CMD_MEM_SEARCH) += mem_search.o +obj-$(CONFIG_CMD_PART_FIND) += part_find.o ifdef CONFIG_CMD_PCI obj-$(CONFIG_CMD_PCI_MPS) += pci_mps.o endif diff --git a/test/cmd/part_find.c b/test/cmd/part_find.c new file mode 100644 index 00000000000..1663d4a654f --- /dev/null +++ b/test/cmd/part_find.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Test for 'part_find' command + * + * Copyright 2024 Google LLC + * Written by Simon Glass <sjg@chromium.org> + */ + +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <dm/ofnode.h> +#include <dm/test.h> +#include <test/cmd.h> +#include <test/ut.h> + +/* Test 'part_find' command */ +static int cmd_test_part_find(struct unit_test_state *uts) +{ + struct udevice *dev; + ofnode root, node; + + /* Enable the requested mmc node since we need a second bootflow */ + root = oftree_root(oftree_default()); + node = ofnode_find_subnode(root, "mmc5"); + ut_assert(ofnode_valid(node)); + ut_assertok(lists_bind_fdt(gd->dm_root, node, &dev, NULL, false)); + + ut_assertok(device_probe(dev)); + + ut_assertok(env_set("target_part", NULL)); + ut_assertok(run_command("part_find c12a7328-f81f-11d2-ba4b-00a0c93ec93b", 0)); + ut_assert_console_end(); + ut_asserteq_str("mmc 5:c", env_get("target_part")); + + ut_asserteq(1, run_command("part_find invalid", 0)); + ut_asserteq_str("mmc 5:c", env_get("target_part")); + + ut_assert_console_end(); + + return 0; +} +CMD_TEST(cmd_test_part_find, UTF_CONSOLE | UTF_DM | UTF_SCAN_FDT); -- 2.43.0

From: Simon Glass <sjg@chromium.org> There should be no need to parse the LMB tables manually. Use the allocation-function provided instead. Adjust the argument checks while we are here. Also enable this command for sandbox and the EFI app, so it is built in CI. Signed-off-by: Simon Glass <sjg@chromium.org> --- cmd/Kconfig | 4 ++-- cmd/addr_find.c | 17 +++++++---------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/cmd/Kconfig b/cmd/Kconfig index 44e1b60c592..05c130b511e 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -129,8 +129,8 @@ config CMD_ACPI want to make hardware changes without the OS needing to be adjusted. config CMD_ADDR_FIND - bool "addr_find" - default y if EFI_APP + bool "addr_find" + default y if SANDBOX || EFI_APP help This command searches for an unused region of address space sufficiently large to hold a file. If successful, it sets the diff --git a/cmd/addr_find.c b/cmd/addr_find.c index 876c58feabd..64ecc816be3 100644 --- a/cmd/addr_find.c +++ b/cmd/addr_find.c @@ -17,8 +17,8 @@ DECLARE_GLOBAL_DATA_PTR; int do_addr_find(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { const char *filename; + phys_addr_t start; loff_t size; - ulong addr; int ret; if (!gd->fdt_blob) { @@ -47,24 +47,21 @@ int do_addr_find(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) return CMD_RET_FAILURE; } - addr = lmb_alloc(size, SZ_1M); - if (!addr) { + start = lmb_alloc(size, SZ_2M); + if ((long)start < 0) { log_err("Failed to find enough RAM for 0x%llx bytes\n", size); - return CMD_RET_FAILURE; - } - if (env_set_hex("loadaddr", addr)) { - log_err("Could not set loadaddr\n"); return CMD_RET_FAILURE; } - log_debug("Set loadaddr to %lx\n", addr); + env_set_hex("loadaddr", start); + debug("Set loadaddr to %llx\n", (u64)start); - return CMD_RET_SUCCESS; + return 0; } U_BOOT_CMD( - addr_find, 7, 1, do_addr_find, + addr_find, 4, 1, do_addr_find, "find a load address suitable for a file", "<interface> [<dev[:part]>] <filename>\n" "- find a consecutive region of memory sufficiently large to hold\n" -- 2.43.0

From: Simon Glass <sjg@chromium.org> We don't particularly need a devicetree to use the addr_find command, so drop this condition. Signed-off-by: Simon Glass <sjg@chromium.org> --- cmd/addr_find.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/cmd/addr_find.c b/cmd/addr_find.c index 64ecc816be3..9d88091f541 100644 --- a/cmd/addr_find.c +++ b/cmd/addr_find.c @@ -21,11 +21,6 @@ int do_addr_find(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) loff_t size; int ret; - if (!gd->fdt_blob) { - log_err("No FDT setup\n"); - return CMD_RET_FAILURE; - } - if (fs_set_blk_dev(argv[1], argc >= 3 ? argv[2] : NULL, FS_TYPE_ANY)) { log_err("Can't set block device\n"); return CMD_RET_FAILURE; -- 2.43.0

From: Simon Glass <sjg@chromium.org> Add documentation and a test for this command. Drop the use of config.h while we are here. Signed-off-by: Simon Glass <sjg@chromium.org> --- cmd/addr_find.c | 1 - doc/usage/cmd/addr_find.rst | 63 +++++++++++++++++++++++++++++++++++++ doc/usage/index.rst | 1 + test/cmd/Makefile | 1 + test/cmd/addr_find.c | 27 ++++++++++++++++ 5 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 doc/usage/cmd/addr_find.rst create mode 100644 test/cmd/addr_find.c diff --git a/cmd/addr_find.c b/cmd/addr_find.c index 9d88091f541..55f50830771 100644 --- a/cmd/addr_find.c +++ b/cmd/addr_find.c @@ -5,7 +5,6 @@ */ #include <blk.h> -#include <config.h> #include <command.h> #include <env.h> #include <fs_legacy.h> diff --git a/doc/usage/cmd/addr_find.rst b/doc/usage/cmd/addr_find.rst new file mode 100644 index 00000000000..0d16ffd236b --- /dev/null +++ b/doc/usage/cmd/addr_find.rst @@ -0,0 +1,63 @@ +.. SPDX-License-Identifier: GPL-2.0+: + +.. index:: + single: addr_find (command) + +addr_find command +================= + +Synopsis +-------- + +:: + + addr_find <interface> [<dev[:part]> [<filename>]] + +Description +----------- + +The addr_find command is used to find a consecutive region of memory +sufficiently large to hold a file, ensuring that the memory is not currently in +use for another file, etc. + +If successful, 'loadaddr' is set to the located address. + +The number of transferred bytes is saved in the environment variable filesize. +The load address is saved in the environment variable fileaddr. + +interface + interface for accessing the block device (mmc, sata, scsi, usb, ....) + +dev + device number + +part + partition number, defaults to 0 (whole device) + +filename + path to file, defaults to environment variable 'bootfile' + +Example +------- + +This shows obtaining an address suitable for a file on an mmc disk:: + + => ls mmc 1 + extlinux/ + 97135227 initramfs-5.3.7-301.fc31.armv7hl.img + dtb-5.3.7-301.fc31.armv7hl/ + 12531628 vmlinuz-5.3.7-301.fc31.armv7hl + + 2 file(s), 2 dir(s) + + => addr_find mmc 1 vmlinuz-5.3.7-301.fc31.armv7hl + => print loadaddr + loadaddr=7c00000 + => + + +Return value +------------ + +The return value $? is set to 0 (true) if the command succeeds. If no suitable +address could be found, the return value $? is set to 1 (false). diff --git a/doc/usage/index.rst b/doc/usage/index.rst index 4d6b2f5227a..21d6d120e7c 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -26,6 +26,7 @@ Shell commands :maxdepth: 1 cmd/acpi + cmd/addr_find cmd/addrmap cmd/armffa cmd/askenv diff --git a/test/cmd/Makefile b/test/cmd/Makefile index 773b3d7569b..ffb78f69041 100644 --- a/test/cmd/Makefile +++ b/test/cmd/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_CMD_PAUSE) += test_pause.o endif obj-y += exit.o obj-$(CONFIG_X86) += cpuid.o msr.o +obj-$(CONFIG_CMD_ADDR_FIND) += addr_find.o obj-$(CONFIG_CMD_ADDRMAP) += addrmap.o obj-$(CONFIG_CMD_BDI) += bdinfo.o obj-$(CONFIG_CMD_CHID) += chid.o diff --git a/test/cmd/addr_find.c b/test/cmd/addr_find.c new file mode 100644 index 00000000000..ce087759d9e --- /dev/null +++ b/test/cmd/addr_find.c @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Test for 'part_find' command + * + * Copyright 2024 Google LLC + * Written by Simon Glass <sjg@chromium.org> + */ + +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <dm/ofnode.h> +#include <dm/test.h> +#include <test/cmd.h> +#include <test/ut.h> + +/* Test 'addr_find' command */ +static int cmd_test_addr_find(struct unit_test_state *uts) +{ + ut_assertok(env_set("loadaddr", NULL)); + ut_assertok(run_command("addr_find mmc 1:1 vmlinuz-5.3.7-301.fc31.armv7hl", 0)); + ut_assert_console_end(); + + ut_assertnonnull(env_get("loadaddr")); + + return 0; +} +CMD_TEST(cmd_test_addr_find, UTF_CONSOLE | UTF_DM | UTF_SCAN_FDT); -- 2.43.0

From: Simon Glass <sjg@chromium.org> Several items use the SCENEOB_DISPLAY_MAX setting which does not work with alignment. Some others have a negative height, which is now checked, so results in the item being invisible. Fix these problems. Signed-off-by: Simon Glass <sjg@chromium.org> --- boot/bootflow_menu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/boot/bootflow_menu.c b/boot/bootflow_menu.c index 602a2e33c88..3365b5c3b06 100644 --- a/boot/bootflow_menu.c +++ b/boot/bootflow_menu.c @@ -67,7 +67,7 @@ int bootflow_menu_new(struct expo **expp) ret |= scene_txt_str(scn, "title", OBJ_MENU_TITLE, STR_MENU_TITLE, "U-Boot - Boot Menu", NULL); ret |= scene_obj_set_bbox(scn, OBJ_MENU_TITLE, 0, 32, - SCENEOB_DISPLAY_MAX, 30); + 1366, 60); ret |= scene_obj_set_halign(scn, OBJ_MENU_TITLE, SCENEOA_CENTRE); logo = video_get_u_boot_logo(NULL); @@ -90,13 +90,13 @@ int bootflow_menu_new(struct expo **expp) "The highlighted entry will be executed automatically in %ds.", NULL); ret |= scene_obj_set_bbox(scn, OBJ_PROMPT1A, 0, 590, - SCENEOB_DISPLAY_MAX, 30); + 1366, 590 + 40); ret |= scene_obj_set_bbox(scn, OBJ_PROMPT1B, 0, 620, - SCENEOB_DISPLAY_MAX, 30); + 1366, 620 + 40); ret |= scene_obj_set_bbox(scn, OBJ_PROMPT2, 100, 650, 1366 - 100, 700); ret |= scene_obj_set_bbox(scn, OBJ_AUTOBOOT, 0, 720, - SCENEOB_DISPLAY_MAX, 750); + 1366, 750); ret |= scene_obj_set_halign(scn, OBJ_PROMPT1A, SCENEOA_CENTRE); ret |= scene_obj_set_halign(scn, OBJ_PROMPT1B, SCENEOA_CENTRE); ret |= scene_obj_set_halign(scn, OBJ_PROMPT2, SCENEOA_CENTRE); -- 2.43.0

From: Simon Glass <sjg@chromium.org> Sometimes we want to position items individually rather than relying on the automatic scene layout. Provide a flag for this, expanding the type to cope. Also add an assertion that the flags fit in the available space. Signed-off-by: Simon Glass <sjg@chromium.org> --- boot/scene.c | 14 ++++++++++++++ include/expo.h | 27 +++++++++++++++++++++++++-- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/boot/scene.c b/boot/scene.c index d7e0d008b56..96130f160fc 100644 --- a/boot/scene.c +++ b/boot/scene.c @@ -359,6 +359,18 @@ int scene_obj_set_hide(struct scene *scn, uint id, bool hide) return 0; } +int scene_obj_set_manual(struct scene *scn, uint id, bool manual) +{ + int ret; + + ret = scene_obj_flag_clrset(scn, id, SCENEOF_MANUAL, + manual ? SCENEOF_MANUAL : 0); + if (ret) + return log_msg_ret("fla", ret); + + return 0; +} + int scene_obj_flag_clrset(struct scene *scn, uint id, uint clr, uint set) { struct scene_obj *obj; @@ -810,6 +822,8 @@ int scene_arrange(struct scene *scn) handle_alignment(obj->horiz, obj->vert, &obj->bbox, &obj->dims, xsize, ysize, &obj->ofs); + if (obj->flags & SCENEOF_MANUAL) + continue; switch (obj->type) { case SCENEOBJT_NONE: case SCENEOBJT_IMAGE: diff --git a/include/expo.h b/include/expo.h index d6983ee77d4..e359da1343b 100644 --- a/include/expo.h +++ b/include/expo.h @@ -313,6 +313,8 @@ enum scene_obj_align { * @SCENEOF_SYNC_SIZE: object's size (width/height) has changed * @SCENEOF_SYNC_WIDTH: object's widget has changed * @SCENEOF_SYNC_BBOX: object's bounding box has changed + * @SCENEOF_MANUAL: manually arrange the items associated with this object + * @SCENEOF_LAST: used just as a check for the size of the flags mask */ enum scene_obj_flags_t { SCENEOF_HIDE = 1 << 0, @@ -323,6 +325,9 @@ enum scene_obj_flags_t { SCENEOF_SYNC_SIZE = BIT(5), SCENEOF_SYNC_WIDTH = BIT(6), SCENEOF_SYNC_BBOX = BIT(7), + SCENEOF_MANUAL = BIT(8), + + SCENEOF_LAST, /* check for size of flags below */ }; enum { @@ -361,12 +366,16 @@ struct scene_obj { struct scene_obj_dims dims; enum scene_obj_align horiz; enum scene_obj_align vert; - u8 flags; - u8 bit_length; + u16 flags; u16 start_bit; + u8 bit_length; struct list_head sibling; }; +/* Ensure the largest flag value fits in the flags field */ +_Static_assert(SCENEOF_LAST < BIT(sizeof(((struct scene_obj *)0)->flags) * 8), + "scene_obj flags exceed flags field capacity"); + /* object can be highlighted when moving around expo */ static inline bool scene_obj_can_highlight(const struct scene_obj *obj) { @@ -977,6 +986,20 @@ int scene_obj_set_valign(struct scene *scn, uint id, enum scene_obj_align aln); */ int scene_obj_set_hide(struct scene *scn, uint id, bool hide); +/** + * scene_obj_set_manual() - Set whether an object arranges its dependents + * + * When this is enabled, scene_arrange() will refrain from moving objects + * attached to this one. E.g. for a menu, normally it moves text objects + * associated with the menu. + * + * @scn: Scene to update + * @id: ID of object to update + * @manual: true to disable arrange dependents when this object is updated + * Returns: 0 if OK, -ENOENT if @id is invalid + */ +int scene_obj_set_manual(struct scene *scn, uint id, bool manual); + /** * scene_menu_set_title() - Set the title of a menu * -- 2.43.0

From: Simon Glass <sjg@chromium.org> The current compiler is gcc-13 which presumably has fixed this bug. Revert the work-around so we can enable Truetype which needs floating point. This reverts commit f43312c974eaeb7301cb2638aa4ab05ed7ca4c44. --- arch/arm/config.mk | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/config.mk b/arch/arm/config.mk index 8a0167c165d..38c49c877c4 100644 --- a/arch/arm/config.mk +++ b/arch/arm/config.mk @@ -23,7 +23,6 @@ endif PLATFORM_RELFLAGS += -fno-common $(FIXED_REG) PLATFORM_RELFLAGS += $(call cc-option, -msoft-float) \ - $(call cc-option,-mgeneral-regs-only) \ $(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,)) # LLVM support -- 2.43.0

From: Simon Glass <sjg@chromium.org> Enable truetype fonts so the menus can look nicer. Signed-off-by: Simon Glass <sjg@chromium.org> --- configs/efi-arm_app64_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/efi-arm_app64_defconfig b/configs/efi-arm_app64_defconfig index 8defb83f9d4..35e8b4d36ed 100644 --- a/configs/efi-arm_app64_defconfig +++ b/configs/efi-arm_app64_defconfig @@ -49,6 +49,7 @@ CONFIG_SYSCON=y CONFIG_DM_RNG=y CONFIG_SYSRESET=y CONFIG_VIDEO=y +CONFIG_CONSOLE_TRUETYPE=y CONFIG_SYS_WHITE_ON_BLACK=y CONFIG_CONSOLE_SCROLL_LINES=5 CONFIG_FAT_WRITE=y -- 2.43.0

From: Simon Glass <sjg@chromium.org> This variable is not needed in the ARM app and can be confusing since there might not be memory at this location. Drop it. Signed-off-by: Simon Glass <sjg@chromium.org> --- board/efi/efi-arm_app/efi-arm_app.env | 1 - 1 file changed, 1 deletion(-) diff --git a/board/efi/efi-arm_app/efi-arm_app.env b/board/efi/efi-arm_app/efi-arm_app.env index 3b839f5710c..b28c15556de 100644 --- a/board/efi/efi-arm_app/efi-arm_app.env +++ b/board/efi/efi-arm_app/efi-arm_app.env @@ -6,7 +6,6 @@ */ /* common console settings */ -fdt_addr=40000000 stdin=serial stdout=serial,vidconsole stderr=serial,vidconsole -- 2.43.0

From: Simon Glass <sjg@chromium.org> Create a new file in lib/efi to handle conversion of keys from EFI format to characters, so we can use it from multiple places. Update the serial_efi driver accordingly. Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/serial/serial_efi.c | 15 +------------- include/efi.h | 32 +++++++++++++++++++++++++++++ lib/efi/Makefile | 1 + lib/efi/input.c | 40 +++++++++++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+), 14 deletions(-) create mode 100644 lib/efi/input.c diff --git a/drivers/serial/serial_efi.c b/drivers/serial/serial_efi.c index b506bb18ffb..6645520e2ca 100644 --- a/drivers/serial/serial_efi.c +++ b/drivers/serial/serial_efi.c @@ -73,7 +73,6 @@ static int serial_efi_get_key(struct serial_efi_priv *priv) static int serial_efi_getc(struct udevice *dev) { struct serial_efi_priv *priv = dev_get_priv(dev); - char conv_scan[10] = {0, 'p', 'n', 'f', 'b', 'a', 'e', 0, 8}; int ret, ch; ret = serial_efi_get_key(priv); @@ -81,19 +80,7 @@ static int serial_efi_getc(struct udevice *dev) return ret; priv->have_key = false; - ch = priv->key.unicode_char; - - /* - * Unicode char 8 (for backspace) is never returned. Instead we get a - * key scan code of 8. Handle this so that backspace works correctly - * in the U-Boot command line. - */ - if (!ch && priv->key.scan_code < sizeof(conv_scan)) { - ch = conv_scan[priv->key.scan_code]; - if (ch >= 'a') - ch -= 'a' - 1; - } - debug(" [%x %x %x] ", ch, priv->key.unicode_char, priv->key.scan_code); + ch = efi_decode_key(&priv->key); return ch; } diff --git a/include/efi.h b/include/efi.h index 52f3a014f1d..3d983bd69a4 100644 --- a/include/efi.h +++ b/include/efi.h @@ -24,6 +24,8 @@ #endif struct abuf; +struct efi_input_key; +struct efi_key_data; struct udevice; /* Type INTN in UEFI specification */ @@ -912,4 +914,34 @@ int efi_read_var(const u16 *name, const efi_guid_t *guid, u32 *attrp, uint16_t *efi_dp_str(struct efi_device_path *dp); +/** + * efi_decode_key() - Convert EFI input key to character + * + * Converts an EFI input key structure to a character code, handling + * both unicode characters and scan codes for special keys like arrow keys + * and backspace. + * + * Unicode characters are returned as-is, with the exception that carriage + * return ('\r') is converted to newline ('\n') for consistency with U-Boot + * conventions. + * + * @key: Pointer to EFI input key structure + * Return: Character code (0-255), or 0 if no valid character + */ +int efi_decode_key(struct efi_input_key *key); + +/** + * efi_decode_key_ex() - Convert EFI extended input key to character + * + * Converts an EFI extended key data structure to a character code by + * extracting the basic input key and calling efi_decode_key(). + * + * This function provides a convenient wrapper for handling EFI Simple Text + * Input EX Protocol key data, which includes modifier keys (currently ignored) + * + * @key_data: Pointer to EFI extended key data structure + * Return: Character code (0-255), or 0 if no valid character + */ +int efi_decode_key_ex(struct efi_key_data *key_data); + #endif /* _LINUX_EFI_H */ diff --git a/lib/efi/Makefile b/lib/efi/Makefile index 842067dcab3..c2e56df7144 100644 --- a/lib/efi/Makefile +++ b/lib/efi/Makefile @@ -6,6 +6,7 @@ obj-y += basename.o obj-y += device_path.o obj-y += helper.o +obj-y += input.o obj-y += load_options.o obj-y += memory.o obj-y += run.o diff --git a/lib/efi/input.c b/lib/efi/input.c new file mode 100644 index 00000000000..4d6b81bf183 --- /dev/null +++ b/lib/efi/input.c @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * EFI input key decoding functions + * + * Copyright (c) 2015 Google, Inc + * Written by Simon Glass <sjg@chromium.org> + */ + +#define LOG_CATEGORY LOGC_EFI + +#include <efi.h> +#include <efi_api.h> +#include <cli.h> + +int efi_decode_key(struct efi_input_key *key) +{ + static const char conv_scan[] = {0, 'p', 'n', 'f', 'b', 'a', 'e', 0, 8}; + int ch; + + ch = key->unicode_char; + + /* + * Unicode char 8 (for backspace) is never returned. Instead we get a + * key scan code of 8. Handle this so that backspace works correctly + * in the U-Boot command line. + */ + if (!ch && key->scan_code < sizeof(conv_scan)) { + ch = conv_scan[key->scan_code]; + if (ch >= 'a') + ch -= 'a' - 1; + } + log_debug(" [%x %x %x] ", ch, key->unicode_char, key->scan_code); + + return ch; +} + +int efi_decode_key_ex(struct efi_key_data *key_data) +{ + return efi_decode_key(&key_data->key); +} -- 2.43.0

From: Simon Glass <sjg@chromium.org> Add a keyboard driver which returns keys produced by EFI. This is basically the same as the serial driver but it doesn't combine input and output into one driver, allowing more control when using a separate screen. Add the required devicetree fragment for ARM (only). Signed-off-by: Simon Glass <sjg@chromium.org> --- arch/arm/dts/efi-arm_app.dts | 4 + drivers/input/Kconfig | 14 +++ drivers/input/Makefile | 2 + drivers/input/efi_keyb.c | 173 +++++++++++++++++++++++++++++++++++ 4 files changed, 193 insertions(+) create mode 100644 drivers/input/efi_keyb.c diff --git a/arch/arm/dts/efi-arm_app.dts b/arch/arm/dts/efi-arm_app.dts index d2a008fba6a..1a7ed77e6a8 100644 --- a/arch/arm/dts/efi-arm_app.dts +++ b/arch/arm/dts/efi-arm_app.dts @@ -29,6 +29,10 @@ bootph-some-ram; }; + keyboard { + compatible = "efi-keyboard"; + }; + mouse { compatible = "efi,mouse"; }; diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 7b34902dd7c..6e19f6f7b3d 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -14,6 +14,7 @@ config TPL_INPUT config DM_KEYBOARD bool "Enable driver model keyboard support" depends on DM + default y if EFI_APP help This adds a uclass for keyboards and implements keyboard support using driver model. The API is implemented by keyboard.h and @@ -63,6 +64,19 @@ config CROS_EC_KEYB Messages are used to request key scans from the EC and these are then decoded into keys by this driver. +config EFI_KEYB + bool "Keyboard on top of EFI" + depends on DM_KEYBOARD && EFI_APP + default y + help + Provides a keyboard driver for EFI. While this is often connected + to the serial driver, that can be confusing on a device which has + both serial and keyboard devices. Provide a separate keyboard + driver. + + For now this is not used, pending further work on teasing this + apart within the EFI subsystem. + config SPL_CROS_EC_KEYB bool "Enable Chrome OS EC keyboard support in SPL" depends on SPL_INPUT diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 4debad9e713..e8888079a1c 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -8,6 +8,8 @@ obj-$(CONFIG_$(PHASE_)OF_CONTROL) += key_matrix.o obj-$(CONFIG_$(PHASE_)DM_KEYBOARD) += input.o keyboard-uclass.o obj-$(CONFIG_BUTTON_KEYBOARD) += button_kbd.o +obj-$(CONFIG_EFI_KEYB) += efi_keyb.o + ifndef CONFIG_XPL_BUILD obj-$(CONFIG_APPLE_SPI_KEYB) += apple_spi_kbd.o diff --git a/drivers/input/efi_keyb.c b/drivers/input/efi_keyb.c new file mode 100644 index 00000000000..0cbb438c6de --- /dev/null +++ b/drivers/input/efi_keyb.c @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * EFI-keyboard input driver + * + * Uses EFI's Simple Text Input Protocol, polling keystrokes and providing them + * to stdio + */ + +#define LOG_CATEGORY LOGC_EFI + +#include <dm.h> +#include <efi_loader.h> +#include <efi.h> +#include <keyboard.h> +#include <log.h> +#include <stdio_dev.h> +#include <linux/delay.h> + +/* + * struct efi_kbd_priv - private information for the keyboard + * + * @ex_con + */ +struct efi_kbd_priv { + struct efi_simple_text_input_ex_protocol *ex_con; + struct efi_simple_text_input_protocol *con_in; + struct efi_input_key key; + struct efi_key_data exkey; + + bool have_key; +}; + +/** + * efi_kbd_tstc() - Test for a character from EFI + * + * @dev: keyboard device + * Return: 1 if a character is available, 0 otherwise. + */ +static int efi_kbd_tstc(struct udevice *dev) +{ + struct efi_kbd_priv *priv = dev_get_priv(dev); + efi_status_t status; + + /* If we already have a key from a previous check, report it's available */ + if (priv->have_key) + return 1; + + /* wait until we don't see EFI_NOT_READY */ + if (priv->ex_con) { + status = priv->ex_con->read_key_stroke_ex(priv->ex_con, + &priv->exkey); + } else { + status = priv->con_in->read_key_stroke(priv->con_in, + &priv->key); + } + if (!status) { + priv->have_key = true; + return 1; + } + + return 0; +} + +/** + * efi_kbd_getc() - Get a character from EFI + * + * Waits until a key is available and returns the associated character + * + * @dev: stdio device pointer + * Return: character code, or 0 if none + */ +static int efi_kbd_getc(struct udevice *dev) +{ + struct efi_kbd_priv *priv = dev_get_priv(dev); + + if (!efi_kbd_tstc(dev)) + return 0; + + priv->have_key = false; + if (priv->ex_con) { + struct efi_input_key *exkey = &priv->exkey.key; + + log_debug("got exkey %x scan %x\n", exkey->unicode_char, + exkey->scan_code); + return efi_decode_key(exkey); + } else { + struct efi_input_key *key = &priv->key; + + log_debug("got key %x\n", key->unicode_char); + return efi_decode_key(key); + } + + return 0; +} + +/** + * efi_kbd_start() - Start the driver + * + * Reset the keyboard ready for use + * + * Return: 0 on success (always) + */ +static int efi_kbd_start(struct udevice *dev) +{ + struct efi_kbd_priv *priv = dev_get_priv(dev); + + log_debug("keyboard start\n"); + + /* reset keyboard to drop anything pressed during UEFI startup */ + priv->con_in->reset(priv->con_in, true); + if (priv->ex_con) + priv->ex_con->reset(priv->ex_con, true); + priv->have_key = false; + + return 0; +} + +static int efi_kbd_probe(struct udevice *dev) +{ + struct keyboard_priv *uc_priv = dev_get_uclass_priv(dev); + struct efi_system_table *systab = efi_get_sys_table(); + struct stdio_dev *sdev = &uc_priv->sdev; + struct efi_kbd_priv *priv = dev_get_priv(dev); + efi_status_t ret_efi; + int ret; + + log_debug("keyboard probe '%s'\n", dev->name); + priv->con_in = systab->con_in; + + /* Try to get the EFI Simple Text Input EX protocol from console handle */ + if (systab->con_in_handle) { + efi_guid_t ex_guid = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID; + + ret_efi = efi_get_boot()->open_protocol(systab->con_in_handle, + &ex_guid, + (void **)&priv->ex_con, + NULL, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret_efi != EFI_SUCCESS) { + log_debug("Extended input protocol not available\n"); + priv->ex_con = NULL; + } + } + + strcpy(sdev->name, "efi-kbd"); + ret = input_stdio_register(sdev); + if (ret) { + log_err("Failed to register\n"); + return ret; + } + + return 0; +} + +static const struct keyboard_ops efi_kbd_ops = { + .start = efi_kbd_start, + .tstc = efi_kbd_tstc, + .getc = efi_kbd_getc, +}; + +static const struct udevice_id efi_kbd_ids[] = { + { .compatible = "efi-keyboard" }, + { } +}; + +U_BOOT_DRIVER(efi_kbd) = { + .name = "efi_kbd", + .id = UCLASS_KEYBOARD, + .of_match = efi_kbd_ids, + .ops = &efi_kbd_ops, + .priv_auto = sizeof(struct efi_kbd_priv), + .probe = efi_kbd_probe, +}; -- 2.43.0
participants (1)
-
Simon Glass