efi_loader: patches for Shell.efi
cover efi_loader: patches for Shell.efi
Re-send of the patch series to get Shell.efi working, and almost get SCT.efi (the UEFI test suite) working.
Since last time, I've updated to Heinrich's latest SetWatchdogTimer patch (as of yesterday evening), and adressed review comments on the three new sets of protocols added. Part of that, to avoid moving changes from my later patch that added implementation on top of Leif's initial stubs was done by simply squashing the patches together.
Heinrich Schuchardt (1):
efi_loader: implement SetWatchdogTimer
Leif Lindholm (3):
efi_loader: Initial EFI_DEVICE_PATH_UTILITIES_PROTOCOL
efi_loader: Initial HII protocols
efi_loader: Initial EFI_UNICODE_COLLATION_PROTOCOL
Rob Clark (7):
efi_loader: SIMPLE_TEXT_INPUT_EX plus wire up objects properly
efi_loader: console support for color attributes
efi_loader: Decouple EFI input/output from stdin/stdout
efi_loader: fix events
efi_loader: Fix disk dp's for pre-DM/legacy devices
efi_loader: Add mem-mapped for fallback
efi_loader: exclude openrd devices
cmd/bootefi.c | 24 ++ include/efi_api.h | 438 ++++++++++++++++++++++++- include/efi_loader.h | 29 +- lib/efi_loader/Kconfig | 2 +- lib/efi_loader/Makefile | 3 +- lib/efi_loader/efi_boottime.c | 256 ++++++++------- lib/efi_loader/efi_console.c | 398 +++++++++++++++++++--- lib/efi_loader/efi_device_path.c | 24 ++ lib/efi_loader/efi_device_path_to_text.c | 9 + lib/efi_loader/efi_device_path_utilities.c | 88 +++++ lib/efi_loader/efi_disk.c | 11 + lib/efi_loader/efi_hii.c | 507 +++++++++++++++++++++++++++++ lib/efi_loader/efi_unicode.c | 170 ++++++++++ lib/efi_loader/efi_watchdog.c | 86 +++++ 14 files changed, 1861 insertions(+), 184 deletions(-) create mode 100644 lib/efi_loader/efi_device_path_utilities.c create mode 100644 lib/efi_loader/efi_hii.c create mode 100644 lib/efi_loader/efi_unicode.c create mode 100644 lib/efi_loader/efi_watchdog.c
Signature · 1 line
2.13.6
PATCH 1/11 efi_loader: Initial EFI_DEVICE_PATH_UTILITIES_PROTOCOL
From: Leif Lindholm <[email protected]>
Not complete, but enough for Shell.efi and SCT.efi. We'll implement the rest as needed or once we have SCT running properly so there is a way to validate the interface against the conformance test suite.
Initial skeleton written by Leif, and then implementation by myself.
--- include/efi_api.h | 34 +++++++++++- include/efi_loader.h | 2 + lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_boottime.c | 4 ++ lib/efi_loader/efi_device_path_utilities.c | 88 ++++++++++++++++++++++++++++++ 5 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 lib/efi_loader/efi_device_path_utilities.c
include/efi_api.h +32 -2
@@ -28,8 +28,9 @@ enum efi_timer_delay { EFI_TIMER_RELATIVE = 2 }; -#define UINTN size_t -typedef long INTN ; +#define UINTN size_t/* TODO this should be removed in a future patch */ +typedef size_t efi_uintn_t ; +typedef ssize_t efi_intn_t ;typedef uint16_t *efi_string_t ;#define EVT_TIMER 0x80000000
@@ -506,6 +507,35 @@ struct efi_device_path_to_text_protocol bool allow_shortcuts); }; +#define EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID \ + EFI_GUID(0x0379be4e, 0xd706, 0x437d, \ + 0xb0, 0x37, 0xed, 0xb8, 0x2f, 0xb7, 0x72, 0xa4) + +struct efi_device_path_utilities_protocol { + efi_uintn_t (EFIAPI *get_device_path_size)( + const struct efi_device_path *device_path); + struct efi_device_path *(EFIAPI *duplicate_device_path)( +const struct efi_device_path *device_path); + struct efi_device_path *(EFIAPI *append_device_path)( +const struct efi_device_path *src1, +const struct efi_device_path *src2); + struct efi_device_path *(EFIAPI *append_device_node)( +const struct efi_device_path *device_path, +const struct efi_device_path *device_node); + struct efi_device_path *(EFIAPI *append_device_path_instance)( +const struct efi_device_path *device_path, +const struct efi_device_path *device_path_instance); + struct efi_device_path *(EFIAPI *get_next_device_path_instance)( +struct efi_device_path **device_path_instance, +efi_uintn_t *device_path_instance_size); + bool (EFIAPI *is_device_path_multi_instance)( +const struct efi_device_path *device_path); + struct efi_device_path *(EFIAPI *create_device_node)( +uint8_t node_type, +uint8_t node_sub_type, +uint16_t node_length); +}; +#define EFI_GOP_GUID \ EFI_GUID(0x9042a9de, 0x23dc, 0x4a38, \ 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a)
include/efi_loader.h +2 -0
@@ -79,6 +79,7 @@ extern const struct efi_simple_text_output_protocol efi_con_out;extern struct efi_simple_input_interface efi_con_in;extern const struct efi_console_control_protocol efi_console_control;extern const struct efi_device_path_to_text_protocol efi_device_path_to_text; +extern const struct efi_device_path_utilities_protocol efi_device_path_utilities;uint16_t *efi_dp_str (struct efi_device_path *dp);
@@ -89,6 +90,7 @@ extern const efi_guid_t efi_guid_loaded_image;extern const efi_guid_t efi_guid_device_path_to_text_protocol;extern const efi_guid_t efi_simple_file_system_protocol_guid;extern const efi_guid_t efi_file_info_guid; +extern const efi_guid_t efi_guid_device_path_utilities_protocol;extern unsigned int __efi_runtime_start, __efi_runtime_stop;extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;
lib/efi_loader/Makefile +1 -0
@@ -17,6 +17,7 @@ endif obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o +obj-y += efi_device_path_utilities.o obj-y += efi_file.o efi_variable.o efi_bootmgr.o obj-$(CONFIG_LCD) += efi_gop.o obj-$(CONFIG_DM_VIDEO) += efi_gop.o
lib/efi_loader/efi_boottime.c +4 -0
@@ -1153,6 +1153,10 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob obj->protocols[3 ].protocol_interface = (void *)&efi_device_path_to_text; + obj->protocols[4 ].guid = &efi_guid_device_path_utilities_protocol; + obj->protocols[4 ].protocol_interface = + (void *)&efi_device_path_utilities; + info->file_path = file_path; info->device_handle =efi_dp_find_obj (device_path,NULL );
lib/efi_loader/efi_device_path_utilities.c new file +88 -0
88 lines not on this page · raw message
Signature · 1 line
2.13.6
PATCH 1/11 efi_loader: Initial EFI_DEVICE_PATH_UTILITIES_PROTOCOL
Quoted 76 lines · Rob Clark
From: Leif Lindholm <[email protected]>
Not complete, but enough for Shell.efi and SCT.efi. We'll implement the rest as needed or once we have SCT running properly so there is a way to validate the interface against the conformance test suite.
Initial skeleton written by Leif, and then implementation by myself.
Cc Leif Lindholm <[email protected]>Signed-off-by Rob Clark <[email protected]>--- include/efi_api.h | 34 +++++++++++- include/efi_loader.h | 2 + lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_boottime.c | 4 ++ lib/efi_loader/efi_device_path_utilities.c | 88 ++++++++++++++++++++++++++++++ 5 files changed, 127 insertions(+), 2 deletions(-)create mode 100644
lib/efi_loader/efi_device_path_utilities.cinclude/efi_api.h +32
-2@@ -28,8 +28,9 @@ enum efi_timer_delay { EFI_TIMER_RELATIVE = 2 }; -#define UINTN size_t -typedef long INTN ; +#define UINTN size_t/* TODO this should be removed in a future patch */ +typedef size_t efi_uintn_t ; +typedef ssize_t efi_intn_t ;typedef uint16_t *efi_string_t ;#define EVT_TIMER 0x80000000@@ -506,6 +507,35 @@ struct efi_device_path_to_text_protocol bool allow_shortcuts); }; +#define EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID \ + EFI_GUID(0x0379be4e, 0xd706, 0x437d, \ + 0xb0, 0x37, 0xed, 0xb8, 0x2f, 0xb7, 0x72, 0xa4) + +struct efi_device_path_utilities_protocol { + efi_uintn_t (EFIAPI *get_device_path_size)( + const struct efi_device_path *device_path); + struct efi_device_path *(EFIAPI *duplicate_device_path)( +const struct efi_device_path *device_path); + struct efi_device_path *(EFIAPI *append_device_path)( +const struct efi_device_path *src1, +const struct efi_device_path *src2); + struct efi_device_path *(EFIAPI *append_device_node)( +const struct efi_device_path *device_path, +const struct efi_device_path *device_node); + struct efi_device_path *(EFIAPI *append_device_path_instance)( +const struct efi_device_path *device_path, +const struct efi_device_path *device_path_instance); + struct efi_device_path *(EFIAPI *get_next_device_path_instance)( +struct efi_device_path **device_path_instance, +efi_uintn_t *device_path_instance_size); + bool (EFIAPI *is_device_path_multi_instance)( +const struct efi_device_path *device_path); + struct efi_device_path *(EFIAPI *create_device_node)( +uint8_t node_type, +uint8_t node_sub_type, +uint16_t node_length); +}; +#define EFI_GOP_GUID \ EFI_GUID(0x9042a9de, 0x23dc, 0x4a38, \ 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a)include/efi_loader.h +0
-0
include/efi_loader.h extern const struct efi_simple_text_output_protocol efi_con_out; · line 82
Quoted 4 lines
include/efi_loader.h +1
-0@@ -79,6 +79,7 @@ extern const struct efi_simple_text_output_protocol efi_con_out;extern struct efi_simple_input_interface efi_con_in;extern const struct efi_console_control_protocol efi_console_control;extern const struct efi_device_path_to_text_protocol efi_device_path_to_text; +extern const struct efi_device_path_utilities_protocol efi_device_path_utilities;
WARNING: line over 80 characters
#95: FILE: include/efi_loader.h:82:
Please, always run scripts/checkpatch.pl before submitting.
lib/efi_loader/efi_boottime.c void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob
Quoted 28 lines
include/efi_loader.h +1
-0uint16_t *efi_dp_str (struct efi_device_path *dp);@@ -89,6 +90,7 @@ extern const efi_guid_t efi_guid_loaded_image;extern const efi_guid_t efi_guid_device_path_to_text_protocol;extern const efi_guid_t efi_simple_file_system_protocol_guid;extern const efi_guid_t efi_file_info_guid; +extern const efi_guid_t efi_guid_device_path_utilities_protocol;extern unsigned int __efi_runtime_start, __efi_runtime_stop;extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;lib/efi_loader/Makefile +1
-0@@ -17,6 +17,7 @@ endif obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o +obj-y += efi_device_path_utilities.o obj-y += efi_file.o efi_variable.o efi_bootmgr.o obj-$(CONFIG_LCD) += efi_gop.o obj-$(CONFIG_DM_VIDEO) += efi_gop.olib/efi_loader/efi_boottime.c +0
-0@@ -1153,6 +1153,10 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob
Applying: efi_loader: Initial EFI_DEVICE_PATH_UTILITIES_PROTOCOL
error: patch failed: lib/efi_loader/efi_boottime.c:1153
Please, rebase.
Quoted 24 lines
lib/efi_loader/efi_boottime.c +4
-0obj->protocols[3 ].protocol_interface = (void *)&efi_device_path_to_text; + obj->protocols[4 ].guid = &efi_guid_device_path_utilities_protocol; + obj->protocols[4 ].protocol_interface = + (void *)&efi_device_path_utilities; + info->file_path = file_path; info->device_handle =efi_dp_find_obj (device_path,NULL );lib/efi_loader/efi_device_path_utilities.c new file +8
-0@@ -0,0 +1,88 @@ +/* +* EFI device path interface +* +* Copyright (c) 2017 Leif Lindholm +* +* SPDX-License-Identifier: GPL-2.0+ +*/ +
lib/efi_loader/efi_device_path_utilities.c line 18
Quoted 10 lines
lib/efi_loader/efi_device_path_utilities.c new file +10
-0+#include <common.h> +#include <efi_loader.h> + +const efi_guid_t efi_guid_device_path_utilities_protocol = +EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID ; + +static efi_uintn_t EFIAPI get_device_path_size( +const struct efi_device_path *device_path) +{ +efi_uintn_t sz =0 ;
WARNING: Missing a blank line after declarations #158: FILE: lib/efi_loader/efi_device_path_utilities.c:19:
Regards
Heinrich
Quoted 71 lines
lib/efi_loader/efi_device_path_utilities.c new file +70
-0+EFI_ENTRY ("%p" , device_path); +/* size includes the END node: */ +if (device_path) + sz =efi_dp_size (device_path) +sizeof (struct efi_device_path ); +return EFI_EXIT (sz); +} + +static struct efi_device_path * EFIAPI duplicate_device_path( +const struct efi_device_path *device_path) +{ +EFI_ENTRY ("%p" , device_path); +return EFI_EXIT (efi_dp_dup (device_path)); +} + +static struct efi_device_path * EFIAPI append_device_path( +const struct efi_device_path *src1, +const struct efi_device_path *src2) +{ +EFI_ENTRY ("%p, %p" , src1, src2); +return EFI_EXIT (efi_dp_append (src1, src2)); +} + +static struct efi_device_path * EFIAPI append_device_node( +const struct efi_device_path *device_path, +const struct efi_device_path *device_node) +{ +EFI_ENTRY ("%p, %p" , device_path, device_node); +return EFI_EXIT (efi_dp_append_node (device_path, device_node)); +} + +static struct efi_device_path * EFIAPI append_device_path_instance( +const struct efi_device_path *device_path, +const struct efi_device_path *device_path_instance) +{ +EFI_ENTRY ("%p, %p" , device_path, device_path_instance); +return EFI_EXIT (NULL ); +} + +static struct efi_device_path * EFIAPI get_next_device_path_instance( +struct efi_device_path **device_path_instance, +efi_uintn_t *device_path_instance_size) +{ +EFI_ENTRY ("%p, %p" , device_path_instance, device_path_instance_size); +return EFI_EXIT (NULL ); +} + +static bool EFIAPI is_device_path_multi_instance( +const struct efi_device_path *device_path) +{ +EFI_ENTRY ("%p" , device_path); +return EFI_EXIT (false); +} + +static struct efi_device_path * EFIAPI create_device_node( +uint8_t node_type,uint8_t node_sub_type,uint16_t node_length) +{ +EFI_ENTRY ("%u, %u, %u" , node_type, node_sub_type, node_length); +return EFI_EXIT (NULL ); +} + +const struct efi_device_path_utilities_protocol efi_device_path_utilities = { + .get_device_path_size = get_device_path_size, + .duplicate_device_path = duplicate_device_path, + .append_device_path = append_device_path, + .append_device_node = append_device_node, + .append_device_path_instance = append_device_path_instance, + .get_next_device_path_instance = get_next_device_path_instance, + .is_device_path_multi_instance = is_device_path_multi_instance, + .create_device_node = create_device_node, +};
PATCH 1/11 efi_loader: Initial EFI_DEVICE_PATH_UTILITIES_PROTOCOL
In reply to Rob ClarkQuoted 24 lines · Rob Clark
From: Leif Lindholm <[email protected]>
Not complete, but enough for Shell.efi and SCT.efi. We'll implement the rest as needed or once we have SCT running properly so there is a way to validate the interface against the conformance test suite.
Initial skeleton written by Leif, and then implementation by myself.
Cc Leif Lindholm <[email protected]>Signed-off-by Rob Clark <[email protected]>--- include/efi_api.h | 34 +++++++++++- include/efi_loader.h | 2 + lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_boottime.c | 4 ++ lib/efi_loader/efi_device_path_utilities.c | 88 ++++++++++++++++++++++++++++++ 5 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 lib/efi_loader/efi_device_path_utilities.cinclude/efi_api.h +0
-0
include/efi_api.h enum efi_timer_delay { · line 31
Quoted 6 lines
include/efi_api.h +1
-2@@ -28,8 +28,9 @@ enum efi_timer_delay { EFI_TIMER_RELATIVE = 2 }; -#define UINTN size_t -typedef long INTN ; +#define UINTN size_t/* TODO this should be removed in a future patch */
$ git grep UINTN | wc -l 13
Just send a preceding patch that introduces efi_uintn_t and replaces all occurences of UINTN with it.
The uintn bits shouldn't be part of the EFI_DEVICE_PATH_UTILITIES_PROTOCOL patch anyways :).
include/efi_api.h enum efi_timer_delay { · line 34
Quoted 3 lines
include/efi_api.h +2
-0+typedef size_t efi_uintn_t ; +typedef ssize_t efi_intn_t ;typedef uint16_t *efi_string_t ;
Alex
PATCH 1/11 efi_loader: Initial EFI_DEVICE_PATH_UTILITIES_PROTOCOL
Quoted 37 lines · Alexander Graf
Quoted 24 lines · Rob Clark
From: Leif Lindholm <[email protected]>
Not complete, but enough for Shell.efi and SCT.efi. We'll implement the rest as needed or once we have SCT running properly so there is a way to validate the interface against the conformance test suite.
Initial skeleton written by Leif, and then implementation by myself.
Cc Leif Lindholm <[email protected]>Signed-off-by Rob Clark <[email protected]>--- include/efi_api.h | 34 +++++++++++- include/efi_loader.h | 2 + lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_boottime.c | 4 ++ lib/efi_loader/efi_device_path_utilities.c | 88 ++++++++++++++++++++++++++++++ 5 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 lib/efi_loader/efi_device_path_utilities.cinclude/efi_api.h +0
-0include/efi_api.h enum efi_timer_delay { · line 31
Quoted 6 lines
include/efi_api.h +1
-2@@ -28,8 +28,9 @@ enum efi_timer_delay { EFI_TIMER_RELATIVE = 2 }; -#define UINTN size_t -typedef long INTN ; +#define UINTN size_t/* TODO this should be removed in a future patch */ $ git grep UINTN | wc -l 13
Quoted 6 lines
Just send a preceding patch that introduces
efi_uintn_tand replaces all occurences of UINTN with it.The uintn bits shouldn't be part of the
EFI_DEVICE_PATH_UTILITIES_PROTOCOLpatch anyways :).
Heinrich mentioned he was doing that, so I didn't want to step on feet. I figured this was the easiest approach regardless of the order of merging patches (should be simple enough to drop the duplicate efi_uintn_t)
BR,
-R
Quoted 6 lines
include/efi_api.h enum efi_timer_delay { · line 34
Quoted 3 lines
include/efi_api.h +2
-0+typedef size_t efi_uintn_t ; +typedef ssize_t efi_intn_t ;typedef uint16_t *efi_string_t ;Alex
PATCH 1/11 efi_loader: Initial EFI_DEVICE_PATH_UTILITIES_PROTOCOL
Quoted 41 lines · Rob Clark
Quoted 40 lines · Alexander Graf
Quoted 24 lines · Rob Clark
From: Leif Lindholm <[email protected]>
Not complete, but enough for Shell.efi and SCT.efi. We'll implement the rest as needed or once we have SCT running properly so there is a way to validate the interface against the conformance test suite.
Initial skeleton written by Leif, and then implementation by myself.
Cc Leif Lindholm <[email protected]>Signed-off-by Rob Clark <[email protected]>--- include/efi_api.h | 34 +++++++++++- include/efi_loader.h | 2 + lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_boottime.c | 4 ++ lib/efi_loader/efi_device_path_utilities.c | 88 ++++++++++++++++++++++++++++++ 5 files changed, 127 insertions(+), 2 deletions(-)create mode 100644
lib/efi_loader/efi_device_path_utilities.cinclude/efi_api.h +0
-0include/efi_api.h enum efi_timer_delay { · line 31
Quoted 6 lines
include/efi_api.h +1
-2@@ -28,8 +28,9 @@ enum efi_timer_delay { EFI_TIMER_RELATIVE = 2 }; -#define UINTN size_t -typedef long INTN ; +#define UINTN size_t/* TODO this should be removed in a future patch */ $ git grep UINTN | wc -l 13Just send a preceding patch that introduces
efi_uintn_tand replaces all occurences of UINTN with it.
Quoted 8 lines
Quoted 3 lines
The uintn bits shouldn't be part of the
EFI_DEVICE_PATH_UTILITIES_PROTOCOLpatch anyways :).Heinrich mentioned he was doing that, so I didn't want to step on feet. I figured this was the easiest approach regardless of the order of merging patches (should be simple enough to drop the duplicate
efi_uintn_t)
I do not mind if you put the change in one of your patches. Just do what is needed to get your patch series merged.
Best regards
Heinrich
Quoted 11 lines
BR,
-RQuoted 6 lines
include/efi_api.h enum efi_timer_delay { · line 34
Quoted 3 lines
include/efi_api.h +2
-0+typedef size_t efi_uintn_t ; +typedef ssize_t efi_intn_t ;typedef uint16_t *efi_string_t ;Alex
PATCH 2/11 efi_loader: Initial HII protocols
In reply to Rob ClarkFrom: Leif Lindholm <[email protected]>
Enough implementation of the following protocols to run Shell.efi and SCT.efi:
EfiHiiConfigRoutingProtocolGuid
EfiHiiDatabaseProtocol
EfiHiiStringProtocol
We'll fill in the rest once SCT is running properly so we can validate the implementation against the conformance test suite.
Initial skeleton written by Leif, and then implementation by myself.
--- include/efi_api.h | 261 ++++++++++++++++++++++ include/efi_loader.h | 6 + lib/efi_loader/Makefile | 2 +- lib/efi_loader/efi_boottime.c | 9 + lib/efi_loader/efi_hii.c | 507 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 784 insertions(+), 1 deletion(-) create mode 100644 lib/efi_loader/efi_hii.c
include/efi_api.h +261 -0
@@ -16,6 +16,7 @@#define _EFI_API_H#include <efi.h> +#include <charset.h> #ifdef CONFIG_EFI_LOADER #include <asm/setjmp.h>
@@ -536,6 +537,266 @@ struct efi_device_path_utilities_protocol { uint16_t node_length); }; +#define EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID \ + EFI_GUID(0x587e72d7, 0xcc50, 0x4f79, \ + 0x82, 0x09, 0xca, 0x29, 0x1f, 0xc1, 0xa1, 0x0f) + +typedef uint16_t efi_string_id_t ; + +struct efi_hii_config_routing_protocol { + efi_status_t(EFIAPI *extract_config)( + const struct efi_hii_config_routing_protocol *this, + const efi_string_t request, + efi_string_t *progress, + efi_string_t *results); + efi_status_t(EFIAPI *export_config)( + const struct efi_hii_config_routing_protocol *this, + efi_string_t *results); + efi_status_t(EFIAPI *route_config)( + const struct efi_hii_config_routing_protocol *this, + const efi_string_t configuration, + efi_string_t *progress); + efi_status_t(EFIAPI *block_to_config)( + const struct efi_hii_config_routing_protocol *this, + const efi_string_t config_request, + const uint8_t *block, + const efi_uintn_t block_size, + efi_string_t *config, + efi_string_t *progress); + efi_status_t(EFIAPI *config_to_block)( + const struct efi_hii_config_routing_protocol *this, + const efi_string_t config_resp, + const uint8_t *block, + const efi_uintn_t *block_size, + efi_string_t *progress); + efi_status_t(EFIAPI *get_alt_config)( + const struct efi_hii_config_routing_protocol *this, + const efi_string_t config_resp, + const efi_guid_t *guid, + const efi_string_t name, + const struct efi_device_path *device_path, + const efi_string_t alt_cfg_id, + efi_string_t *alt_cfg_resp); +}; + +#define EFI_HII_DATABASE_PROTOCOL_GUID \ + EFI_GUID(0xef9fc172, 0xa1b2, 0x4693, \ + 0xb3, 0x27, 0x6d, 0x32, 0xfc, 0x41, 0x60, 0x42) + +typedef enum { +EFI_KEY_LCTRL ,EFI_KEY_A0 ,EFI_KEY_LALT ,EFI_KEY_SPACE_BAR , +EFI_KEY_A2 ,EFI_KEY_A3 ,EFI_KEY_A4 ,EFI_KEY_RCTRL ,EFI_KEY_LEFT_ARROW , +EFI_KEY_DOWN_ARROW ,EFI_KEY_RIGHT_ARROW ,EFI_KEY_ZERO , +EFI_KEY_PERIOD ,EFI_KEY_ENTER ,EFI_KEY_LSHIFT ,EFI_KEY_B0 , +EFI_KEY_B1 ,EFI_KEY_B2 ,EFI_KEY_B3 ,EFI_KEY_B4 ,EFI_KEY_B5 ,EFI_KEY_B6 , +EFI_KEY_B7 ,EFI_KEY_B8 ,EFI_KEY_B9 ,EFI_KEY_B10 ,EFI_KEY_RSHIFT , +EFI_KEY_UP_ARROW ,EFI_KEY_ONE ,EFI_KEY_TWO ,EFI_KEY_THREE , +EFI_KEY_CAPS_LOCK ,EFI_KEY_C1 ,EFI_KEY_C2 ,EFI_KEY_C3 ,EFI_KEY_C4 , +EFI_KEY_C5 ,EFI_KEY_C6 ,EFI_KEY_C7 ,EFI_KEY_C8 ,EFI_KEY_C9 , +EFI_KEY_C10 ,EFI_KEY_C11 ,EFI_KEY_C12 ,EFI_KEY_FOUR ,EFI_KEY_FIVE , +EFI_KEY_SIX ,EFI_KEY_PLUS ,EFI_KEY_TAB ,EFI_KEY_D1 ,EFI_KEY_D2 , +EFI_KEY_D3 ,EFI_KEY_D4 ,EFI_KEY_D5 ,EFI_KEY_D6 ,EFI_KEY_D7 ,EFI_KEY_D8 , +EFI_KEY_D9 ,EFI_KEY_D10 ,EFI_KEY_D11 ,EFI_KEY_D12 ,EFI_KEY_D13 , +EFI_KEY_DEL ,EFI_KEY_END ,EFI_KEY_PG_DN ,EFI_KEY_SEVEN ,EFI_KEY_EIGHT , +EFI_KEY_NINE ,EFI_KEY_E0 ,EFI_KEY_E1 ,EFI_KEY_E2 ,EFI_KEY_E3 , +EFI_KEY_E4 ,EFI_KEY_E5 ,EFI_KEY_E6 ,EFI_KEY_E7 ,EFI_KEY_E8 ,EFI_KEY_E9 , +EFI_KEY_E10 ,EFI_KEY_E11 ,EFI_KEY_E12 ,EFI_KEY_BACK_SPACE , +EFI_KEY_INS ,EFI_KEY_HOME ,EFI_KEY_PG_UP ,EFI_KEY_NLCK ,EFI_KEY_SLASH , +EFI_KEY_ASTERISK ,EFI_KEY_MINUS ,EFI_KEY_ESC ,EFI_KEY_F1 ,EFI_KEY_F2 , +EFI_KEY_F3 ,EFI_KEY_F4 ,EFI_KEY_F5 ,EFI_KEY_F6 ,EFI_KEY_F7 ,EFI_KEY_F8 , +EFI_KEY_F9 ,EFI_KEY_F10 ,EFI_KEY_F11 ,EFI_KEY_F12 ,EFI_KEY_PRINT , +EFI_KEY_SLCK ,EFI_KEY_PAUSE , +}efi_key ; + +struct efi_key_descriptor { +efi_key key; +uint16_t unicode; +uint16_t shifted_unicode; +uint16_t alt_gr_unicode; +uint16_t shifted_alt_gr_unicode; +uint16_t modifier; +uint16_t affected_attribute; +}; + +struct efi_hii_keyboard_layout { +uint16_t layout_length; +efi_guid_t guid; +uint32_t layout_descriptor_string_offset; +uint8_t descriptor_count; +struct efi_key_descriptor descriptors[]; +}; + +struct efi_hii_package_list_header { +efi_guid_t package_list_guid; +uint32_t package_length; +} __packed; + +struct efi_hii_package_header { +uint32_t length :24 ; +uint32_t type :8 ; +} __packed; + +#define EFI_HII_PACKAGE_TYPE_ALL 0x00 +#define EFI_HII_PACKAGE_TYPE_GUID 0x01 +#define EFI_HII_PACKAGE_FORMS 0x02 +#define EFI_HII_PACKAGE_STRINGS 0x04 +#define EFI_HII_PACKAGE_FONTS 0x05 +#define EFI_HII_PACKAGE_IMAGES 0x06 +#define EFI_HII_PACKAGE_SIMPLE_FONTS 0x07 +#define EFI_HII_PACKAGE_DEVICE_PATH 0x08 +#define EFI_HII_PACKAGE_KEYBOARD_LAYOUT 0x09 +#define EFI_HII_PACKAGE_ANIMATIONS 0x0A +#define EFI_HII_PACKAGE_END 0xDF +#define EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN 0xE0 +#define EFI_HII_PACKAGE_TYPE_SYSTEM_END 0xFF + +struct efi_hii_strings_package { +struct efi_hii_package_header header; +uint32_t header_size; +uint32_t string_info_offset; +uint16_t language_window[16 ]; +efi_string_id_t language_name; +uint8_t language[]; +} __packed; + +struct efi_hii_string_block { +uint8_t block_type; +/*uint8_t block_body[];*/ +} __packed; + +#define EFI_HII_SIBT_END 0x00 // The end of the string information. +#define EFI_HII_SIBT_STRING_SCSU 0x10 // Single string using default font information. +#define EFI_HII_SIBT_STRING_SCSU_FONT 0x11 // Single string with font information. +#define EFI_HII_SIBT_STRINGS_SCSU 0x12 // Multiple strings using default font information. +#define EFI_HII_SIBT_STRINGS_SCSU_FONT 0x13 // Multiple strings with font information. +#define EFI_HII_SIBT_STRING_UCS2 0x14 // Single UCS-2 string using default font information. +#define EFI_HII_SIBT_STRING_UCS2_FONT 0x15 // Single UCS-2 string with font information +#define EFI_HII_SIBT_STRINGS_UCS2 0x16 // Multiple UCS-2 strings using default font information. +#define EFI_HII_SIBT_STRINGS_UCS2_FONT 0x17 // Multiple UCS-2 strings with font information. +#define EFI_HII_SIBT_DUPLICATE 0x20 // Create a duplicate of an existing string. +#define EFI_HII_SIBT_SKIP2 0x21 // Skip a certain number of string identifiers. +#define EFI_HII_SIBT_SKIP1 0x22 // Skip a certain number of string identifiers. +#define EFI_HII_SIBT_EXT1 0x30 // For future expansion (one byte length field) +#define EFI_HII_SIBT_EXT2 0x31 // For future expansion (two byte length field) +#define EFI_HII_SIBT_EXT4 0x32 // For future expansion (four byte length field) +#define EFI_HII_SIBT_FONT 0x40 // Font information. + +struct efi_hii_sibt_string_ucs2_block { +struct efi_hii_string_block header; +uint16_t string_text[]; +} __packed; + +static inline struct efi_hii_string_block *efi_hii_sibt_string_ucs2_block_next ( +struct efi_hii_sibt_string_ucs2_block *blk) +{ +return ((void *)blk) +sizeof (*blk) + + (utf16_strlen (blk->string_text) +1 ) *2 ; +} + +typedef void *efi_hii_handle_t ; + +struct efi_hii_database_protocol { + efi_status_t(EFIAPI *new_package_list)( + const struct efi_hii_database_protocol *this, + const struct efi_hii_package_list_header *package_list, + const efi_handle_t driver_handle, + efi_hii_handle_t *handle); + efi_status_t(EFIAPI *remove_package_list)( + const struct efi_hii_database_protocol *this, + efi_hii_handle_t handle); + efi_status_t(EFIAPI *update_package_list)( + const struct efi_hii_database_protocol *this, + efi_hii_handle_t handle, + const struct efi_hii_package_list_header *package_list); + efi_status_t(EFIAPI *list_package_lists)( + const struct efi_hii_database_protocol *this, + uint8_t package_type, + const efi_guid_t *package_guid, + efi_uintn_t *handle_buffer_length, + efi_hii_handle_t *handle); + efi_status_t(EFIAPI *export_package_lists)( + const struct efi_hii_database_protocol *this, + efi_hii_handle_t handle, + efi_uintn_t *buffer_size, + struct efi_hii_package_list_header *buffer); + efi_status_t(EFIAPI *register_package_notify)( + const struct efi_hii_database_protocol *this, + uint8_t package_type, + const efi_guid_t *package_guid, + const void *package_notify_fn, + efi_uintn_t notify_type, + efi_handle_t *notify_handle); + efi_status_t(EFIAPI *unregister_package_notify)( + const struct efi_hii_database_protocol *this, + efi_handle_t notification_handle + ); + efi_status_t(EFIAPI *find_keyboard_layouts)( + const struct efi_hii_database_protocol *this, + uint16_t *key_guid_buffer_length, + efi_guid_t *key_guid_buffer); + efi_status_t(EFIAPI *get_keyboard_layout)( + const struct efi_hii_database_protocol *this, + efi_guid_t *key_guid, + uint16_t *keyboard_layout_length, + struct efi_hii_keyboard_layout *keyboard_layout); + efi_status_t(EFIAPI *set_keyboard_layout)( + const struct efi_hii_database_protocol *this, + efi_guid_t *key_guid); + efi_status_t(EFIAPI *get_package_list_handle)( + const struct efi_hii_database_protocol *this, + efi_hii_handle_t package_list_handle, + efi_handle_t *driver_handle); +}; + +#define EFI_HII_STRING_PROTOCOL_GUID \ + EFI_GUID(0x0fd96974, 0x23aa, 0x4cdc, \ + 0xb9, 0xcb, 0x98, 0xd1, 0x77, 0x50, 0x32, 0x2a) + +typedef uint32_t efi_hii_font_style_t ; + +struct efi_font_info { +efi_hii_font_style_t font_style; +uint16_t font_size; +uint16_t font_name[1 ]; +}; + +struct efi_hii_string_protocol { + efi_status_t(EFIAPI *new_string)( + const struct efi_hii_string_protocol *this, + efi_hii_handle_t package_list, + efi_string_id_t *string_id, + const uint8_t *language, + const uint16_t *language_name, + const efi_string_t string, + const struct efi_font_info *string_font_info); + efi_status_t(EFIAPI *get_string)( + const struct efi_hii_string_protocol *this, + const uint8_t *language, + efi_hii_handle_t package_list, + efi_string_id_t string_id, + efi_string_t string, + efi_uintn_t *string_size, + struct efi_font_info **string_font_info); + efi_status_t(EFIAPI *set_string)( + const struct efi_hii_string_protocol *this, + efi_hii_handle_t package_list, + efi_string_id_t string_id, + const uint8_t *language, + const efi_string_t string, + const struct efi_font_info *string_font_info); + efi_status_t(EFIAPI *get_languages)( + const struct efi_hii_string_protocol *this, + efi_hii_handle_t package_list, + uint8_t *languages, + efi_uintn_t *languages_size); + efi_status_t(EFIAPI *get_secondary_languages)( + const struct efi_hii_string_protocol *this, + efi_hii_handle_t package_list, + const uint8_t *primary_language, + uint8_t *secondary_languages, + efi_uintn_t *secondary_languages_size); +}; +#define EFI_GOP_GUID \ EFI_GUID(0x9042a9de, 0x23dc, 0x4a38, \ 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a)
include/efi_loader.h +6 -0
@@ -80,6 +80,9 @@ extern struct efi_simple_input_interface efi_con_in;extern const struct efi_console_control_protocol efi_console_control;extern const struct efi_device_path_to_text_protocol efi_device_path_to_text;extern const struct efi_device_path_utilities_protocol efi_device_path_utilities; +extern const struct efi_hii_config_routing_protocol efi_hii_config_routing; +extern const struct efi_hii_database_protocol efi_hii_database; +extern const struct efi_hii_string_protocol efi_hii_string;uint16_t *efi_dp_str (struct efi_device_path *dp);
@@ -91,6 +94,9 @@ extern const efi_guid_t efi_guid_device_path_to_text_protocol;extern const efi_guid_t efi_simple_file_system_protocol_guid;extern const efi_guid_t efi_file_info_guid;extern const efi_guid_t efi_guid_device_path_utilities_protocol; +extern const efi_guid_t efi_guid_hii_config_routing_protocol; +extern const efi_guid_t efi_guid_hii_database_protocol; +extern const efi_guid_t efi_guid_hii_string_protocol;extern unsigned int __efi_runtime_start, __efi_runtime_stop;extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;
lib/efi_loader/Makefile +1 -1
@@ -17,7 +17,7 @@ endif obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o -obj-y += efi_device_path_utilities.o +obj-y += efi_device_path_utilities.o efi_hii.o obj-y += efi_file.o efi_variable.o efi_bootmgr.o obj-$(CONFIG_LCD) += efi_gop.o obj-$(CONFIG_DM_VIDEO) += efi_gop.o
lib/efi_loader/efi_boottime.c +9 -0
@@ -1157,6 +1157,15 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob obj->protocols[4 ].protocol_interface = (void *)&efi_device_path_utilities; + obj->protocols[5 ].guid = &efi_guid_hii_string_protocol; + obj->protocols[5 ].protocol_interface = (void *)&efi_hii_string; + + obj->protocols[6 ].guid = &efi_guid_hii_database_protocol; + obj->protocols[6 ].protocol_interface = (void *)&efi_hii_database; + + obj->protocols[7 ].guid = &efi_guid_hii_config_routing_protocol; + obj->protocols[7 ].protocol_interface = (void *)&efi_hii_config_routing; + info->file_path = file_path; info->device_handle =efi_dp_find_obj (device_path,NULL );
lib/efi_loader/efi_hii.c new file +507 -0
507 lines not on this page · raw message
Signature · 1 line
2.13.6
PATCH 2/11 efi_loader: Initial HII protocols
Quoted 129 lines · Rob Clark
From: Leif Lindholm <[email protected]>
Enough implementation of the following protocols to run Shell.efi and SCT.efi:
EfiHiiConfigRoutingProtocolGuid
EfiHiiDatabaseProtocol
EfiHiiStringProtocolWe'll fill in the rest once SCT is running properly so we can validate the implementation against the conformance test suite.
Initial skeleton written by Leif, and then implementation by myself.
Cc Leif Lindholm <[email protected]>Signed-off-by Rob Clark <[email protected]>--- include/efi_api.h | 261 ++++++++++++++++++++++ include/efi_loader.h | 6 + lib/efi_loader/Makefile | 2 +- lib/efi_loader/efi_boottime.c | 9 + lib/efi_loader/efi_hii.c | 507 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 784 insertions(+), 1 deletion(-) create mode 100644 lib/efi_loader/efi_hii.cinclude/efi_api.h +89
-0@@ -16,6 +16,7 @@#define _EFI_API_H#include <efi.h> +#include <charset.h> #ifdef CONFIG_EFI_LOADER #include <asm/setjmp.h> @@ -536,6 +537,266 @@ struct efi_device_path_utilities_protocol { uint16_t node_length); }; +#define EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID \ + EFI_GUID(0x587e72d7, 0xcc50, 0x4f79, \ + 0x82, 0x09, 0xca, 0x29, 0x1f, 0xc1, 0xa1, 0x0f) + +typedef uint16_t efi_string_id_t ; + +struct efi_hii_config_routing_protocol { + efi_status_t(EFIAPI *extract_config)( + const struct efi_hii_config_routing_protocol *this, + const efi_string_t request, + efi_string_t *progress, + efi_string_t *results); + efi_status_t(EFIAPI *export_config)( + const struct efi_hii_config_routing_protocol *this, + efi_string_t *results); + efi_status_t(EFIAPI *route_config)( + const struct efi_hii_config_routing_protocol *this, + const efi_string_t configuration, + efi_string_t *progress); + efi_status_t(EFIAPI *block_to_config)( + const struct efi_hii_config_routing_protocol *this, + const efi_string_t config_request, + const uint8_t *block, + const efi_uintn_t block_size, + efi_string_t *config, + efi_string_t *progress); + efi_status_t(EFIAPI *config_to_block)( + const struct efi_hii_config_routing_protocol *this, + const efi_string_t config_resp, + const uint8_t *block, + const efi_uintn_t *block_size, + efi_string_t *progress); + efi_status_t(EFIAPI *get_alt_config)( + const struct efi_hii_config_routing_protocol *this, + const efi_string_t config_resp, + const efi_guid_t *guid, + const efi_string_t name, + const struct efi_device_path *device_path, + const efi_string_t alt_cfg_id, + efi_string_t *alt_cfg_resp); +}; + +#define EFI_HII_DATABASE_PROTOCOL_GUID \ + EFI_GUID(0xef9fc172, 0xa1b2, 0x4693, \ + 0xb3, 0x27, 0x6d, 0x32, 0xfc, 0x41, 0x60, 0x42) + +typedef enum { +EFI_KEY_LCTRL ,EFI_KEY_A0 ,EFI_KEY_LALT ,EFI_KEY_SPACE_BAR , +EFI_KEY_A2 ,EFI_KEY_A3 ,EFI_KEY_A4 ,EFI_KEY_RCTRL ,EFI_KEY_LEFT_ARROW , +EFI_KEY_DOWN_ARROW ,EFI_KEY_RIGHT_ARROW ,EFI_KEY_ZERO , +EFI_KEY_PERIOD ,EFI_KEY_ENTER ,EFI_KEY_LSHIFT ,EFI_KEY_B0 , +EFI_KEY_B1 ,EFI_KEY_B2 ,EFI_KEY_B3 ,EFI_KEY_B4 ,EFI_KEY_B5 ,EFI_KEY_B6 , +EFI_KEY_B7 ,EFI_KEY_B8 ,EFI_KEY_B9 ,EFI_KEY_B10 ,EFI_KEY_RSHIFT , +EFI_KEY_UP_ARROW ,EFI_KEY_ONE ,EFI_KEY_TWO ,EFI_KEY_THREE , +EFI_KEY_CAPS_LOCK ,EFI_KEY_C1 ,EFI_KEY_C2 ,EFI_KEY_C3 ,EFI_KEY_C4 , +EFI_KEY_C5 ,EFI_KEY_C6 ,EFI_KEY_C7 ,EFI_KEY_C8 ,EFI_KEY_C9 , +EFI_KEY_C10 ,EFI_KEY_C11 ,EFI_KEY_C12 ,EFI_KEY_FOUR ,EFI_KEY_FIVE , +EFI_KEY_SIX ,EFI_KEY_PLUS ,EFI_KEY_TAB ,EFI_KEY_D1 ,EFI_KEY_D2 , +EFI_KEY_D3 ,EFI_KEY_D4 ,EFI_KEY_D5 ,EFI_KEY_D6 ,EFI_KEY_D7 ,EFI_KEY_D8 , +EFI_KEY_D9 ,EFI_KEY_D10 ,EFI_KEY_D11 ,EFI_KEY_D12 ,EFI_KEY_D13 , +EFI_KEY_DEL ,EFI_KEY_END ,EFI_KEY_PG_DN ,EFI_KEY_SEVEN ,EFI_KEY_EIGHT , +EFI_KEY_NINE ,EFI_KEY_E0 ,EFI_KEY_E1 ,EFI_KEY_E2 ,EFI_KEY_E3 , +EFI_KEY_E4 ,EFI_KEY_E5 ,EFI_KEY_E6 ,EFI_KEY_E7 ,EFI_KEY_E8 ,EFI_KEY_E9 , +EFI_KEY_E10 ,EFI_KEY_E11 ,EFI_KEY_E12 ,EFI_KEY_BACK_SPACE , +EFI_KEY_INS ,EFI_KEY_HOME ,EFI_KEY_PG_UP ,EFI_KEY_NLCK ,EFI_KEY_SLASH , +EFI_KEY_ASTERISK ,EFI_KEY_MINUS ,EFI_KEY_ESC ,EFI_KEY_F1 ,EFI_KEY_F2 , +EFI_KEY_F3 ,EFI_KEY_F4 ,EFI_KEY_F5 ,EFI_KEY_F6 ,EFI_KEY_F7 ,EFI_KEY_F8 , +EFI_KEY_F9 ,EFI_KEY_F10 ,EFI_KEY_F11 ,EFI_KEY_F12 ,EFI_KEY_PRINT , +EFI_KEY_SLCK ,EFI_KEY_PAUSE , +}efi_key ; + +struct efi_key_descriptor { +efi_key key; +uint16_t unicode; +uint16_t shifted_unicode; +uint16_t alt_gr_unicode; +uint16_t shifted_alt_gr_unicode; +uint16_t modifier; +uint16_t affected_attribute; +}; + +struct efi_hii_keyboard_layout { +uint16_t layout_length; +efi_guid_t guid; +uint32_t layout_descriptor_string_offset; +uint8_t descriptor_count; +struct efi_key_descriptor descriptors[]; +};
include/efi_api.h struct efi_device_path_utilities_protocol { · line 637
Quoted 10 lines
include/efi_api.h +10
-0+ +struct efi_hii_package_list_header { +efi_guid_t package_list_guid; +uint32_t package_length; +} __packed; + +struct efi_hii_package_header { +uint32_t length :24 ; +uint32_t type :8 ; +} __packed;
Bitfields are terribly evil - they're probably one of the worst defined things in C. A different compiler may even give you different ordering here. I've certainly seen bitfields explode in weird ways on cross-endian conversions.
Do you think you could just make that a uint32_t altogether and work with MASK/SHIFT defines instead?
Quoted 46 lines
include/efi_api.h +46
-0+ +#define EFI_HII_PACKAGE_TYPE_ALL 0x00 +#define EFI_HII_PACKAGE_TYPE_GUID 0x01 +#define EFI_HII_PACKAGE_FORMS 0x02 +#define EFI_HII_PACKAGE_STRINGS 0x04 +#define EFI_HII_PACKAGE_FONTS 0x05 +#define EFI_HII_PACKAGE_IMAGES 0x06 +#define EFI_HII_PACKAGE_SIMPLE_FONTS 0x07 +#define EFI_HII_PACKAGE_DEVICE_PATH 0x08 +#define EFI_HII_PACKAGE_KEYBOARD_LAYOUT 0x09 +#define EFI_HII_PACKAGE_ANIMATIONS 0x0A +#define EFI_HII_PACKAGE_END 0xDF +#define EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN 0xE0 +#define EFI_HII_PACKAGE_TYPE_SYSTEM_END 0xFF + +struct efi_hii_strings_package { +struct efi_hii_package_header header; +uint32_t header_size; +uint32_t string_info_offset; +uint16_t language_window[16 ]; +efi_string_id_t language_name; +uint8_t language[]; +} __packed; + +struct efi_hii_string_block { +uint8_t block_type; +/*uint8_t block_body[];*/ +} __packed; + +#define EFI_HII_SIBT_END 0x00 // The end of the string information. +#define EFI_HII_SIBT_STRING_SCSU 0x10 // Single string using default font information. +#define EFI_HII_SIBT_STRING_SCSU_FONT 0x11 // Single string with font information. +#define EFI_HII_SIBT_STRINGS_SCSU 0x12 // Multiple strings using default font information. +#define EFI_HII_SIBT_STRINGS_SCSU_FONT 0x13 // Multiple strings with font information. +#define EFI_HII_SIBT_STRING_UCS2 0x14 // Single UCS-2 string using default font information. +#define EFI_HII_SIBT_STRING_UCS2_FONT 0x15 // Single UCS-2 string with font information +#define EFI_HII_SIBT_STRINGS_UCS2 0x16 // Multiple UCS-2 strings using default font information. +#define EFI_HII_SIBT_STRINGS_UCS2_FONT 0x17 // Multiple UCS-2 strings with font information. +#define EFI_HII_SIBT_DUPLICATE 0x20 // Create a duplicate of an existing string. +#define EFI_HII_SIBT_SKIP2 0x21 // Skip a certain number of string identifiers. +#define EFI_HII_SIBT_SKIP1 0x22 // Skip a certain number of string identifiers. +#define EFI_HII_SIBT_EXT1 0x30 // For future expansion (one byte length field) +#define EFI_HII_SIBT_EXT2 0x31 // For future expansion (two byte length field) +#define EFI_HII_SIBT_EXT4 0x32 // For future expansion (four byte length field) +#define EFI_HII_SIBT_FONT 0x40 // Font information. +
include/efi_api.h struct efi_device_path_utilities_protocol { · line 693
Quoted 10 lines
include/efi_api.h +10
-0+struct efi_hii_sibt_string_ucs2_block { +struct efi_hii_string_block header; +uint16_t string_text[]; +} __packed; + +static inline struct efi_hii_string_block *efi_hii_sibt_string_ucs2_block_next ( +struct efi_hii_sibt_string_ucs2_block *blk) +{ +return ((void *)blk) +sizeof (*blk) + + (utf16_strlen (blk->string_text) +1 ) *2 ;
Since you're dealing with actual utf16, is this correct? One character may as well span 4 bytes, right?
I think we need a different function that actually tells us the bytes occupied by a utf16 string.
Quoted 267 lines
include/efi_api.h +106
-0+} + +typedef void *efi_hii_handle_t ; + +struct efi_hii_database_protocol { + efi_status_t(EFIAPI *new_package_list)( + const struct efi_hii_database_protocol *this, + const struct efi_hii_package_list_header *package_list, + const efi_handle_t driver_handle, + efi_hii_handle_t *handle); + efi_status_t(EFIAPI *remove_package_list)( + const struct efi_hii_database_protocol *this, + efi_hii_handle_t handle); + efi_status_t(EFIAPI *update_package_list)( + const struct efi_hii_database_protocol *this, + efi_hii_handle_t handle, + const struct efi_hii_package_list_header *package_list); + efi_status_t(EFIAPI *list_package_lists)( + const struct efi_hii_database_protocol *this, + uint8_t package_type, + const efi_guid_t *package_guid, + efi_uintn_t *handle_buffer_length, + efi_hii_handle_t *handle); + efi_status_t(EFIAPI *export_package_lists)( + const struct efi_hii_database_protocol *this, + efi_hii_handle_t handle, + efi_uintn_t *buffer_size, + struct efi_hii_package_list_header *buffer); + efi_status_t(EFIAPI *register_package_notify)( + const struct efi_hii_database_protocol *this, + uint8_t package_type, + const efi_guid_t *package_guid, + const void *package_notify_fn, + efi_uintn_t notify_type, + efi_handle_t *notify_handle); + efi_status_t(EFIAPI *unregister_package_notify)( + const struct efi_hii_database_protocol *this, + efi_handle_t notification_handle + ); + efi_status_t(EFIAPI *find_keyboard_layouts)( + const struct efi_hii_database_protocol *this, + uint16_t *key_guid_buffer_length, + efi_guid_t *key_guid_buffer); + efi_status_t(EFIAPI *get_keyboard_layout)( + const struct efi_hii_database_protocol *this, + efi_guid_t *key_guid, + uint16_t *keyboard_layout_length, + struct efi_hii_keyboard_layout *keyboard_layout); + efi_status_t(EFIAPI *set_keyboard_layout)( + const struct efi_hii_database_protocol *this, + efi_guid_t *key_guid); + efi_status_t(EFIAPI *get_package_list_handle)( + const struct efi_hii_database_protocol *this, + efi_hii_handle_t package_list_handle, + efi_handle_t *driver_handle); +}; + +#define EFI_HII_STRING_PROTOCOL_GUID \ + EFI_GUID(0x0fd96974, 0x23aa, 0x4cdc, \ + 0xb9, 0xcb, 0x98, 0xd1, 0x77, 0x50, 0x32, 0x2a) + +typedef uint32_t efi_hii_font_style_t ; + +struct efi_font_info { +efi_hii_font_style_t font_style; +uint16_t font_size; +uint16_t font_name[1 ]; +}; + +struct efi_hii_string_protocol { + efi_status_t(EFIAPI *new_string)( + const struct efi_hii_string_protocol *this, + efi_hii_handle_t package_list, + efi_string_id_t *string_id, + const uint8_t *language, + const uint16_t *language_name, + const efi_string_t string, + const struct efi_font_info *string_font_info); + efi_status_t(EFIAPI *get_string)( + const struct efi_hii_string_protocol *this, + const uint8_t *language, + efi_hii_handle_t package_list, + efi_string_id_t string_id, + efi_string_t string, + efi_uintn_t *string_size, + struct efi_font_info **string_font_info); + efi_status_t(EFIAPI *set_string)( + const struct efi_hii_string_protocol *this, + efi_hii_handle_t package_list, + efi_string_id_t string_id, + const uint8_t *language, + const efi_string_t string, + const struct efi_font_info *string_font_info); + efi_status_t(EFIAPI *get_languages)( + const struct efi_hii_string_protocol *this, + efi_hii_handle_t package_list, + uint8_t *languages, + efi_uintn_t *languages_size); + efi_status_t(EFIAPI *get_secondary_languages)( + const struct efi_hii_string_protocol *this, + efi_hii_handle_t package_list, + const uint8_t *primary_language, + uint8_t *secondary_languages, + efi_uintn_t *secondary_languages_size); +}; +#define EFI_GOP_GUID \ EFI_GUID(0x9042a9de, 0x23dc, 0x4a38, \ 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a)include/efi_loader.h +6
-0@@ -80,6 +80,9 @@ extern struct efi_simple_input_interface efi_con_in;extern const struct efi_console_control_protocol efi_console_control;extern const struct efi_device_path_to_text_protocol efi_device_path_to_text;extern const struct efi_device_path_utilities_protocol efi_device_path_utilities; +extern const struct efi_hii_config_routing_protocol efi_hii_config_routing; +extern const struct efi_hii_database_protocol efi_hii_database; +extern const struct efi_hii_string_protocol efi_hii_string;uint16_t *efi_dp_str (struct efi_device_path *dp);@@ -91,6 +94,9 @@ extern const efi_guid_t efi_guid_device_path_to_text_protocol;extern const efi_guid_t efi_simple_file_system_protocol_guid;extern const efi_guid_t efi_file_info_guid;extern const efi_guid_t efi_guid_device_path_utilities_protocol; +extern const efi_guid_t efi_guid_hii_config_routing_protocol; +extern const efi_guid_t efi_guid_hii_database_protocol; +extern const efi_guid_t efi_guid_hii_string_protocol;extern unsigned int __efi_runtime_start, __efi_runtime_stop;extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;lib/efi_loader/Makefile +1
-1@@ -17,7 +17,7 @@ endif obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o -obj-y += efi_device_path_utilities.o +obj-y += efi_device_path_utilities.o efi_hii.o obj-y += efi_file.o efi_variable.o efi_bootmgr.o obj-$(CONFIG_LCD) += efi_gop.o obj-$(CONFIG_DM_VIDEO) += efi_gop.olib/efi_loader/efi_boottime.c +9
-0@@ -1157,6 +1157,15 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob obj->protocols[4 ].protocol_interface = (void *)&efi_device_path_utilities; + obj->protocols[5 ].guid = &efi_guid_hii_string_protocol; + obj->protocols[5 ].protocol_interface = (void *)&efi_hii_string; + + obj->protocols[6 ].guid = &efi_guid_hii_database_protocol; + obj->protocols[6 ].protocol_interface = (void *)&efi_hii_database; + + obj->protocols[7 ].guid = &efi_guid_hii_config_routing_protocol; + obj->protocols[7 ].protocol_interface = (void *)&efi_hii_config_routing; + info->file_path = file_path; info->device_handle =efi_dp_find_obj (device_path,NULL );lib/efi_loader/efi_hii.c new file +95
-0@@ -0,0 +1,507 @@ +/* +* EFI Human Interface Infrastructure ... interface +* +* Copyright (c) 2017 Leif Lindholm +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <malloc.h> +#include <efi_loader.h> + +const efi_guid_t efi_guid_hii_config_routing_protocol = +EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID ; +const efi_guid_t efi_guid_hii_database_protocol =EFI_HII_DATABASE_PROTOCOL_GUID ; +const efi_guid_t efi_guid_hii_string_protocol =EFI_HII_STRING_PROTOCOL_GUID ; + +struct hii_package { +// TODO should there be an associated efi_object? +struct list_head string_tables;/* list of string_table */ +/* we could also track fonts, images, etc */ +}; + +struct string_table { +struct list_head link; +efi_string_id_t language_name; +char *language; +uint32_t nstrings; +/* NOTE: string id starts at 1 so value is stbl->strings[id-1] */ +struct { +efi_string_t string; +/* we could also track font info, etc */ + } strings[]; +}; + +static void free_strings_table (struct string_table *stbl) +{ +int i; + +for (i =0 ; i < stbl->nstrings; i++) +free (stbl->strings[i].string); +free (stbl->language); +free (stbl); +} + +static struct hii_package *new_package (void ) +{ +struct hii_package *hii =malloc (sizeof (*hii)); +INIT_LIST_HEAD (&hii->string_tables); +return hii; +} + +static void free_package (struct hii_package *hii) +{ + +while (!list_empty (&hii->string_tables)) { +struct string_table *stbl; + + stbl =list_first_entry (&hii->string_tables, + struct string_table, link); +list_del (&stbl->link); +free_strings_table (stbl); + } + +free (hii); +} + +static efi_status_t add_strings_package (struct hii_package *hii, +struct efi_hii_strings_package *strings_package) +{ +struct efi_hii_string_block *block; +void *end = ((void *)strings_package) + strings_package->header.length; +uint32_t nstrings =0 ; +unsigned id =0 ; + +debug ("header_size: %08x\n" , strings_package->header_size); +debug ("string_info_offset: %08x\n" , strings_package->string_info_offset); +debug ("language_name: %u\n" , strings_package->language_name); +debug ("language: %s\n" , strings_package->language); + +/* count # of string entries: */ + block = ((void *)strings_package) + strings_package->string_info_offset; +while ((void *)block < end) { +switch (block->block_type) { +case EFI_HII_SIBT_STRING_UCS2 : { +struct efi_hii_sibt_string_ucs2_block *ucs2 = + (void *)block; + nstrings++; + block =efi_hii_sibt_string_ucs2_block_next (ucs2); +break ; + } +case EFI_HII_SIBT_END : + block = end; +break ; +default :
lib/efi_loader/efi_hii.c line 105
Quoted 10 lines
lib/efi_loader/efi_hii.c new file +10
-0+debug ("unknown HII string block type: %02x\n" , + block->block_type); +return EFI_INVALID_PARAMETER ; + } + } + +struct string_table *stbl =malloc (sizeof (*stbl) + + (nstrings *sizeof (stbl->strings[0 ]))); + stbl->language_name = strings_package->language_name; + stbl->language =strdup ((char *)strings_package->language);
Where does the strings_package come from? And why is the language in it in UTF8?
Quoted 290 lines
lib/efi_loader/efi_hii.c new file +290
-0+ stbl->nstrings = nstrings; + +list_add (&stbl->link, &hii->string_tables); + +/* and now parse string entries and populate string_table */ + block = ((void *)strings_package) + strings_package->string_info_offset; + +while ((void *)block < end) { +switch (block->block_type) { +case EFI_HII_SIBT_STRING_UCS2 : { +struct efi_hii_sibt_string_ucs2_block *ucs2 = + (void *)block; + id++; +debug ("%4u: \"%ls\"\n" , id, ucs2->string_text); + stbl->strings[id-1 ].string = +utf16_strdup (ucs2->string_text); + block =efi_hii_sibt_string_ucs2_block_next (ucs2); +break ; + } +case EFI_HII_SIBT_END : +return EFI_SUCCESS ; +default : +debug ("unknown HII string block type: %02x\n" , + block->block_type); +return EFI_INVALID_PARAMETER ; + } + } + +return EFI_SUCCESS ; +} + +/* +* EFI_HII_CONFIG_ROUTING_PROTOCOL +*/ + +static efi_status_t EFIAPI extract_config( +const struct efi_hii_config_routing_protocol *this, +const efi_string_t request, +efi_string_t *progress, +efi_string_t *results) +{ +EFI_ENTRY ("%p, \"%ls\", %p, %p" , this, request, progress, results); +return EFI_EXIT (EFI_OUT_OF_RESOURCES ); +} + +static efi_status_t EFIAPI export_config( +const struct efi_hii_config_routing_protocol *this, +efi_string_t *results) +{ +EFI_ENTRY ("%p, %p" , this, results); +return EFI_EXIT (EFI_OUT_OF_RESOURCES ); +} + +static efi_status_t EFIAPI route_config( +const struct efi_hii_config_routing_protocol *this, +const efi_string_t configuration, +efi_string_t *progress) +{ +EFI_ENTRY ("%p, \"%ls\", %p" , this, configuration, progress); +return EFI_EXIT (EFI_OUT_OF_RESOURCES ); +} + +static efi_status_t EFIAPI block_to_config( +const struct efi_hii_config_routing_protocol *this, +const efi_string_t config_request, +const uint8_t *block, +const efi_uintn_t block_size, +efi_string_t *config, +efi_string_t *progress) +{ +EFI_ENTRY ("%p, \"%ls\", %p, %zu, %p, %p" , this, config_request, block, + block_size, config, progress); +return EFI_EXIT (EFI_OUT_OF_RESOURCES ); +} + +static efi_status_t EFIAPI config_to_block( +const struct efi_hii_config_routing_protocol *this, +const efi_string_t config_resp, +const uint8_t *block, +const efi_uintn_t *block_size, +efi_string_t *progress) +{ +EFI_ENTRY ("%p, \"%ls\", %p, %p, %p" , this, config_resp, block, + block_size, progress); +return EFI_EXIT (EFI_OUT_OF_RESOURCES ); +} + +static efi_status_t EFIAPI get_alt_config( +const struct efi_hii_config_routing_protocol *this, +const efi_string_t config_resp, +const efi_guid_t *guid, +const efi_string_t name, +const struct efi_device_path *device_path, +const efi_string_t alt_cfg_id, +efi_string_t *alt_cfg_resp) +{ +EFI_ENTRY ("%p, \"%ls\", %pUl, \"%ls\", %p, \"%ls\", %p" , this, + config_resp, guid, name, device_path, alt_cfg_id, + alt_cfg_resp); +return EFI_EXIT (EFI_OUT_OF_RESOURCES ); +} + + +/* +* EFI_HII_DATABASE_PROTOCOL +*/ + +static efi_status_t EFIAPI new_package_list( +const struct efi_hii_database_protocol *this, +const struct efi_hii_package_list_header *package_list, +const efi_handle_t driver_handle, +efi_hii_handle_t *handle) +{ +efi_status_t ret =EFI_SUCCESS ; + +EFI_ENTRY ("%p, %p, %p, %p" , this, package_list, driver_handle, handle); + +if (!package_list || !driver_handle) +return EFI_EXIT (EFI_INVALID_PARAMETER ); + +struct hii_package *hii =new_package (); +struct efi_hii_package_header *package; +void *end = ((void *)package_list) + package_list->package_length; + +debug ("package_list: %pUl (%u)\n" , &package_list->package_list_guid, + package_list->package_length); + + package = ((void *)package_list) +sizeof (*package_list); +while ((void *)package < end) { +debug ("package=%p, package type=%x, length=%u\n" , package, + package->type, package->length); +switch (package->type) { +case EFI_HII_PACKAGE_STRINGS : + ret =add_strings_package (hii, + (struct efi_hii_strings_package *)package); +break ; +default : +break ; + } + +if (ret !=EFI_SUCCESS ) + goto error; + + package = ((void *)package) + package->length; + } + +// TODO in theory there is some notifications that should be sent.. + + *handle = hii; + +return EFI_EXIT (EFI_SUCCESS ); + +error: +free_package (hii); +return EFI_EXIT (ret); +} + +static efi_status_t EFIAPI remove_package_list( +const struct efi_hii_database_protocol *this, +efi_hii_handle_t handle) +{ +struct hii_package *hii = handle; +EFI_ENTRY ("%p, %p" , this, handle); +free_package (hii); +return EFI_EXIT (EFI_SUCCESS ); +} + +static efi_status_t EFIAPI update_package_list( +const struct efi_hii_database_protocol *this, +efi_hii_handle_t handle, +const struct efi_hii_package_list_header *package_list) +{ +EFI_ENTRY ("%p, %p, %p" , this, handle, package_list); +return EFI_EXIT (EFI_NOT_FOUND ); +} + +static efi_status_t EFIAPI list_package_lists( +const struct efi_hii_database_protocol *this, +uint8_t package_type, +const efi_guid_t *package_guid, +efi_uintn_t *handle_buffer_length, +efi_hii_handle_t *handle) +{ +EFI_ENTRY ("%p, %u, %pUl, %p, %p" , this, package_type, package_guid, + handle_buffer_length, handle); +return EFI_EXIT (EFI_NOT_FOUND ); +} + +static efi_status_t EFIAPI export_package_lists( +const struct efi_hii_database_protocol *this, +efi_hii_handle_t handle, +efi_uintn_t *buffer_size, +struct efi_hii_package_list_header *buffer) +{ +EFI_ENTRY ("%p, %p, %p, %p" , this, handle, buffer_size, buffer); +return EFI_EXIT (EFI_NOT_FOUND ); +} + +static efi_status_t EFIAPI register_package_notify( +const struct efi_hii_database_protocol *this, +uint8_t package_type, +const efi_guid_t *package_guid, +const void *package_notify_fn, +efi_uintn_t notify_type, +efi_handle_t *notify_handle) +{ +EFI_ENTRY ("%p, %u, %pUl, %p, %zu, %p" , this, package_type, + package_guid, package_notify_fn, notify_type, + notify_handle); +return EFI_EXIT (EFI_OUT_OF_RESOURCES ); +} + +static efi_status_t EFIAPI unregister_package_notify( +const struct efi_hii_database_protocol *this, +efi_handle_t notification_handle) +{ +EFI_ENTRY ("%p, %p" , this, notification_handle); +return EFI_EXIT (EFI_NOT_FOUND ); +} + +static efi_status_t EFIAPI find_keyboard_layouts( +const struct efi_hii_database_protocol *this, +uint16_t *key_guid_buffer_length, +efi_guid_t *key_guid_buffer) +{ +EFI_ENTRY ("%p, %p, %p" , this, key_guid_buffer_length, key_guid_buffer); +return EFI_EXIT (EFI_NOT_FOUND );/* Invalid */ +} + +static efi_status_t EFIAPI get_keyboard_layout( +const struct efi_hii_database_protocol *this, +efi_guid_t *key_guid, +uint16_t *keyboard_layout_length, +struct efi_hii_keyboard_layout *keyboard_layout) +{ +EFI_ENTRY ("%p, %pUl, %p, %p" , this, key_guid, keyboard_layout_length, + keyboard_layout); +return EFI_EXIT (EFI_NOT_FOUND ); +} + +static efi_status_t EFIAPI set_keyboard_layout( +const struct efi_hii_database_protocol *this, +efi_guid_t *key_guid) +{ +EFI_ENTRY ("%p, %pUl" , this, key_guid); +return EFI_EXIT (EFI_NOT_FOUND ); +} + +static efi_status_t EFIAPI get_package_list_handle( +const struct efi_hii_database_protocol *this, +efi_hii_handle_t package_list_handle, +efi_handle_t *driver_handle) +{ +EFI_ENTRY ("%p, %p, %p" , this, package_list_handle, driver_handle); +return EFI_EXIT (EFI_INVALID_PARAMETER ); +} + + +/* +* EFI_HII_STRING_PROTOCOL +*/ + +static efi_status_t EFIAPI new_string( +const struct efi_hii_string_protocol *this, +efi_hii_handle_t package_list, +efi_string_id_t *string_id, +const uint8_t *language, +const uint16_t *language_name, +const efi_string_t string, +const struct efi_font_info *string_font_info) +{ +EFI_ENTRY ("%p, %p, %p, \"%s\", %p, \"%ls\", %p" , this, package_list, + string_id, language, language_name, string, + string_font_info); +return EFI_EXIT (EFI_NOT_FOUND ); +} + +static efi_status_t EFIAPI get_string( +const struct efi_hii_string_protocol *this, +const uint8_t *language, +efi_hii_handle_t package_list, +efi_string_id_t string_id, +efi_string_t string, +efi_uintn_t *string_size, +struct efi_font_info **string_font_info) +{ +struct hii_package *hii = package_list; +struct string_table *stbl; + + EFI_ENTRY("%p, \"%s\", %p, %u, %p, %p, %p", this, language,
lib/efi_loader/efi_hii.c line 405
Quoted 10 lines
lib/efi_loader/efi_hii.c new file +10
-0+ package_list, string_id, string, string_size, + string_font_info); + +list_for_each_entry (stbl, &hii->string_tables, link) { +if (!strcmp ((char *)language, (char *)stbl->language)) { +unsigned idx = string_id -1 ; +if (idx > stbl->nstrings) +return EFI_EXIT (EFI_NOT_FOUND ); +efi_string_t str = stbl->strings[idx].string; +size_t len =utf16_strlen (str) +1 ;
I assume that's wrong for sizing too?
Also please try not to define variables mid-scope :). Just define them above the if() and fill them after ...
Then also for the sake of readability add a blank line after the variable definitions and before the return.
I think you'd also do yourself a favor if you reduced the indenting a bit. Just abort the list_for_each when you found and entry and then process it in the top level scope.
static struct string_table *find_stbl_by_lang(const char *language)
{
list_for_each(...) {
if (matches) {
return stbl;
}
}
return NULL;
}stbl = find_stbl_by_lang(lang);
if (!stbl)
return EFI_EXIT(EFI_NOT_FOUND)
work_with_stbl;
return EFI_EXIT(EFI_SUCCESS);
Alex
Quoted 103 lines
lib/efi_loader/efi_hii.c new file +102
-0+if (*string_size < len *2 ) { + *string_size = len *2 ; +return EFI_EXIT (EFI_BUFFER_TOO_SMALL ); + } +memcpy (string, str, len *2 ); + *string_size = len *2 ; +return EFI_EXIT (EFI_SUCCESS ); + } + } + +return EFI_EXIT (EFI_NOT_FOUND ); +} + +static efi_status_t EFIAPI set_string( +const struct efi_hii_string_protocol *this, +efi_hii_handle_t package_list, +efi_string_id_t string_id, +const uint8_t *language, +const efi_string_t string, +const struct efi_font_info *string_font_info) +{ +EFI_ENTRY ("%p, %p, %u, \"%s\", \"%ls\", %p" , this, package_list, + string_id, language, string, string_font_info); +return EFI_EXIT (EFI_NOT_FOUND ); +} + +static efi_status_t EFIAPI get_languages( +const struct efi_hii_string_protocol *this, +efi_hii_handle_t package_list, +uint8_t *languages, +efi_uintn_t *languages_size) +{ +struct hii_package *hii = package_list; +struct string_table *stbl; +size_t len =0 ; + +EFI_ENTRY ("%p, %p, %p, %p" , this, package_list, languages, + languages_size); + +/* figure out required size: */ +list_for_each_entry (stbl, &hii->string_tables, link) { + len +=strlen ((char *)stbl->language) +1 ; + } + +if (*languages_size < len) { + *languages_size = len; +return EFI_EXIT (EFI_BUFFER_TOO_SMALL ); + } + +char *p = (char *)languages; +list_for_each_entry (stbl, &hii->string_tables, link) { +if (p != (char *)languages) + p +=sprintf (p,";" ); + p +=sprintf (p,"%s" , stbl->language); + } + +debug ("languages: %s\n" , languages); + +return EFI_EXIT (EFI_SUCCESS ); +} + +static efi_status_t EFIAPI get_secondary_languages( +const struct efi_hii_string_protocol *this, +efi_hii_handle_t package_list, +const uint8_t *primary_language, +uint8_t *secondary_languages, +efi_uintn_t *secondary_languages_size) +{ +EFI_ENTRY ("%p, %p, \"%s\", %p, %p" , this, package_list, + primary_language, secondary_languages, + secondary_languages_size); +return EFI_EXIT (EFI_NOT_FOUND ); +} + +const struct efi_hii_config_routing_protocol efi_hii_config_routing = { + .extract_config = extract_config, + .export_config = export_config, + .route_config = route_config, + .block_to_config = block_to_config, + .config_to_block = config_to_block, + .get_alt_config = get_alt_config +}; +const struct efi_hii_database_protocol efi_hii_database = { + .new_package_list = new_package_list, + .remove_package_list = remove_package_list, + .update_package_list = update_package_list, + .list_package_lists = list_package_lists, + .export_package_lists = export_package_lists, + .register_package_notify = register_package_notify, + .unregister_package_notify = unregister_package_notify, + .find_keyboard_layouts = find_keyboard_layouts, + .get_keyboard_layout = get_keyboard_layout, + .set_keyboard_layout = set_keyboard_layout, + .get_package_list_handle = get_package_list_handle +}; +const struct efi_hii_string_protocol efi_hii_string = { + .new_string = new_string, + .get_string = get_string, + .set_string = set_string, + .get_languages = get_languages, + .get_secondary_languages = get_secondary_languages +};
PATCH 2/11 efi_loader: Initial HII protocols
Quoted 139 lines · Alexander Graf
Quoted 136 lines · Rob Clark
From: Leif Lindholm <[email protected]>
Enough implementation of the following protocols to run Shell.efi and SCT.efi:
EfiHiiConfigRoutingProtocolGuid
EfiHiiDatabaseProtocol
EfiHiiStringProtocolWe'll fill in the rest once SCT is running properly so we can validate the implementation against the conformance test suite.
Initial skeleton written by Leif, and then implementation by myself.
Cc Leif Lindholm <[email protected]>Signed-off-by Rob Clark <[email protected]>--- include/efi_api.h | 261 ++++++++++++++++++++++ include/efi_loader.h | 6 + lib/efi_loader/Makefile | 2 +- lib/efi_loader/efi_boottime.c | 9 + lib/efi_loader/efi_hii.c | 507 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 784 insertions(+), 1 deletion(-) create mode 100644 lib/efi_loader/efi_hii.cinclude/efi_api.h +96
-0@@ -16,6 +16,7 @@#define _EFI_API_H#include <efi.h> +#include <charset.h> #ifdef CONFIG_EFI_LOADER #include <asm/setjmp.h> @@ -536,6 +537,266 @@ struct efi_device_path_utilities_protocol { uint16_t node_length); }; +#define EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID \ + EFI_GUID(0x587e72d7, 0xcc50, 0x4f79, \ + 0x82, 0x09, 0xca, 0x29, 0x1f, 0xc1, 0xa1, 0x0f) + +typedef uint16_t efi_string_id_t ; + +struct efi_hii_config_routing_protocol { + efi_status_t(EFIAPI *extract_config)( + const struct efi_hii_config_routing_protocol *this, + const efi_string_t request, + efi_string_t *progress, + efi_string_t *results); + efi_status_t(EFIAPI *export_config)( + const struct efi_hii_config_routing_protocol *this, + efi_string_t *results); + efi_status_t(EFIAPI *route_config)( + const struct efi_hii_config_routing_protocol *this, + const efi_string_t configuration, + efi_string_t *progress); + efi_status_t(EFIAPI *block_to_config)( + const struct efi_hii_config_routing_protocol *this, + const efi_string_t config_request, + const uint8_t *block, + const efi_uintn_t block_size, + efi_string_t *config, + efi_string_t *progress); + efi_status_t(EFIAPI *config_to_block)( + const struct efi_hii_config_routing_protocol *this, + const efi_string_t config_resp, + const uint8_t *block, + const efi_uintn_t *block_size, + efi_string_t *progress); + efi_status_t(EFIAPI *get_alt_config)( + const struct efi_hii_config_routing_protocol *this, + const efi_string_t config_resp, + const efi_guid_t *guid, + const efi_string_t name, + const struct efi_device_path *device_path, + const efi_string_t alt_cfg_id, + efi_string_t *alt_cfg_resp); +}; + +#define EFI_HII_DATABASE_PROTOCOL_GUID \ + EFI_GUID(0xef9fc172, 0xa1b2, 0x4693, \ + 0xb3, 0x27, 0x6d, 0x32, 0xfc, 0x41, 0x60, 0x42) + +typedef enum { +EFI_KEY_LCTRL ,EFI_KEY_A0 ,EFI_KEY_LALT ,EFI_KEY_SPACE_BAR , +EFI_KEY_A2 ,EFI_KEY_A3 ,EFI_KEY_A4 ,EFI_KEY_RCTRL ,EFI_KEY_LEFT_ARROW , +EFI_KEY_DOWN_ARROW ,EFI_KEY_RIGHT_ARROW ,EFI_KEY_ZERO , +EFI_KEY_PERIOD ,EFI_KEY_ENTER ,EFI_KEY_LSHIFT ,EFI_KEY_B0 , +EFI_KEY_B1 ,EFI_KEY_B2 ,EFI_KEY_B3 ,EFI_KEY_B4 ,EFI_KEY_B5 ,EFI_KEY_B6 , +EFI_KEY_B7 ,EFI_KEY_B8 ,EFI_KEY_B9 ,EFI_KEY_B10 ,EFI_KEY_RSHIFT , +EFI_KEY_UP_ARROW ,EFI_KEY_ONE ,EFI_KEY_TWO ,EFI_KEY_THREE , +EFI_KEY_CAPS_LOCK ,EFI_KEY_C1 ,EFI_KEY_C2 ,EFI_KEY_C3 ,EFI_KEY_C4 , +EFI_KEY_C5 ,EFI_KEY_C6 ,EFI_KEY_C7 ,EFI_KEY_C8 ,EFI_KEY_C9 , +EFI_KEY_C10 ,EFI_KEY_C11 ,EFI_KEY_C12 ,EFI_KEY_FOUR ,EFI_KEY_FIVE , +EFI_KEY_SIX ,EFI_KEY_PLUS ,EFI_KEY_TAB ,EFI_KEY_D1 ,EFI_KEY_D2 , +EFI_KEY_D3 ,EFI_KEY_D4 ,EFI_KEY_D5 ,EFI_KEY_D6 ,EFI_KEY_D7 ,EFI_KEY_D8 , +EFI_KEY_D9 ,EFI_KEY_D10 ,EFI_KEY_D11 ,EFI_KEY_D12 ,EFI_KEY_D13 , +EFI_KEY_DEL ,EFI_KEY_END ,EFI_KEY_PG_DN ,EFI_KEY_SEVEN ,EFI_KEY_EIGHT , +EFI_KEY_NINE ,EFI_KEY_E0 ,EFI_KEY_E1 ,EFI_KEY_E2 ,EFI_KEY_E3 , +EFI_KEY_E4 ,EFI_KEY_E5 ,EFI_KEY_E6 ,EFI_KEY_E7 ,EFI_KEY_E8 ,EFI_KEY_E9 , +EFI_KEY_E10 ,EFI_KEY_E11 ,EFI_KEY_E12 ,EFI_KEY_BACK_SPACE , +EFI_KEY_INS ,EFI_KEY_HOME ,EFI_KEY_PG_UP ,EFI_KEY_NLCK ,EFI_KEY_SLASH , +EFI_KEY_ASTERISK ,EFI_KEY_MINUS ,EFI_KEY_ESC ,EFI_KEY_F1 ,EFI_KEY_F2 , +EFI_KEY_F3 ,EFI_KEY_F4 ,EFI_KEY_F5 ,EFI_KEY_F6 ,EFI_KEY_F7 ,EFI_KEY_F8 , +EFI_KEY_F9 ,EFI_KEY_F10 ,EFI_KEY_F11 ,EFI_KEY_F12 ,EFI_KEY_PRINT , +EFI_KEY_SLCK ,EFI_KEY_PAUSE , +}efi_key ; + +struct efi_key_descriptor { +efi_key key; +uint16_t unicode; +uint16_t shifted_unicode; +uint16_t alt_gr_unicode; +uint16_t shifted_alt_gr_unicode; +uint16_t modifier; +uint16_t affected_attribute; +}; + +struct efi_hii_keyboard_layout { +uint16_t layout_length; +efi_guid_t guid; +uint32_t layout_descriptor_string_offset; +uint8_t descriptor_count; +struct efi_key_descriptor descriptors[]; +}; + +struct efi_hii_package_list_header { +efi_guid_t package_list_guid; +uint32_t package_length; +} __packed; + +struct efi_hii_package_header {
Quoted 8 lines
include/efi_api.h struct efi_device_path_utilities_protocol { · line 637
Quoted 3 lines
include/efi_api.h +3
-0+ uint32_t length : 24; + uint32_t type : 8; +} __packed;Bitfields are terribly evil - they're probably one of the worst defined things in C. A different compiler may even give you different ordering here. I've certainly seen bitfields explode in weird ways on cross-endian conversions.
edk2 defines it in the same way. And this is UEFI we are talking about here, big endian is strictly out of scope.
Quoted 64 lines
Do you think you could just make that a
uint32_taltogether and work with MASK/SHIFT defines instead?Quoted 46 lines
include/efi_api.h +46
-0+ +#define EFI_HII_PACKAGE_TYPE_ALL 0x00 +#define EFI_HII_PACKAGE_TYPE_GUID 0x01 +#define EFI_HII_PACKAGE_FORMS 0x02 +#define EFI_HII_PACKAGE_STRINGS 0x04 +#define EFI_HII_PACKAGE_FONTS 0x05 +#define EFI_HII_PACKAGE_IMAGES 0x06 +#define EFI_HII_PACKAGE_SIMPLE_FONTS 0x07 +#define EFI_HII_PACKAGE_DEVICE_PATH 0x08 +#define EFI_HII_PACKAGE_KEYBOARD_LAYOUT 0x09 +#define EFI_HII_PACKAGE_ANIMATIONS 0x0A +#define EFI_HII_PACKAGE_END 0xDF +#define EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN 0xE0 +#define EFI_HII_PACKAGE_TYPE_SYSTEM_END 0xFF + +struct efi_hii_strings_package { +struct efi_hii_package_header header; +uint32_t header_size; +uint32_t string_info_offset; +uint16_t language_window[16 ]; +efi_string_id_t language_name; +uint8_t language[]; +} __packed; + +struct efi_hii_string_block { +uint8_t block_type; +/*uint8_t block_body[];*/ +} __packed; + +#define EFI_HII_SIBT_END 0x00 // The end of the string information. +#define EFI_HII_SIBT_STRING_SCSU 0x10 // Single string using default font information. +#define EFI_HII_SIBT_STRING_SCSU_FONT 0x11 // Single string with font information. +#define EFI_HII_SIBT_STRINGS_SCSU 0x12 // Multiple strings using default font information. +#define EFI_HII_SIBT_STRINGS_SCSU_FONT 0x13 // Multiple strings with font information. +#define EFI_HII_SIBT_STRING_UCS2 0x14 // Single UCS-2 string using default font information. +#define EFI_HII_SIBT_STRING_UCS2_FONT 0x15 // Single UCS-2 string with font information +#define EFI_HII_SIBT_STRINGS_UCS2 0x16 // Multiple UCS-2 strings using default font information. +#define EFI_HII_SIBT_STRINGS_UCS2_FONT 0x17 // Multiple UCS-2 strings with font information. +#define EFI_HII_SIBT_DUPLICATE 0x20 // Create a duplicate of an existing string. +#define EFI_HII_SIBT_SKIP2 0x21 // Skip a certain number of string identifiers. +#define EFI_HII_SIBT_SKIP1 0x22 // Skip a certain number of string identifiers. +#define EFI_HII_SIBT_EXT1 0x30 // For future expansion (one byte length field) +#define EFI_HII_SIBT_EXT2 0x31 // For future expansion (two byte length field) +#define EFI_HII_SIBT_EXT4 0x32 // For future expansion (four byte length field) +#define EFI_HII_SIBT_FONT 0x40 // Font information. +include/efi_api.h struct efi_device_path_utilities_protocol { · line 693
Quoted 10 lines
include/efi_api.h +10
-0+struct efi_hii_sibt_string_ucs2_block { +struct efi_hii_string_block header; +uint16_t string_text[]; +} __packed; + +static inline struct efi_hii_string_block *efi_hii_sibt_string_ucs2_block_next ( +struct efi_hii_sibt_string_ucs2_block *blk) +{ +return ((void *)blk) +sizeof (*blk) + + (utf16_strlen (blk->string_text) +1 ) *2 ;Since you're dealing with actual utf16, is this correct? One character may as well span 4 bytes, right?
Quoted 2 lines
I think we need a different function that actually tells us the bytes occupied by a utf16 string.
as mentioned on IRC (just repeating here for those who weren't following #u-boot), utf16_strlen() is actually telling us the number of 16b "bytes" in a utf16 string, not the number of "characters". Similar to strlen() with a utf8 string.
Quoted 272 lines
Quoted 272 lines
include/efi_api.h +106
-0+} + +typedef void *efi_hii_handle_t ; + +struct efi_hii_database_protocol { + efi_status_t(EFIAPI *new_package_list)( + const struct efi_hii_database_protocol *this, + const struct efi_hii_package_list_header *package_list, + const efi_handle_t driver_handle, + efi_hii_handle_t *handle); + efi_status_t(EFIAPI *remove_package_list)( + const struct efi_hii_database_protocol *this, + efi_hii_handle_t handle); + efi_status_t(EFIAPI *update_package_list)( + const struct efi_hii_database_protocol *this, + efi_hii_handle_t handle, + const struct efi_hii_package_list_header *package_list); + efi_status_t(EFIAPI *list_package_lists)( + const struct efi_hii_database_protocol *this, + uint8_t package_type, + const efi_guid_t *package_guid, + efi_uintn_t *handle_buffer_length, + efi_hii_handle_t *handle); + efi_status_t(EFIAPI *export_package_lists)( + const struct efi_hii_database_protocol *this, + efi_hii_handle_t handle, + efi_uintn_t *buffer_size, + struct efi_hii_package_list_header *buffer); + efi_status_t(EFIAPI *register_package_notify)( + const struct efi_hii_database_protocol *this, + uint8_t package_type, + const efi_guid_t *package_guid, + const void *package_notify_fn, + efi_uintn_t notify_type, + efi_handle_t *notify_handle); + efi_status_t(EFIAPI *unregister_package_notify)( + const struct efi_hii_database_protocol *this, + efi_handle_t notification_handle + ); + efi_status_t(EFIAPI *find_keyboard_layouts)( + const struct efi_hii_database_protocol *this, + uint16_t *key_guid_buffer_length, + efi_guid_t *key_guid_buffer); + efi_status_t(EFIAPI *get_keyboard_layout)( + const struct efi_hii_database_protocol *this, + efi_guid_t *key_guid, + uint16_t *keyboard_layout_length, + struct efi_hii_keyboard_layout *keyboard_layout); + efi_status_t(EFIAPI *set_keyboard_layout)( + const struct efi_hii_database_protocol *this, + efi_guid_t *key_guid); + efi_status_t(EFIAPI *get_package_list_handle)( + const struct efi_hii_database_protocol *this, + efi_hii_handle_t package_list_handle, + efi_handle_t *driver_handle); +}; + +#define EFI_HII_STRING_PROTOCOL_GUID \ + EFI_GUID(0x0fd96974, 0x23aa, 0x4cdc, \ + 0xb9, 0xcb, 0x98, 0xd1, 0x77, 0x50, 0x32, 0x2a) + +typedef uint32_t efi_hii_font_style_t ; + +struct efi_font_info { +efi_hii_font_style_t font_style; +uint16_t font_size; +uint16_t font_name[1 ]; +}; + +struct efi_hii_string_protocol { + efi_status_t(EFIAPI *new_string)( + const struct efi_hii_string_protocol *this, + efi_hii_handle_t package_list, + efi_string_id_t *string_id, + const uint8_t *language, + const uint16_t *language_name, + const efi_string_t string, + const struct efi_font_info *string_font_info); + efi_status_t(EFIAPI *get_string)( + const struct efi_hii_string_protocol *this, + const uint8_t *language, + efi_hii_handle_t package_list, + efi_string_id_t string_id, + efi_string_t string, + efi_uintn_t *string_size, + struct efi_font_info **string_font_info); + efi_status_t(EFIAPI *set_string)( + const struct efi_hii_string_protocol *this, + efi_hii_handle_t package_list, + efi_string_id_t string_id, + const uint8_t *language, + const efi_string_t string, + const struct efi_font_info *string_font_info); + efi_status_t(EFIAPI *get_languages)( + const struct efi_hii_string_protocol *this, + efi_hii_handle_t package_list, + uint8_t *languages, + efi_uintn_t *languages_size); + efi_status_t(EFIAPI *get_secondary_languages)( + const struct efi_hii_string_protocol *this, + efi_hii_handle_t package_list, + const uint8_t *primary_language, + uint8_t *secondary_languages, + efi_uintn_t *secondary_languages_size); +}; +#define EFI_GOP_GUID \ EFI_GUID(0x9042a9de, 0x23dc, 0x4a38, \ 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a)include/efi_loader.h +6
-0@@ -80,6 +80,9 @@ extern struct efi_simple_input_interface efi_con_in;extern const struct efi_console_control_protocol efi_console_control;extern const struct efi_device_path_to_text_protocol efi_device_path_to_text;extern const struct efi_device_path_utilities_protocol efi_device_path_utilities; +extern const struct efi_hii_config_routing_protocol efi_hii_config_routing; +extern const struct efi_hii_database_protocol efi_hii_database; +extern const struct efi_hii_string_protocol efi_hii_string;uint16_t *efi_dp_str (struct efi_device_path *dp);@@ -91,6 +94,9 @@ extern const efi_guid_t efi_guid_device_path_to_text_protocol;extern const efi_guid_t efi_simple_file_system_protocol_guid;extern const efi_guid_t efi_file_info_guid;extern const efi_guid_t efi_guid_device_path_utilities_protocol; +extern const efi_guid_t efi_guid_hii_config_routing_protocol; +extern const efi_guid_t efi_guid_hii_database_protocol; +extern const efi_guid_t efi_guid_hii_string_protocol;extern unsigned int __efi_runtime_start, __efi_runtime_stop;extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;lib/efi_loader/Makefile +1
-1@@ -17,7 +17,7 @@ endif obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o -obj-y += efi_device_path_utilities.o +obj-y += efi_device_path_utilities.o efi_hii.o obj-y += efi_file.o efi_variable.o efi_bootmgr.o obj-$(CONFIG_LCD) += efi_gop.o obj-$(CONFIG_DM_VIDEO) += efi_gop.olib/efi_loader/efi_boottime.c +9
-0@@ -1157,6 +1157,15 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob obj->protocols[4 ].protocol_interface = (void *)&efi_device_path_utilities; + obj->protocols[5 ].guid = &efi_guid_hii_string_protocol; + obj->protocols[5 ].protocol_interface = (void *)&efi_hii_string; + + obj->protocols[6 ].guid = &efi_guid_hii_database_protocol; + obj->protocols[6 ].protocol_interface = (void *)&efi_hii_database; + + obj->protocols[7 ].guid = &efi_guid_hii_config_routing_protocol; + obj->protocols[7 ].protocol_interface = (void *)&efi_hii_config_routing; + info->file_path = file_path; info->device_handle =efi_dp_find_obj (device_path,NULL );lib/efi_loader/efi_hii.c new file +100
-0@@ -0,0 +1,507 @@ +/* +* EFI Human Interface Infrastructure ... interface +* +* Copyright (c) 2017 Leif Lindholm +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <malloc.h> +#include <efi_loader.h> + +const efi_guid_t efi_guid_hii_config_routing_protocol = +EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID ; +const efi_guid_t efi_guid_hii_database_protocol =EFI_HII_DATABASE_PROTOCOL_GUID ; +const efi_guid_t efi_guid_hii_string_protocol =EFI_HII_STRING_PROTOCOL_GUID ; + +struct hii_package { +// TODO should there be an associated efi_object? +struct list_head string_tables;/* list of string_table */ +/* we could also track fonts, images, etc */ +}; + +struct string_table { +struct list_head link; +efi_string_id_t language_name; +char *language; +uint32_t nstrings; +/* NOTE: string id starts at 1 so value is stbl->strings[id-1] */ +struct { +efi_string_t string; +/* we could also track font info, etc */ + } strings[]; +}; + +static void free_strings_table (struct string_table *stbl) +{ +int i; + +for (i =0 ; i < stbl->nstrings; i++) +free (stbl->strings[i].string); +free (stbl->language); +free (stbl); +} + +static struct hii_package *new_package (void ) +{ +struct hii_package *hii =malloc (sizeof (*hii)); +INIT_LIST_HEAD (&hii->string_tables); +return hii; +} + +static void free_package (struct hii_package *hii) +{ + +while (!list_empty (&hii->string_tables)) { +struct string_table *stbl; + + stbl =list_first_entry (&hii->string_tables, + struct string_table, link); +list_del (&stbl->link); +free_strings_table (stbl); + } + +free (hii); +} + +static efi_status_t add_strings_package (struct hii_package *hii, +struct efi_hii_strings_package *strings_package) +{ +struct efi_hii_string_block *block; +void *end = ((void *)strings_package) + strings_package->header.length; +uint32_t nstrings =0 ; +unsigned id =0 ; + +debug ("header_size: %08x\n" , strings_package->header_size); +debug ("string_info_offset: %08x\n" , strings_package->string_info_offset); +debug ("language_name: %u\n" , strings_package->language_name); +debug ("language: %s\n" , strings_package->language); + +/* count # of string entries: */ + block = ((void *)strings_package) + strings_package->string_info_offset; +while ((void *)block < end) { +switch (block->block_type) { +case EFI_HII_SIBT_STRING_UCS2 : { +struct efi_hii_sibt_string_ucs2_block *ucs2 = + (void *)block; + nstrings++; + block =efi_hii_sibt_string_ucs2_block_next (ucs2); +break ; + } +case EFI_HII_SIBT_END : + block = end; +break ; +default : +debug ("unknown HII string block type: %02x\n" , + block->block_type); +return EFI_INVALID_PARAMETER ; + } + }
Quoted 8 lines
lib/efi_loader/efi_hii.c line 105
Quoted 5 lines
lib/efi_loader/efi_hii.c new file +5
-0+ +struct string_table *stbl =malloc (sizeof (*stbl) + + (nstrings *sizeof (stbl->strings[0 ]))); + stbl->language_name = strings_package->language_name; + stbl->language =strdup ((char *)strings_package->language);Where does the
strings_packagecome from? And why is the language in it in UTF8?
The strings_package is a part of the "package list" blob passed in from (in this case) Shell.efi. The package list can actually contain a lot more (fonts/glyphs/images/forms), but not really sure how much of that we'll actually support. (HII seems to be able to do enough for rendering a full blown GUI.. kinda overkill, IMHO.. but Shell.efi wants it for silly reasons.)
This is actually utf8.. it is a "RFC 4646 language code identifier". See appendix M.
Quoted 295 lines
Quoted 295 lines
lib/efi_loader/efi_hii.c new file +294
-0+ stbl->nstrings = nstrings; + +list_add (&stbl->link, &hii->string_tables); + +/* and now parse string entries and populate string_table */ + block = ((void *)strings_package) + strings_package->string_info_offset; + +while ((void *)block < end) { +switch (block->block_type) { +case EFI_HII_SIBT_STRING_UCS2 : { +struct efi_hii_sibt_string_ucs2_block *ucs2 = + (void *)block; + id++; +debug ("%4u: \"%ls\"\n" , id, ucs2->string_text); + stbl->strings[id-1 ].string = +utf16_strdup (ucs2->string_text); + block =efi_hii_sibt_string_ucs2_block_next (ucs2); +break ; + } +case EFI_HII_SIBT_END : +return EFI_SUCCESS ; +default : +debug ("unknown HII string block type: %02x\n" , + block->block_type); +return EFI_INVALID_PARAMETER ; + } + } + +return EFI_SUCCESS ; +} + +/* +* EFI_HII_CONFIG_ROUTING_PROTOCOL +*/ + +static efi_status_t EFIAPI extract_config( +const struct efi_hii_config_routing_protocol *this, +const efi_string_t request, +efi_string_t *progress, +efi_string_t *results) +{ +EFI_ENTRY ("%p, \"%ls\", %p, %p" , this, request, progress, results); +return EFI_EXIT (EFI_OUT_OF_RESOURCES ); +} + +static efi_status_t EFIAPI export_config( +const struct efi_hii_config_routing_protocol *this, +efi_string_t *results) +{ +EFI_ENTRY ("%p, %p" , this, results); +return EFI_EXIT (EFI_OUT_OF_RESOURCES ); +} + +static efi_status_t EFIAPI route_config( +const struct efi_hii_config_routing_protocol *this, +const efi_string_t configuration, +efi_string_t *progress) +{ +EFI_ENTRY ("%p, \"%ls\", %p" , this, configuration, progress); +return EFI_EXIT (EFI_OUT_OF_RESOURCES ); +} + +static efi_status_t EFIAPI block_to_config( +const struct efi_hii_config_routing_protocol *this, +const efi_string_t config_request, +const uint8_t *block, +const efi_uintn_t block_size, +efi_string_t *config, +efi_string_t *progress) +{ +EFI_ENTRY ("%p, \"%ls\", %p, %zu, %p, %p" , this, config_request, block, + block_size, config, progress); +return EFI_EXIT (EFI_OUT_OF_RESOURCES ); +} + +static efi_status_t EFIAPI config_to_block( +const struct efi_hii_config_routing_protocol *this, +const efi_string_t config_resp, +const uint8_t *block, +const efi_uintn_t *block_size, +efi_string_t *progress) +{ +EFI_ENTRY ("%p, \"%ls\", %p, %p, %p" , this, config_resp, block, + block_size, progress); +return EFI_EXIT (EFI_OUT_OF_RESOURCES ); +} + +static efi_status_t EFIAPI get_alt_config( +const struct efi_hii_config_routing_protocol *this, +const efi_string_t config_resp, +const efi_guid_t *guid, +const efi_string_t name, +const struct efi_device_path *device_path, +const efi_string_t alt_cfg_id, +efi_string_t *alt_cfg_resp) +{ +EFI_ENTRY ("%p, \"%ls\", %pUl, \"%ls\", %p, \"%ls\", %p" , this, + config_resp, guid, name, device_path, alt_cfg_id, + alt_cfg_resp); +return EFI_EXIT (EFI_OUT_OF_RESOURCES ); +} + + +/* +* EFI_HII_DATABASE_PROTOCOL +*/ + +static efi_status_t EFIAPI new_package_list( +const struct efi_hii_database_protocol *this, +const struct efi_hii_package_list_header *package_list, +const efi_handle_t driver_handle, +efi_hii_handle_t *handle) +{ +efi_status_t ret =EFI_SUCCESS ; + +EFI_ENTRY ("%p, %p, %p, %p" , this, package_list, driver_handle, handle); + +if (!package_list || !driver_handle) +return EFI_EXIT (EFI_INVALID_PARAMETER ); + +struct hii_package *hii =new_package (); +struct efi_hii_package_header *package; +void *end = ((void *)package_list) + package_list->package_length; + +debug ("package_list: %pUl (%u)\n" , &package_list->package_list_guid, + package_list->package_length); + + package = ((void *)package_list) +sizeof (*package_list); +while ((void *)package < end) { +debug ("package=%p, package type=%x, length=%u\n" , package, + package->type, package->length); +switch (package->type) { +case EFI_HII_PACKAGE_STRINGS : + ret =add_strings_package (hii, + (struct efi_hii_strings_package *)package); +break ; +default : +break ; + } + +if (ret !=EFI_SUCCESS ) + goto error; + + package = ((void *)package) + package->length; + } + +// TODO in theory there is some notifications that should be sent.. + + *handle = hii; + +return EFI_EXIT (EFI_SUCCESS ); + +error: +free_package (hii); +return EFI_EXIT (ret); +} + +static efi_status_t EFIAPI remove_package_list( +const struct efi_hii_database_protocol *this, +efi_hii_handle_t handle) +{ +struct hii_package *hii = handle; +EFI_ENTRY ("%p, %p" , this, handle); +free_package (hii); +return EFI_EXIT (EFI_SUCCESS ); +} + +static efi_status_t EFIAPI update_package_list( +const struct efi_hii_database_protocol *this, +efi_hii_handle_t handle, +const struct efi_hii_package_list_header *package_list) +{ +EFI_ENTRY ("%p, %p, %p" , this, handle, package_list); +return EFI_EXIT (EFI_NOT_FOUND ); +} + +static efi_status_t EFIAPI list_package_lists( +const struct efi_hii_database_protocol *this, +uint8_t package_type, +const efi_guid_t *package_guid, +efi_uintn_t *handle_buffer_length, +efi_hii_handle_t *handle) +{ +EFI_ENTRY ("%p, %u, %pUl, %p, %p" , this, package_type, package_guid, + handle_buffer_length, handle); +return EFI_EXIT (EFI_NOT_FOUND ); +} + +static efi_status_t EFIAPI export_package_lists( +const struct efi_hii_database_protocol *this, +efi_hii_handle_t handle, +efi_uintn_t *buffer_size, +struct efi_hii_package_list_header *buffer) +{ +EFI_ENTRY ("%p, %p, %p, %p" , this, handle, buffer_size, buffer); +return EFI_EXIT (EFI_NOT_FOUND ); +} + +static efi_status_t EFIAPI register_package_notify( +const struct efi_hii_database_protocol *this, +uint8_t package_type, +const efi_guid_t *package_guid, +const void *package_notify_fn, +efi_uintn_t notify_type, +efi_handle_t *notify_handle) +{ +EFI_ENTRY ("%p, %u, %pUl, %p, %zu, %p" , this, package_type, + package_guid, package_notify_fn, notify_type, + notify_handle); +return EFI_EXIT (EFI_OUT_OF_RESOURCES ); +} + +static efi_status_t EFIAPI unregister_package_notify( +const struct efi_hii_database_protocol *this, +efi_handle_t notification_handle) +{ +EFI_ENTRY ("%p, %p" , this, notification_handle); +return EFI_EXIT (EFI_NOT_FOUND ); +} + +static efi_status_t EFIAPI find_keyboard_layouts( +const struct efi_hii_database_protocol *this, +uint16_t *key_guid_buffer_length, +efi_guid_t *key_guid_buffer) +{ +EFI_ENTRY ("%p, %p, %p" , this, key_guid_buffer_length, key_guid_buffer); +return EFI_EXIT (EFI_NOT_FOUND );/* Invalid */ +} + +static efi_status_t EFIAPI get_keyboard_layout( +const struct efi_hii_database_protocol *this, +efi_guid_t *key_guid, +uint16_t *keyboard_layout_length, +struct efi_hii_keyboard_layout *keyboard_layout) +{ +EFI_ENTRY ("%p, %pUl, %p, %p" , this, key_guid, keyboard_layout_length, + keyboard_layout); +return EFI_EXIT (EFI_NOT_FOUND ); +} + +static efi_status_t EFIAPI set_keyboard_layout( +const struct efi_hii_database_protocol *this, +efi_guid_t *key_guid) +{ +EFI_ENTRY ("%p, %pUl" , this, key_guid); +return EFI_EXIT (EFI_NOT_FOUND ); +} + +static efi_status_t EFIAPI get_package_list_handle( +const struct efi_hii_database_protocol *this, +efi_hii_handle_t package_list_handle, +efi_handle_t *driver_handle) +{ +EFI_ENTRY ("%p, %p, %p" , this, package_list_handle, driver_handle); +return EFI_EXIT (EFI_INVALID_PARAMETER ); +} + + +/* +* EFI_HII_STRING_PROTOCOL +*/ + +static efi_status_t EFIAPI new_string( +const struct efi_hii_string_protocol *this, +efi_hii_handle_t package_list, +efi_string_id_t *string_id, +const uint8_t *language, +const uint16_t *language_name, +const efi_string_t string, +const struct efi_font_info *string_font_info) +{ +EFI_ENTRY ("%p, %p, %p, \"%s\", %p, \"%ls\", %p" , this, package_list, + string_id, language, language_name, string, + string_font_info); +return EFI_EXIT (EFI_NOT_FOUND ); +} + +static efi_status_t EFIAPI get_string( +const struct efi_hii_string_protocol *this, +const uint8_t *language, +efi_hii_handle_t package_list, +efi_string_id_t string_id, +efi_string_t string, +efi_uintn_t *string_size, +struct efi_font_info **string_font_info) +{ +struct hii_package *hii = package_list; +struct string_table *stbl; + +EFI_ENTRY ("%p, \"%s\", %p, %u, %p, %p, %p" , this, language, + package_list, string_id, string, string_size, + string_font_info); + +list_for_each_entry (stbl, &hii->string_tables, link) {
Quoted 8 lines
lib/efi_loader/efi_hii.c line 405
Quoted 6 lines
lib/efi_loader/efi_hii.c new file +6
-0+if (!strcmp ((char *)language, (char *)stbl->language)) { +unsigned idx = string_id -1 ; +if (idx > stbl->nstrings) +return EFI_EXIT (EFI_NOT_FOUND ); +efi_string_t str = stbl->strings[idx].string; +size_t len =utf16_strlen (str) +1 ;I assume that's wrong for sizing too?
nope :-)
Quoted 2 lines
Also please try not to define variables mid-scope :). Just define them above the
if()and fill them after ...
Hmm, I'd have the inverse comment if someone else wrote it and defined all the variables at the top ;-)
Quoted 18 lines
Then also for the sake of readability add a blank line after the variable definitions and before the return.
I think you'd also do yourself a favor if you reduced the indenting a bit. Just abort the
list_for_eachwhen you found and entry and then process it in the top level scope.static struct
string_table*find_stbl_by_lang(const char *language){ list_for_each(...) { if (matches) { return stbl; } } return NULL; }
Quoted 3 lines
stbl =
find_stbl_by_lang(lang);
if (!stbl)
returnEFI_EXIT(EFI_NOT_FOUND)
yeah, perhaps
BR,
-R
Quoted 110 lines
work_with_stbl;return
EFI_EXIT(EFI_SUCCESS);Alex
Quoted 103 lines
lib/efi_loader/efi_hii.c new file +102
-0+if (*string_size < len *2 ) { + *string_size = len *2 ; +return EFI_EXIT (EFI_BUFFER_TOO_SMALL ); + } +memcpy (string, str, len *2 ); + *string_size = len *2 ; +return EFI_EXIT (EFI_SUCCESS ); + } + } + +return EFI_EXIT (EFI_NOT_FOUND ); +} + +static efi_status_t EFIAPI set_string( +const struct efi_hii_string_protocol *this, +efi_hii_handle_t package_list, +efi_string_id_t string_id, +const uint8_t *language, +const efi_string_t string, +const struct efi_font_info *string_font_info) +{ +EFI_ENTRY ("%p, %p, %u, \"%s\", \"%ls\", %p" , this, package_list, + string_id, language, string, string_font_info); +return EFI_EXIT (EFI_NOT_FOUND ); +} + +static efi_status_t EFIAPI get_languages( +const struct efi_hii_string_protocol *this, +efi_hii_handle_t package_list, +uint8_t *languages, +efi_uintn_t *languages_size) +{ +struct hii_package *hii = package_list; +struct string_table *stbl; +size_t len =0 ; + +EFI_ENTRY ("%p, %p, %p, %p" , this, package_list, languages, + languages_size); + +/* figure out required size: */ +list_for_each_entry (stbl, &hii->string_tables, link) { + len +=strlen ((char *)stbl->language) +1 ; + } + +if (*languages_size < len) { + *languages_size = len; +return EFI_EXIT (EFI_BUFFER_TOO_SMALL ); + } + +char *p = (char *)languages; +list_for_each_entry (stbl, &hii->string_tables, link) { +if (p != (char *)languages) + p +=sprintf (p,";" ); + p +=sprintf (p,"%s" , stbl->language); + } + +debug ("languages: %s\n" , languages); + +return EFI_EXIT (EFI_SUCCESS ); +} + +static efi_status_t EFIAPI get_secondary_languages( +const struct efi_hii_string_protocol *this, +efi_hii_handle_t package_list, +const uint8_t *primary_language, +uint8_t *secondary_languages, +efi_uintn_t *secondary_languages_size) +{ +EFI_ENTRY ("%p, %p, \"%s\", %p, %p" , this, package_list, + primary_language, secondary_languages, + secondary_languages_size); +return EFI_EXIT (EFI_NOT_FOUND ); +} + +const struct efi_hii_config_routing_protocol efi_hii_config_routing = { + .extract_config = extract_config, + .export_config = export_config, + .route_config = route_config, + .block_to_config = block_to_config, + .config_to_block = config_to_block, + .get_alt_config = get_alt_config +}; +const struct efi_hii_database_protocol efi_hii_database = { + .new_package_list = new_package_list, + .remove_package_list = remove_package_list, + .update_package_list = update_package_list, + .list_package_lists = list_package_lists, + .export_package_lists = export_package_lists, + .register_package_notify = register_package_notify, + .unregister_package_notify = unregister_package_notify, + .find_keyboard_layouts = find_keyboard_layouts, + .get_keyboard_layout = get_keyboard_layout, + .set_keyboard_layout = set_keyboard_layout, + .get_package_list_handle = get_package_list_handle +}; +const struct efi_hii_string_protocol efi_hii_string = { + .new_string = new_string, + .get_string = get_string, + .set_string = set_string, + .get_languages = get_languages, + .get_secondary_languages = get_secondary_languages +};
PATCH 2/11 efi_loader: Initial HII protocols
Quoted 149 lines · Rob Clark
Quoted 139 lines · Alexander Graf
Quoted 136 lines · Rob Clark
From: Leif Lindholm <[email protected]>
Enough implementation of the following protocols to run Shell.efi and SCT.efi:
EfiHiiConfigRoutingProtocolGuid
EfiHiiDatabaseProtocol
EfiHiiStringProtocolWe'll fill in the rest once SCT is running properly so we can validate the implementation against the conformance test suite.
Initial skeleton written by Leif, and then implementation by myself.
Cc Leif Lindholm <[email protected]>Signed-off-by Rob Clark <[email protected]>--- include/efi_api.h | 261 ++++++++++++++++++++++ include/efi_loader.h | 6 + lib/efi_loader/Makefile | 2 +- lib/efi_loader/efi_boottime.c | 9 + lib/efi_loader/efi_hii.c | 507 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 784 insertions(+), 1 deletion(-) create mode 100644 lib/efi_loader/efi_hii.cinclude/efi_api.h +96
-0@@ -16,6 +16,7 @@#define _EFI_API_H#include <efi.h> +#include <charset.h> #ifdef CONFIG_EFI_LOADER #include <asm/setjmp.h> @@ -536,6 +537,266 @@ struct efi_device_path_utilities_protocol { uint16_t node_length); }; +#define EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID \ + EFI_GUID(0x587e72d7, 0xcc50, 0x4f79, \ + 0x82, 0x09, 0xca, 0x29, 0x1f, 0xc1, 0xa1, 0x0f) + +typedef uint16_t efi_string_id_t ; + +struct efi_hii_config_routing_protocol { + efi_status_t(EFIAPI *extract_config)( + const struct efi_hii_config_routing_protocol *this, + const efi_string_t request, + efi_string_t *progress, + efi_string_t *results); + efi_status_t(EFIAPI *export_config)( + const struct efi_hii_config_routing_protocol *this, + efi_string_t *results); + efi_status_t(EFIAPI *route_config)( + const struct efi_hii_config_routing_protocol *this, + const efi_string_t configuration, + efi_string_t *progress); + efi_status_t(EFIAPI *block_to_config)( + const struct efi_hii_config_routing_protocol *this, + const efi_string_t config_request, + const uint8_t *block, + const efi_uintn_t block_size, + efi_string_t *config, + efi_string_t *progress); + efi_status_t(EFIAPI *config_to_block)( + const struct efi_hii_config_routing_protocol *this, + const efi_string_t config_resp, + const uint8_t *block, + const efi_uintn_t *block_size, + efi_string_t *progress); + efi_status_t(EFIAPI *get_alt_config)( + const struct efi_hii_config_routing_protocol *this, + const efi_string_t config_resp, + const efi_guid_t *guid, + const efi_string_t name, + const struct efi_device_path *device_path, + const efi_string_t alt_cfg_id, + efi_string_t *alt_cfg_resp); +}; + +#define EFI_HII_DATABASE_PROTOCOL_GUID \ + EFI_GUID(0xef9fc172, 0xa1b2, 0x4693, \ + 0xb3, 0x27, 0x6d, 0x32, 0xfc, 0x41, 0x60, 0x42) + +typedef enum { +EFI_KEY_LCTRL ,EFI_KEY_A0 ,EFI_KEY_LALT ,EFI_KEY_SPACE_BAR , +EFI_KEY_A2 ,EFI_KEY_A3 ,EFI_KEY_A4 ,EFI_KEY_RCTRL ,EFI_KEY_LEFT_ARROW , +EFI_KEY_DOWN_ARROW ,EFI_KEY_RIGHT_ARROW ,EFI_KEY_ZERO , +EFI_KEY_PERIOD ,EFI_KEY_ENTER ,EFI_KEY_LSHIFT ,EFI_KEY_B0 , +EFI_KEY_B1 ,EFI_KEY_B2 ,EFI_KEY_B3 ,EFI_KEY_B4 ,EFI_KEY_B5 ,EFI_KEY_B6 , +EFI_KEY_B7 ,EFI_KEY_B8 ,EFI_KEY_B9 ,EFI_KEY_B10 ,EFI_KEY_RSHIFT , +EFI_KEY_UP_ARROW ,EFI_KEY_ONE ,EFI_KEY_TWO ,EFI_KEY_THREE , +EFI_KEY_CAPS_LOCK ,EFI_KEY_C1 ,EFI_KEY_C2 ,EFI_KEY_C3 ,EFI_KEY_C4 , +EFI_KEY_C5 ,EFI_KEY_C6 ,EFI_KEY_C7 ,EFI_KEY_C8 ,EFI_KEY_C9 , +EFI_KEY_C10 ,EFI_KEY_C11 ,EFI_KEY_C12 ,EFI_KEY_FOUR ,EFI_KEY_FIVE , +EFI_KEY_SIX ,EFI_KEY_PLUS ,EFI_KEY_TAB ,EFI_KEY_D1 ,EFI_KEY_D2 , +EFI_KEY_D3 ,EFI_KEY_D4 ,EFI_KEY_D5 ,EFI_KEY_D6 ,EFI_KEY_D7 ,EFI_KEY_D8 , +EFI_KEY_D9 ,EFI_KEY_D10 ,EFI_KEY_D11 ,EFI_KEY_D12 ,EFI_KEY_D13 , +EFI_KEY_DEL ,EFI_KEY_END ,EFI_KEY_PG_DN ,EFI_KEY_SEVEN ,EFI_KEY_EIGHT , +EFI_KEY_NINE ,EFI_KEY_E0 ,EFI_KEY_E1 ,EFI_KEY_E2 ,EFI_KEY_E3 , +EFI_KEY_E4 ,EFI_KEY_E5 ,EFI_KEY_E6 ,EFI_KEY_E7 ,EFI_KEY_E8 ,EFI_KEY_E9 , +EFI_KEY_E10 ,EFI_KEY_E11 ,EFI_KEY_E12 ,EFI_KEY_BACK_SPACE , +EFI_KEY_INS ,EFI_KEY_HOME ,EFI_KEY_PG_UP ,EFI_KEY_NLCK ,EFI_KEY_SLASH , +EFI_KEY_ASTERISK ,EFI_KEY_MINUS ,EFI_KEY_ESC ,EFI_KEY_F1 ,EFI_KEY_F2 , +EFI_KEY_F3 ,EFI_KEY_F4 ,EFI_KEY_F5 ,EFI_KEY_F6 ,EFI_KEY_F7 ,EFI_KEY_F8 , +EFI_KEY_F9 ,EFI_KEY_F10 ,EFI_KEY_F11 ,EFI_KEY_F12 ,EFI_KEY_PRINT , +EFI_KEY_SLCK ,EFI_KEY_PAUSE , +}efi_key ; + +struct efi_key_descriptor { +efi_key key; +uint16_t unicode; +uint16_t shifted_unicode; +uint16_t alt_gr_unicode; +uint16_t shifted_alt_gr_unicode; +uint16_t modifier; +uint16_t affected_attribute; +}; + +struct efi_hii_keyboard_layout { +uint16_t layout_length; +efi_guid_t guid; +uint32_t layout_descriptor_string_offset; +uint8_t descriptor_count; +struct efi_key_descriptor descriptors[]; +}; + +struct efi_hii_package_list_header { +efi_guid_t package_list_guid; +uint32_t package_length; +} __packed; + +struct efi_hii_package_header {Quoted 8 lines
include/efi_api.h struct efi_device_path_utilities_protocol { · line 637
Quoted 3 lines
include/efi_api.h +3
-0+ uint32_t length : 24; + uint32_t type : 8; +} __packed;Bitfields are terribly evil - they're probably one of the worst defined things in C. A different compiler may even give you different ordering here. I've certainly seen bitfields explode in weird ways on cross-endian conversions.
Quoted 2 lines
edk2 defines it in the same way. And this is UEFI we are talking about here, big endian is strictly out of scope.
I don't see why big endian is strictly out of scope. I don't want to ignore it light heartedly. All we'd need to do is byte swap every input/output there is today.
So please change it to not use bitmasks. I don't think we should copy bad design decisions from edk2.
Quoted 693 lines
Quoted 66 lines
Do you think you could just make that a
uint32_taltogether and work with MASK/SHIFT defines instead?Quoted 46 lines
include/efi_api.h +46
-0+ +#define EFI_HII_PACKAGE_TYPE_ALL 0x00 +#define EFI_HII_PACKAGE_TYPE_GUID 0x01 +#define EFI_HII_PACKAGE_FORMS 0x02 +#define EFI_HII_PACKAGE_STRINGS 0x04 +#define EFI_HII_PACKAGE_FONTS 0x05 +#define EFI_HII_PACKAGE_IMAGES 0x06 +#define EFI_HII_PACKAGE_SIMPLE_FONTS 0x07 +#define EFI_HII_PACKAGE_DEVICE_PATH 0x08 +#define EFI_HII_PACKAGE_KEYBOARD_LAYOUT 0x09 +#define EFI_HII_PACKAGE_ANIMATIONS 0x0A +#define EFI_HII_PACKAGE_END 0xDF +#define EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN 0xE0 +#define EFI_HII_PACKAGE_TYPE_SYSTEM_END 0xFF + +struct efi_hii_strings_package { +struct efi_hii_package_header header; +uint32_t header_size; +uint32_t string_info_offset; +uint16_t language_window[16 ]; +efi_string_id_t language_name; +uint8_t language[]; +} __packed; + +struct efi_hii_string_block { +uint8_t block_type; +/*uint8_t block_body[];*/ +} __packed; + +#define EFI_HII_SIBT_END 0x00 // The end of the string information. +#define EFI_HII_SIBT_STRING_SCSU 0x10 // Single string using default font information. +#define EFI_HII_SIBT_STRING_SCSU_FONT 0x11 // Single string with font information. +#define EFI_HII_SIBT_STRINGS_SCSU 0x12 // Multiple strings using default font information. +#define EFI_HII_SIBT_STRINGS_SCSU_FONT 0x13 // Multiple strings with font information. +#define EFI_HII_SIBT_STRING_UCS2 0x14 // Single UCS-2 string using default font information. +#define EFI_HII_SIBT_STRING_UCS2_FONT 0x15 // Single UCS-2 string with font information +#define EFI_HII_SIBT_STRINGS_UCS2 0x16 // Multiple UCS-2 strings using default font information. +#define EFI_HII_SIBT_STRINGS_UCS2_FONT 0x17 // Multiple UCS-2 strings with font information. +#define EFI_HII_SIBT_DUPLICATE 0x20 // Create a duplicate of an existing string. +#define EFI_HII_SIBT_SKIP2 0x21 // Skip a certain number of string identifiers. +#define EFI_HII_SIBT_SKIP1 0x22 // Skip a certain number of string identifiers. +#define EFI_HII_SIBT_EXT1 0x30 // For future expansion (one byte length field) +#define EFI_HII_SIBT_EXT2 0x31 // For future expansion (two byte length field) +#define EFI_HII_SIBT_EXT4 0x32 // For future expansion (four byte length field) +#define EFI_HII_SIBT_FONT 0x40 // Font information. +include/efi_api.h struct efi_device_path_utilities_protocol { · line 693
Quoted 10 lines
include/efi_api.h +10
-0+struct efi_hii_sibt_string_ucs2_block { +struct efi_hii_string_block header; +uint16_t string_text[]; +} __packed; + +static inline struct efi_hii_string_block *efi_hii_sibt_string_ucs2_block_next ( +struct efi_hii_sibt_string_ucs2_block *blk) +{ +return ((void *)blk) +sizeof (*blk) + + (utf16_strlen (blk->string_text) +1 ) *2 ;Since you're dealing with actual utf16, is this correct? One character may as well span 4 bytes, right?
Quoted 2 lines
I think we need a different function that actually tells us the bytes occupied by a utf16 string.
as mentioned on IRC (just repeating here for those who weren't following #u-boot),
utf16_strlen()is actually telling us the number of 16b "bytes" in a utf16 string, not the number of "characters". Similar tostrlen()with a utf8 string.Quoted 272 lines
Quoted 272 lines
include/efi_api.h +106
-0+} + +typedef void *efi_hii_handle_t ; + +struct efi_hii_database_protocol { + efi_status_t(EFIAPI *new_package_list)( + const struct efi_hii_database_protocol *this, + const struct efi_hii_package_list_header *package_list, + const efi_handle_t driver_handle, + efi_hii_handle_t *handle); + efi_status_t(EFIAPI *remove_package_list)( + const struct efi_hii_database_protocol *this, + efi_hii_handle_t handle); + efi_status_t(EFIAPI *update_package_list)( + const struct efi_hii_database_protocol *this, + efi_hii_handle_t handle, + const struct efi_hii_package_list_header *package_list); + efi_status_t(EFIAPI *list_package_lists)( + const struct efi_hii_database_protocol *this, + uint8_t package_type, + const efi_guid_t *package_guid, + efi_uintn_t *handle_buffer_length, + efi_hii_handle_t *handle); + efi_status_t(EFIAPI *export_package_lists)( + const struct efi_hii_database_protocol *this, + efi_hii_handle_t handle, + efi_uintn_t *buffer_size, + struct efi_hii_package_list_header *buffer); + efi_status_t(EFIAPI *register_package_notify)( + const struct efi_hii_database_protocol *this, + uint8_t package_type, + const efi_guid_t *package_guid, + const void *package_notify_fn, + efi_uintn_t notify_type, + efi_handle_t *notify_handle); + efi_status_t(EFIAPI *unregister_package_notify)( + const struct efi_hii_database_protocol *this, + efi_handle_t notification_handle + ); + efi_status_t(EFIAPI *find_keyboard_layouts)( + const struct efi_hii_database_protocol *this, + uint16_t *key_guid_buffer_length, + efi_guid_t *key_guid_buffer); + efi_status_t(EFIAPI *get_keyboard_layout)( + const struct efi_hii_database_protocol *this, + efi_guid_t *key_guid, + uint16_t *keyboard_layout_length, + struct efi_hii_keyboard_layout *keyboard_layout); + efi_status_t(EFIAPI *set_keyboard_layout)( + const struct efi_hii_database_protocol *this, + efi_guid_t *key_guid); + efi_status_t(EFIAPI *get_package_list_handle)( + const struct efi_hii_database_protocol *this, + efi_hii_handle_t package_list_handle, + efi_handle_t *driver_handle); +}; + +#define EFI_HII_STRING_PROTOCOL_GUID \ + EFI_GUID(0x0fd96974, 0x23aa, 0x4cdc, \ + 0xb9, 0xcb, 0x98, 0xd1, 0x77, 0x50, 0x32, 0x2a) + +typedef uint32_t efi_hii_font_style_t ; + +struct efi_font_info { +efi_hii_font_style_t font_style; +uint16_t font_size; +uint16_t font_name[1 ]; +}; + +struct efi_hii_string_protocol { + efi_status_t(EFIAPI *new_string)( + const struct efi_hii_string_protocol *this, + efi_hii_handle_t package_list, + efi_string_id_t *string_id, + const uint8_t *language, + const uint16_t *language_name, + const efi_string_t string, + const struct efi_font_info *string_font_info); + efi_status_t(EFIAPI *get_string)( + const struct efi_hii_string_protocol *this, + const uint8_t *language, + efi_hii_handle_t package_list, + efi_string_id_t string_id, + efi_string_t string, + efi_uintn_t *string_size, + struct efi_font_info **string_font_info); + efi_status_t(EFIAPI *set_string)( + const struct efi_hii_string_protocol *this, + efi_hii_handle_t package_list, + efi_string_id_t string_id, + const uint8_t *language, + const efi_string_t string, + const struct efi_font_info *string_font_info); + efi_status_t(EFIAPI *get_languages)( + const struct efi_hii_string_protocol *this, + efi_hii_handle_t package_list, + uint8_t *languages, + efi_uintn_t *languages_size); + efi_status_t(EFIAPI *get_secondary_languages)( + const struct efi_hii_string_protocol *this, + efi_hii_handle_t package_list, + const uint8_t *primary_language, + uint8_t *secondary_languages, + efi_uintn_t *secondary_languages_size); +}; +#define EFI_GOP_GUID \ EFI_GUID(0x9042a9de, 0x23dc, 0x4a38, \ 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a)include/efi_loader.h +6
-0@@ -80,6 +80,9 @@ extern struct efi_simple_input_interface efi_con_in;extern const struct efi_console_control_protocol efi_console_control;extern const struct efi_device_path_to_text_protocol efi_device_path_to_text;extern const struct efi_device_path_utilities_protocol efi_device_path_utilities; +extern const struct efi_hii_config_routing_protocol efi_hii_config_routing; +extern const struct efi_hii_database_protocol efi_hii_database; +extern const struct efi_hii_string_protocol efi_hii_string;uint16_t *efi_dp_str (struct efi_device_path *dp);@@ -91,6 +94,9 @@ extern const efi_guid_t efi_guid_device_path_to_text_protocol;extern const efi_guid_t efi_simple_file_system_protocol_guid;extern const efi_guid_t efi_file_info_guid;extern const efi_guid_t efi_guid_device_path_utilities_protocol; +extern const efi_guid_t efi_guid_hii_config_routing_protocol; +extern const efi_guid_t efi_guid_hii_database_protocol; +extern const efi_guid_t efi_guid_hii_string_protocol;extern unsigned int __efi_runtime_start, __efi_runtime_stop;extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;lib/efi_loader/Makefile +1
-1@@ -17,7 +17,7 @@ endif obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o -obj-y += efi_device_path_utilities.o +obj-y += efi_device_path_utilities.o efi_hii.o obj-y += efi_file.o efi_variable.o efi_bootmgr.o obj-$(CONFIG_LCD) += efi_gop.o obj-$(CONFIG_DM_VIDEO) += efi_gop.olib/efi_loader/efi_boottime.c +9
-0@@ -1157,6 +1157,15 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob obj->protocols[4 ].protocol_interface = (void *)&efi_device_path_utilities; + obj->protocols[5 ].guid = &efi_guid_hii_string_protocol; + obj->protocols[5 ].protocol_interface = (void *)&efi_hii_string; + + obj->protocols[6 ].guid = &efi_guid_hii_database_protocol; + obj->protocols[6 ].protocol_interface = (void *)&efi_hii_database; + + obj->protocols[7 ].guid = &efi_guid_hii_config_routing_protocol; + obj->protocols[7 ].protocol_interface = (void *)&efi_hii_config_routing; + info->file_path = file_path; info->device_handle =efi_dp_find_obj (device_path,NULL );lib/efi_loader/efi_hii.c new file +100
-0@@ -0,0 +1,507 @@ +/* +* EFI Human Interface Infrastructure ... interface +* +* Copyright (c) 2017 Leif Lindholm +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <malloc.h> +#include <efi_loader.h> + +const efi_guid_t efi_guid_hii_config_routing_protocol = +EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID ; +const efi_guid_t efi_guid_hii_database_protocol =EFI_HII_DATABASE_PROTOCOL_GUID ; +const efi_guid_t efi_guid_hii_string_protocol =EFI_HII_STRING_PROTOCOL_GUID ; + +struct hii_package { +// TODO should there be an associated efi_object? +struct list_head string_tables;/* list of string_table */ +/* we could also track fonts, images, etc */ +}; + +struct string_table { +struct list_head link; +efi_string_id_t language_name; +char *language; +uint32_t nstrings; +/* NOTE: string id starts at 1 so value is stbl->strings[id-1] */ +struct { +efi_string_t string; +/* we could also track font info, etc */ + } strings[]; +}; + +static void free_strings_table (struct string_table *stbl) +{ +int i; + +for (i =0 ; i < stbl->nstrings; i++) +free (stbl->strings[i].string); +free (stbl->language); +free (stbl); +} + +static struct hii_package *new_package (void ) +{ +struct hii_package *hii =malloc (sizeof (*hii)); +INIT_LIST_HEAD (&hii->string_tables); +return hii; +} + +static void free_package (struct hii_package *hii) +{ + +while (!list_empty (&hii->string_tables)) { +struct string_table *stbl; + + stbl =list_first_entry (&hii->string_tables, + struct string_table, link); +list_del (&stbl->link); +free_strings_table (stbl); + } + +free (hii); +} + +static efi_status_t add_strings_package (struct hii_package *hii, +struct efi_hii_strings_package *strings_package) +{ +struct efi_hii_string_block *block; +void *end = ((void *)strings_package) + strings_package->header.length; +uint32_t nstrings =0 ; +unsigned id =0 ; + +debug ("header_size: %08x\n" , strings_package->header_size); +debug ("string_info_offset: %08x\n" , strings_package->string_info_offset); +debug ("language_name: %u\n" , strings_package->language_name); +debug ("language: %s\n" , strings_package->language); + +/* count # of string entries: */ + block = ((void *)strings_package) + strings_package->string_info_offset; +while ((void *)block < end) { +switch (block->block_type) { +case EFI_HII_SIBT_STRING_UCS2 : { +struct efi_hii_sibt_string_ucs2_block *ucs2 = + (void *)block; + nstrings++; + block =efi_hii_sibt_string_ucs2_block_next (ucs2); +break ; + } +case EFI_HII_SIBT_END : + block = end; +break ; +default : +debug ("unknown HII string block type: %02x\n" , + block->block_type); +return EFI_INVALID_PARAMETER ; + } + }Quoted 8 lines
lib/efi_loader/efi_hii.c line 105
Quoted 5 lines
lib/efi_loader/efi_hii.c new file +5
-0+ +struct string_table *stbl =malloc (sizeof (*stbl) + + (nstrings *sizeof (stbl->strings[0 ]))); + stbl->language_name = strings_package->language_name; + stbl->language =strdup ((char *)strings_package->language);Where does the
strings_packagecome from? And why is the language in it in UTF8?The
strings_packageis a part of the "package list" blob passed in from (in this case) Shell.efi. The package list can actually contain a lot more (fonts/glyphs/images/forms), but not really sure how much of that we'll actually support. (HII seems to be able to do enough for rendering a full blown GUI.. kinda overkill, IMHO.. but Shell.efi wants it for silly reasons.)This is actually utf8.. it is a "RFC 4646 language code identifier". See appendix M.
Quoted 295 lines
Quoted 295 lines
lib/efi_loader/efi_hii.c new file +294
-0+ stbl->nstrings = nstrings; + +list_add (&stbl->link, &hii->string_tables); + +/* and now parse string entries and populate string_table */ + block = ((void *)strings_package) + strings_package->string_info_offset; + +while ((void *)block < end) { +switch (block->block_type) { +case EFI_HII_SIBT_STRING_UCS2 : { +struct efi_hii_sibt_string_ucs2_block *ucs2 = + (void *)block; + id++; +debug ("%4u: \"%ls\"\n" , id, ucs2->string_text); + stbl->strings[id-1 ].string = +utf16_strdup (ucs2->string_text); + block =efi_hii_sibt_string_ucs2_block_next (ucs2); +break ; + } +case EFI_HII_SIBT_END : +return EFI_SUCCESS ; +default : +debug ("unknown HII string block type: %02x\n" , + block->block_type); +return EFI_INVALID_PARAMETER ; + } + } + +return EFI_SUCCESS ; +} + +/* +* EFI_HII_CONFIG_ROUTING_PROTOCOL +*/ + +static efi_status_t EFIAPI extract_config( +const struct efi_hii_config_routing_protocol *this, +const efi_string_t request, +efi_string_t *progress, +efi_string_t *results) +{ +EFI_ENTRY ("%p, \"%ls\", %p, %p" , this, request, progress, results); +return EFI_EXIT (EFI_OUT_OF_RESOURCES ); +} + +static efi_status_t EFIAPI export_config( +const struct efi_hii_config_routing_protocol *this, +efi_string_t *results) +{ +EFI_ENTRY ("%p, %p" , this, results); +return EFI_EXIT (EFI_OUT_OF_RESOURCES ); +} + +static efi_status_t EFIAPI route_config( +const struct efi_hii_config_routing_protocol *this, +const efi_string_t configuration, +efi_string_t *progress) +{ +EFI_ENTRY ("%p, \"%ls\", %p" , this, configuration, progress); +return EFI_EXIT (EFI_OUT_OF_RESOURCES ); +} + +static efi_status_t EFIAPI block_to_config( +const struct efi_hii_config_routing_protocol *this, +const efi_string_t config_request, +const uint8_t *block, +const efi_uintn_t block_size, +efi_string_t *config, +efi_string_t *progress) +{ +EFI_ENTRY ("%p, \"%ls\", %p, %zu, %p, %p" , this, config_request, block, + block_size, config, progress); +return EFI_EXIT (EFI_OUT_OF_RESOURCES ); +} + +static efi_status_t EFIAPI config_to_block( +const struct efi_hii_config_routing_protocol *this, +const efi_string_t config_resp, +const uint8_t *block, +const efi_uintn_t *block_size, +efi_string_t *progress) +{ +EFI_ENTRY ("%p, \"%ls\", %p, %p, %p" , this, config_resp, block, + block_size, progress); +return EFI_EXIT (EFI_OUT_OF_RESOURCES ); +} + +static efi_status_t EFIAPI get_alt_config( +const struct efi_hii_config_routing_protocol *this, +const efi_string_t config_resp, +const efi_guid_t *guid, +const efi_string_t name, +const struct efi_device_path *device_path, +const efi_string_t alt_cfg_id, +efi_string_t *alt_cfg_resp) +{ +EFI_ENTRY ("%p, \"%ls\", %pUl, \"%ls\", %p, \"%ls\", %p" , this, + config_resp, guid, name, device_path, alt_cfg_id, + alt_cfg_resp); +return EFI_EXIT (EFI_OUT_OF_RESOURCES ); +} + + +/* +* EFI_HII_DATABASE_PROTOCOL +*/ + +static efi_status_t EFIAPI new_package_list( +const struct efi_hii_database_protocol *this, +const struct efi_hii_package_list_header *package_list, +const efi_handle_t driver_handle, +efi_hii_handle_t *handle) +{ +efi_status_t ret =EFI_SUCCESS ; + +EFI_ENTRY ("%p, %p, %p, %p" , this, package_list, driver_handle, handle); + +if (!package_list || !driver_handle) +return EFI_EXIT (EFI_INVALID_PARAMETER ); + +struct hii_package *hii =new_package (); +struct efi_hii_package_header *package; +void *end = ((void *)package_list) + package_list->package_length; + +debug ("package_list: %pUl (%u)\n" , &package_list->package_list_guid, + package_list->package_length); + + package = ((void *)package_list) +sizeof (*package_list); +while ((void *)package < end) { +debug ("package=%p, package type=%x, length=%u\n" , package, + package->type, package->length); +switch (package->type) { +case EFI_HII_PACKAGE_STRINGS : + ret =add_strings_package (hii, + (struct efi_hii_strings_package *)package); +break ; +default : +break ; + } + +if (ret !=EFI_SUCCESS ) + goto error; + + package = ((void *)package) + package->length; + } + +// TODO in theory there is some notifications that should be sent.. + + *handle = hii; + +return EFI_EXIT (EFI_SUCCESS ); + +error: +free_package (hii); +return EFI_EXIT (ret); +} + +static efi_status_t EFIAPI remove_package_list( +const struct efi_hii_database_protocol *this, +efi_hii_handle_t handle) +{ +struct hii_package *hii = handle; +EFI_ENTRY ("%p, %p" , this, handle); +free_package (hii); +return EFI_EXIT (EFI_SUCCESS ); +} + +static efi_status_t EFIAPI update_package_list( +const struct efi_hii_database_protocol *this, +efi_hii_handle_t handle, +const struct efi_hii_package_list_header *package_list) +{ +EFI_ENTRY ("%p, %p, %p" , this, handle, package_list); +return EFI_EXIT (EFI_NOT_FOUND ); +} + +static efi_status_t EFIAPI list_package_lists( +const struct efi_hii_database_protocol *this, +uint8_t package_type, +const efi_guid_t *package_guid, +efi_uintn_t *handle_buffer_length, +efi_hii_handle_t *handle) +{ +EFI_ENTRY ("%p, %u, %pUl, %p, %p" , this, package_type, package_guid, + handle_buffer_length, handle); +return EFI_EXIT (EFI_NOT_FOUND ); +} + +static efi_status_t EFIAPI export_package_lists( +const struct efi_hii_database_protocol *this, +efi_hii_handle_t handle, +efi_uintn_t *buffer_size, +struct efi_hii_package_list_header *buffer) +{ +EFI_ENTRY ("%p, %p, %p, %p" , this, handle, buffer_size, buffer); +return EFI_EXIT (EFI_NOT_FOUND ); +} + +static efi_status_t EFIAPI register_package_notify( +const struct efi_hii_database_protocol *this, +uint8_t package_type, +const efi_guid_t *package_guid, +const void *package_notify_fn, +efi_uintn_t notify_type, +efi_handle_t *notify_handle) +{ +EFI_ENTRY ("%p, %u, %pUl, %p, %zu, %p" , this, package_type, + package_guid, package_notify_fn, notify_type, + notify_handle); +return EFI_EXIT (EFI_OUT_OF_RESOURCES ); +} + +static efi_status_t EFIAPI unregister_package_notify( +const struct efi_hii_database_protocol *this, +efi_handle_t notification_handle) +{ +EFI_ENTRY ("%p, %p" , this, notification_handle); +return EFI_EXIT (EFI_NOT_FOUND ); +} + +static efi_status_t EFIAPI find_keyboard_layouts( +const struct efi_hii_database_protocol *this, +uint16_t *key_guid_buffer_length, +efi_guid_t *key_guid_buffer) +{ +EFI_ENTRY ("%p, %p, %p" , this, key_guid_buffer_length, key_guid_buffer); +return EFI_EXIT (EFI_NOT_FOUND );/* Invalid */ +} + +static efi_status_t EFIAPI get_keyboard_layout( +const struct efi_hii_database_protocol *this, +efi_guid_t *key_guid, +uint16_t *keyboard_layout_length, +struct efi_hii_keyboard_layout *keyboard_layout) +{ +EFI_ENTRY ("%p, %pUl, %p, %p" , this, key_guid, keyboard_layout_length, + keyboard_layout); +return EFI_EXIT (EFI_NOT_FOUND ); +} + +static efi_status_t EFIAPI set_keyboard_layout( +const struct efi_hii_database_protocol *this, +efi_guid_t *key_guid) +{ +EFI_ENTRY ("%p, %pUl" , this, key_guid); +return EFI_EXIT (EFI_NOT_FOUND ); +} + +static efi_status_t EFIAPI get_package_list_handle( +const struct efi_hii_database_protocol *this, +efi_hii_handle_t package_list_handle, +efi_handle_t *driver_handle) +{ +EFI_ENTRY ("%p, %p, %p" , this, package_list_handle, driver_handle); +return EFI_EXIT (EFI_INVALID_PARAMETER ); +} + + +/* +* EFI_HII_STRING_PROTOCOL +*/ + +static efi_status_t EFIAPI new_string( +const struct efi_hii_string_protocol *this, +efi_hii_handle_t package_list, +efi_string_id_t *string_id, +const uint8_t *language, +const uint16_t *language_name, +const efi_string_t string, +const struct efi_font_info *string_font_info) +{ +EFI_ENTRY ("%p, %p, %p, \"%s\", %p, \"%ls\", %p" , this, package_list, + string_id, language, language_name, string, + string_font_info); +return EFI_EXIT (EFI_NOT_FOUND ); +} + +static efi_status_t EFIAPI get_string( +const struct efi_hii_string_protocol *this, +const uint8_t *language, +efi_hii_handle_t package_list, +efi_string_id_t string_id, +efi_string_t string, +efi_uintn_t *string_size, +struct efi_font_info **string_font_info) +{ +struct hii_package *hii = package_list; +struct string_table *stbl; + +EFI_ENTRY ("%p, \"%s\", %p, %u, %p, %p, %p" , this, language, + package_list, string_id, string, string_size, + string_font_info); + +list_for_each_entry (stbl, &hii->string_tables, link) {Quoted 8 lines
lib/efi_loader/efi_hii.c line 405
Quoted 6 lines
lib/efi_loader/efi_hii.c new file +6
-0+if (!strcmp ((char *)language, (char *)stbl->language)) { +unsigned idx = string_id -1 ; +if (idx > stbl->nstrings) +return EFI_EXIT (EFI_NOT_FOUND ); +efi_string_t str = stbl->strings[idx].string; +size_t len =utf16_strlen (str) +1 ;I assume that's wrong for sizing too?
nope :-)
Quoted 2 lines
Also please try not to define variables mid-scope :). Just define them above the
if()and fill them after ...Hmm, I'd have the inverse comment if someone else wrote it and defined all the variables at the top ;-)
Quoted 15 lines
Then also for the sake of readability add a blank line after the variable definitions and before the return.
I think you'd also do yourself a favor if you reduced the indenting a bit. Just abort the
list_for_eachwhen you found and entry and then process it in the top level scope.static struct
string_table*find_stbl_by_lang(const char *language){ list_for_each(...) { if (matches) { return stbl; } }
Quoted 8 lines
Quoted 6 lines
return NULL; }stbl =
find_stbl_by_lang(lang);
if (!stbl)
returnEFI_EXIT(EFI_NOT_FOUND)yeah, perhaps
Please rework it for v2 :)
Alex
PATCH 2/11 efi_loader: Initial HII protocols
Quoted 152 lines · Alexander Graf
Quoted 149 lines · Rob Clark
Quoted 147 lines · Alexander Graf
Quoted 129 lines · Rob Clark
From: Leif Lindholm <[email protected]>
Enough implementation of the following protocols to run Shell.efi and SCT.efi:
EfiHiiConfigRoutingProtocolGuid
EfiHiiDatabaseProtocol
EfiHiiStringProtocolWe'll fill in the rest once SCT is running properly so we can validate the implementation against the conformance test suite.
Initial skeleton written by Leif, and then implementation by myself.
Cc Leif Lindholm <[email protected]>Signed-off-by Rob Clark <[email protected]>--- include/efi_api.h | 261 ++++++++++++++++++++++ include/efi_loader.h | 6 + lib/efi_loader/Makefile | 2 +- lib/efi_loader/efi_boottime.c | 9 + lib/efi_loader/efi_hii.c | 507 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 784 insertions(+), 1 deletion(-) create mode 100644 lib/efi_loader/efi_hii.cinclude/efi_api.h +89
-0@@ -16,6 +16,7 @@#define _EFI_API_H#include <efi.h> +#include <charset.h> #ifdef CONFIG_EFI_LOADER #include <asm/setjmp.h> @@ -536,6 +537,266 @@ struct efi_device_path_utilities_protocol { uint16_t node_length); }; +#define EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID \ + EFI_GUID(0x587e72d7, 0xcc50, 0x4f79, \ + 0x82, 0x09, 0xca, 0x29, 0x1f, 0xc1, 0xa1, 0x0f) + +typedef uint16_t efi_string_id_t ; + +struct efi_hii_config_routing_protocol { + efi_status_t(EFIAPI *extract_config)( + const struct efi_hii_config_routing_protocol *this, + const efi_string_t request, + efi_string_t *progress, + efi_string_t *results); + efi_status_t(EFIAPI *export_config)( + const struct efi_hii_config_routing_protocol *this, + efi_string_t *results); + efi_status_t(EFIAPI *route_config)( + const struct efi_hii_config_routing_protocol *this, + const efi_string_t configuration, + efi_string_t *progress); + efi_status_t(EFIAPI *block_to_config)( + const struct efi_hii_config_routing_protocol *this, + const efi_string_t config_request, + const uint8_t *block, + const efi_uintn_t block_size, + efi_string_t *config, + efi_string_t *progress); + efi_status_t(EFIAPI *config_to_block)( + const struct efi_hii_config_routing_protocol *this, + const efi_string_t config_resp, + const uint8_t *block, + const efi_uintn_t *block_size, + efi_string_t *progress); + efi_status_t(EFIAPI *get_alt_config)( + const struct efi_hii_config_routing_protocol *this, + const efi_string_t config_resp, + const efi_guid_t *guid, + const efi_string_t name, + const struct efi_device_path *device_path, + const efi_string_t alt_cfg_id, + efi_string_t *alt_cfg_resp); +}; + +#define EFI_HII_DATABASE_PROTOCOL_GUID \ + EFI_GUID(0xef9fc172, 0xa1b2, 0x4693, \ + 0xb3, 0x27, 0x6d, 0x32, 0xfc, 0x41, 0x60, 0x42) + +typedef enum { +EFI_KEY_LCTRL ,EFI_KEY_A0 ,EFI_KEY_LALT ,EFI_KEY_SPACE_BAR , +EFI_KEY_A2 ,EFI_KEY_A3 ,EFI_KEY_A4 ,EFI_KEY_RCTRL ,EFI_KEY_LEFT_ARROW , +EFI_KEY_DOWN_ARROW ,EFI_KEY_RIGHT_ARROW ,EFI_KEY_ZERO , +EFI_KEY_PERIOD ,EFI_KEY_ENTER ,EFI_KEY_LSHIFT ,EFI_KEY_B0 , +EFI_KEY_B1 ,EFI_KEY_B2 ,EFI_KEY_B3 ,EFI_KEY_B4 ,EFI_KEY_B5 ,EFI_KEY_B6 , +EFI_KEY_B7 ,EFI_KEY_B8 ,EFI_KEY_B9 ,EFI_KEY_B10 ,EFI_KEY_RSHIFT , +EFI_KEY_UP_ARROW ,EFI_KEY_ONE ,EFI_KEY_TWO ,EFI_KEY_THREE , +EFI_KEY_CAPS_LOCK ,EFI_KEY_C1 ,EFI_KEY_C2 ,EFI_KEY_C3 ,EFI_KEY_C4 , +EFI_KEY_C5 ,EFI_KEY_C6 ,EFI_KEY_C7 ,EFI_KEY_C8 ,EFI_KEY_C9 , +EFI_KEY_C10 ,EFI_KEY_C11 ,EFI_KEY_C12 ,EFI_KEY_FOUR ,EFI_KEY_FIVE , +EFI_KEY_SIX ,EFI_KEY_PLUS ,EFI_KEY_TAB ,EFI_KEY_D1 ,EFI_KEY_D2 , +EFI_KEY_D3 ,EFI_KEY_D4 ,EFI_KEY_D5 ,EFI_KEY_D6 ,EFI_KEY_D7 ,EFI_KEY_D8 , +EFI_KEY_D9 ,EFI_KEY_D10 ,EFI_KEY_D11 ,EFI_KEY_D12 ,EFI_KEY_D13 , +EFI_KEY_DEL ,EFI_KEY_END ,EFI_KEY_PG_DN ,EFI_KEY_SEVEN ,EFI_KEY_EIGHT , +EFI_KEY_NINE ,EFI_KEY_E0 ,EFI_KEY_E1 ,EFI_KEY_E2 ,EFI_KEY_E3 , +EFI_KEY_E4 ,EFI_KEY_E5 ,EFI_KEY_E6 ,EFI_KEY_E7 ,EFI_KEY_E8 ,EFI_KEY_E9 , +EFI_KEY_E10 ,EFI_KEY_E11 ,EFI_KEY_E12 ,EFI_KEY_BACK_SPACE , +EFI_KEY_INS ,EFI_KEY_HOME ,EFI_KEY_PG_UP ,EFI_KEY_NLCK ,EFI_KEY_SLASH , +EFI_KEY_ASTERISK ,EFI_KEY_MINUS ,EFI_KEY_ESC ,EFI_KEY_F1 ,EFI_KEY_F2 , +EFI_KEY_F3 ,EFI_KEY_F4 ,EFI_KEY_F5 ,EFI_KEY_F6 ,EFI_KEY_F7 ,EFI_KEY_F8 , +EFI_KEY_F9 ,EFI_KEY_F10 ,EFI_KEY_F11 ,EFI_KEY_F12 ,EFI_KEY_PRINT , +EFI_KEY_SLCK ,EFI_KEY_PAUSE , +}efi_key ; + +struct efi_key_descriptor { +efi_key key; +uint16_t unicode; +uint16_t shifted_unicode; +uint16_t alt_gr_unicode; +uint16_t shifted_alt_gr_unicode; +uint16_t modifier; +uint16_t affected_attribute; +}; + +struct efi_hii_keyboard_layout { +uint16_t layout_length; +efi_guid_t guid; +uint32_t layout_descriptor_string_offset; +uint8_t descriptor_count; +struct efi_key_descriptor descriptors[]; +};include/efi_api.h struct efi_device_path_utilities_protocol { · line 637
Quoted 10 lines
include/efi_api.h +10
-0+ +struct efi_hii_package_list_header { +efi_guid_t package_list_guid; +uint32_t package_length; +} __packed; + +struct efi_hii_package_header { +uint32_t length :24 ; +uint32_t type :8 ; +} __packed;Bitfields are terribly evil - they're probably one of the worst defined things in C. A different compiler may even give you different ordering here. I've certainly seen bitfields explode in weird ways on cross-endian conversions.
Quoted 6 lines
Quoted 2 lines
edk2 defines it in the same way. And this is UEFI we are talking about here, big endian is strictly out of scope.
I don't see why big endian is strictly out of scope. I don't want to ignore it light heartedly. All we'd need to do is byte swap every input/output there is today.
See section 1.9.1:
"
Supported processors are “little endian” machines. This distinction means that the low-
order byte of a multibyte data item in memory is at the lowest address, while the high-
order byte is at the highest address. Some supported 64-bit processors may be configured for both “little endian” and “big endian” operation. All implementations
designed to conform to this specification use “little endian” operation. "
even power9 got sane and is finally is switching to LE ;-)
BR,
-R
Quoted 709 lines
So please change it to not use bitmasks. I don't think we should copy bad design decisions from edk2.
Quoted 693 lines
Quoted 66 lines
Do you think you could just make that a
uint32_taltogether and work with MASK/SHIFT defines instead?Quoted 46 lines
include/efi_api.h +46
-0+ +#define EFI_HII_PACKAGE_TYPE_ALL 0x00 +#define EFI_HII_PACKAGE_TYPE_GUID 0x01 +#define EFI_HII_PACKAGE_FORMS 0x02 +#define EFI_HII_PACKAGE_STRINGS 0x04 +#define EFI_HII_PACKAGE_FONTS 0x05 +#define EFI_HII_PACKAGE_IMAGES 0x06 +#define EFI_HII_PACKAGE_SIMPLE_FONTS 0x07 +#define EFI_HII_PACKAGE_DEVICE_PATH 0x08 +#define EFI_HII_PACKAGE_KEYBOARD_LAYOUT 0x09 +#define EFI_HII_PACKAGE_ANIMATIONS 0x0A +#define EFI_HII_PACKAGE_END 0xDF +#define EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN 0xE0 +#define EFI_HII_PACKAGE_TYPE_SYSTEM_END 0xFF + +struct efi_hii_strings_package { +struct efi_hii_package_header header; +uint32_t header_size; +uint32_t string_info_offset; +uint16_t language_window[16 ]; +efi_string_id_t language_name; +uint8_t language[]; +} __packed; + +struct efi_hii_string_block { +uint8_t block_type; +/*uint8_t block_body[];*/ +} __packed; + +#define EFI_HII_SIBT_END 0x00 // The end of the string information. +#define EFI_HII_SIBT_STRING_SCSU 0x10 // Single string using default font information. +#define EFI_HII_SIBT_STRING_SCSU_FONT 0x11 // Single string with font information. +#define EFI_HII_SIBT_STRINGS_SCSU 0x12 // Multiple strings using default font information. +#define EFI_HII_SIBT_STRINGS_SCSU_FONT 0x13 // Multiple strings with font information. +#define EFI_HII_SIBT_STRING_UCS2 0x14 // Single UCS-2 string using default font information. +#define EFI_HII_SIBT_STRING_UCS2_FONT 0x15 // Single UCS-2 string with font information +#define EFI_HII_SIBT_STRINGS_UCS2 0x16 // Multiple UCS-2 strings using default font information. +#define EFI_HII_SIBT_STRINGS_UCS2_FONT 0x17 // Multiple UCS-2 strings with font information. +#define EFI_HII_SIBT_DUPLICATE 0x20 // Create a duplicate of an existing string. +#define EFI_HII_SIBT_SKIP2 0x21 // Skip a certain number of string identifiers. +#define EFI_HII_SIBT_SKIP1 0x22 // Skip a certain number of string identifiers. +#define EFI_HII_SIBT_EXT1 0x30 // For future expansion (one byte length field) +#define EFI_HII_SIBT_EXT2 0x31 // For future expansion (two byte length field) +#define EFI_HII_SIBT_EXT4 0x32 // For future expansion (four byte length field) +#define EFI_HII_SIBT_FONT 0x40 // Font information. +include/efi_api.h struct efi_device_path_utilities_protocol { · line 693
Quoted 10 lines
include/efi_api.h +10
-0+struct efi_hii_sibt_string_ucs2_block { +struct efi_hii_string_block header; +uint16_t string_text[]; +} __packed; + +static inline struct efi_hii_string_block *efi_hii_sibt_string_ucs2_block_next ( +struct efi_hii_sibt_string_ucs2_block *blk) +{ +return ((void *)blk) +sizeof (*blk) + + (utf16_strlen (blk->string_text) +1 ) *2 ;Since you're dealing with actual utf16, is this correct? One character may as well span 4 bytes, right?
Quoted 2 lines
I think we need a different function that actually tells us the bytes occupied by a utf16 string.
as mentioned on IRC (just repeating here for those who weren't following #u-boot),
utf16_strlen()is actually telling us the number of 16b "bytes" in a utf16 string, not the number of "characters". Similar tostrlen()with a utf8 string.Quoted 272 lines
Quoted 272 lines
include/efi_api.h +106
-0+} + +typedef void *efi_hii_handle_t ; + +struct efi_hii_database_protocol { + efi_status_t(EFIAPI *new_package_list)( + const struct efi_hii_database_protocol *this, + const struct efi_hii_package_list_header *package_list, + const efi_handle_t driver_handle, + efi_hii_handle_t *handle); + efi_status_t(EFIAPI *remove_package_list)( + const struct efi_hii_database_protocol *this, + efi_hii_handle_t handle); + efi_status_t(EFIAPI *update_package_list)( + const struct efi_hii_database_protocol *this, + efi_hii_handle_t handle, + const struct efi_hii_package_list_header *package_list); + efi_status_t(EFIAPI *list_package_lists)( + const struct efi_hii_database_protocol *this, + uint8_t package_type, + const efi_guid_t *package_guid, + efi_uintn_t *handle_buffer_length, + efi_hii_handle_t *handle); + efi_status_t(EFIAPI *export_package_lists)( + const struct efi_hii_database_protocol *this, + efi_hii_handle_t handle, + efi_uintn_t *buffer_size, + struct efi_hii_package_list_header *buffer); + efi_status_t(EFIAPI *register_package_notify)( + const struct efi_hii_database_protocol *this, + uint8_t package_type, + const efi_guid_t *package_guid, + const void *package_notify_fn, + efi_uintn_t notify_type, + efi_handle_t *notify_handle); + efi_status_t(EFIAPI *unregister_package_notify)( + const struct efi_hii_database_protocol *this, + efi_handle_t notification_handle + ); + efi_status_t(EFIAPI *find_keyboard_layouts)( + const struct efi_hii_database_protocol *this, + uint16_t *key_guid_buffer_length, + efi_guid_t *key_guid_buffer); + efi_status_t(EFIAPI *get_keyboard_layout)( + const struct efi_hii_database_protocol *this, + efi_guid_t *key_guid, + uint16_t *keyboard_layout_length, + struct efi_hii_keyboard_layout *keyboard_layout); + efi_status_t(EFIAPI *set_keyboard_layout)( + const struct efi_hii_database_protocol *this, + efi_guid_t *key_guid); + efi_status_t(EFIAPI *get_package_list_handle)( + const struct efi_hii_database_protocol *this, + efi_hii_handle_t package_list_handle, + efi_handle_t *driver_handle); +}; + +#define EFI_HII_STRING_PROTOCOL_GUID \ + EFI_GUID(0x0fd96974, 0x23aa, 0x4cdc, \ + 0xb9, 0xcb, 0x98, 0xd1, 0x77, 0x50, 0x32, 0x2a) + +typedef uint32_t efi_hii_font_style_t ; + +struct efi_font_info { +efi_hii_font_style_t font_style; +uint16_t font_size; +uint16_t font_name[1 ]; +}; + +struct efi_hii_string_protocol { + efi_status_t(EFIAPI *new_string)( + const struct efi_hii_string_protocol *this, + efi_hii_handle_t package_list, + efi_string_id_t *string_id, + const uint8_t *language, + const uint16_t *language_name, + const efi_string_t string, + const struct efi_font_info *string_font_info); + efi_status_t(EFIAPI *get_string)( + const struct efi_hii_string_protocol *this, + const uint8_t *language, + efi_hii_handle_t package_list, + efi_string_id_t string_id, + efi_string_t string, + efi_uintn_t *string_size, + struct efi_font_info **string_font_info); + efi_status_t(EFIAPI *set_string)( + const struct efi_hii_string_protocol *this, + efi_hii_handle_t package_list, + efi_string_id_t string_id, + const uint8_t *language, + const efi_string_t string, + const struct efi_font_info *string_font_info); + efi_status_t(EFIAPI *get_languages)( + const struct efi_hii_string_protocol *this, + efi_hii_handle_t package_list, + uint8_t *languages, + efi_uintn_t *languages_size); + efi_status_t(EFIAPI *get_secondary_languages)( + const struct efi_hii_string_protocol *this, + efi_hii_handle_t package_list, + const uint8_t *primary_language, + uint8_t *secondary_languages, + efi_uintn_t *secondary_languages_size); +}; +#define EFI_GOP_GUID \ EFI_GUID(0x9042a9de, 0x23dc, 0x4a38, \ 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a)include/efi_loader.h +6
-0@@ -80,6 +80,9 @@ extern struct efi_simple_input_interface efi_con_in;extern const struct efi_console_control_protocol efi_console_control;extern const struct efi_device_path_to_text_protocol efi_device_path_to_text;extern const struct efi_device_path_utilities_protocol efi_device_path_utilities; +extern const struct efi_hii_config_routing_protocol efi_hii_config_routing; +extern const struct efi_hii_database_protocol efi_hii_database; +extern const struct efi_hii_string_protocol efi_hii_string;uint16_t *efi_dp_str (struct efi_device_path *dp);@@ -91,6 +94,9 @@ extern const efi_guid_t efi_guid_device_path_to_text_protocol;extern const efi_guid_t efi_simple_file_system_protocol_guid;extern const efi_guid_t efi_file_info_guid;extern const efi_guid_t efi_guid_device_path_utilities_protocol; +extern const efi_guid_t efi_guid_hii_config_routing_protocol; +extern const efi_guid_t efi_guid_hii_database_protocol; +extern const efi_guid_t efi_guid_hii_string_protocol;extern unsigned int __efi_runtime_start, __efi_runtime_stop;extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;lib/efi_loader/Makefile +1
-1@@ -17,7 +17,7 @@ endif obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o -obj-y += efi_device_path_utilities.o +obj-y += efi_device_path_utilities.o efi_hii.o obj-y += efi_file.o efi_variable.o efi_bootmgr.o obj-$(CONFIG_LCD) += efi_gop.o obj-$(CONFIG_DM_VIDEO) += efi_gop.olib/efi_loader/efi_boottime.c +9
-0@@ -1157,6 +1157,15 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob obj->protocols[4 ].protocol_interface = (void *)&efi_device_path_utilities; + obj->protocols[5 ].guid = &efi_guid_hii_string_protocol; + obj->protocols[5 ].protocol_interface = (void *)&efi_hii_string; + + obj->protocols[6 ].guid = &efi_guid_hii_database_protocol; + obj->protocols[6 ].protocol_interface = (void *)&efi_hii_database; + + obj->protocols[7 ].guid = &efi_guid_hii_config_routing_protocol; + obj->protocols[7 ].protocol_interface = (void *)&efi_hii_config_routing; + info->file_path = file_path; info->device_handle =efi_dp_find_obj (device_path,NULL );lib/efi_loader/efi_hii.c new file +100
-0@@ -0,0 +1,507 @@ +/* +* EFI Human Interface Infrastructure ... interface +* +* Copyright (c) 2017 Leif Lindholm +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <malloc.h> +#include <efi_loader.h> + +const efi_guid_t efi_guid_hii_config_routing_protocol = +EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID ; +const efi_guid_t efi_guid_hii_database_protocol =EFI_HII_DATABASE_PROTOCOL_GUID ; +const efi_guid_t efi_guid_hii_string_protocol =EFI_HII_STRING_PROTOCOL_GUID ; + +struct hii_package { +// TODO should there be an associated efi_object? +struct list_head string_tables;/* list of string_table */ +/* we could also track fonts, images, etc */ +}; + +struct string_table { +struct list_head link; +efi_string_id_t language_name; +char *language; +uint32_t nstrings; +/* NOTE: string id starts at 1 so value is stbl->strings[id-1] */ +struct { +efi_string_t string; +/* we could also track font info, etc */ + } strings[]; +}; + +static void free_strings_table (struct string_table *stbl) +{ +int i; + +for (i =0 ; i < stbl->nstrings; i++) +free (stbl->strings[i].string); +free (stbl->language); +free (stbl); +} + +static struct hii_package *new_package (void ) +{ +struct hii_package *hii =malloc (sizeof (*hii)); +INIT_LIST_HEAD (&hii->string_tables); +return hii; +} + +static void free_package (struct hii_package *hii) +{ + +while (!list_empty (&hii->string_tables)) { +struct string_table *stbl; + + stbl =list_first_entry (&hii->string_tables, + struct string_table, link); +list_del (&stbl->link); +free_strings_table (stbl); + } + +free (hii); +} + +static efi_status_t add_strings_package (struct hii_package *hii, +struct efi_hii_strings_package *strings_package) +{ +struct efi_hii_string_block *block; +void *end = ((void *)strings_package) + strings_package->header.length; +uint32_t nstrings =0 ; +unsigned id =0 ; + +debug ("header_size: %08x\n" , strings_package->header_size); +debug ("string_info_offset: %08x\n" , strings_package->string_info_offset); +debug ("language_name: %u\n" , strings_package->language_name); +debug ("language: %s\n" , strings_package->language); + +/* count # of string entries: */ + block = ((void *)strings_package) + strings_package->string_info_offset; +while ((void *)block < end) { +switch (block->block_type) { +case EFI_HII_SIBT_STRING_UCS2 : { +struct efi_hii_sibt_string_ucs2_block *ucs2 = + (void *)block; + nstrings++; + block =efi_hii_sibt_string_ucs2_block_next (ucs2); +break ; + } +case EFI_HII_SIBT_END : + block = end; +break ; +default : +debug ("unknown HII string block type: %02x\n" , + block->block_type); +return EFI_INVALID_PARAMETER ; + } + }Quoted 8 lines
lib/efi_loader/efi_hii.c line 105
Quoted 5 lines
lib/efi_loader/efi_hii.c new file +5
-0+ +struct string_table *stbl =malloc (sizeof (*stbl) + + (nstrings *sizeof (stbl->strings[0 ]))); + stbl->language_name = strings_package->language_name; + stbl->language =strdup ((char *)strings_package->language);Where does the
strings_packagecome from? And why is the language in it in UTF8?The
strings_packageis a part of the "package list" blob passed in from (in this case) Shell.efi. The package list can actually contain a lot more (fonts/glyphs/images/forms), but not really sure how much of that we'll actually support. (HII seems to be able to do enough for rendering a full blown GUI.. kinda overkill, IMHO.. but Shell.efi wants it for silly reasons.)This is actually utf8.. it is a "RFC 4646 language code identifier". See appendix M.
Quoted 295 lines
Quoted 295 lines
lib/efi_loader/efi_hii.c new file +294
-0+ stbl->nstrings = nstrings; + +list_add (&stbl->link, &hii->string_tables); + +/* and now parse string entries and populate string_table */ + block = ((void *)strings_package) + strings_package->string_info_offset; + +while ((void *)block < end) { +switch (block->block_type) { +case EFI_HII_SIBT_STRING_UCS2 : { +struct efi_hii_sibt_string_ucs2_block *ucs2 = + (void *)block; + id++; +debug ("%4u: \"%ls\"\n" , id, ucs2->string_text); + stbl->strings[id-1 ].string = +utf16_strdup (ucs2->string_text); + block =efi_hii_sibt_string_ucs2_block_next (ucs2); +break ; + } +case EFI_HII_SIBT_END : +return EFI_SUCCESS ; +default : +debug ("unknown HII string block type: %02x\n" , + block->block_type); +return EFI_INVALID_PARAMETER ; + } + } + +return EFI_SUCCESS ; +} + +/* +* EFI_HII_CONFIG_ROUTING_PROTOCOL +*/ + +static efi_status_t EFIAPI extract_config( +const struct efi_hii_config_routing_protocol *this, +const efi_string_t request, +efi_string_t *progress, +efi_string_t *results) +{ +EFI_ENTRY ("%p, \"%ls\", %p, %p" , this, request, progress, results); +return EFI_EXIT (EFI_OUT_OF_RESOURCES ); +} + +static efi_status_t EFIAPI export_config( +const struct efi_hii_config_routing_protocol *this, +efi_string_t *results) +{ +EFI_ENTRY ("%p, %p" , this, results); +return EFI_EXIT (EFI_OUT_OF_RESOURCES ); +} + +static efi_status_t EFIAPI route_config( +const struct efi_hii_config_routing_protocol *this, +const efi_string_t configuration, +efi_string_t *progress) +{ +EFI_ENTRY ("%p, \"%ls\", %p" , this, configuration, progress); +return EFI_EXIT (EFI_OUT_OF_RESOURCES ); +} + +static efi_status_t EFIAPI block_to_config( +const struct efi_hii_config_routing_protocol *this, +const efi_string_t config_request, +const uint8_t *block, +const efi_uintn_t block_size, +efi_string_t *config, +efi_string_t *progress) +{ +EFI_ENTRY ("%p, \"%ls\", %p, %zu, %p, %p" , this, config_request, block, + block_size, config, progress); +return EFI_EXIT (EFI_OUT_OF_RESOURCES ); +} + +static efi_status_t EFIAPI config_to_block( +const struct efi_hii_config_routing_protocol *this, +const efi_string_t config_resp, +const uint8_t *block, +const efi_uintn_t *block_size, +efi_string_t *progress) +{ +EFI_ENTRY ("%p, \"%ls\", %p, %p, %p" , this, config_resp, block, + block_size, progress); +return EFI_EXIT (EFI_OUT_OF_RESOURCES ); +} + +static efi_status_t EFIAPI get_alt_config( +const struct efi_hii_config_routing_protocol *this, +const efi_string_t config_resp, +const efi_guid_t *guid, +const efi_string_t name, +const struct efi_device_path *device_path, +const efi_string_t alt_cfg_id, +efi_string_t *alt_cfg_resp) +{ +EFI_ENTRY ("%p, \"%ls\", %pUl, \"%ls\", %p, \"%ls\", %p" , this, + config_resp, guid, name, device_path, alt_cfg_id, + alt_cfg_resp); +return EFI_EXIT (EFI_OUT_OF_RESOURCES ); +} + + +/* +* EFI_HII_DATABASE_PROTOCOL +*/ + +static efi_status_t EFIAPI new_package_list( +const struct efi_hii_database_protocol *this, +const struct efi_hii_package_list_header *package_list, +const efi_handle_t driver_handle, +efi_hii_handle_t *handle) +{ +efi_status_t ret =EFI_SUCCESS ; + +EFI_ENTRY ("%p, %p, %p, %p" , this, package_list, driver_handle, handle); + +if (!package_list || !driver_handle) +return EFI_EXIT (EFI_INVALID_PARAMETER ); + +struct hii_package *hii =new_package (); +struct efi_hii_package_header *package; +void *end = ((void *)package_list) + package_list->package_length; + +debug ("package_list: %pUl (%u)\n" , &package_list->package_list_guid, + package_list->package_length); + + package = ((void *)package_list) +sizeof (*package_list); +while ((void *)package < end) { +debug ("package=%p, package type=%x, length=%u\n" , package, + package->type, package->length); +switch (package->type) { +case EFI_HII_PACKAGE_STRINGS : + ret =add_strings_package (hii, + (struct efi_hii_strings_package *)package); +break ; +default : +break ; + } + +if (ret !=EFI_SUCCESS ) + goto error; + + package = ((void *)package) + package->length; + } + +// TODO in theory there is some notifications that should be sent.. + + *handle = hii; + +return EFI_EXIT (EFI_SUCCESS ); + +error: +free_package (hii); +return EFI_EXIT (ret); +} + +static efi_status_t EFIAPI remove_package_list( +const struct efi_hii_database_protocol *this, +efi_hii_handle_t handle) +{ +struct hii_package *hii = handle; +EFI_ENTRY ("%p, %p" , this, handle); +free_package (hii); +return EFI_EXIT (EFI_SUCCESS ); +} + +static efi_status_t EFIAPI update_package_list( +const struct efi_hii_database_protocol *this, +efi_hii_handle_t handle, +const struct efi_hii_package_list_header *package_list) +{ +EFI_ENTRY ("%p, %p, %p" , this, handle, package_list); +return EFI_EXIT (EFI_NOT_FOUND ); +} + +static efi_status_t EFIAPI list_package_lists( +const struct efi_hii_database_protocol *this, +uint8_t package_type, +const efi_guid_t *package_guid, +efi_uintn_t *handle_buffer_length, +efi_hii_handle_t *handle) +{ +EFI_ENTRY ("%p, %u, %pUl, %p, %p" , this, package_type, package_guid, + handle_buffer_length, handle); +return EFI_EXIT (EFI_NOT_FOUND ); +} + +static efi_status_t EFIAPI export_package_lists( +const struct efi_hii_database_protocol *this, +efi_hii_handle_t handle, +efi_uintn_t *buffer_size, +struct efi_hii_package_list_header *buffer) +{ +EFI_ENTRY ("%p, %p, %p, %p" , this, handle, buffer_size, buffer); +return EFI_EXIT (EFI_NOT_FOUND ); +} + +static efi_status_t EFIAPI register_package_notify( +const struct efi_hii_database_protocol *this, +uint8_t package_type, +const efi_guid_t *package_guid, +const void *package_notify_fn, +efi_uintn_t notify_type, +efi_handle_t *notify_handle) +{ +EFI_ENTRY ("%p, %u, %pUl, %p, %zu, %p" , this, package_type, + package_guid, package_notify_fn, notify_type, + notify_handle); +return EFI_EXIT (EFI_OUT_OF_RESOURCES ); +} + +static efi_status_t EFIAPI unregister_package_notify( +const struct efi_hii_database_protocol *this, +efi_handle_t notification_handle) +{ +EFI_ENTRY ("%p, %p" , this, notification_handle); +return EFI_EXIT (EFI_NOT_FOUND ); +} + +static efi_status_t EFIAPI find_keyboard_layouts( +const struct efi_hii_database_protocol *this, +uint16_t *key_guid_buffer_length, +efi_guid_t *key_guid_buffer) +{ +EFI_ENTRY ("%p, %p, %p" , this, key_guid_buffer_length, key_guid_buffer); +return EFI_EXIT (EFI_NOT_FOUND );/* Invalid */ +} + +static efi_status_t EFIAPI get_keyboard_layout( +const struct efi_hii_database_protocol *this, +efi_guid_t *key_guid, +uint16_t *keyboard_layout_length, +struct efi_hii_keyboard_layout *keyboard_layout) +{ +EFI_ENTRY ("%p, %pUl, %p, %p" , this, key_guid, keyboard_layout_length, + keyboard_layout); +return EFI_EXIT (EFI_NOT_FOUND ); +} + +static efi_status_t EFIAPI set_keyboard_layout( +const struct efi_hii_database_protocol *this, +efi_guid_t *key_guid) +{ +EFI_ENTRY ("%p, %pUl" , this, key_guid); +return EFI_EXIT (EFI_NOT_FOUND ); +} + +static efi_status_t EFIAPI get_package_list_handle( +const struct efi_hii_database_protocol *this, +efi_hii_handle_t package_list_handle, +efi_handle_t *driver_handle) +{ +EFI_ENTRY ("%p, %p, %p" , this, package_list_handle, driver_handle); +return EFI_EXIT (EFI_INVALID_PARAMETER ); +} + + +/* +* EFI_HII_STRING_PROTOCOL +*/ + +static efi_status_t EFIAPI new_string( +const struct efi_hii_string_protocol *this, +efi_hii_handle_t package_list, +efi_string_id_t *string_id, +const uint8_t *language, +const uint16_t *language_name, +const efi_string_t string, +const struct efi_font_info *string_font_info) +{ +EFI_ENTRY ("%p, %p, %p, \"%s\", %p, \"%ls\", %p" , this, package_list, + string_id, language, language_name, string, + string_font_info); +return EFI_EXIT (EFI_NOT_FOUND ); +} + +static efi_status_t EFIAPI get_string( +const struct efi_hii_string_protocol *this, +const uint8_t *language, +efi_hii_handle_t package_list, +efi_string_id_t string_id, +efi_string_t string, +efi_uintn_t *string_size, +struct efi_font_info **string_font_info) +{ +struct hii_package *hii = package_list; +struct string_table *stbl; + +EFI_ENTRY ("%p, \"%s\", %p, %u, %p, %p, %p" , this, language, + package_list, string_id, string, string_size, + string_font_info); + +list_for_each_entry (stbl, &hii->string_tables, link) {Quoted 8 lines
lib/efi_loader/efi_hii.c line 405
Quoted 6 lines
lib/efi_loader/efi_hii.c new file +6
-0+if (!strcmp ((char *)language, (char *)stbl->language)) { +unsigned idx = string_id -1 ; +if (idx > stbl->nstrings) +return EFI_EXIT (EFI_NOT_FOUND ); +efi_string_t str = stbl->strings[idx].string; +size_t len =utf16_strlen (str) +1 ;I assume that's wrong for sizing too?
nope :-)
Quoted 2 lines
Also please try not to define variables mid-scope :). Just define them above the
if()and fill them after ...Hmm, I'd have the inverse comment if someone else wrote it and defined all the variables at the top ;-)
Quoted 15 lines
Then also for the sake of readability add a blank line after the variable definitions and before the return.
I think you'd also do yourself a favor if you reduced the indenting a bit. Just abort the
list_for_eachwhen you found and entry and then process it in the top level scope.static struct
string_table*find_stbl_by_lang(const char *language){ list_for_each(...) { if (matches) { return stbl; } }Quoted 8 lines
Quoted 6 lines
return NULL; }stbl =
find_stbl_by_lang(lang);
if (!stbl)
returnEFI_EXIT(EFI_NOT_FOUND)yeah, perhaps
Please rework it for v2 :)
Alex
PATCH 2/11 efi_loader: Initial HII protocols
Quoted 167 lines · Rob Clark
Quoted 148 lines · Alexander Graf
Quoted 146 lines · Rob Clark
Quoted 145 lines · Alexander Graf
Quoted 129 lines · Rob Clark
From: Leif Lindholm <[email protected]>
Enough implementation of the following protocols to run Shell.efi and SCT.efi:
EfiHiiConfigRoutingProtocolGuid
EfiHiiDatabaseProtocol
EfiHiiStringProtocolWe'll fill in the rest once SCT is running properly so we can validate the implementation against the conformance test suite.
Initial skeleton written by Leif, and then implementation by myself.
Cc Leif Lindholm <[email protected]>Signed-off-by Rob Clark <[email protected]>--- include/efi_api.h | 261 ++++++++++++++++++++++ include/efi_loader.h | 6 + lib/efi_loader/Makefile | 2 +- lib/efi_loader/efi_boottime.c | 9 + lib/efi_loader/efi_hii.c | 507 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 784 insertions(+), 1 deletion(-)create mode 100644
lib/efi_loader/efi_hii.cinclude/efi_api.h +89
-0@@ -16,6 +16,7 @@#define _EFI_API_H#include <efi.h> +#include <charset.h> #ifdef CONFIG_EFI_LOADER #include <asm/setjmp.h> @@ -536,6 +537,266 @@ struct efi_device_path_utilities_protocol { uint16_t node_length); }; +#define EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID \ + EFI_GUID(0x587e72d7, 0xcc50, 0x4f79, \ + 0x82, 0x09, 0xca, 0x29, 0x1f, 0xc1, 0xa1, 0x0f) + +typedef uint16_t efi_string_id_t ; + +struct efi_hii_config_routing_protocol { + efi_status_t(EFIAPI *extract_config)( + const struct efi_hii_config_routing_protocol *this, + const efi_string_t request, + efi_string_t *progress, + efi_string_t *results); + efi_status_t(EFIAPI *export_config)( + const struct efi_hii_config_routing_protocol *this, + efi_string_t *results); + efi_status_t(EFIAPI *route_config)( + const struct efi_hii_config_routing_protocol *this, + const efi_string_t configuration, + efi_string_t *progress); + efi_status_t(EFIAPI *block_to_config)( + const struct efi_hii_config_routing_protocol *this, + const efi_string_t config_request, + const uint8_t *block, + const efi_uintn_t block_size, + efi_string_t *config, + efi_string_t *progress); + efi_status_t(EFIAPI *config_to_block)( + const struct efi_hii_config_routing_protocol *this, + const efi_string_t config_resp, + const uint8_t *block, + const efi_uintn_t *block_size, + efi_string_t *progress); + efi_status_t(EFIAPI *get_alt_config)( + const struct efi_hii_config_routing_protocol *this, + const efi_string_t config_resp, + const efi_guid_t *guid, + const efi_string_t name, + const struct efi_device_path *device_path, + const efi_string_t alt_cfg_id, + efi_string_t *alt_cfg_resp); +}; + +#define EFI_HII_DATABASE_PROTOCOL_GUID \ + EFI_GUID(0xef9fc172, 0xa1b2, 0x4693, \ + 0xb3, 0x27, 0x6d, 0x32, 0xfc, 0x41, 0x60, 0x42) + +typedef enum { +EFI_KEY_LCTRL ,EFI_KEY_A0 ,EFI_KEY_LALT ,EFI_KEY_SPACE_BAR , +EFI_KEY_A2 ,EFI_KEY_A3 ,EFI_KEY_A4 ,EFI_KEY_RCTRL ,EFI_KEY_LEFT_ARROW , +EFI_KEY_DOWN_ARROW ,EFI_KEY_RIGHT_ARROW ,EFI_KEY_ZERO , +EFI_KEY_PERIOD ,EFI_KEY_ENTER ,EFI_KEY_LSHIFT ,EFI_KEY_B0 , +EFI_KEY_B1 ,EFI_KEY_B2 ,EFI_KEY_B3 ,EFI_KEY_B4 ,EFI_KEY_B5 ,EFI_KEY_B6 , +EFI_KEY_B7 ,EFI_KEY_B8 ,EFI_KEY_B9 ,EFI_KEY_B10 ,EFI_KEY_RSHIFT , +EFI_KEY_UP_ARROW ,EFI_KEY_ONE ,EFI_KEY_TWO ,EFI_KEY_THREE , +EFI_KEY_CAPS_LOCK ,EFI_KEY_C1 ,EFI_KEY_C2 ,EFI_KEY_C3 ,EFI_KEY_C4 , +EFI_KEY_C5 ,EFI_KEY_C6 ,EFI_KEY_C7 ,EFI_KEY_C8 ,EFI_KEY_C9 , +EFI_KEY_C10 ,EFI_KEY_C11 ,EFI_KEY_C12 ,EFI_KEY_FOUR ,EFI_KEY_FIVE , +EFI_KEY_SIX ,EFI_KEY_PLUS ,EFI_KEY_TAB ,EFI_KEY_D1 ,EFI_KEY_D2 , +EFI_KEY_D3 ,EFI_KEY_D4 ,EFI_KEY_D5 ,EFI_KEY_D6 ,EFI_KEY_D7 ,EFI_KEY_D8 , +EFI_KEY_D9 ,EFI_KEY_D10 ,EFI_KEY_D11 ,EFI_KEY_D12 ,EFI_KEY_D13 , +EFI_KEY_DEL ,EFI_KEY_END ,EFI_KEY_PG_DN ,EFI_KEY_SEVEN ,EFI_KEY_EIGHT , +EFI_KEY_NINE ,EFI_KEY_E0 ,EFI_KEY_E1 ,EFI_KEY_E2 ,EFI_KEY_E3 , +EFI_KEY_E4 ,EFI_KEY_E5 ,EFI_KEY_E6 ,EFI_KEY_E7 ,EFI_KEY_E8 ,EFI_KEY_E9 , +EFI_KEY_E10 ,EFI_KEY_E11 ,EFI_KEY_E12 ,EFI_KEY_BACK_SPACE , +EFI_KEY_INS ,EFI_KEY_HOME ,EFI_KEY_PG_UP ,EFI_KEY_NLCK ,EFI_KEY_SLASH , +EFI_KEY_ASTERISK ,EFI_KEY_MINUS ,EFI_KEY_ESC ,EFI_KEY_F1 ,EFI_KEY_F2 , +EFI_KEY_F3 ,EFI_KEY_F4 ,EFI_KEY_F5 ,EFI_KEY_F6 ,EFI_KEY_F7 ,EFI_KEY_F8 , +EFI_KEY_F9 ,EFI_KEY_F10 ,EFI_KEY_F11 ,EFI_KEY_F12 ,EFI_KEY_PRINT , +EFI_KEY_SLCK ,EFI_KEY_PAUSE , +}efi_key ; + +struct efi_key_descriptor { +efi_key key; +uint16_t unicode; +uint16_t shifted_unicode; +uint16_t alt_gr_unicode; +uint16_t shifted_alt_gr_unicode; +uint16_t modifier; +uint16_t affected_attribute; +}; + +struct efi_hii_keyboard_layout { +uint16_t layout_length; +efi_guid_t guid; +uint32_t layout_descriptor_string_offset; +uint8_t descriptor_count; +struct efi_key_descriptor descriptors[]; +};include/efi_api.h struct efi_device_path_utilities_protocol { · line 637
Quoted 10 lines
include/efi_api.h +10
-0+ +struct efi_hii_package_list_header { +efi_guid_t package_list_guid; +uint32_t package_length; +} __packed; + +struct efi_hii_package_header { +uint32_t length :24 ; +uint32_t type :8 ; +} __packed;Bitfields are terribly evil - they're probably one of the worst defined things in C. A different compiler may even give you different ordering here. I've certainly seen bitfields explode in weird ways on cross-endian conversions.
Quoted 5 lines
Quoted 2 lines
edk2 defines it in the same way. And this is UEFI we are talking about here, big endian is strictly out of scope.
I don't see why big endian is strictly out of scope. I don't want to ignore it light heartedly. All we'd need to do is byte swap every input/output there is today.
See section 1.9.1:
"
Supported processors are “little endian” machines. This distinction means that the low-
order byte of a multibyte data item in memory is at the lowest address, while the high-
order byte is at the highest address. Some supported 64-bit processors may be configured for both “little endian” and “big endian” operation. All implementations
designed to conform to this specification use “little endian” operation. "
Quoted 1 line
even power9 got sane and is finally is switching to LE ;-)
You know as well as me that specs are changeable :). I think UEFI will always stay LE, but that doesn't mean that it always has to also be executed in an LE environment. We've done funny stunts with grub before where we ran LE grub on a BE OpenFirmware implementation.
Really, I just always cringe when I see bitfields.
Alex
PATCH 2/11 efi_loader: Initial HII protocols
In reply to Rob ClarkQuoted 8 lines · Rob Clark
From: Leif Lindholm <[email protected]>
Enough implementation of the following protocols to run Shell.efi and SCT.efi:
EfiHiiConfigRoutingProtocolGuid
EfiHiiDatabaseProtocol
EfiHiiStringProtocol
The i386 Shell.efi also tries to open these before failing:
EfiHiiFontProtocol
EfiHiiImageProtocol
Best regards
Heinrich Schuchardt
PATCH 2/11 efi_loader: Initial HII protocols
Quoted 6 lines · Heinrich Schuchardt
Quoted 5 lines · Rob Clark
From: Leif Lindholm <[email protected]>
Enough implementation of the following protocols to run Shell.efi and SCT.efi:
Quoted 8 lines
Quoted 3 lines
EfiHiiConfigRoutingProtocolGuid
EfiHiiDatabaseProtocol
EfiHiiStringProtocolThe i386 Shell.efi also tries to open these before failing:
EfiHiiFontProtocol
EfiHiiImageProtocol
That sounds like a bug. The UEFI spec only mandates the following in section 2.6.2:
2. If a platform includes a configuration infrastructure, then the EFI_HII_DATABASE_PROTOCOL, EFI_HII_STRING_PROTOCOL, EFI_HII_CONFIG_ROUTING_PROTOCOL, and EFI_HII_CONFIG_ACCESS_PROTOCOL are required. If you support bitmapped fonts, you must support EFI_HII_FONT_PROTOCOL.
Well, in my book the whole fact that the UEFI shell requires HII sounds like a bad design decision, but it should at least not require the font protocol :).
Also, I have built my own x86_64 shell.efi from latest edk2 git manually and that works fine (even in sandbox). Maybe that is only the minimal shell though? Their build system is still a bit of a mystery to me :).
Alex
AKASHI
PATCH 2/11 efi_loader: Initial HII protocols
Alex,
Quoted 18 lines · Alexander Graf
Quoted 6 lines · Heinrich Schuchardt
Quoted 5 lines · Rob Clark
From: Leif Lindholm <[email protected]>
Enough implementation of the following protocols to run Shell.efi and SCT.efi:
Quoted 8 lines
Quoted 3 lines
EfiHiiConfigRoutingProtocolGuid
EfiHiiDatabaseProtocol
EfiHiiStringProtocolThe i386 Shell.efi also tries to open these before failing:
EfiHiiFontProtocol
EfiHiiImageProtocol
Quoted 7 lines
That sounds like a bug. The UEFI spec only mandates the following in section 2.6.2:
2. If a platform includes a configuration infrastructure, then the
EFI_HII_DATABASE_PROTOCOL,EFI_HII_STRING_PROTOCOL,EFI_HII_CONFIG_ROUTING_PROTOCOL, andEFI_HII_CONFIG_ACCESS_PROTOCOLare required.
Do you think efi implementation on u-boot also wants those protocols? (Apparently, config access protocol can be optional for shell unless we want driver configuration?)
Among others, UEFI spec defines lots of "packages" for HII database:
string, guid, font, image, device path, keyboard layout and etc.
Do you expect all of them be supported from the beginning? If not, what criteria do you think is reasonable so that you feel comfortable in accepting an initial commit of HII database support?
Thanks,
-Takahiro Akashi
Quoted 13 lines
If you support bitmapped fonts, you must support
EFI_HII_FONT_PROTOCOL.Well, in my book the whole fact that the UEFI shell requires HII sounds like a bad design decision, but it should at least not require the font protocol :).
Also, I have built my own
x86_64shell.efi from latest edk2 git manually and that works fine (even in sandbox). Maybe that is only the minimal shell though? Their build system is still a bit of a mystery to me :).Alex
AKASHI
PATCH 2/11 efi_loader: Initial HII protocols
Quoted 25 lines · Takahiro
Alex,
Quoted 21 lines · Alexander Graf
Quoted 6 lines · Heinrich Schuchardt
Quoted 5 lines · Rob Clark
From: Leif Lindholm <[email protected]>
Enough implementation of the following protocols to run Shell.efi and SCT.efi:
Quoted 8 lines
Quoted 3 lines
EfiHiiConfigRoutingProtocolGuid
EfiHiiDatabaseProtocol
EfiHiiStringProtocolThe i386 Shell.efi also tries to open these before failing:
EfiHiiFontProtocol
EfiHiiImageProtocolThat sounds like a bug. The UEFI spec only mandates the following in section 2.6.2:
Quoted 8 lines
Quoted 4 lines
2. If a platform includes a configuration infrastructure, then the
EFI_HII_DATABASE_PROTOCOL,EFI_HII_STRING_PROTOCOL,EFI_HII_CONFIG_ROUTING_PROTOCOL, andEFI_HII_CONFIG_ACCESS_PROTOCOLare required.Do you think efi implementation on u-boot also wants those protocols? (Apparently, config access protocol can be optional for shell unless we want driver configuration?)
One more question:
Does u-boot support any kind of "UEFI driver"?
If yes, is there any good example?
If no, do you expect that it should be supported?
Thanks,
-Takahiro Akashi
Quoted 23 lines
Among others, UEFI spec defines lots of "packages" for HII database:
string, guid, font, image, device path, keyboard layout and etc.Do you expect all of them be supported from the beginning? If not, what criteria do you think is reasonable so that you feel comfortable in accepting an initial commit of HII database support?
Thanks,
-Takahiro AkashiQuoted 13 lines
If you support bitmapped fonts, you must support
EFI_HII_FONT_PROTOCOL.Well, in my book the whole fact that the UEFI shell requires HII sounds like a bad design decision, but it should at least not require the font protocol :).
Also, I have built my own
x86_64shell.efi from latest edk2 git manually and that works fine (even in sandbox). Maybe that is only the minimal shell though? Their build system is still a bit of a mystery to me :).Alex
PATCH 2/11 efi_loader: Initial HII protocols
Quoted 5 lines · Takahiro
Quoted 5 lines
Quoted 4 lines
2. If a platform includes a configuration infrastructure, then the
EFI_HII_DATABASE_PROTOCOL,EFI_HII_STRING_PROTOCOL,EFI_HII_CONFIG_ROUTING_PROTOCOL, andEFI_HII_CONFIG_ACCESS_PROTOCOLare required.
Quoted 8 lines
Quoted 3 lines
Do you think efi implementation on u-boot also wants those protocols? (Apparently, config access protocol can be optional for shell unless we want driver configuration?)
One more question:
Does u-boot support any kind of "UEFI driver"?
If yes, is there any good example?
If no, do you expect that it should be supported?
I don't think full-on option ROMs with configuration menus are something we care about for EBBR-style implementations. What could be useful is things like shim - a simple driver installing a protocol that lets other applications running at boot-time access it. But I think that is already (mostly?) supported.
If someone at a later date decides that they want to support option ROMs, basically using U-Boot for an SBBR implementation, that will come with additional work required for the menu support. And should be possible to configure out at build time for users who don't want it.
/
Leif
PATCH 2/11 efi_loader: Initial HII protocols
Quoted 12 lines · Leif Lindholm
Quoted 11 lines · Takahiro
Quoted 7 lines
Quoted 4 lines
2. If a platform includes a configuration infrastructure, then the
EFI_HII_DATABASE_PROTOCOL,EFI_HII_STRING_PROTOCOL,EFI_HII_CONFIG_ROUTING_PROTOCOL, andEFI_HII_CONFIG_ACCESS_PROTOCOLare required.Do you think efi implementation on u-boot also wants those protocols? (Apparently, config access protocol can be optional for shell unless we want driver configuration?)
One more question:
Does u-boot support any kind of "UEFI driver"?
If yes, is there any good example?
If no, do you expect that it should be supported?
Quoted 5 lines
I don't think full-on option ROMs with configuration menus are something we care about for EBBR-style implementations. What could be useful is things like shim - a simple driver installing a protocol that lets other applications running at boot-time access it. But I think that is already (mostly?) supported.
That works, iPXE also works. But neither use HII from what I'm aware of.
Quoted 4 lines
If someone at a later date decides that they want to support option ROMs, basically using U-Boot for an SBBR implementation, that will come with additional work required for the menu support. And should be possible to configure out at build time for users who don't want it.
Yeah, IMHO for HII we can treat it as a Shell.efi only wart we have to live with, but implement as little as we can get away with.
Alex
AKASHI
PATCH 2/11 efi_loader: Initial HII protocols
Quoted 13 lines · Alexander Graf
Quoted 12 lines · Leif Lindholm
Quoted 11 lines · Takahiro
Quoted 7 lines
Quoted 4 lines
2. If a platform includes a configuration infrastructure, then the
EFI_HII_DATABASE_PROTOCOL,EFI_HII_STRING_PROTOCOL,EFI_HII_CONFIG_ROUTING_PROTOCOL, andEFI_HII_CONFIG_ACCESS_PROTOCOLare required.Do you think efi implementation on u-boot also wants those protocols? (Apparently, config access protocol can be optional for shell unless we want driver configuration?)
One more question:
Does u-boot support any kind of "UEFI driver"?
If yes, is there any good example?
If no, do you expect that it should be supported?
Quoted 7 lines
Quoted 5 lines
I don't think full-on option ROMs with configuration menus are something we care about for EBBR-style implementations. What could be useful is things like shim - a simple driver installing a protocol that lets other applications running at boot-time access it. But I think that is already (mostly?) supported.
That works, iPXE also works. But neither use HII from what I'm aware of.
After all, do both of you say that we neither have to have Config Routing nor Config Access Protocol for now?
Quoted 7 lines
Quoted 4 lines
If someone at a later date decides that they want to support option ROMs, basically using U-Boot for an SBBR implementation, that will come with additional work required for the menu support. And should be possible to configure out at build time for users who don't want it.
Yeah, IMHO for HII we can treat it as a Shell.efi only wart we have to live with, but implement as little as we can get away with.
Do you have any specific idea about what is really missing in Leif's/Rob's HII patch?
(My original question.)
-Takahiro Akashi
Quoted 3 lines
Alex
PATCH 2/11 efi_loader: Initial HII protocols
Quoted 5 lines · Takahiro
Do you have any specific idea about what is really missing in Leif's/Rob's HII patch?
(My original question.)-Takahiro Akashi
Please, see https://patchwork.ozlabs.org/patch/823807/
Open topics were:
- usage of bitfields
- incorrect determination of string lengths
- too deep nesting of of loops and ifs
- incomplete implementation of the protocols
As other protocols are based on the HII database protocol we should start with this protocol in a separate patch. We should have a unit test in lib/efi_selftest/ for all methods of the protocol.
Best regards
Heinrich
AKASHI
PATCH 2/11 efi_loader: Initial HII protocols
Heinrich,
Quoted 8 lines · Heinrich Schuchardt
Quoted 5 lines · Takahiro
Do you have any specific idea about what is really missing in Leif's/Rob's HII patch?
(My original question.)-Takahiro Akashi
Please, see https://patchwork.ozlabs.org/patch/823807/
Thanks, I didn't notice this thread.
Quoted 4 lines
Open topics were:
- usage of bitfields
- incorrect determination of string lengths
- too deep nesting of of loops and ifs
Okay, those seem to be easily fixable at a glance.
Quoted 1 line
- incomplete implementation of the protocols
That is a matter I'm concerned about.
There's no consensus yet about what should be in an "initial" port.
BTW, you said there were some missing protocols to run i386 version of Shell: EFI HII font protocol and EFI HII Image protocol. Do you still believe so even after Alex's comment?
Thanks,
-Takahiro Akashi
Quoted 7 lines
As other protocols are based on the HII database protocol we should start with this protocol in a separate patch. We should have a unit test in
lib/efi_selftest/for all methods of the protocol.Best regards
Heinrich
PATCH 2/11 efi_loader: Initial HII protocols
In reply to Leif LindholmQuoted 6 lines · Leif Lindholm
Quoted 5 lines · Takahiro
Quoted 5 lines
Quoted 4 lines
2. If a platform includes a configuration infrastructure, then the
EFI_HII_DATABASE_PROTOCOL,EFI_HII_STRING_PROTOCOL,EFI_HII_CONFIG_ROUTING_PROTOCOL, andEFI_HII_CONFIG_ACCESS_PROTOCOLare required.
Quoted 6 lines
Quoted 6 lines
Quoted 3 lines
Do you think efi implementation on u-boot also wants those protocols? (Apparently, config access protocol can be optional for shell unless we want driver configuration?)
One more question:
Does u-boot support any kind of "UEFI driver"?
I am currently working on patches to fix StartImage(), Exit(), and UnloadImage() that will enable installing EFI drivers.
Currently the image handle is destroyed when a driver calls Exit().
Regards
Heinrich
Quoted 17 lines
Quoted 2 lines
If yes, is there any good example?
If no, do you expect that it should be supported?I don't think full-on option ROMs with configuration menus are something we care about for EBBR-style implementations. What could be useful is things like shim - a simple driver installing a protocol that lets other applications running at boot-time access it. But I think that is already (mostly?) supported.
If someone at a later date decides that they want to support option ROMs, basically using U-Boot for an SBBR implementation, that will come with additional work required for the menu support. And should be possible to configure out at build time for users who don't want it.
/
Leif
PATCH 3/11 efi_loader: Initial EFI_UNICODE_COLLATION_PROTOCOL
In reply to Rob ClarkFrom: Leif Lindholm <[email protected]>
Not complete, but enough for Shell.efi and SCT.efi.
Initial skeleton written by Leif, and then implementation by myself.
--- include/efi_api.h | 41 ++++++++++ include/efi_loader.h | 3 + lib/efi_loader/Makefile | 2 +- lib/efi_loader/efi_boottime.c | 6 ++ lib/efi_loader/efi_unicode.c | 170 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 221 insertions(+), 1 deletion(-) create mode 100644 lib/efi_loader/efi_unicode.c
include/efi_api.h +41 -0
@@ -797,6 +797,47 @@ struct efi_hii_string_protocol { efi_uintn_t *secondary_languages_size); }; +/* +* Both UNICODE_COLLATION protocols seem to be the same thing, but +* advertised with two different GUID's because, why not? +*/ + +#define EFI_UNICODE_COLLATION_PROTOCOL_GUID \ + EFI_GUID(0x1d85cd7f, 0xf43d, 0x11d2, \ + 0x9a, 0x0c, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) + +#define EFI_UNICODE_COLLATION_PROTOCOL2_GUID \ + EFI_GUID(0xa4c751fc, 0x23ae, 0x4c3e, \ + 0x92, 0xe9, 0x49, 0x64, 0xcf, 0x63, 0xf3, 0x49) + +struct efi_unicode_collation_protocol { + efi_intn_t (EFIAPI *stri_coll)( + struct efi_unicode_collation_protocol *this, + efi_string_t s1, + efi_string_t s2); + bool (EFIAPI *metai_match)( +struct efi_unicode_collation_protocol *this, +efi_string_t string, +efi_string_t pattern); + void (EFIAPI *str_lwr)( +struct efi_unicode_collation_protocol *this, +efi_string_t string); + void (EFIAPI *str_upr)( +struct efi_unicode_collation_protocol *this, +efi_string_t string); + void (EFIAPI *fat_to_str)( +struct efi_unicode_collation_protocol *this, +efi_uintn_t fat_size, +uint8_t *fat, +efi_string_t string); + bool (EFIAPI *str_to_fat)( +struct efi_unicode_collation_protocol *this, +efi_string_t string, +efi_uintn_t fat_size, +uint8_t *fat); +uint8_t *supported_languages; +}; +#define EFI_GOP_GUID \ EFI_GUID(0x9042a9de, 0x23dc, 0x4a38, \ 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a)
include/efi_loader.h +3 -0
@@ -83,6 +83,7 @@ extern const struct efi_device_path_utilities_protocol efi_device_path_utilitiesextern const struct efi_hii_config_routing_protocol efi_hii_config_routing;extern const struct efi_hii_database_protocol efi_hii_database;extern const struct efi_hii_string_protocol efi_hii_string; +extern const struct efi_unicode_collation_protocol efi_unicode_collation;uint16_t *efi_dp_str (struct efi_device_path *dp);
@@ -97,6 +98,8 @@ extern const efi_guid_t efi_guid_device_path_utilities_protocol;extern const efi_guid_t efi_guid_hii_config_routing_protocol;extern const efi_guid_t efi_guid_hii_database_protocol;extern const efi_guid_t efi_guid_hii_string_protocol; +extern const efi_guid_t efi_guid_unicode_collation_protocol; +extern const efi_guid_t efi_guid_unicode_collation_protocol2;extern unsigned int __efi_runtime_start, __efi_runtime_stop;extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;
lib/efi_loader/Makefile +1 -1
@@ -17,7 +17,7 @@ endif obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o -obj-y += efi_device_path_utilities.o efi_hii.o +obj-y += efi_device_path_utilities.o efi_hii.o efi_unicode.o obj-y += efi_file.o efi_variable.o efi_bootmgr.o obj-$(CONFIG_LCD) += efi_gop.o obj-$(CONFIG_DM_VIDEO) += efi_gop.o
lib/efi_loader/efi_boottime.c +6 -0
@@ -1166,6 +1166,12 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob obj->protocols[7 ].guid = &efi_guid_hii_config_routing_protocol; obj->protocols[7 ].protocol_interface = (void *)&efi_hii_config_routing; + obj->protocols[8 ].guid = &efi_guid_unicode_collation_protocol; + obj->protocols[8 ].protocol_interface = (void *)&efi_unicode_collation; + + obj->protocols[9 ].guid = &efi_guid_unicode_collation_protocol2; + obj->protocols[9 ].protocol_interface = (void *)&efi_unicode_collation; + info->file_path = file_path; info->device_handle =efi_dp_find_obj (device_path,NULL );
lib/efi_loader/efi_unicode.c new file +170 -0
170 lines not on this page · raw message
Signature · 1 line
2.13.6
PATCH 3/11 efi_loader: Initial EFI_UNICODE_COLLATION_PROTOCOL
Quoted 240 lines · Rob Clark
From: Leif Lindholm <[email protected]>
Not complete, but enough for Shell.efi and SCT.efi.
Initial skeleton written by Leif, and then implementation by myself.
Cc Leif Lindholm <[email protected]>Signed-off-by Rob Clark <[email protected]>--- include/efi_api.h | 41 ++++++++++ include/efi_loader.h | 3 + lib/efi_loader/Makefile | 2 +- lib/efi_loader/efi_boottime.c | 6 ++ lib/efi_loader/efi_unicode.c | 170 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 221 insertions(+), 1 deletion(-) create mode 100644 lib/efi_loader/efi_unicode.cinclude/efi_api.h +41
-0@@ -797,6 +797,47 @@ struct efi_hii_string_protocol { efi_uintn_t *secondary_languages_size); }; +/* +* Both UNICODE_COLLATION protocols seem to be the same thing, but +* advertised with two different GUID's because, why not? +*/ + +#define EFI_UNICODE_COLLATION_PROTOCOL_GUID \ + EFI_GUID(0x1d85cd7f, 0xf43d, 0x11d2, \ + 0x9a, 0x0c, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) + +#define EFI_UNICODE_COLLATION_PROTOCOL2_GUID \ + EFI_GUID(0xa4c751fc, 0x23ae, 0x4c3e, \ + 0x92, 0xe9, 0x49, 0x64, 0xcf, 0x63, 0xf3, 0x49) + +struct efi_unicode_collation_protocol { + efi_intn_t (EFIAPI *stri_coll)( + struct efi_unicode_collation_protocol *this, + efi_string_t s1, + efi_string_t s2); + bool (EFIAPI *metai_match)( +struct efi_unicode_collation_protocol *this, +efi_string_t string, +efi_string_t pattern); + void (EFIAPI *str_lwr)( +struct efi_unicode_collation_protocol *this, +efi_string_t string); + void (EFIAPI *str_upr)( +struct efi_unicode_collation_protocol *this, +efi_string_t string); + void (EFIAPI *fat_to_str)( +struct efi_unicode_collation_protocol *this, +efi_uintn_t fat_size, +uint8_t *fat, +efi_string_t string); + bool (EFIAPI *str_to_fat)( +struct efi_unicode_collation_protocol *this, +efi_string_t string, +efi_uintn_t fat_size, +uint8_t *fat); +uint8_t *supported_languages; +}; +#define EFI_GOP_GUID \ EFI_GUID(0x9042a9de, 0x23dc, 0x4a38, \ 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a)include/efi_loader.h +3
-0@@ -83,6 +83,7 @@ extern const struct efi_device_path_utilities_protocol efi_device_path_utilitiesextern const struct efi_hii_config_routing_protocol efi_hii_config_routing;extern const struct efi_hii_database_protocol efi_hii_database;extern const struct efi_hii_string_protocol efi_hii_string; +extern const struct efi_unicode_collation_protocol efi_unicode_collation;uint16_t *efi_dp_str (struct efi_device_path *dp);@@ -97,6 +98,8 @@ extern const efi_guid_t efi_guid_device_path_utilities_protocol;extern const efi_guid_t efi_guid_hii_config_routing_protocol;extern const efi_guid_t efi_guid_hii_database_protocol;extern const efi_guid_t efi_guid_hii_string_protocol; +extern const efi_guid_t efi_guid_unicode_collation_protocol; +extern const efi_guid_t efi_guid_unicode_collation_protocol2;extern unsigned int __efi_runtime_start, __efi_runtime_stop;extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;lib/efi_loader/Makefile +1
-1@@ -17,7 +17,7 @@ endif obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o -obj-y += efi_device_path_utilities.o efi_hii.o +obj-y += efi_device_path_utilities.o efi_hii.o efi_unicode.o obj-y += efi_file.o efi_variable.o efi_bootmgr.o obj-$(CONFIG_LCD) += efi_gop.o obj-$(CONFIG_DM_VIDEO) += efi_gop.olib/efi_loader/efi_boottime.c +6
-0@@ -1166,6 +1166,12 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob obj->protocols[7 ].guid = &efi_guid_hii_config_routing_protocol; obj->protocols[7 ].protocol_interface = (void *)&efi_hii_config_routing; + obj->protocols[8 ].guid = &efi_guid_unicode_collation_protocol; + obj->protocols[8 ].protocol_interface = (void *)&efi_unicode_collation; + + obj->protocols[9 ].guid = &efi_guid_unicode_collation_protocol2; + obj->protocols[9 ].protocol_interface = (void *)&efi_unicode_collation; + info->file_path = file_path; info->device_handle =efi_dp_find_obj (device_path,NULL );lib/efi_loader/efi_unicode.c new file +114
-0@@ -0,0 +1,170 @@ +/* +* EFI Unicode interface +* +* Copyright (c) 2017 Leif Lindholm +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <charset.h> +#include <linux/ctype.h> +#include <efi_loader.h> + +const efi_guid_t efi_guid_unicode_collation_protocol = +EFI_UNICODE_COLLATION_PROTOCOL_GUID ; + +const efi_guid_t efi_guid_unicode_collation_protocol2 = +EFI_UNICODE_COLLATION_PROTOCOL2_GUID ; + +static int matchn (efi_string_t s1,unsigned n1,efi_string_t s2,unsigned n2) +{ +char u1[MAX_UTF8_PER_UTF16 * n1 +1 ]; +char u2[MAX_UTF8_PER_UTF16 * n2 +1 ]; + + *utf16_to_utf8 ((u8 *)u1, s1, n1) ='\0' ; + *utf16_to_utf8 ((u8 *)u2, s2, n2) ='\0' ; + +return strcasecmp (u1, u2); +} + +static efi_intn_t EFIAPI stri_coll(struct efi_unicode_collation_protocol *this, +efi_string_t s1, +efi_string_t s2) +{ +EFI_ENTRY ("%p, \"%ls\", \"%ls\"" , this, s1, s2); + +unsigned n1 =utf16_strlen (s1); +unsigned n2 =utf16_strlen (s2); + +return EFI_EXIT (matchn (s1, n1, s2, n2)); +} + +static bool match (efi_string_t string,efi_string_t pattern) +{ +while (true) { +uint16_t p = *pattern++; +bool matches = false; + +if (p =='\0' || *string =='\0' ) { +/* +* End of pattern or string, succeed if +* end of both: +*/ +return *string == p; + } + +switch (p) { +case '*' : +/* Match zero or more chars: */ +while (*string !='\0' ) { +if (match (string, pattern)) +return true; + string++; + } +return match (string, pattern); +case '?' : +/* Match any one char: */ + string++; +break ; +case '[' : +/* Match char set, either [abc] or [a-c]: */ + +if (pattern[0 ] =='\0' || pattern[0 ] ==']' ) { +/* invalid pattern */ +return false; + } + +if (pattern[1 ] =='-' ) { +uint16_t lo, hi, c; + +/* range: [a-c] */ + lo = pattern[0 ]; + hi = pattern[2 ]; + +if (hi =='\0' || hi ==']' || pattern[3 ] !=']' ) { +/* invalid pattern */ +return false; + } + + c =tolower (*string); + lo =tolower (lo); + hi =tolower (hi); + +if (lo <= c && c <= hi) + matches = true; + + pattern +=4 ; + }else { +/* set: [abc] */ +while ((p = *pattern++) && p !=']' ) +if (matchn (string,1 , &p,1 )) + matches = true; + } + +if (!matches) +return false; + + string++; +break ; +default : +if (matchn (string,1 , &p,1 )) +return false; + string++; +break ;
lib/efi_loader/efi_unicode.c line 124
Quoted 10 lines
lib/efi_loader/efi_unicode.c new file +10
-0+ } + } +} + +static bool EFIAPI metai_match(struct efi_unicode_collation_protocol *this, +efi_string_t string, +efi_string_t pattern) +{ +EFI_ENTRY ("%p, \"%ls\", \"%ls\"" , this, string, pattern); +return EFI_EXIT (match (string, pattern));
EFI_EXIT wants a success/failure parameter, not true/false (which can be randomly defined). Please either have match() return EFI return codes or convert it in here :).
lib/efi_loader/efi_unicode.c line 131
Quoted 7 lines
lib/efi_loader/efi_unicode.c new file +7
-0+} + +static void EFIAPI str_lwr(struct efi_unicode_collation_protocol *this, +efi_string_t string) +{ +EFI_ENTRY ("%p, \"%ls\"" , this, string); +EFI_EXIT (EFI_SUCCESS );
This is not implemented, right? Better indicate that in the EFI_EXIT() hint so that someone tracing a log of calls will catch it later.
lib/efi_loader/efi_unicode.c line 132
Quoted 1 line
lib/efi_loader/efi_unicode.c new file +1
-0+return ;
Not needed, no?
lib/efi_loader/efi_unicode.c line 139
Quoted 7 lines
lib/efi_loader/efi_unicode.c new file +7
-0+} + +static void EFIAPI str_upr(struct efi_unicode_collation_protocol *this, +efi_string_t string) +{ +EFI_ENTRY ("%p, \"%ls\"" , this, string); +EFI_EXIT (EFI_SUCCESS );
Same here
lib/efi_loader/efi_unicode.c line 149
Quoted 10 lines
lib/efi_loader/efi_unicode.c new file +10
-0+return ; +} + +static void EFIAPI fat_to_str(struct efi_unicode_collation_protocol *this, +efi_uintn_t fat_size, +uint8_t *fat, +efi_string_t string) +{ +EFI_ENTRY ("%p, %zu, \"%s\", %p" , this, fat_size, fat, string); +EFI_EXIT (EFI_SUCCESS );
Same here
lib/efi_loader/efi_unicode.c line 159
Quoted 10 lines
lib/efi_loader/efi_unicode.c new file +10
-0+return ; +} + +static bool EFIAPI str_to_fat(struct efi_unicode_collation_protocol *this, +efi_string_t string, +efi_uintn_t fat_size, +uint8_t *fat) +{ +EFI_ENTRY ("%p, \"%ls\", %zu, %p" , this, string, fat_size, fat); +return EFI_EXIT (false);
Again, please don't pass true/false to EFI_EXIT().
Alex
Quoted 12 lines
lib/efi_loader/efi_unicode.c new file +11
-0+} + +const struct efi_unicode_collation_protocol efi_unicode_collation = { + .stri_coll = stri_coll, + .metai_match = metai_match, + .str_lwr = str_lwr, + .str_upr = str_upr, + .fat_to_str = fat_to_str, + .str_to_fat = str_to_fat, + .supported_languages = (uint8_t *)"eng" , +};
PATCH 3/11 efi_loader: Initial EFI_UNICODE_COLLATION_PROTOCOL
Quoted 249 lines · Alexander Graf
Quoted 246 lines · Rob Clark
From: Leif Lindholm <[email protected]>
Not complete, but enough for Shell.efi and SCT.efi.
Initial skeleton written by Leif, and then implementation by myself.
Cc Leif Lindholm <[email protected]>Signed-off-by Rob Clark <[email protected]>--- include/efi_api.h | 41 ++++++++++ include/efi_loader.h | 3 + lib/efi_loader/Makefile | 2 +- lib/efi_loader/efi_boottime.c | 6 ++ lib/efi_loader/efi_unicode.c | 170 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 221 insertions(+), 1 deletion(-) create mode 100644 lib/efi_loader/efi_unicode.cinclude/efi_api.h +41
-0@@ -797,6 +797,47 @@ struct efi_hii_string_protocol { efi_uintn_t *secondary_languages_size); }; +/* +* Both UNICODE_COLLATION protocols seem to be the same thing, but +* advertised with two different GUID's because, why not? +*/ + +#define EFI_UNICODE_COLLATION_PROTOCOL_GUID \ + EFI_GUID(0x1d85cd7f, 0xf43d, 0x11d2, \ + 0x9a, 0x0c, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) + +#define EFI_UNICODE_COLLATION_PROTOCOL2_GUID \ + EFI_GUID(0xa4c751fc, 0x23ae, 0x4c3e, \ + 0x92, 0xe9, 0x49, 0x64, 0xcf, 0x63, 0xf3, 0x49) + +struct efi_unicode_collation_protocol { + efi_intn_t (EFIAPI *stri_coll)( + struct efi_unicode_collation_protocol *this, + efi_string_t s1, + efi_string_t s2); + bool (EFIAPI *metai_match)( +struct efi_unicode_collation_protocol *this, +efi_string_t string, +efi_string_t pattern); + void (EFIAPI *str_lwr)( +struct efi_unicode_collation_protocol *this, +efi_string_t string); + void (EFIAPI *str_upr)( +struct efi_unicode_collation_protocol *this, +efi_string_t string); + void (EFIAPI *fat_to_str)( +struct efi_unicode_collation_protocol *this, +efi_uintn_t fat_size, +uint8_t *fat, +efi_string_t string); + bool (EFIAPI *str_to_fat)( +struct efi_unicode_collation_protocol *this, +efi_string_t string, +efi_uintn_t fat_size, +uint8_t *fat); +uint8_t *supported_languages; +}; +#define EFI_GOP_GUID \ EFI_GUID(0x9042a9de, 0x23dc, 0x4a38, \ 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a)include/efi_loader.h +3
-0@@ -83,6 +83,7 @@ extern const struct efi_device_path_utilities_protocol efi_device_path_utilitiesextern const struct efi_hii_config_routing_protocol efi_hii_config_routing;extern const struct efi_hii_database_protocol efi_hii_database;extern const struct efi_hii_string_protocol efi_hii_string; +extern const struct efi_unicode_collation_protocol efi_unicode_collation;uint16_t *efi_dp_str (struct efi_device_path *dp);@@ -97,6 +98,8 @@ extern const efi_guid_t efi_guid_device_path_utilities_protocol;extern const efi_guid_t efi_guid_hii_config_routing_protocol;extern const efi_guid_t efi_guid_hii_database_protocol;extern const efi_guid_t efi_guid_hii_string_protocol; +extern const efi_guid_t efi_guid_unicode_collation_protocol; +extern const efi_guid_t efi_guid_unicode_collation_protocol2;extern unsigned int __efi_runtime_start, __efi_runtime_stop;extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;lib/efi_loader/Makefile +1
-1@@ -17,7 +17,7 @@ endif obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o -obj-y += efi_device_path_utilities.o efi_hii.o +obj-y += efi_device_path_utilities.o efi_hii.o efi_unicode.o obj-y += efi_file.o efi_variable.o efi_bootmgr.o obj-$(CONFIG_LCD) += efi_gop.o obj-$(CONFIG_DM_VIDEO) += efi_gop.olib/efi_loader/efi_boottime.c +6
-0@@ -1166,6 +1166,12 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob obj->protocols[7 ].guid = &efi_guid_hii_config_routing_protocol; obj->protocols[7 ].protocol_interface = (void *)&efi_hii_config_routing; + obj->protocols[8 ].guid = &efi_guid_unicode_collation_protocol; + obj->protocols[8 ].protocol_interface = (void *)&efi_unicode_collation; + + obj->protocols[9 ].guid = &efi_guid_unicode_collation_protocol2; + obj->protocols[9 ].protocol_interface = (void *)&efi_unicode_collation; + info->file_path = file_path; info->device_handle =efi_dp_find_obj (device_path,NULL );lib/efi_loader/efi_unicode.c new file +120
-0@@ -0,0 +1,170 @@ +/* +* EFI Unicode interface +* +* Copyright (c) 2017 Leif Lindholm +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <charset.h> +#include <linux/ctype.h> +#include <efi_loader.h> + +const efi_guid_t efi_guid_unicode_collation_protocol = +EFI_UNICODE_COLLATION_PROTOCOL_GUID ; + +const efi_guid_t efi_guid_unicode_collation_protocol2 = +EFI_UNICODE_COLLATION_PROTOCOL2_GUID ; + +static int matchn (efi_string_t s1,unsigned n1,efi_string_t s2,unsigned n2) +{ +char u1[MAX_UTF8_PER_UTF16 * n1 +1 ]; +char u2[MAX_UTF8_PER_UTF16 * n2 +1 ]; + + *utf16_to_utf8 ((u8 *)u1, s1, n1) ='\0' ; + *utf16_to_utf8 ((u8 *)u2, s2, n2) ='\0' ; + +return strcasecmp (u1, u2); +} + +static efi_intn_t EFIAPI stri_coll(struct efi_unicode_collation_protocol *this, +efi_string_t s1, +efi_string_t s2) +{ +EFI_ENTRY ("%p, \"%ls\", \"%ls\"" , this, s1, s2); + +unsigned n1 =utf16_strlen (s1); +unsigned n2 =utf16_strlen (s2); + +return EFI_EXIT (matchn (s1, n1, s2, n2)); +} + +static bool match (efi_string_t string,efi_string_t pattern) +{ +while (true) { +uint16_t p = *pattern++; +bool matches = false; + +if (p =='\0' || *string =='\0' ) { +/* +* End of pattern or string, succeed if +* end of both: +*/ +return *string == p; + } + +switch (p) { +case '*' : +/* Match zero or more chars: */ +while (*string !='\0' ) { +if (match (string, pattern)) +return true; + string++; + } +return match (string, pattern); +case '?' : +/* Match any one char: */ + string++; +break ; +case '[' : +/* Match char set, either [abc] or [a-c]: */ + +if (pattern[0 ] =='\0' || pattern[0 ] ==']' ) { +/* invalid pattern */ +return false; + } + +if (pattern[1 ] =='-' ) { +uint16_t lo, hi, c; + +/* range: [a-c] */ + lo = pattern[0 ]; + hi = pattern[2 ]; + +if (hi =='\0' || hi ==']' || pattern[3 ] !=']' ) { +/* invalid pattern */ +return false; + } + + c =tolower (*string); + lo =tolower (lo); + hi =tolower (hi); + +if (lo <= c && c <= hi) + matches = true; + + pattern +=4 ; + }else { +/* set: [abc] */ +while ((p = *pattern++) && p !=']' ) +if (matchn (string,1 , &p,1 )) + matches = true; + } + +if (!matches) +return false; + + string++; +break ; +default : +if (matchn (string,1 , &p,1 )) +return false; + string++; +break ; + } + } +} + +static bool EFIAPI metai_match(struct efi_unicode_collation_protocol *this, + efi_string_t string,
Quoted 8 lines
lib/efi_loader/efi_unicode.c line 124
Quoted 4 lines
lib/efi_loader/efi_unicode.c new file +4
-0+ efi_string_t pattern) +{ +EFI_ENTRY ("%p, \"%ls\", \"%ls\"" , this, string, pattern); +return EFI_EXIT (match (string, pattern));
EFI_EXITwants a success/failure parameter, not true/false (which can be randomly defined). Please either havematch()return EFI return codes or convert it in here :).
That isn't strictly true, it does use typeof(ret).. and while it masks the resulting debug msg with ~EFI_ERROR_MASK, in practice it isn't a problem with boolean return. Just a bit funny.
And there already other EFI entry points that return something other than efi_status_t.. trying to force them all into efi_status_t mold makes them somewhat more awkward.
BR,
-R
Quoted 66 lines
lib/efi_loader/efi_unicode.c line 131
Quoted 7 lines
lib/efi_loader/efi_unicode.c new file +7
-0+} + +static void EFIAPI str_lwr(struct efi_unicode_collation_protocol *this, +efi_string_t string) +{ +EFI_ENTRY ("%p, \"%ls\"" , this, string); +EFI_EXIT (EFI_SUCCESS );This is not implemented, right? Better indicate that in the
EFI_EXIT()hint so that someone tracing a log of calls will catch it later.lib/efi_loader/efi_unicode.c line 132
Quoted 1 line
lib/efi_loader/efi_unicode.c new file +1
-0+return ;Not needed, no?
lib/efi_loader/efi_unicode.c line 139
Quoted 7 lines
lib/efi_loader/efi_unicode.c new file +7
-0+} + +static void EFIAPI str_upr(struct efi_unicode_collation_protocol *this, +efi_string_t string) +{ +EFI_ENTRY ("%p, \"%ls\"" , this, string); +EFI_EXIT (EFI_SUCCESS );Same here
lib/efi_loader/efi_unicode.c line 149
Quoted 10 lines
lib/efi_loader/efi_unicode.c new file +10
-0+return ; +} + +static void EFIAPI fat_to_str(struct efi_unicode_collation_protocol *this, +efi_uintn_t fat_size, +uint8_t *fat, +efi_string_t string) +{ +EFI_ENTRY ("%p, %zu, \"%s\", %p" , this, fat_size, fat, string); +EFI_EXIT (EFI_SUCCESS );Same here
lib/efi_loader/efi_unicode.c line 159
Quoted 10 lines
lib/efi_loader/efi_unicode.c new file +10
-0+return ; +} + +static bool EFIAPI str_to_fat(struct efi_unicode_collation_protocol *this, +efi_string_t string, +efi_uintn_t fat_size, +uint8_t *fat) +{ +EFI_ENTRY ("%p, \"%ls\", %zu, %p" , this, string, fat_size, fat); +return EFI_EXIT (false);Again, please don't pass true/false to
EFI_EXIT().Alex
Quoted 12 lines
lib/efi_loader/efi_unicode.c new file +11
-0+} + +const struct efi_unicode_collation_protocol efi_unicode_collation = { + .stri_coll = stri_coll, + .metai_match = metai_match, + .str_lwr = str_lwr, + .str_upr = str_upr, + .fat_to_str = fat_to_str, + .str_to_fat = str_to_fat, + .supported_languages = (uint8_t *)"eng" , +};
PATCH 3/11 efi_loader: Initial EFI_UNICODE_COLLATION_PROTOCOL
Quoted 259 lines · Rob Clark
Quoted 249 lines · Alexander Graf
Quoted 246 lines · Rob Clark
From: Leif Lindholm <[email protected]>
Not complete, but enough for Shell.efi and SCT.efi.
Initial skeleton written by Leif, and then implementation by myself.
Cc Leif Lindholm <[email protected]>Signed-off-by Rob Clark <[email protected]>--- include/efi_api.h | 41 ++++++++++ include/efi_loader.h | 3 + lib/efi_loader/Makefile | 2 +- lib/efi_loader/efi_boottime.c | 6 ++ lib/efi_loader/efi_unicode.c | 170 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 221 insertions(+), 1 deletion(-) create mode 100644 lib/efi_loader/efi_unicode.cinclude/efi_api.h +41
-0@@ -797,6 +797,47 @@ struct efi_hii_string_protocol { efi_uintn_t *secondary_languages_size); }; +/* +* Both UNICODE_COLLATION protocols seem to be the same thing, but +* advertised with two different GUID's because, why not? +*/ + +#define EFI_UNICODE_COLLATION_PROTOCOL_GUID \ + EFI_GUID(0x1d85cd7f, 0xf43d, 0x11d2, \ + 0x9a, 0x0c, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) + +#define EFI_UNICODE_COLLATION_PROTOCOL2_GUID \ + EFI_GUID(0xa4c751fc, 0x23ae, 0x4c3e, \ + 0x92, 0xe9, 0x49, 0x64, 0xcf, 0x63, 0xf3, 0x49) + +struct efi_unicode_collation_protocol { + efi_intn_t (EFIAPI *stri_coll)( + struct efi_unicode_collation_protocol *this, + efi_string_t s1, + efi_string_t s2); + bool (EFIAPI *metai_match)( +struct efi_unicode_collation_protocol *this, +efi_string_t string, +efi_string_t pattern); + void (EFIAPI *str_lwr)( +struct efi_unicode_collation_protocol *this, +efi_string_t string); + void (EFIAPI *str_upr)( +struct efi_unicode_collation_protocol *this, +efi_string_t string); + void (EFIAPI *fat_to_str)( +struct efi_unicode_collation_protocol *this, +efi_uintn_t fat_size, +uint8_t *fat, +efi_string_t string); + bool (EFIAPI *str_to_fat)( +struct efi_unicode_collation_protocol *this, +efi_string_t string, +efi_uintn_t fat_size, +uint8_t *fat); +uint8_t *supported_languages; +}; +#define EFI_GOP_GUID \ EFI_GUID(0x9042a9de, 0x23dc, 0x4a38, \ 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a)include/efi_loader.h +3
-0@@ -83,6 +83,7 @@ extern const struct efi_device_path_utilities_protocol efi_device_path_utilitiesextern const struct efi_hii_config_routing_protocol efi_hii_config_routing;extern const struct efi_hii_database_protocol efi_hii_database;extern const struct efi_hii_string_protocol efi_hii_string; +extern const struct efi_unicode_collation_protocol efi_unicode_collation;uint16_t *efi_dp_str (struct efi_device_path *dp);@@ -97,6 +98,8 @@ extern const efi_guid_t efi_guid_device_path_utilities_protocol;extern const efi_guid_t efi_guid_hii_config_routing_protocol;extern const efi_guid_t efi_guid_hii_database_protocol;extern const efi_guid_t efi_guid_hii_string_protocol; +extern const efi_guid_t efi_guid_unicode_collation_protocol; +extern const efi_guid_t efi_guid_unicode_collation_protocol2;extern unsigned int __efi_runtime_start, __efi_runtime_stop;extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;lib/efi_loader/Makefile +1
-1@@ -17,7 +17,7 @@ endif obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o -obj-y += efi_device_path_utilities.o efi_hii.o +obj-y += efi_device_path_utilities.o efi_hii.o efi_unicode.o obj-y += efi_file.o efi_variable.o efi_bootmgr.o obj-$(CONFIG_LCD) += efi_gop.o obj-$(CONFIG_DM_VIDEO) += efi_gop.olib/efi_loader/efi_boottime.c +6
-0@@ -1166,6 +1166,12 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob obj->protocols[7 ].guid = &efi_guid_hii_config_routing_protocol; obj->protocols[7 ].protocol_interface = (void *)&efi_hii_config_routing; + obj->protocols[8 ].guid = &efi_guid_unicode_collation_protocol; + obj->protocols[8 ].protocol_interface = (void *)&efi_unicode_collation; + + obj->protocols[9 ].guid = &efi_guid_unicode_collation_protocol2; + obj->protocols[9 ].protocol_interface = (void *)&efi_unicode_collation; + info->file_path = file_path; info->device_handle =efi_dp_find_obj (device_path,NULL );lib/efi_loader/efi_unicode.c new file +120
-0@@ -0,0 +1,170 @@ +/* +* EFI Unicode interface +* +* Copyright (c) 2017 Leif Lindholm +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <charset.h> +#include <linux/ctype.h> +#include <efi_loader.h> + +const efi_guid_t efi_guid_unicode_collation_protocol = +EFI_UNICODE_COLLATION_PROTOCOL_GUID ; + +const efi_guid_t efi_guid_unicode_collation_protocol2 = +EFI_UNICODE_COLLATION_PROTOCOL2_GUID ; + +static int matchn (efi_string_t s1,unsigned n1,efi_string_t s2,unsigned n2) +{ +char u1[MAX_UTF8_PER_UTF16 * n1 +1 ]; +char u2[MAX_UTF8_PER_UTF16 * n2 +1 ]; + + *utf16_to_utf8 ((u8 *)u1, s1, n1) ='\0' ; + *utf16_to_utf8 ((u8 *)u2, s2, n2) ='\0' ; + +return strcasecmp (u1, u2); +} + +static efi_intn_t EFIAPI stri_coll(struct efi_unicode_collation_protocol *this, +efi_string_t s1, +efi_string_t s2) +{ +EFI_ENTRY ("%p, \"%ls\", \"%ls\"" , this, s1, s2); + +unsigned n1 =utf16_strlen (s1); +unsigned n2 =utf16_strlen (s2); + +return EFI_EXIT (matchn (s1, n1, s2, n2)); +} + +static bool match (efi_string_t string,efi_string_t pattern) +{ +while (true) { +uint16_t p = *pattern++; +bool matches = false; + +if (p =='\0' || *string =='\0' ) { +/* +* End of pattern or string, succeed if +* end of both: +*/ +return *string == p; + } + +switch (p) { +case '*' : +/* Match zero or more chars: */ +while (*string !='\0' ) { +if (match (string, pattern)) +return true; + string++; + } +return match (string, pattern); +case '?' : +/* Match any one char: */ + string++; +break ; +case '[' : +/* Match char set, either [abc] or [a-c]: */ + +if (pattern[0 ] =='\0' || pattern[0 ] ==']' ) { +/* invalid pattern */ +return false; + } + +if (pattern[1 ] =='-' ) { +uint16_t lo, hi, c; + +/* range: [a-c] */ + lo = pattern[0 ]; + hi = pattern[2 ]; + +if (hi =='\0' || hi ==']' || pattern[3 ] !=']' ) { +/* invalid pattern */ +return false; + } + + c =tolower (*string); + lo =tolower (lo); + hi =tolower (hi); + +if (lo <= c && c <= hi) + matches = true; + + pattern +=4 ; + }else { +/* set: [abc] */ +while ((p = *pattern++) && p !=']' ) +if (matchn (string,1 , &p,1 )) + matches = true; + } + +if (!matches) +return false; + + string++; +break ; +default : +if (matchn (string,1 , &p,1 )) +return false; + string++; +break ; + } + } +} + +static bool EFIAPI metai_match(struct efi_unicode_collation_protocol *this, + efi_string_t string,Quoted 8 lines
lib/efi_loader/efi_unicode.c line 124
Quoted 4 lines
lib/efi_loader/efi_unicode.c new file +4
-0+ efi_string_t pattern) +{ +EFI_ENTRY ("%p, \"%ls\", \"%ls\"" , this, string, pattern); +return EFI_EXIT (match (string, pattern));
EFI_EXITwants a success/failure parameter, not true/false (which can be randomly defined). Please either havematch()return EFI return codes or convert it in here :).
Quoted 7 lines
That isn't strictly true, it does use typeof(ret).. and while it masks the resulting debug msg with ~EFI_ERROR_MASK, in practice it isn't a problem with boolean return. Just a bit funny.
And there already other EFI entry points that return something other than
efi_status_t.. trying to force them all intoefi_status_tmold makes them somewhat more awkward.
Well, anything that casts well into an integer is reasonably valid for EFI_EXIT(). But with bool things aren't always as clear as they should be. I'm for example not 100% sure if the return value of a bool function can never be different from 0 or 1.
So please just use something more obvious and keep bool values as inputs for conditional branches :). Even something like EFI_EXIT(foo ? EFI_TRUE : EFI_FALSE); would work for me. Or you just make the return type of those functions an enum efi_bool.
The resulting code should basically be the same if the compiler is smart, but at least I'm 100% sure when reading it that it does "the right thing".
Alex
PATCH 3/11 efi_loader: Initial EFI_UNICODE_COLLATION_PROTOCOL
Quoted 262 lines · Alexander Graf
Quoted 260 lines · Rob Clark
Quoted 247 lines · Alexander Graf
Quoted 245 lines · Rob Clark
From: Leif Lindholm <[email protected]>
Not complete, but enough for Shell.efi and SCT.efi.
Initial skeleton written by Leif, and then implementation by myself.
Cc Leif Lindholm <[email protected]>Signed-off-by Rob Clark <[email protected]>--- include/efi_api.h | 41 ++++++++++ include/efi_loader.h | 3 + lib/efi_loader/Makefile | 2 +- lib/efi_loader/efi_boottime.c | 6 ++ lib/efi_loader/efi_unicode.c | 170 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 221 insertions(+), 1 deletion(-)create mode 100644
lib/efi_loader/efi_unicode.cinclude/efi_api.h +41
-0@@ -797,6 +797,47 @@ struct efi_hii_string_protocol { efi_uintn_t *secondary_languages_size); }; +/* +* Both UNICODE_COLLATION protocols seem to be the same thing, but +* advertised with two different GUID's because, why not? +*/ + +#define EFI_UNICODE_COLLATION_PROTOCOL_GUID \ + EFI_GUID(0x1d85cd7f, 0xf43d, 0x11d2, \ + 0x9a, 0x0c, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) + +#define EFI_UNICODE_COLLATION_PROTOCOL2_GUID \ + EFI_GUID(0xa4c751fc, 0x23ae, 0x4c3e, \ + 0x92, 0xe9, 0x49, 0x64, 0xcf, 0x63, 0xf3, 0x49) + +struct efi_unicode_collation_protocol { + efi_intn_t (EFIAPI *stri_coll)( + struct efi_unicode_collation_protocol *this, + efi_string_t s1, + efi_string_t s2); + bool (EFIAPI *metai_match)( +struct efi_unicode_collation_protocol *this, +efi_string_t string, +efi_string_t pattern); + void (EFIAPI *str_lwr)( +struct efi_unicode_collation_protocol *this, +efi_string_t string); + void (EFIAPI *str_upr)( +struct efi_unicode_collation_protocol *this, +efi_string_t string); + void (EFIAPI *fat_to_str)( +struct efi_unicode_collation_protocol *this, +efi_uintn_t fat_size, +uint8_t *fat, +efi_string_t string); + bool (EFIAPI *str_to_fat)( +struct efi_unicode_collation_protocol *this, +efi_string_t string, +efi_uintn_t fat_size, +uint8_t *fat); +uint8_t *supported_languages; +}; +#define EFI_GOP_GUID \ EFI_GUID(0x9042a9de, 0x23dc, 0x4a38, \ 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a)include/efi_loader.h +3
-0@@ -83,6 +83,7 @@ extern const struct efi_device_path_utilities_protocol efi_device_path_utilitiesextern const struct efi_hii_config_routing_protocol efi_hii_config_routing;extern const struct efi_hii_database_protocol efi_hii_database;extern const struct efi_hii_string_protocol efi_hii_string; +extern const struct efi_unicode_collation_protocol efi_unicode_collation;uint16_t *efi_dp_str (struct efi_device_path *dp);@@ -97,6 +98,8 @@ extern const efi_guid_t efi_guid_device_path_utilities_protocol;extern const efi_guid_t efi_guid_hii_config_routing_protocol;extern const efi_guid_t efi_guid_hii_database_protocol;extern const efi_guid_t efi_guid_hii_string_protocol; +extern const efi_guid_t efi_guid_unicode_collation_protocol; +extern const efi_guid_t efi_guid_unicode_collation_protocol2;extern unsigned int __efi_runtime_start, __efi_runtime_stop;extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;lib/efi_loader/Makefile +1
-1@@ -17,7 +17,7 @@ endif obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o -obj-y += efi_device_path_utilities.o efi_hii.o +obj-y += efi_device_path_utilities.o efi_hii.o efi_unicode.o obj-y += efi_file.o efi_variable.o efi_bootmgr.o obj-$(CONFIG_LCD) += efi_gop.o obj-$(CONFIG_DM_VIDEO) += efi_gop.olib/efi_loader/efi_boottime.c +6
-0@@ -1166,6 +1166,12 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob obj->protocols[7 ].guid = &efi_guid_hii_config_routing_protocol; obj->protocols[7 ].protocol_interface = (void *)&efi_hii_config_routing; + obj->protocols[8 ].guid = &efi_guid_unicode_collation_protocol; + obj->protocols[8 ].protocol_interface = (void *)&efi_unicode_collation; + + obj->protocols[9 ].guid = &efi_guid_unicode_collation_protocol2; + obj->protocols[9 ].protocol_interface = (void *)&efi_unicode_collation; + info->file_path = file_path; info->device_handle =efi_dp_find_obj (device_path,NULL );lib/efi_loader/efi_unicode.c new file +119
-0@@ -0,0 +1,170 @@ +/* +* EFI Unicode interface +* +* Copyright (c) 2017 Leif Lindholm +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <charset.h> +#include <linux/ctype.h> +#include <efi_loader.h> + +const efi_guid_t efi_guid_unicode_collation_protocol = +EFI_UNICODE_COLLATION_PROTOCOL_GUID ; + +const efi_guid_t efi_guid_unicode_collation_protocol2 = +EFI_UNICODE_COLLATION_PROTOCOL2_GUID ; + +static int matchn (efi_string_t s1,unsigned n1,efi_string_t s2,unsigned n2) +{ +char u1[MAX_UTF8_PER_UTF16 * n1 +1 ]; +char u2[MAX_UTF8_PER_UTF16 * n2 +1 ]; + + *utf16_to_utf8 ((u8 *)u1, s1, n1) ='\0' ; + *utf16_to_utf8 ((u8 *)u2, s2, n2) ='\0' ; + +return strcasecmp (u1, u2); +} + +static efi_intn_t EFIAPI stri_coll(struct efi_unicode_collation_protocol *this, +efi_string_t s1, +efi_string_t s2) +{ +EFI_ENTRY ("%p, \"%ls\", \"%ls\"" , this, s1, s2); + +unsigned n1 =utf16_strlen (s1); +unsigned n2 =utf16_strlen (s2); + +return EFI_EXIT (matchn (s1, n1, s2, n2)); +} + +static bool match (efi_string_t string,efi_string_t pattern) +{ +while (true) { +uint16_t p = *pattern++; +bool matches = false; + +if (p =='\0' || *string =='\0' ) { +/* +* End of pattern or string, succeed if +* end of both: +*/ +return *string == p; + } + +switch (p) { +case '*' : +/* Match zero or more chars: */ +while (*string !='\0' ) { +if (match (string, pattern)) +return true; + string++; + } +return match (string, pattern); +case '?' : +/* Match any one char: */ + string++; +break ; +case '[' : +/* Match char set, either [abc] or [a-c]: */ + +if (pattern[0 ] =='\0' || pattern[0 ] ==']' ) { +/* invalid pattern */ +return false; + } + +if (pattern[1 ] =='-' ) { +uint16_t lo, hi, c; + +/* range: [a-c] */ + lo = pattern[0 ]; + hi = pattern[2 ]; + +if (hi =='\0' || hi ==']' || pattern[3 ] !=']' ) { +/* invalid pattern */ +return false; + } + + c =tolower (*string); + lo =tolower (lo); + hi =tolower (hi); + +if (lo <= c && c <= hi) + matches = true; + + pattern +=4 ; + }else { +/* set: [abc] */ +while ((p = *pattern++) && p !=']' ) +if (matchn (string,1 , &p,1 )) + matches = true; + } + +if (!matches) +return false; + + string++; +break ; +default : +if (matchn (string,1 , &p,1 )) +return false; + string++; +break ; + } + } +} + +static bool EFIAPI metai_match(struct efi_unicode_collation_protocol *this,Quoted 8 lines
lib/efi_loader/efi_unicode.c line 124
Quoted 5 lines
lib/efi_loader/efi_unicode.c new file +5
-0+ efi_string_t string, + efi_string_t pattern) +{ +EFI_ENTRY ("%p, \"%ls\", \"%ls\"" , this, string, pattern); +return EFI_EXIT (match (string, pattern));
EFI_EXITwants a success/failure parameter, not true/false (which can be randomly defined). Please either havematch()return EFI return codes or convert it in here :).That isn't strictly true, it does use typeof(ret).. and while it masks the resulting debug msg with ~EFI_ERROR_MASK, in practice it isn't a problem with boolean return. Just a bit funny.
Quoted 7 lines
Quoted 3 lines
And there already other EFI entry points that return something other than
efi_status_t.. trying to force them all intoefi_status_tmold makes them somewhat more awkward.Well, anything that casts well into an integer is reasonably valid for
EFI_EXIT(). But with bool things aren't always as clear as they should be. I'm for example not 100% sure if the return value of a bool function can never be different from 0 or 1.
So I just double-checked with one of our compiler guys. Since we compile with at least C99, bool is defined as _Bool which is defined as an unsigned 1-bit data type that is defined as 0 or 1.
In a nutshell, keeping it as bool is fine I hope.
Alex
PATCH 4/11 efi_loader: SIMPLE_TEXT_INPUT_EX plus wire up objects properly
In reply to Rob ClarkWe need the _EX version for SCT.. and we need to wire up the corresponding objects in the systab properly, as well as dealing with the console_in object advertising multiple protocols.
--- include/efi_api.h | 61 +++++++++- include/efi_loader.h | 10 +- lib/efi_loader/efi_boottime.c | 3 + lib/efi_loader/efi_console.c | 264 +++++++++++++++++++++++++++++++++++++++--- 4 files changed, 308 insertions(+), 30 deletions(-)
include/efi_api.h +58 -3
@@ -243,11 +243,11 @@ struct efi_system_table {struct efi_table_hdr hdr;unsigned long fw_vendor;/* physical addr of wchar_t vendor string */ u32 fw_revision; -unsigned long con_in_handle; +efi_handle_t con_in_handle;struct efi_simple_input_interface *con_in; -unsigned long con_out_handle; +efi_handle_t con_out_handle;struct efi_simple_text_output_protocol *con_out; -unsigned long stderr_handle; +efi_handle_t stderr_handle;struct efi_simple_text_output_protocol *std_err;struct efi_runtime_services *runtime;struct efi_boot_services *boottime;
@@ -474,6 +474,61 @@ struct efi_simple_input_interface {struct efi_event *wait_for_key; }; + +#define EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID \ + EFI_GUID(0xdd9e7534, 0x7762, 0x4698, \ + 0x8c, 0x14, 0xf5, 0x85, 0x17, 0xa6, 0x25, 0xaa) + +/* key-shift state: */ +#define EFI_SHIFT_STATE_VALID 0x80000000 +#define EFI_RIGHT_SHIFT_PRESSED 0x00000001 +#define EFI_LEFT_SHIFT_PRESSED 0x00000002 +#define EFI_RIGHT_CONTROL_PRESSED 0x00000004 +#define EFI_LEFT_CONTROL_PRESSED 0x00000008 +#define EFI_RIGHT_ALT_PRESSED 0x00000010 +#define EFI_EFI_LEFT_ALT_PRESSED 0x00000020 +#define EFI_RIGHT_LOGO_PRESSED 0x00000040 +#define EFI_LEFT_LOGO_PRESSED 0x00000080 +#define EFI_MENU_KEY_PRESSED 0x00000100 +#define EFI_SYS_REQ_PRESSED 0x00000200 + +/* key-toggle state: */ +#define EFI_TOGGLE_STATE_VALID 0x80 +#define EFI_SCROLL_LOCK_ACTIVE 0x01 +#define EFI_NUM_LOCK_ACTIVE 0x02 +#define EFI_CAPS_LOCK_ACTIVE 0x04 + +struct efi_key_state { +uint32_t key_shift_state; +uint8_t key_toggle_state; +}; + +struct efi_key_data { +struct efi_input_key key; +struct efi_key_state key_state; +}; + +struct efi_simple_text_input_ex_interface { + efi_status_t (EFIAPI *reset)( + struct efi_simple_text_input_ex_interface *this, + bool ExtendedVerification); + efi_status_t (EFIAPI *read_key_stroke)( + struct efi_simple_text_input_ex_interface *this, + struct efi_key_data *key_data); +struct efi_event *wait_for_key; + efi_status_t (EFIAPI *set_state)( + struct efi_simple_text_input_ex_interface *this, + uint8_t key_toggle_state); + efi_status_t (EFIAPI *register_key_notify)( + struct efi_simple_text_input_ex_interface *this, + struct efi_key_data *key_data, + efi_status_t (EFIAPI *notify_fn)(struct efi_key_data *key_data), + efi_handle_t *notify_handle); + efi_status_t (EFIAPI *unregister_key_notify)( + struct efi_simple_text_input_ex_interface *this, + efi_handle_t notify_handle); +}; +#define CONSOLE_CONTROL_GUID \ EFI_GUID(0xf42f7782, 0x12e, 0x4c12, \ 0x99, 0x56, 0x49, 0xf9, 0x43, 0x4, 0xf7, 0x21)
include/efi_loader.h +2 -8
@@ -75,7 +75,9 @@ const char *__efi_nesting_dec(void);extern struct efi_runtime_services efi_runtime_services;extern struct efi_system_table systab; +extern struct efi_object efi_console_output_obj;extern const struct efi_simple_text_output_protocol efi_con_out; +extern struct efi_object efi_console_input_obj;extern struct efi_simple_input_interface efi_con_in;extern const struct efi_console_control_protocol efi_console_control;extern const struct efi_device_path_to_text_protocol efi_device_path_to_text;
@@ -129,14 +131,6 @@ struct efi_object {void *handle; }; -#define EFI_PROTOCOL_OBJECT (_guid, _protocol) (struct efi_object){ \ - .protocols = {{ \ - .guid = &(_guid), \ - .protocol_interface = (void *)(_protocol), \ - }}, \ - .handle = (void *)(_protocol), \ -} -/** * struct efi_event *
lib/efi_loader/efi_boottime.c +3 -0
@@ -2077,8 +2077,11 @@ struct efi_system_table __efi_runtime_data systab = { .headersize = sizeof(struct efi_table_hdr), }, .fw_vendor = (long)firmware_vendor, + .con_in_handle = &efi_console_input_obj, .con_in = (void*)&efi_con_in, + .con_out_handle = &efi_console_output_obj, .con_out = (void*)&efi_con_out, + .stderr_handle = &efi_console_output_obj, .std_err = (void*)&efi_con_out, .runtime = (void*)&efi_runtime_services, .boottime = (void*)&efi_boot_services,
lib/efi_loader/efi_console.c +245 -19
329 lines not on this page · raw message
Signature · 1 line
2.13.6
PATCH 4/11 efi_loader: SIMPLE_TEXT_INPUT_EX plus wire up objects properly
Quoted 5 lines · Rob Clark
We need the
_EXversion for SCT.. and we need to wire up the corresponding objects in the systab properly, as well as dealing with theconsole_inobject advertising multiple protocols.Signed-off-by Rob Clark <[email protected]>
Alex
Alexander Graf
AppliedPATCH 4/11 efi_loader: SIMPLE_TEXT_INPUT_EX plus wire up objects properly
In reply to Rob ClarkQuoted 6 lines
We need the
_EXversion for SCT.. and we need to wire up the corresponding objects in the systab properly, as well as dealing with theconsole_inobject advertising multiple protocols.Signed-off-by Rob Clark <[email protected]>Reviewed-by Alexander Graf <[email protected]>
Thanks, applied to efi-next
Alex
PATCH 5/11 efi_loader: console support for color attributes
In reply to Rob ClarkShell.efi uses this, and supporting color attributes makes things look nicer. Map the EFI fg/bg color attributes to ANSI escape sequences. Not all colors have a perfect match, but spec just says "Devices supporting a different number of text colors are required to emulate the above colors to the best of the device’s capabilities".
--- include/efi_api.h | 33 +++++++++++++++++++++++++++++++++ lib/efi_loader/efi_console.c | 27 +++++++++++++++++++++++++-- 2 files changed, 58 insertions(+), 2 deletions(-)
include/efi_api.h +33 -0
@@ -427,6 +427,39 @@ struct simple_text_output_mode {EFI_GUID (0x387477c2 ,0x69c7 ,0x11d2 , \ 0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b) +#define EFI_BLACK 0x00 +#define EFI_BLUE 0x01 +#define EFI_GREEN 0x02 +#define EFI_CYAN 0x03 +#define EFI_RED 0x04 +#define EFI_MAGENTA 0x05 +#define EFI_BROWN 0x06 +#define EFI_LIGHTGRAY 0x07 +#define EFI_BRIGHT 0x08 +#define EFI_DARKGRAY 0x08 +#define EFI_LIGHTBLUE 0x09 +#define EFI_LIGHTGREEN 0x0a +#define EFI_LIGHTCYAN 0x0b +#define EFI_LIGHTRED 0x0c +#define EFI_LIGHTMAGENTA 0x0d +#define EFI_YELLOW 0x0e +#define EFI_WHITE 0x0f +#define EFI_BACKGROUND_BLACK 0x00 +#define EFI_BACKGROUND_BLUE 0x10 +#define EFI_BACKGROUND_GREEN 0x20 +#define EFI_BACKGROUND_CYAN 0x30 +#define EFI_BACKGROUND_RED 0x40 +#define EFI_BACKGROUND_MAGENTA 0x50 +#define EFI_BACKGROUND_BROWN 0x60 +#define EFI_BACKGROUND_LIGHTGRAY 0x70 + +/* extract foreground color from EFI attribute */ +#define EFI_ATTR_FG (attr) ((attr) & 0x07) +/* treat high bit of FG as bright/bold (similar to edk2) */ +#define EFI_ATTR_BOLD (attr) (((attr) >> 3) & 0x01) +/* extract background color from EFI attribute */ +#define EFI_ATTR_BG (attr) (((attr) >> 4) & 0x7) +struct efi_simple_text_output_protocol {void *reset; efi_status_t (EFIAPI *output_string)(
lib/efi_loader/efi_console.c +25 -2
@@ -316,14 +316,37 @@ static efi_status_t EFIAPI efi_cout_set_mode(return EFI_EXIT (EFI_SUCCESS ); } +static const struct { +unsigned fg; +unsigned bg; +} color[] = { + {30 ,40 },/* 0: black */ + {34 ,44 },/* 1: blue */ + {32 ,42 },/* 2: green */ + {36 ,46 },/* 3: cyan */ + {31 ,41 },/* 4: red */ + {35 ,45 },/* 5: magenta */ + {33 ,43 },/* 6: brown, map to yellow as edk2 does*/ + {37 ,47 },/* 7: light grey, map to white */ +}; + +/* See EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetAttribute(). */ static efi_status_t EFIAPI efi_cout_set_attribute(struct efi_simple_text_output_protocol *this,unsigned long attribute) { +unsigned int bold =EFI_ATTR_BOLD (attribute); +unsigned int fg =EFI_ATTR_FG (attribute); +unsigned int bg =EFI_ATTR_BG (attribute); +EFI_ENTRY ("%p, %lx" , this, attribute); -/* Just ignore attributes (colors) for now */ -return EFI_EXIT (EFI_UNSUPPORTED ); +if (attribute) +printf (ESC "[%u;%u;%um" , bold, color[fg].fg, color[bg].bg); +else +printf (ESC "[0;37;40m" ); + +return EFI_EXIT (EFI_SUCCESS ); } static efi_status_t EFIAPI efi_cout_clear_screen(
Signature · 1 line
2.13.6
PATCH 5/11 efi_loader: console support for color attributes
Quoted 84 lines · Rob Clark
Shell.efi uses this, and supporting color attributes makes things look nicer. Map the EFI fg/bg color attributes to ANSI escape sequences. Not all colors have a perfect match, but spec just says "Devices supporting a different number of text colors are required to emulate the above colors to the best of the device’s capabilities".
Signed-off-by Rob Clark <[email protected]>--- include/efi_api.h | 33 +++++++++++++++++++++++++++++++++ lib/efi_loader/efi_console.c | 27 +++++++++++++++++++++++++-- 2 files changed, 58 insertions(+), 2 deletions(-)include/efi_api.h +33
-0@@ -427,6 +427,39 @@ struct simple_text_output_mode {EFI_GUID (0x387477c2 ,0x69c7 ,0x11d2 , \ 0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b) +#define EFI_BLACK 0x00 +#define EFI_BLUE 0x01 +#define EFI_GREEN 0x02 +#define EFI_CYAN 0x03 +#define EFI_RED 0x04 +#define EFI_MAGENTA 0x05 +#define EFI_BROWN 0x06 +#define EFI_LIGHTGRAY 0x07 +#define EFI_BRIGHT 0x08 +#define EFI_DARKGRAY 0x08 +#define EFI_LIGHTBLUE 0x09 +#define EFI_LIGHTGREEN 0x0a +#define EFI_LIGHTCYAN 0x0b +#define EFI_LIGHTRED 0x0c +#define EFI_LIGHTMAGENTA 0x0d +#define EFI_YELLOW 0x0e +#define EFI_WHITE 0x0f +#define EFI_BACKGROUND_BLACK 0x00 +#define EFI_BACKGROUND_BLUE 0x10 +#define EFI_BACKGROUND_GREEN 0x20 +#define EFI_BACKGROUND_CYAN 0x30 +#define EFI_BACKGROUND_RED 0x40 +#define EFI_BACKGROUND_MAGENTA 0x50 +#define EFI_BACKGROUND_BROWN 0x60 +#define EFI_BACKGROUND_LIGHTGRAY 0x70 + +/* extract foreground color from EFI attribute */ +#define EFI_ATTR_FG (attr) ((attr) & 0x07) +/* treat high bit of FG as bright/bold (similar to edk2) */ +#define EFI_ATTR_BOLD (attr) (((attr) >> 3) & 0x01) +/* extract background color from EFI attribute */ +#define EFI_ATTR_BG (attr) (((attr) >> 4) & 0x7) +struct efi_simple_text_output_protocol {void *reset; efi_status_t (EFIAPI *output_string)(lib/efi_loader/efi_console.c +16
-0@@ -316,14 +316,37 @@ static efi_status_t EFIAPI efi_cout_set_mode(return EFI_EXIT (EFI_SUCCESS ); } +static const struct { +unsigned fg; +unsigned bg; +} color[] = { + {30 ,40 },/* 0: black */ + {34 ,44 },/* 1: blue */ + {32 ,42 },/* 2: green */ + {36 ,46 },/* 3: cyan */ + {31 ,41 },/* 4: red */ + {35 ,45 },/* 5: magenta */ + {33 ,43 },/* 6: brown, map to yellow as edk2 does*/ + {37 ,47 },/* 7: light grey, map to white */ +}; + +/* See EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetAttribute(). */ static efi_status_t EFIAPI efi_cout_set_attribute(struct efi_simple_text_output_protocol *this,unsigned long attribute) { +unsigned int bold =EFI_ATTR_BOLD (attribute);
lib/efi_loader/efi_console.c static efi_status_t EFIAPI efi_cout_set_mode( · line 346
Quoted 10 lines
lib/efi_loader/efi_console.c +6
-2+unsigned int fg =EFI_ATTR_FG (attribute); +unsigned int bg =EFI_ATTR_BG (attribute); +EFI_ENTRY ("%p, %lx" , this, attribute); -/* Just ignore attributes (colors) for now */ -return EFI_EXIT (EFI_UNSUPPORTED ); +if (attribute) +printf (ESC "[%u;%u;%um" , bold, color[fg].fg, color[bg].bg); +else
Maybe Alex can just add a comment here when merging:
/* EFI console expects attribute = 0 to result in default colors. */
lib/efi_loader/efi_console.c static efi_status_t EFIAPI efi_cout_set_mode( · line 352
Quoted 7 lines
lib/efi_loader/efi_console.c +3
-0+printf (ESC "[0;37;40m" ); + +return EFI_EXIT (EFI_SUCCESS ); } static efi_status_t EFIAPI efi_cout_clear_screen(
Works fine.
See appended screenshot.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Screenshot_20171011_013002.png
Type: image/png
Size: 15190 bytes
Desc: not available
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20171011/11de4d77/attachment.png>
PATCH 5/11 efi_loader: console support for color attributes
In reply to Rob ClarkQuoted 7 lines · Rob Clark
Shell.efi uses this, and supporting color attributes makes things look nicer. Map the EFI fg/bg color attributes to ANSI escape sequences. Not all colors have a perfect match, but spec just says "Devices supporting a different number of text colors are required to emulate the above colors to the best of the device’s capabilities".
Signed-off-by Rob Clark <[email protected]>
Alex
Alexander Graf
AppliedPATCH 5/11 efi_loader: console support for color attributes
In reply to Rob ClarkQuoted 9 lines
Shell.efi uses this, and supporting color attributes makes things look nicer. Map the EFI fg/bg color attributes to ANSI escape sequences. Not all colors have a perfect match, but spec just says "Devices supporting a different number of text colors are required to emulate the above colors to the best of the device’s capabilities".
Signed-off-by Rob Clark <[email protected]>Tested-by Heinrich Schuchardt <[email protected]>Reviewed-by Alexander Graf <[email protected]>
Thanks, applied to efi-next
Alex
PATCH 6/11 efi_loader: Decouple EFI input/output from stdin/stdout
In reply to Rob ClarkIn some cases, it is quite useful to have (for example) EFI on screen but u-boot on serial port.
This adds two new optional environment variables, "efiin" and "efiout", which can be used to set EFI console input/output independently of u-boot's input/output. If unset, EFI console will default to stdin/ stdout as before.
---
As mentioned yesterday, this triggers some problems w/ qemu + 'bootefi hello' since puts() != fputs(stdout). So you can hold off applying this one for now if you want until we figure out a solution. It is not strictly required, only nice-to-have (and nice for enabling debug traces on serial without interfering with Shell.efi output on screen)
lib/efi_loader/efi_console.c | 111 ++++++++++++++++++++++++++++++++----------- 1 file changed, 82 insertions(+), 29 deletions(-)
lib/efi_loader/efi_console.c +82 -29
@@ -47,6 +47,38 @@ static struct cout_mode efi_cout_modes[] = {const efi_guid_t efi_guid_console_control =CONSOLE_CONTROL_GUID ; +static struct stdio_dev *efiin, *efiout; + +static int efi_tstc (void ) +{ +return efiin->tstc (efiin); +} + +static int efi_getc (void ) +{ +return efiin->getc (efiin); +} + +static int efi_printf (const char *fmt, ...) +{ +va_list args; +uint i; +char printbuffer[CONFIG_SYS_PBSIZE ]; + +va_start (args, fmt); + +/* +* For this to work, printbuffer must be larger than +* anything we ever want to print. +*/ + i =vsnprintf (printbuffer,sizeof (printbuffer), fmt, args); +va_end (args); + +/* Print the string */ + efiout->puts (efiout, printbuffer); +return i; +} +#define cESC '\x1b'#define ESC "\x1b"
@@ -111,16 +143,16 @@ static int term_read_reply(int *n, int maxnum, char end_char)char c;int i =0 ; - c =getc (); + c =efi_getc ();if (c != cESC)return -1 ; - c =getc (); + c =efi_getc ();if (c !='[' )return -1 ; n[0 ] =0 ;while (1 ) { - c =getc (); + c =efi_getc ();if (c ==';' ) { i++;if (i >= maxnum)
@@ -164,7 +196,7 @@ static efi_status_t EFIAPI efi_cout_output_string( *utf16_to_utf8 ((u8 *)buf, string, n16) ='\0' ; -fputs (stdout, buf); + efiout->puts (efiout, buf);for (p = buf; *p; p++) {switch (*p) {
@@ -217,14 +249,14 @@ static int query_console_serial(int *rows, int *cols)u64 timeout;/* Empty input buffer */ -while (tstc ()) -getc (); +while (efi_tstc ()) +efi_getc (); -printf (ESC "[18t" ); +efi_printf (ESC "[18t" );/* Check if we have a terminal that understands */ timeout =timer_get_us () +1000000 ; -while (!tstc ()) +while (!efi_tstc ())if (timer_get_us () > timeout)return -1 ;
@@ -246,16 +278,13 @@ static efi_status_t EFIAPI efi_cout_query_mode(EFI_ENTRY ("%p, %ld, %p, %p" , this, mode_number, columns, rows);if (!console_size_queried) { -const char *stdout_name =env_get ("stdout" );int rows, cols; console_size_queried = true; -if (stdout_name && !strcmp (stdout_name,"vidconsole" ) && +if (!strcmp (efiout->name,"vidconsole" ) &&IS_ENABLED (CONFIG_DM_VIDEO )) { -struct stdio_dev *stdout_dev = -stdio_get_by_name ("vidconsole" ); -struct udevice *dev = stdout_dev->priv; +struct udevice *dev = efiout->priv;struct vidconsole_priv *priv =dev_get_uclass_priv (dev); rows = priv->rows;
@@ -342,9 +371,9 @@ static efi_status_t EFIAPI efi_cout_set_attribute(EFI_ENTRY ("%p, %lx" , this, attribute);if (attribute) -printf (ESC "[%u;%u;%um" , bold, color[fg].fg, color[bg].bg); +efi_printf (ESC "[%u;%u;%um" , bold, color[fg].fg, color[bg].bg);else -printf (ESC "[0;37;40m" ); +efi_printf (ESC "[0;37;40m" );return EFI_EXIT (EFI_SUCCESS ); }
@@ -354,7 +383,7 @@ static efi_status_t EFIAPI efi_cout_clear_screen( {EFI_ENTRY ("%p" , this); -printf (ESC "[2J" ); +efi_printf (ESC "[2J" );return EFI_EXIT (EFI_SUCCESS ); }
@@ -365,7 +394,7 @@ static efi_status_t EFIAPI efi_cout_set_cursor_position( {EFI_ENTRY ("%p, %ld, %ld" , this, column, row); -printf (ESC "[%d;%df" , (int )row, (int )column); +efi_printf (ESC "[%d;%df" , (int )row, (int )column); efi_con_mode.cursor_column = column; efi_con_mode.cursor_row = row;
@@ -378,7 +407,7 @@ static efi_status_t EFIAPI efi_cout_enable_cursor( {EFI_ENTRY ("%p, %d" , this, enable); -printf (ESC "[?25%c" , enable ?'h' :'l' ); +efi_printf (ESC "[?25%c" , enable ?'h' :'l' );return EFI_EXIT (EFI_SUCCESS ); }
@@ -464,28 +493,28 @@ static efi_status_t read_key_stroke(struct efi_key_data *key_data) };char ch; -if (!tstc ()) { +if (!efi_tstc ()) {/* No key pressed */ return EFI_NOT_READY ; } - ch =getc (); + ch =efi_getc ();if (ch == cESC) {/* Escape Sequence */ - ch =getc (); + ch =efi_getc ();switch (ch) {case cESC:/* ESC */ pressed_key.scan_code =23 ;break ;case 'O' :/* F1 - F4 */ - pressed_key.scan_code =getc () -'P' +11 ; + pressed_key.scan_code =efi_getc () -'P' +11 ;break ; case 'a'...'z': key_state.key_shift_state =EFI_SHIFT_STATE_VALID |EFI_EFI_LEFT_ALT_PRESSED ;break ;case '[' : - ch =getc (); + ch =efi_getc ();switch (ch) { case 'A'...'D': /* up, down right, left */ pressed_key.scan_code = ch -'A' +1 ;
@@ -497,16 +526,16 @@ static efi_status_t read_key_stroke(struct efi_key_data *key_data) pressed_key.scan_code =5 ;break ;case '1' :/* F5 - F8 */ - pressed_key.scan_code =getc () -'0' +11 ; -getc (); + pressed_key.scan_code =efi_getc () -'0' +11 ; +efi_getc ();break ;case '2' :/* F9 - F12 */ - pressed_key.scan_code =getc () -'0' +19 ; -getc (); + pressed_key.scan_code =efi_getc () -'0' +19 ; +efi_getc ();break ;case '3' :/* DEL */ pressed_key.scan_code =8 ; -getc (); +efi_getc ();break ; }break ;
@@ -584,7 +613,7 @@ static void EFIAPI efi_console_timer_notify(struct efi_event *event, void *context) {EFI_ENTRY ("%p, %p" , event, context); -if (tstc ()) { +if (efi_tstc ()) {read_keys (); efi_con_in.wait_for_key->is_signaled = true;efi_signal_event (efi_con_in.wait_for_key);
@@ -723,6 +752,27 @@ struct efi_object efi_console_input_obj = { .handle = &efi_console_input_obj, }; +static struct stdio_dev *get_stdio_dev (const char *envname,int default_dev) +{ +const char *name; +struct stdio_dev *dev =NULL ; + + name =env_get (envname); +if (name) { + dev =stdio_get_by_name (name); +if (dev && dev->start) { +int ret = dev->start (dev); +if (ret <0 ) + dev =NULL ; + } + } + +if (!dev) + dev = stdio_devices[default_dev]; + +return dev; +} +/* This gets called from do_bootefi_exec(). */ int efi_console_register (void ) {
@@ -733,6 +783,9 @@ int efi_console_register(void)list_add_tail (&efi_console_output_obj.link, &efi_obj_list);list_add_tail (&efi_console_input_obj.link, &efi_obj_list); + efiout =get_stdio_dev ("efiout" , stdout); + efiin =get_stdio_dev ("efiin" , stdin); + r =efi_create_event (EVT_NOTIFY_WAIT ,TPL_CALLBACK , efi_key_notify,NULL , &efi_con_in.wait_for_key);if (r !=EFI_SUCCESS ) {
Signature · 1 line
2.13.6
PATCH 6/11 efi_loader: Decouple EFI input/output from stdin/stdout
Quoted 9 lines · Rob Clark
In some cases, it is quite useful to have (for example) EFI on screen but u-boot on serial port.
This adds two new optional environment variables, "efiin" and "efiout", which can be used to set EFI console input/output independently of u-boot's input/output. If unset, EFI console will default to stdin/ stdout as before.
Signed-off-by Rob Clark <[email protected]>
With this patch, we lose the ability to have the efi in/out go to both graphical and serial console, right? This is critical functionality to have, since we don't necessarily know which output/input a user ends up using.
Alex
PATCH 6/11 efi_loader: Decouple EFI input/output from stdin/stdout
Quoted 11 lines · Alexander Graf
Quoted 8 lines · Rob Clark
In some cases, it is quite useful to have (for example) EFI on screen but u-boot on serial port.
This adds two new optional environment variables, "efiin" and "efiout", which can be used to set EFI console input/output independently of u-boot's input/output. If unset, EFI console will default to stdin/ stdout as before.
Quoted 6 lines
Quoted 1 line
Signed-off-by Rob Clark <[email protected]>With this patch, we lose the ability to have the efi in/out go to both graphical and serial console, right? This is critical functionality to have, since we don't necessarily know which output/input a user ends up using.
I'll think about how to support iomux.. but some things like console size are just not going to work properly there. And as long as we fix the stdout shenanigans (ie. what I was seeing w/ qemu-x86) you can simply not set efiout var and have things working as before, so you don't loose any existing functionality (although, like I said, if the two different consoles have different sizes things aren't going to work properly for anything other than simple cases).
In most cases, the display driver should be able to detect whether a display is connected.. this is what I've done on dragonboard410c, so if no display plugged in, 'efiout=vidconsole' fails and you fall back to serial, else you get efi on screen like you would on a "real" computer. For boards that have a display driver that isn't able to do the basic check of whether a cable is plugged in, just don't set "efiout" (or fix the display driver) ;-)
BR,
-R
Quoted 2 lines
Alex
PATCH 6/11 efi_loader: Decouple EFI input/output from stdin/stdout
Quoted 14 lines · Rob Clark
Quoted 13 lines · Alexander Graf
Quoted 9 lines · Rob Clark
In some cases, it is quite useful to have (for example) EFI on screen but u-boot on serial port.
This adds two new optional environment variables, "efiin" and "efiout", which can be used to set EFI console input/output independently of u-boot's input/output. If unset, EFI console will default to stdin/ stdout as before.
Signed-off-by Rob Clark <[email protected]>
Quoted 7 lines
Quoted 4 lines
With this patch, we lose the ability to have the efi in/out go to both graphical and serial console, right? This is critical functionality to have, since we don't necessarily know which output/input a user ends up using.
I'll think about how to support iomux.. but some things like console size are just not going to work properly there. And as long as we fix
Yeah, those probably would need to get special cased.
Quoted 6 lines
the stdout shenanigans (ie. what I was seeing w/ qemu-x86) you can simply not set efiout var and have things working as before, so you don't loose any existing functionality (although, like I said, if the two different consoles have different sizes things aren't going to work properly for anything other than simple cases).
Quoted 7 lines
In most cases, the display driver should be able to detect whether a display is connected.. this is what I've done on dragonboard410c, so if no display plugged in, 'efiout=vidconsole' fails and you fall back to serial, else you get efi on screen like you would on a "real" computer. For boards that have a display driver that isn't able to do the basic check of whether a cable is plugged in, just don't set "efiout" (or fix the display driver) ;-)
Are you sure that's what happens on a "real" computer? As far as I remember from all ARM servers running edk2 based firmware that I've touched so far, the default is always to display on serial *and* graphical output at the same time.
Alex
PATCH 6/11 efi_loader: Decouple EFI input/output from stdin/stdout
Quoted 41 lines · Alexander Graf
Quoted 14 lines · Rob Clark
Quoted 13 lines · Alexander Graf
Quoted 9 lines · Rob Clark
In some cases, it is quite useful to have (for example) EFI on screen but u-boot on serial port.
This adds two new optional environment variables, "efiin" and "efiout", which can be used to set EFI console input/output independently of u-boot's input/output. If unset, EFI console will default to stdin/ stdout as before.
Signed-off-by Rob Clark <[email protected]>Quoted 7 lines
Quoted 4 lines
With this patch, we lose the ability to have the efi in/out go to both graphical and serial console, right? This is critical functionality to have, since we don't necessarily know which output/input a user ends up using.
I'll think about how to support iomux.. but some things like console size are just not going to work properly there. And as long as we fix
Yeah, those probably would need to get special cased.
Quoted 6 lines
the stdout shenanigans (ie. what I was seeing w/ qemu-x86) you can simply not set efiout var and have things working as before, so you don't loose any existing functionality (although, like I said, if the two different consoles have different sizes things aren't going to work properly for anything other than simple cases).
Quoted 7 lines
In most cases, the display driver should be able to detect whether a display is connected.. this is what I've done on dragonboard410c, so if no display plugged in, 'efiout=vidconsole' fails and you fall back to serial, else you get efi on screen like you would on a "real" computer. For boards that have a display driver that isn't able to do the basic check of whether a cable is plugged in, just don't set "efiout" (or fix the display driver) ;-)
Quoted 4 lines
Are you sure that's what happens on a "real" computer? As far as I remember from all ARM servers running edk2 based firmware that I've touched so far, the default is always to display on serial *and* graphical output at the same time.
Well, I suppose some of the arm64 server vendors have done a better job than others on firmware.. you'd hope they would probe EDID, and report correct console dimensions based on display resolution, etc.
Doing both serial and display works for simple stuff, but it goes badly once the efi payload starts trying to change the cursor position and write to specific parts of the screen (which both Shell.efi and grub try to do).
BR,
-R
PATCH 6/11 efi_loader: Decouple EFI input/output from stdin/stdout
Quoted 51 lines · Rob Clark
Quoted 41 lines · Alexander Graf
Quoted 14 lines · Rob Clark
Quoted 13 lines · Alexander Graf
Quoted 9 lines · Rob Clark
In some cases, it is quite useful to have (for example) EFI on screen but u-boot on serial port.
This adds two new optional environment variables, "efiin" and "efiout", which can be used to set EFI console input/output independently of u-boot's input/output. If unset, EFI console will default to stdin/ stdout as before.
Signed-off-by Rob Clark <[email protected]>Quoted 7 lines
Quoted 4 lines
With this patch, we lose the ability to have the efi in/out go to both graphical and serial console, right? This is critical functionality to have, since we don't necessarily know which output/input a user ends up using.
I'll think about how to support iomux.. but some things like console size are just not going to work properly there. And as long as we fix
Yeah, those probably would need to get special cased.
Quoted 6 lines
the stdout shenanigans (ie. what I was seeing w/ qemu-x86) you can simply not set efiout var and have things working as before, so you don't loose any existing functionality (although, like I said, if the two different consoles have different sizes things aren't going to work properly for anything other than simple cases).
Quoted 7 lines
In most cases, the display driver should be able to detect whether a display is connected.. this is what I've done on dragonboard410c, so if no display plugged in, 'efiout=vidconsole' fails and you fall back to serial, else you get efi on screen like you would on a "real" computer. For boards that have a display driver that isn't able to do the basic check of whether a cable is plugged in, just don't set "efiout" (or fix the display driver) ;-)
Quoted 4 lines
Are you sure that's what happens on a "real" computer? As far as I remember from all ARM servers running edk2 based firmware that I've touched so far, the default is always to display on serial *and* graphical output at the same time.
Well, I suppose some of the arm64 server vendors have done a better job than others on firmware.. you'd hope they would probe EDID, and report correct console dimensions based on display resolution, etc.
Quoted 8 lines
Doing both serial and display works for simple stuff, but it goes badly once the efi payload starts trying to change the cursor position and write to specific parts of the screen (which both Shell.efi and grub try to do).
BR,
-R
Hello Rob,
I do not know which program you use for connecting to your serial console. I use minicom which is a Debian/Ubuntu package. I had no problem using grub, vim, nano or any other console program.
Minicom just provides a VT100 emulation and that is close enough to what Linux expects.
So I would not see what should be so special about Shell.efi.
My U-Boot system all have video but I never have a monitor connected.
So being able to use serial even if video is available is a necessity.
Best regards
Heinrich
PATCH 6/11 efi_loader: Decouple EFI input/output from stdin/stdout
Quoted 73 lines · Heinrich Schuchardt
Quoted 62 lines · Rob Clark
Quoted 50 lines · Alexander Graf
Quoted 19 lines · Rob Clark
Quoted 17 lines · Alexander Graf
Quoted 11 lines · Rob Clark
In some cases, it is quite useful to have (for example) EFI on screen but u-boot on serial port.
This adds two new optional environment variables, "efiin" and "efiout",
which can be used to set EFI console input/output independently of u-boot's input/output. If unset, EFI console will default to stdin/ stdout as before.Signed-off-by Rob Clark <[email protected]>Quoted 8 lines
Quoted 4 lines
With this patch, we lose the ability to have the efi in/out go to both graphical and serial console, right? This is critical functionality to have, since we don't necessarily know which output/input a user ends up using.
I'll think about how to support iomux.. but some things like console size are just not going to work properly there. And as long as we fix
Yeah, those probably would need to get special cased.
Quoted 6 lines
the stdout shenanigans (ie. what I was seeing w/ qemu-x86) you can simply not set efiout var and have things working as before, so you don't loose any existing functionality (although, like I said, if the two different consoles have different sizes things aren't going to work properly for anything other than simple cases).
Quoted 7 lines
In most cases, the display driver should be able to detect whether a display is connected.. this is what I've done on dragonboard410c, so if no display plugged in, 'efiout=vidconsole' fails and you fall back to serial, else you get efi on screen like you would on a "real" computer. For boards that have a display driver that isn't able to do the basic check of whether a cable is plugged in, just don't set "efiout" (or fix the display driver) ;-)
Quoted 4 lines
Are you sure that's what happens on a "real" computer? As far as I remember from all ARM servers running edk2 based firmware that I've touched so far, the default is always to display on serial *and* graphical output at the same time.
Well, I suppose some of the arm64 server vendors have done a better job than others on firmware.. you'd hope they would probe EDID, and report correct console dimensions based on display resolution, etc.
Quoted 8 lines
Doing both serial and display works for simple stuff, but it goes badly once the efi payload starts trying to change the cursor position and write to specific parts of the screen (which both Shell.efi and grub try to do).
BR,
-R
Quoted 8 lines
Hello Rob,
I do not know which program you use for connecting to your serial console. I use minicom which is a Debian/Ubuntu package. I had no problem using grub, vim, nano or any other console program.
Minicom just provides a VT100 emulation and that is close enough to what Linux expects.
fwiw, I generally use kermit so my terminal emulator is whatever "xterm" type app I'm using. (Currently a big fan of Tilix).. but that isn't so much the issue..
Quoted 1 line
So I would not see what should be so special about Shell.efi.
I'm not explaining the problem well, but you can see basically the same issue if you resize your terminal emulator to something smaller than what grub/shell/etc think you are using.
I guess if they just fall back to assuming 80x25 like agraf mentioned, that would kind of work. It just means shell or grub will only use the tiny upper-left corner of your monitor.
Quoted 3 lines
My U-Boot system all have video but I never have a monitor connected.
So being able to use serial even if video is available is a necessity.
If the video driver doesn't detect that it is unconnected, someone should really fix that, otherwise you'll have problems booting an image where grub tries to use gfxterm if GOP is present (but we are really getting off topic here)
Either way, you still have the option of not setting efiout (or setting it to serial)
But for end users (at least of boards that I care about), if they plug in a monitor they should get grub on screen. Not everyone has a serial cable attached.
BR,
-R
PATCH 6/11 efi_loader: Decouple EFI input/output from stdin/stdout
Quoted 92 lines · Rob Clark
Quoted 62 lines · Heinrich Schuchardt
Quoted 52 lines · Rob Clark
Quoted 42 lines · Alexander Graf
Quoted 15 lines · Rob Clark
Quoted 14 lines · Alexander Graf
Quoted 10 lines · Rob Clark
In some cases, it is quite useful to have (for example) EFI on screen but u-boot on serial port.
This adds two new optional environment variables, "efiin" and "efiout",
which can be used to set EFI console input/output independently of u-boot's input/output. If unset, EFI console will default to stdin/ stdout as before.Signed-off-by Rob Clark <[email protected]>Quoted 7 lines
Quoted 4 lines
With this patch, we lose the ability to have the efi in/out go to both graphical and serial console, right? This is critical functionality to have, since we don't necessarily know which output/input a user ends up using.
I'll think about how to support iomux.. but some things like console size are just not going to work properly there. And as long as we fix
Yeah, those probably would need to get special cased.
Quoted 6 lines
the stdout shenanigans (ie. what I was seeing w/ qemu-x86) you can simply not set efiout var and have things working as before, so you don't loose any existing functionality (although, like I said, if the two different consoles have different sizes things aren't going to work properly for anything other than simple cases).
Quoted 7 lines
In most cases, the display driver should be able to detect whether a display is connected.. this is what I've done on dragonboard410c, so if no display plugged in, 'efiout=vidconsole' fails and you fall back to serial, else you get efi on screen like you would on a "real" computer. For boards that have a display driver that isn't able to do the basic check of whether a cable is plugged in, just don't set "efiout" (or fix the display driver) ;-)
Quoted 4 lines
Are you sure that's what happens on a "real" computer? As far as I remember from all ARM servers running edk2 based firmware that I've touched so far, the default is always to display on serial *and* graphical output at the same time.
Well, I suppose some of the arm64 server vendors have done a better job than others on firmware.. you'd hope they would probe EDID, and report correct console dimensions based on display resolution, etc.
Quoted 8 lines
Doing both serial and display works for simple stuff, but it goes badly once the efi payload starts trying to change the cursor position and write to specific parts of the screen (which both Shell.efi and grub try to do).
BR,
-RQuoted 8 lines
Hello Rob,
I do not know which program you use for connecting to your serial console. I use minicom which is a Debian/Ubuntu package. I had no problem using grub, vim, nano or any other console program.
Minicom just provides a VT100 emulation and that is close enough to what Linux expects.
fwiw, I generally use kermit so my terminal emulator is whatever "xterm" type app I'm using. (Currently a big fan of Tilix).. but that isn't so much the issue..
Quoted 1 line
So I would not see what should be so special about Shell.efi.
I'm not explaining the problem well, but you can see basically the same issue if you resize your terminal emulator to something smaller than what grub/shell/etc think you are using.
I guess if they just fall back to assuming 80x25 like agraf mentioned, that would kind of work. It just means shell or grub will only use the tiny upper-left corner of your monitor.
Quoted 3 lines
My U-Boot system all have video but I never have a monitor connected.
So being able to use serial even if video is available is a necessity.
If the video driver doesn't detect that it is unconnected, someone should really fix that, otherwise you'll have problems booting an image where grub tries to use gfxterm if GOP is present (but we are really getting off topic here)
Quoted 6 lines
Either way, you still have the option of not setting efiout (or setting it to serial)
But for end users (at least of boards that I care about), if they plug in a monitor they should get grub on screen. Not everyone has a serial cable attached.
I fully agree there. The same applies the other way around too. Even if they have a monitor attached, they should get grub on serial if serial is a valid output :). Just attaching a monitor doesn't mean you only use that monitor to control the system.
I think for multi-out we really just have to do what edk2 does and limit the screen size to 80x25. I guess you'd just create an iomux target there that would return the fake size info?
Alex
PATCH 6/11 efi_loader: Decouple EFI input/output from stdin/stdout
Quoted 124 lines · Alexander Graf
Quoted 115 lines · Rob Clark
Quoted 80 lines · Heinrich Schuchardt
Quoted 67 lines · Rob Clark
Quoted 55 lines · Alexander Graf
Quoted 30 lines · Rob Clark
Quoted 18 lines · Alexander Graf
Quoted 5 lines · Rob Clark
In some cases, it is quite useful to have (for example) EFI on screen
but u-boot on serial port.Quoted 7 lines
This adds two new optional environment variables, "efiin" and "efiout",
which can be used to set EFI console input/output independently of u-boot's input/output. If unset, EFI console will default to stdin/ stdout as before.Signed-off-by Rob Clark <[email protected]>Quoted 7 lines
With this patch, we lose the ability to have the efi in/out go to both
graphical and serial console, right? This is critical functionality to
have, since we don't necessarily know which output/input a user ends up
using.Quoted 2 lines
I'll think about how to support iomux.. but some things like console size are just not going to work properly there. And as long as we fix
Yeah, those probably would need to get special cased.
Quoted 6 lines
the stdout shenanigans (ie. what I was seeing w/ qemu-x86) you can simply not set efiout var and have things working as before, so you don't loose any existing functionality (although, like I said, if the two different consoles have different sizes things aren't going to work properly for anything other than simple cases).
Quoted 7 lines
In most cases, the display driver should be able to detect whether a display is connected.. this is what I've done on dragonboard410c, so if no display plugged in, 'efiout=vidconsole' fails and you fall back to serial, else you get efi on screen like you would on a "real" computer. For boards that have a display driver that isn't able to do the basic check of whether a cable is plugged in, just don't set "efiout" (or fix the display driver) ;-)
Quoted 4 lines
Are you sure that's what happens on a "real" computer? As far as I remember from all ARM servers running edk2 based firmware that I've touched so far, the default is always to display on serial *and* graphical output at the same time.
Well, I suppose some of the arm64 server vendors have done a better job than others on firmware.. you'd hope they would probe EDID, and report correct console dimensions based on display resolution, etc.
Quoted 8 lines
Doing both serial and display works for simple stuff, but it goes badly once the efi payload starts trying to change the cursor position and write to specific parts of the screen (which both Shell.efi and grub try to do).
BR,
-RHello Rob,
Quoted 8 lines
I do not know which program you use for connecting to your serial console. I
use minicom which is a Debian/Ubuntu package. I had no problem using grub,
vim, nano or any other console program.Minicom just provides a VT100 emulation and that is close enough to what Linux expects.
fwiw, I generally use kermit so my terminal emulator is whatever "xterm" type app I'm using. (Currently a big fan of Tilix).. but that isn't so much the issue..
Quoted 1 line
So I would not see what should be so special about Shell.efi.
I'm not explaining the problem well, but you can see basically the same issue if you resize your terminal emulator to something smaller than what grub/shell/etc think you are using.
I guess if they just fall back to assuming 80x25 like agraf mentioned, that would kind of work. It just means shell or grub will only use the tiny upper-left corner of your monitor.
Quoted 3 lines
My U-Boot system all have video but I never have a monitor connected.
So being able to use serial even if video is available is a necessity.
If the video driver doesn't detect that it is unconnected, someone should really fix that, otherwise you'll have problems booting an image where grub tries to use gfxterm if GOP is present (but we are really getting off topic here)
Quoted 6 lines
Either way, you still have the option of not setting efiout (or setting it to serial)
But for end users (at least of boards that I care about), if they plug in a monitor they should get grub on screen. Not everyone has a serial cable attached.
Quoted 4 lines
I fully agree there. The same applies the other way around too. Even if they have a monitor attached, they should get grub on serial if serial is a valid output :). Just attaching a monitor doesn't mean you only use that monitor to control the system.
We could, I suppose, try probing the serial console's size, as an approximation of hotplug detect for serial. If we timeout without getting a response, assume no serial console.
That would also let us pick the minimum of each dimension to report to the payload, which is less horrible than just having an 80x25 grub menu on your 4k screen. And if no serial attached, then we can use the full screen.
BR,
-R
PATCH 6/11 efi_loader: Decouple EFI input/output from stdin/stdout
Quoted 113 lines · Rob Clark
Quoted 104 lines · Alexander Graf
Quoted 103 lines · Rob Clark
Quoted 69 lines · Heinrich Schuchardt
Quoted 57 lines · Rob Clark
Quoted 47 lines · Alexander Graf
Quoted 25 lines · Rob Clark
Quoted 15 lines · Alexander Graf
Quoted 11 lines · Rob Clark
In some cases, it is quite useful to have (for example) EFI on screen
but u-boot on serial port.This adds two new optional environment variables, "efiin" and "efiout",
which can be used to set EFI console input/output independently of u-boot's input/output. If unset, EFI console will default to stdin/ stdout as before.Signed-off-by Rob Clark <[email protected]>Quoted 7 lines
With this patch, we lose the ability to have the efi in/out go to both
graphical and serial console, right? This is critical functionality to
have, since we don't necessarily know which output/input a user ends up
using.Quoted 2 lines
I'll think about how to support iomux.. but some things like console size are just not going to work properly there. And as long as we fix
Yeah, those probably would need to get special cased.
Quoted 6 lines
the stdout shenanigans (ie. what I was seeing w/ qemu-x86) you can simply not set efiout var and have things working as before, so you don't loose any existing functionality (although, like I said, if the two different consoles have different sizes things aren't going to work properly for anything other than simple cases).
Quoted 7 lines
In most cases, the display driver should be able to detect whether a display is connected.. this is what I've done on dragonboard410c, so if no display plugged in, 'efiout=vidconsole' fails and you fall back to serial, else you get efi on screen like you would on a "real" computer. For boards that have a display driver that isn't able to do the basic check of whether a cable is plugged in, just don't set "efiout" (or fix the display driver) ;-)
Quoted 4 lines
Are you sure that's what happens on a "real" computer? As far as I remember from all ARM servers running edk2 based firmware that I've touched so far, the default is always to display on serial *and* graphical output at the same time.
Well, I suppose some of the arm64 server vendors have done a better job than others on firmware.. you'd hope they would probe EDID, and report correct console dimensions based on display resolution, etc.
Quoted 8 lines
Doing both serial and display works for simple stuff, but it goes badly once the efi payload starts trying to change the cursor position and write to specific parts of the screen (which both Shell.efi and grub try to do).
BR,
-RHello Rob,
Quoted 8 lines
I do not know which program you use for connecting to your serial console. I
use minicom which is a Debian/Ubuntu package. I had no problem using grub,
vim, nano or any other console program.Minicom just provides a VT100 emulation and that is close enough to what Linux expects.
fwiw, I generally use kermit so my terminal emulator is whatever "xterm" type app I'm using. (Currently a big fan of Tilix).. but that isn't so much the issue..
Quoted 1 line
So I would not see what should be so special about Shell.efi.
I'm not explaining the problem well, but you can see basically the same issue if you resize your terminal emulator to something smaller than what grub/shell/etc think you are using.
I guess if they just fall back to assuming 80x25 like agraf mentioned, that would kind of work. It just means shell or grub will only use the tiny upper-left corner of your monitor.
Quoted 3 lines
My U-Boot system all have video but I never have a monitor connected.
So being able to use serial even if video is available is a necessity.
If the video driver doesn't detect that it is unconnected, someone should really fix that, otherwise you'll have problems booting an image where grub tries to use gfxterm if GOP is present (but we are really getting off topic here)
Either way, you still have the option of not setting efiout (or setting it to serial)
Quoted 8 lines
Quoted 3 lines
But for end users (at least of boards that I care about), if they plug in a monitor they should get grub on screen. Not everyone has a serial cable attached.
I fully agree there. The same applies the other way around too. Even if they have a monitor attached, they should get grub on serial if serial is a valid output :). Just attaching a monitor doesn't mean you only use that monitor to control the system.
Quoted 8 lines
We could, I suppose, try probing the serial console's size, as an approximation of hotplug detect for serial. If we timeout without getting a response, assume no serial console.
That would also let us pick the minimum of each dimension to report to the payload, which is less horrible than just having an 80x25 grub menu on your 4k screen. And if no serial attached, then we can use the full screen.
Now we're talking - that sounds much nicer indeed :)
Alex
PATCH 6/11 efi_loader: Decouple EFI input/output from stdin/stdout
In reply to Rob ClarkQuoted 128 lines
From: Rob Clark <[email protected]>
Date: Thu, 12 Oct 2017 10:28:43 -0400Quoted 124 lines · Alexander Graf
Quoted 121 lines · Rob Clark
Quoted 80 lines · Heinrich Schuchardt
Quoted 67 lines · Rob Clark
Quoted 55 lines · Alexander Graf
Quoted 30 lines · Rob Clark
Quoted 18 lines · Alexander Graf
Quoted 5 lines · Rob Clark
In some cases, it is quite useful to have (for example) EFI on screen
but u-boot on serial port.Quoted 7 lines
This adds two new optional environment variables, "efiin" and "efiout",
which can be used to set EFI console input/output independently of u-boot's input/output. If unset, EFI console will default to stdin/ stdout as before.Signed-off-by Rob Clark <[email protected]>Quoted 7 lines
With this patch, we lose the ability to have the efi in/out go to both
graphical and serial console, right? This is critical functionality to
have, since we don't necessarily know which output/input a user ends up
using.Quoted 2 lines
I'll think about how to support iomux.. but some things like console size are just not going to work properly there. And as long as we fix
Yeah, those probably would need to get special cased.
Quoted 6 lines
the stdout shenanigans (ie. what I was seeing w/ qemu-x86) you can simply not set efiout var and have things working as before, so you don't loose any existing functionality (although, like I said, if the two different consoles have different sizes things aren't going to work properly for anything other than simple cases).
Quoted 7 lines
In most cases, the display driver should be able to detect whether a display is connected.. this is what I've done on dragonboard410c, so if no display plugged in, 'efiout=vidconsole' fails and you fall back to serial, else you get efi on screen like you would on a "real" computer. For boards that have a display driver that isn't able to do the basic check of whether a cable is plugged in, just don't set "efiout" (or fix the display driver) ;-)
Quoted 4 lines
Are you sure that's what happens on a "real" computer? As far as I remember from all ARM servers running edk2 based firmware that I've touched so far, the default is always to display on serial *and* graphical output at the same time.
Well, I suppose some of the arm64 server vendors have done a better job than others on firmware.. you'd hope they would probe EDID, and report correct console dimensions based on display resolution, etc.
Quoted 8 lines
Doing both serial and display works for simple stuff, but it goes badly once the efi payload starts trying to change the cursor position and write to specific parts of the screen (which both Shell.efi and grub try to do).
BR,
-RHello Rob,
Quoted 8 lines
I do not know which program you use for connecting to your serial console. I
use minicom which is a Debian/Ubuntu package. I had no problem using grub,
vim, nano or any other console program.Minicom just provides a VT100 emulation and that is close enough to what Linux expects.
fwiw, I generally use kermit so my terminal emulator is whatever "xterm" type app I'm using. (Currently a big fan of Tilix).. but that isn't so much the issue..
Quoted 1 line
So I would not see what should be so special about Shell.efi.
I'm not explaining the problem well, but you can see basically the same issue if you resize your terminal emulator to something smaller than what grub/shell/etc think you are using.
I guess if they just fall back to assuming 80x25 like agraf mentioned, that would kind of work. It just means shell or grub will only use the tiny upper-left corner of your monitor.
Quoted 3 lines
My U-Boot system all have video but I never have a monitor connected.
So being able to use serial even if video is available is a necessity.
If the video driver doesn't detect that it is unconnected, someone should really fix that, otherwise you'll have problems booting an image where grub tries to use gfxterm if GOP is present (but we are really getting off topic here)
Either way, you still have the option of not setting efiout (or setting it to serial)
But for end users (at least of boards that I care about), if they plug in a monitor they should get grub on screen. Not everyone has a serial cable attached.
Quoted 8 lines
Quoted 4 lines
I fully agree there. The same applies the other way around too. Even if they have a monitor attached, they should get grub on serial if serial is a valid output :). Just attaching a monitor doesn't mean you only use that monitor to control the system.
We could, I suppose, try probing the serial console's size, as an approximation of hotplug detect for serial. If we timeout without getting a response, assume no serial console.
By spitting out random control characters and hope they match the terminal emulation on the other end? Sounds like a bad idea to me to do that by default.
Or would you only do it for EFI payload that uses more than just the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL? That might be acceptable.
PATCH 6/11 efi_loader: Decouple EFI input/output from stdin/stdout
Am 12.10.2017 um 18:00 schrieb Mark Kettenis <[email protected]>:
Quoted 133 lines
Quoted 133 lines
From: Rob Clark <[email protected]>
Date: Thu, 12 Oct 2017 10:28:43 -0400Quoted 129 lines · Alexander Graf
Quoted 116 lines · Rob Clark
Quoted 80 lines · Heinrich Schuchardt
Quoted 70 lines · Rob Clark
Quoted 57 lines · Alexander Graf
Quoted 34 lines · Rob Clark
Quoted 18 lines · Alexander Graf
Quoted 9 lines · Rob Clark
In some cases, it is quite useful to have (for example) EFI on screen
but u-boot on serial port.Quoted 7 lines
This adds two new optional environment variables, "efiin" and "efiout",
which can be used to set EFI console input/output independently of u-boot's input/output. If unset, EFI console will default to stdin/ stdout as before.Signed-off-by Rob Clark <[email protected]>Quoted 7 lines
With this patch, we lose the ability to have the efi in/out go to both
graphical and serial console, right? This is critical functionality to
have, since we don't necessarily know which output/input a user ends up
using.Quoted 2 lines
I'll think about how to support iomux.. but some things like console size are just not going to work properly there. And as long as we fix
Yeah, those probably would need to get special cased.
Quoted 6 lines
the stdout shenanigans (ie. what I was seeing w/ qemu-x86) you can simply not set efiout var and have things working as before, so you don't loose any existing functionality (although, like I said, if the two different consoles have different sizes things aren't going to work properly for anything other than simple cases).
Quoted 7 lines
In most cases, the display driver should be able to detect whether a display is connected.. this is what I've done on dragonboard410c, so if no display plugged in, 'efiout=vidconsole' fails and you fall back to serial, else you get efi on screen like you would on a "real" computer. For boards that have a display driver that isn't able to do the basic check of whether a cable is plugged in, just don't set "efiout" (or fix the display driver) ;-)
Quoted 4 lines
Are you sure that's what happens on a "real" computer? As far as I remember from all ARM servers running edk2 based firmware that I've touched so far, the default is always to display on serial *and* graphical output at the same time.
Well, I suppose some of the arm64 server vendors have done a better job than others on firmware.. you'd hope they would probe EDID, and report correct console dimensions based on display resolution, etc.
Quoted 8 lines
Doing both serial and display works for simple stuff, but it goes badly once the efi payload starts trying to change the cursor position and write to specific parts of the screen (which both Shell.efi and grub try to do).
BR,
-RHello Rob,
Quoted 8 lines
I do not know which program you use for connecting to your serial console. I
use minicom which is a Debian/Ubuntu package. I had no problem using grub,
vim, nano or any other console program.Minicom just provides a VT100 emulation and that is close enough to what Linux expects.
fwiw, I generally use kermit so my terminal emulator is whatever "xterm" type app I'm using. (Currently a big fan of Tilix).. but that isn't so much the issue..
Quoted 1 line
So I would not see what should be so special about Shell.efi.
I'm not explaining the problem well, but you can see basically the same issue if you resize your terminal emulator to something smaller than what grub/shell/etc think you are using.
I guess if they just fall back to assuming 80x25 like agraf mentioned, that would kind of work. It just means shell or grub will only use the tiny upper-left corner of your monitor.
Quoted 3 lines
My U-Boot system all have video but I never have a monitor connected.
So being able to use serial even if video is available is a necessity.
If the video driver doesn't detect that it is unconnected, someone should really fix that, otherwise you'll have problems booting an image where grub tries to use gfxterm if GOP is present (but we are really getting off topic here)
Quoted 6 lines
Either way, you still have the option of not setting efiout (or setting it to serial)
But for end users (at least of boards that I care about), if they plug in a monitor they should get grub on screen. Not everyone has a serial cable attached.
I fully agree there. The same applies the other way around too. Even if they have a monitor attached, they should get grub on serial if serial is a valid output :). Just attaching a monitor doesn't mean you only use that monitor to control the system.
Quoted 7 lines
Quoted 3 lines
We could, I suppose, try probing the serial console's size, as an approximation of hotplug detect for serial. If we timeout without getting a response, assume no serial console.
By spitting out random control characters and hope they match the terminal emulation on the other end? Sounds like a bad idea to me to do that by default.
We actually do exactly that today already :).
Quoted 3 lines
Or would you only do it for EFI payload that uses more than just the
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL? That might be acceptable.
Simply only to the first call that wants to know the screen size ;)
Alex
Quoted 2 lines
PATCH 6/11 efi_loader: Decouple EFI input/output from stdin/stdout
In reply to Rob ClarkQuoted 125 lines · Rob Clark
Quoted 124 lines · Alexander Graf
Quoted 121 lines · Rob Clark
Quoted 80 lines · Heinrich Schuchardt
Quoted 67 lines · Rob Clark
Quoted 55 lines · Alexander Graf
Quoted 30 lines · Rob Clark
Quoted 18 lines · Alexander Graf
Quoted 5 lines · Rob Clark
In some cases, it is quite useful to have (for example) EFI on screen
but u-boot on serial port.Quoted 7 lines
This adds two new optional environment variables, "efiin" and "efiout",
which can be used to set EFI console input/output independently of u-boot's input/output. If unset, EFI console will default to stdin/ stdout as before.Signed-off-by Rob Clark <[email protected]>Quoted 7 lines
With this patch, we lose the ability to have the efi in/out go to both
graphical and serial console, right? This is critical functionality to
have, since we don't necessarily know which output/input a user ends up
using.Quoted 2 lines
I'll think about how to support iomux.. but some things like console size are just not going to work properly there. And as long as we fix
Yeah, those probably would need to get special cased.
Quoted 6 lines
the stdout shenanigans (ie. what I was seeing w/ qemu-x86) you can simply not set efiout var and have things working as before, so you don't loose any existing functionality (although, like I said, if the two different consoles have different sizes things aren't going to work properly for anything other than simple cases).
Quoted 7 lines
In most cases, the display driver should be able to detect whether a display is connected.. this is what I've done on dragonboard410c, so if no display plugged in, 'efiout=vidconsole' fails and you fall back to serial, else you get efi on screen like you would on a "real" computer. For boards that have a display driver that isn't able to do the basic check of whether a cable is plugged in, just don't set "efiout" (or fix the display driver) ;-)
Quoted 4 lines
Are you sure that's what happens on a "real" computer? As far as I remember from all ARM servers running edk2 based firmware that I've touched so far, the default is always to display on serial *and* graphical output at the same time.
Well, I suppose some of the arm64 server vendors have done a better job than others on firmware.. you'd hope they would probe EDID, and report correct console dimensions based on display resolution, etc.
Quoted 8 lines
Doing both serial and display works for simple stuff, but it goes badly once the efi payload starts trying to change the cursor position and write to specific parts of the screen (which both Shell.efi and grub try to do).
BR,
-RHello Rob,
Quoted 8 lines
I do not know which program you use for connecting to your serial console. I
use minicom which is a Debian/Ubuntu package. I had no problem using grub,
vim, nano or any other console program.Minicom just provides a VT100 emulation and that is close enough to what Linux expects.
fwiw, I generally use kermit so my terminal emulator is whatever "xterm" type app I'm using. (Currently a big fan of Tilix).. but that isn't so much the issue..
Quoted 1 line
So I would not see what should be so special about Shell.efi.
I'm not explaining the problem well, but you can see basically the same issue if you resize your terminal emulator to something smaller than what grub/shell/etc think you are using.
I guess if they just fall back to assuming 80x25 like agraf mentioned, that would kind of work. It just means shell or grub will only use the tiny upper-left corner of your monitor.
Quoted 3 lines
My U-Boot system all have video but I never have a monitor connected.
So being able to use serial even if video is available is a necessity.
If the video driver doesn't detect that it is unconnected, someone should really fix that, otherwise you'll have problems booting an image where grub tries to use gfxterm if GOP is present (but we are really getting off topic here)
Either way, you still have the option of not setting efiout (or setting it to serial)
But for end users (at least of boards that I care about), if they plug in a monitor they should get grub on screen. Not everyone has a serial cable attached.
Quoted 8 lines
Quoted 4 lines
I fully agree there. The same applies the other way around too. Even if they have a monitor attached, they should get grub on serial if serial is a valid output :). Just attaching a monitor doesn't mean you only use that monitor to control the system.
We could, I suppose, try probing the serial console's size, as an approximation of hotplug detect for serial. If we timeout without getting a response, assume no serial console.
Your assumption is illegal:
If no terminal emulation is used don't expect any reply unless the user (or the control program at the other end of the line) is typing. Typically there is not even flow control on the serial connection.
Only if a terminal emulation is active you may be able to determine the console size by putting the cursor into the lower right corner. Then send ESC[6n. An ANSI terminal will respond by ESC[n;mR, where n is the row and m is the column.
Quoted 6 lines
That would also let us pick the minimum of each dimension to report to the payload, which is less horrible than just having an 80x25 grub menu on your 4k screen. And if no serial attached, then we can use the full screen.
A bit off-topic:
My horror is 4k resolution terminal mode with letters so small that you cannot read them without magnifying glasses. For grub 80x25 blown up to screen size is fully sufficient. I never had more than 5 lines to choose from.
Regards
Heinrich
PATCH 6/11 efi_loader: Decouple EFI input/output from stdin/stdout
Quoted 137 lines · Heinrich Schuchardt
Quoted 125 lines · Rob Clark
Quoted 124 lines · Alexander Graf
Quoted 121 lines · Rob Clark
Quoted 80 lines · Heinrich Schuchardt
Quoted 67 lines · Rob Clark
Quoted 55 lines · Alexander Graf
Quoted 30 lines · Rob Clark
Quoted 18 lines · Alexander Graf
Quoted 5 lines · Rob Clark
In some cases, it is quite useful to have (for example) EFI on screen
but u-boot on serial port.Quoted 7 lines
This adds two new optional environment variables, "efiin" and "efiout",
which can be used to set EFI console input/output independently of u-boot's input/output. If unset, EFI console will default to stdin/ stdout as before.Signed-off-by Rob Clark <[email protected]>Quoted 7 lines
With this patch, we lose the ability to have the efi in/out go to both
graphical and serial console, right? This is critical functionality to
have, since we don't necessarily know which output/input a user ends up
using.Quoted 2 lines
I'll think about how to support iomux.. but some things like console size are just not going to work properly there. And as long as we fix
Yeah, those probably would need to get special cased.
Quoted 6 lines
the stdout shenanigans (ie. what I was seeing w/ qemu-x86) you can simply not set efiout var and have things working as before, so you don't loose any existing functionality (although, like I said, if the two different consoles have different sizes things aren't going to work properly for anything other than simple cases).
Quoted 7 lines
In most cases, the display driver should be able to detect whether a display is connected.. this is what I've done on dragonboard410c, so if no display plugged in, 'efiout=vidconsole' fails and you fall back to serial, else you get efi on screen like you would on a "real" computer. For boards that have a display driver that isn't able to do the basic check of whether a cable is plugged in, just don't set "efiout" (or fix the display driver) ;-)
Quoted 4 lines
Are you sure that's what happens on a "real" computer? As far as I remember from all ARM servers running edk2 based firmware that I've touched so far, the default is always to display on serial *and* graphical output at the same time.
Well, I suppose some of the arm64 server vendors have done a better job than others on firmware.. you'd hope they would probe EDID, and report correct console dimensions based on display resolution, etc.
Quoted 8 lines
Doing both serial and display works for simple stuff, but it goes badly once the efi payload starts trying to change the cursor position and write to specific parts of the screen (which both Shell.efi and grub try to do).
BR,
-RHello Rob,
Quoted 8 lines
I do not know which program you use for connecting to your serial console. I
use minicom which is a Debian/Ubuntu package. I had no problem using grub,
vim, nano or any other console program.Minicom just provides a VT100 emulation and that is close enough to what Linux expects.
fwiw, I generally use kermit so my terminal emulator is whatever "xterm" type app I'm using. (Currently a big fan of Tilix).. but that isn't so much the issue..
Quoted 1 line
So I would not see what should be so special about Shell.efi.
I'm not explaining the problem well, but you can see basically the same issue if you resize your terminal emulator to something smaller than what grub/shell/etc think you are using.
I guess if they just fall back to assuming 80x25 like agraf mentioned, that would kind of work. It just means shell or grub will only use the tiny upper-left corner of your monitor.
Quoted 3 lines
My U-Boot system all have video but I never have a monitor connected.
So being able to use serial even if video is available is a necessity.
If the video driver doesn't detect that it is unconnected, someone should really fix that, otherwise you'll have problems booting an image where grub tries to use gfxterm if GOP is present (but we are really getting off topic here)
Either way, you still have the option of not setting efiout (or setting it to serial)
But for end users (at least of boards that I care about), if they plug in a monitor they should get grub on screen. Not everyone has a serial cable attached.
Quoted 8 lines
Quoted 4 lines
I fully agree there. The same applies the other way around too. Even if they have a monitor attached, they should get grub on serial if serial is a valid output :). Just attaching a monitor doesn't mean you only use that monitor to control the system.
We could, I suppose, try probing the serial console's size, as an approximation of hotplug detect for serial. If we timeout without getting a response, assume no serial console.
Your assumption is illegal:
Quoted 8 lines
If no terminal emulation is used don't expect any reply unless the user (or the control program at the other end of the line) is typing. Typically there is not even flow control on the serial connection.
Only if a terminal emulation is active you may be able to determine the console size by putting the cursor into the lower right corner. Then send ESC[6n. An ANSI terminal will respond by ESC[n;mR, where n is the row and m is the column.
I think I'm ok with the requirement of a terminal emulator, at least for sane default behavior.. things aren't really going to work without a terminal emulator anyways. You aren't going to be able to query the terminal size, and you are going to see a whole lot of jibberish when grub/shell/etc attempt to set the cursor position and set attributes.
We can make something like efiout=serial just force serial, term emulator or not. A sane default behavior doesn't have to be exclusive to catering to someone's crazy oddball setup. People with oddball setups can set an env var.
Quoted 8 lines
Quoted 7 lines
That would also let us pick the minimum of each dimension to report to the payload, which is less horrible than just having an 80x25 grub menu on your 4k screen. And if no serial attached, then we can use the full screen.
Quoted 5 lines
A bit off-topic:
My horror is 4k resolution terminal mode with letters so small that you cannot read them without magnifying glasses. For grub 80x25 blown up to screen size is fully sufficient. I never had more than 5 lines to choose from.
yeah, but scaling up isn't going to be what happens ;-)
and 80x25 is kinda sub-optimal when you need to edit a kernel cmdline
BR,
-R
PATCH 6/11 efi_loader: Decouple EFI input/output from stdin/stdout
Quoted 153 lines · Rob Clark
Quoted 137 lines · Heinrich Schuchardt
Quoted 125 lines · Rob Clark
Quoted 124 lines · Alexander Graf
Quoted 121 lines · Rob Clark
Quoted 80 lines · Heinrich Schuchardt
Quoted 67 lines · Rob Clark
Quoted 55 lines · Alexander Graf
Quoted 30 lines · Rob Clark
Quoted 18 lines · Alexander Graf
Quoted 5 lines · Rob Clark
In some cases, it is quite useful to have (for example) EFI on screen
but u-boot on serial port.Quoted 7 lines
This adds two new optional environment variables, "efiin" and "efiout",
which can be used to set EFI console input/output independently of u-boot's input/output. If unset, EFI console will default to stdin/ stdout as before.Signed-off-by Rob Clark <[email protected]>Quoted 7 lines
With this patch, we lose the ability to have the efi in/out go to both
graphical and serial console, right? This is critical functionality to
have, since we don't necessarily know which output/input a user ends up
using.Quoted 2 lines
I'll think about how to support iomux.. but some things like console size are just not going to work properly there. And as long as we fix
Yeah, those probably would need to get special cased.
Quoted 6 lines
the stdout shenanigans (ie. what I was seeing w/ qemu-x86) you can simply not set efiout var and have things working as before, so you don't loose any existing functionality (although, like I said, if the two different consoles have different sizes things aren't going to work properly for anything other than simple cases).
Quoted 7 lines
In most cases, the display driver should be able to detect whether a display is connected.. this is what I've done on dragonboard410c, so if no display plugged in, 'efiout=vidconsole' fails and you fall back to serial, else you get efi on screen like you would on a "real" computer. For boards that have a display driver that isn't able to do the basic check of whether a cable is plugged in, just don't set "efiout" (or fix the display driver) ;-)
Quoted 4 lines
Are you sure that's what happens on a "real" computer? As far as I remember from all ARM servers running edk2 based firmware that I've touched so far, the default is always to display on serial *and* graphical output at the same time.
Well, I suppose some of the arm64 server vendors have done a better job than others on firmware.. you'd hope they would probe EDID, and report correct console dimensions based on display resolution, etc.
Quoted 8 lines
Doing both serial and display works for simple stuff, but it goes badly once the efi payload starts trying to change the cursor position and write to specific parts of the screen (which both Shell.efi and grub try to do).
BR,
-RHello Rob,
Quoted 8 lines
I do not know which program you use for connecting to your serial console. I
use minicom which is a Debian/Ubuntu package. I had no problem using grub,
vim, nano or any other console program.Minicom just provides a VT100 emulation and that is close enough to what Linux expects.
fwiw, I generally use kermit so my terminal emulator is whatever "xterm" type app I'm using. (Currently a big fan of Tilix).. but that isn't so much the issue..
Quoted 1 line
So I would not see what should be so special about Shell.efi.
I'm not explaining the problem well, but you can see basically the same issue if you resize your terminal emulator to something smaller than what grub/shell/etc think you are using.
I guess if they just fall back to assuming 80x25 like agraf mentioned, that would kind of work. It just means shell or grub will only use the tiny upper-left corner of your monitor.
Quoted 3 lines
My U-Boot system all have video but I never have a monitor connected.
So being able to use serial even if video is available is a necessity.
If the video driver doesn't detect that it is unconnected, someone should really fix that, otherwise you'll have problems booting an image where grub tries to use gfxterm if GOP is present (but we are really getting off topic here)
Either way, you still have the option of not setting efiout (or setting it to serial)
But for end users (at least of boards that I care about), if they plug in a monitor they should get grub on screen. Not everyone has a serial cable attached.
Quoted 8 lines
Quoted 4 lines
I fully agree there. The same applies the other way around too. Even if they have a monitor attached, they should get grub on serial if serial is a valid output :). Just attaching a monitor doesn't mean you only use that monitor to control the system.
We could, I suppose, try probing the serial console's size, as an approximation of hotplug detect for serial. If we timeout without getting a response, assume no serial console.
Your assumption is illegal:
Quoted 8 lines
If no terminal emulation is used don't expect any reply unless the user (or the control program at the other end of the line) is typing. Typically there is not even flow control on the serial connection.
Only if a terminal emulation is active you may be able to determine the console size by putting the cursor into the lower right corner. Then send ESC[6n. An ANSI terminal will respond by ESC[n;mR, where n is the row and m is the column.
I think I'm ok with the requirement of a terminal emulator, at least for sane default behavior.. things aren't really going to work without a terminal emulator anyways. You aren't going to be able to query the terminal size, and you are going to see a whole lot of jibberish when grub/shell/etc attempt to set the cursor position and set attributes.
Quoted 5 lines
We can make something like efiout=serial just force serial, term emulator or not. A sane default behavior doesn't have to be exclusive to catering to someone's crazy oddball setup. People with oddball setups can set an env var.
I thought you were close to finishing off this patch series.
Is this patch essential?
Or could you simply resubmit the series without this patch and sort the questions about this patch out later?
Best regards
Heinrich
Quoted 21 lines
Quoted 8 lines
Quoted 7 lines
That would also let us pick the minimum of each dimension to report to the payload, which is less horrible than just having an 80x25 grub menu on your 4k screen. And if no serial attached, then we can use the full screen.
Quoted 5 lines
A bit off-topic:
My horror is 4k resolution terminal mode with letters so small that you cannot read them without magnifying glasses. For grub 80x25 blown up to screen size is fully sufficient. I never had more than 5 lines to choose from.yeah, but scaling up isn't going to be what happens ;-)
and 80x25 is kinda sub-optimal when you need to edit a kernel cmdline
BR,
-R
PATCH 6/11 efi_loader: Decouple EFI input/output from stdin/stdout
Quoted 160 lines · Heinrich Schuchardt
Quoted 153 lines · Rob Clark
Quoted 137 lines · Heinrich Schuchardt
Quoted 125 lines · Rob Clark
Quoted 124 lines · Alexander Graf
Quoted 121 lines · Rob Clark
Quoted 80 lines · Heinrich Schuchardt
Quoted 67 lines · Rob Clark
Quoted 55 lines · Alexander Graf
Quoted 30 lines · Rob Clark
Quoted 18 lines · Alexander Graf
Quoted 5 lines · Rob Clark
In some cases, it is quite useful to have (for example) EFI on screen
but u-boot on serial port.Quoted 7 lines
This adds two new optional environment variables, "efiin" and "efiout",
which can be used to set EFI console input/output independently of u-boot's input/output. If unset, EFI console will default to stdin/ stdout as before.Signed-off-by Rob Clark <[email protected]>Quoted 7 lines
With this patch, we lose the ability to have the efi in/out go to both
graphical and serial console, right? This is critical functionality to
have, since we don't necessarily know which output/input a user ends up
using.Quoted 2 lines
I'll think about how to support iomux.. but some things like console size are just not going to work properly there. And as long as we fix
Yeah, those probably would need to get special cased.
Quoted 6 lines
the stdout shenanigans (ie. what I was seeing w/ qemu-x86) you can simply not set efiout var and have things working as before, so you don't loose any existing functionality (although, like I said, if the two different consoles have different sizes things aren't going to work properly for anything other than simple cases).
Quoted 7 lines
In most cases, the display driver should be able to detect whether a display is connected.. this is what I've done on dragonboard410c, so if no display plugged in, 'efiout=vidconsole' fails and you fall back to serial, else you get efi on screen like you would on a "real" computer. For boards that have a display driver that isn't able to do the basic check of whether a cable is plugged in, just don't set "efiout" (or fix the display driver) ;-)
Quoted 4 lines
Are you sure that's what happens on a "real" computer? As far as I remember from all ARM servers running edk2 based firmware that I've touched so far, the default is always to display on serial *and* graphical output at the same time.
Well, I suppose some of the arm64 server vendors have done a better job than others on firmware.. you'd hope they would probe EDID, and report correct console dimensions based on display resolution, etc.
Quoted 8 lines
Doing both serial and display works for simple stuff, but it goes badly once the efi payload starts trying to change the cursor position and write to specific parts of the screen (which both Shell.efi and grub try to do).
BR,
-RHello Rob,
Quoted 8 lines
I do not know which program you use for connecting to your serial console. I
use minicom which is a Debian/Ubuntu package. I had no problem using grub,
vim, nano or any other console program.Minicom just provides a VT100 emulation and that is close enough to what Linux expects.
fwiw, I generally use kermit so my terminal emulator is whatever "xterm" type app I'm using. (Currently a big fan of Tilix).. but that isn't so much the issue..
Quoted 1 line
So I would not see what should be so special about Shell.efi.
I'm not explaining the problem well, but you can see basically the same issue if you resize your terminal emulator to something smaller than what grub/shell/etc think you are using.
I guess if they just fall back to assuming 80x25 like agraf mentioned, that would kind of work. It just means shell or grub will only use the tiny upper-left corner of your monitor.
Quoted 3 lines
My U-Boot system all have video but I never have a monitor connected.
So being able to use serial even if video is available is a necessity.
If the video driver doesn't detect that it is unconnected, someone should really fix that, otherwise you'll have problems booting an image where grub tries to use gfxterm if GOP is present (but we are really getting off topic here)
Either way, you still have the option of not setting efiout (or setting it to serial)
But for end users (at least of boards that I care about), if they plug in a monitor they should get grub on screen. Not everyone has a serial cable attached.
Quoted 8 lines
Quoted 4 lines
I fully agree there. The same applies the other way around too. Even if they have a monitor attached, they should get grub on serial if serial is a valid output :). Just attaching a monitor doesn't mean you only use that monitor to control the system.
We could, I suppose, try probing the serial console's size, as an approximation of hotplug detect for serial. If we timeout without getting a response, assume no serial console.
Your assumption is illegal:
Quoted 8 lines
If no terminal emulation is used don't expect any reply unless the user (or the control program at the other end of the line) is typing. Typically there is not even flow control on the serial connection.
Only if a terminal emulation is active you may be able to determine the console size by putting the cursor into the lower right corner. Then send ESC[6n. An ANSI terminal will respond by ESC[n;mR, where n is the row and m is the column.
I think I'm ok with the requirement of a terminal emulator, at least for sane default behavior.. things aren't really going to work without a terminal emulator anyways. You aren't going to be able to query the terminal size, and you are going to see a whole lot of jibberish when grub/shell/etc attempt to set the cursor position and set attributes.
Quoted 5 lines
We can make something like efiout=serial just force serial, term emulator or not. A sane default behavior doesn't have to be exclusive to catering to someone's crazy oddball setup. People with oddball setups can set an env var.
Quoted 7 lines
I thought you were close to finishing off this patch series.
Is this patch essential?
Or could you simply resubmit the series without this patch and sort the questions about this patch out later?
I talked to agraf on IRC.. there were a couple patches that I suggested to pull in asap for 2017.11.. the rest of the new proto's/etc for Shell.efi, including this, aren't really immediately useful for end users, so I suggested a separate efi-next-for-2018.1 (?) which we can start to pull these patches into, as well as other things you are working on, to better coordinate our work on further UEFI features independently of fixes destined for 2017.11. At this point, the new protocol stuff I mostly wanted to get into *some* branch so we aren't stepping on each other's toes.
For this particular patch, IMHO the main prerequisite is to fix u-boot's output layer so puts() == fputs(stdout), which I'm not quite yet sure how to do. Once that is done, this patch changes *no* behaviour if you don't set efiout/efiin variables, so there should be no controversy. Although I do like the idea of expanding this to (at least for default behavior, not preventing anyone to override it for special cases) to try to detect if a serial console is attached.. that would let us improve the default behavior to cater to both u-boot dev's who like their serial ports and end users (who are the real target audience) in a more sane way..
BR,
-R
PATCH 6/11 efi_loader: Decouple EFI input/output from stdin/stdout
In reply to Rob ClarkQuoted 36 lines · Rob Clark
Quoted 35 lines · Alexander Graf
Quoted 11 lines · Rob Clark
Quoted 10 lines · Alexander Graf
Quoted 8 lines · Rob Clark
In some cases, it is quite useful to have (for example) EFI on screen but u-boot on serial port.
This adds two new optional environment variables, "efiin" and "efiout", which can be used to set EFI console input/output independently of u-boot's input/output. If unset, EFI console will default to stdin/ stdout as before.
Quoted 7 lines
Quoted 5 lines
Quoted 1 line
Signed-off-by Rob Clark <[email protected]>With this patch, we lose the ability to have the efi in/out go to both graphical and serial console, right? This is critical functionality to have, since we don't necessarily know which output/input a user ends up using.
I'll think about how to support iomux.. but some things like console size are just not going to work properly there. And as long as we fix
Yeah, those probably would need to get special cased.
Quoted 13 lines
the stdout shenanigans (ie. what I was seeing w/ qemu-x86) you can simply not set efiout var and have things working as before, so you don't loose any existing functionality (although, like I said, if the two different consoles have different sizes things aren't going to work properly for anything other than simple cases).
In most cases, the display driver should be able to detect whether a display is connected.. this is what I've done on dragonboard410c, so if no display plugged in, 'efiout=vidconsole' fails and you fall back to serial, else you get efi on screen like you would on a "real" computer. For boards that have a display driver that isn't able to do the basic check of whether a cable is plugged in, just don't set "efiout" (or fix the display driver) ;-)
Quoted 7 lines
Quoted 4 lines
Are you sure that's what happens on a "real" computer? As far as I remember from all ARM servers running edk2 based firmware that I've touched so far, the default is always to display on serial *and* graphical output at the same time.
Well, I suppose some of the arm64 server vendors have done a better job than others on firmware.. you'd hope they would probe EDID, and report correct console dimensions based on display resolution, etc.
Not sure that's terribly helpful. Most of these servers have built-in BMC chips that just go to a fake video console, so they always get EDID information, but that doesn't mean that it's sensible for what the user ends up seeing.
I think what happens is that in most cases they just assume you have a 80x25 console :).
Quoted 4 lines
Doing both serial and display works for simple stuff, but it goes badly once the efi payload starts trying to change the cursor position and write to specific parts of the screen (which both Shell.efi and grub try to do).
Yes, and on basically all arm servers what you see happening is that grub gets squeezed into 80x25 for the text output. For graphical output, at least SUSE usually just defaults to gfxterm which directly drives GOP.
Alex
PATCH 6/11 efi_loader: Decouple EFI input/output from stdin/stdout
Quoted 57 lines · Alexander Graf
Quoted 46 lines · Rob Clark
Quoted 44 lines · Alexander Graf
Quoted 17 lines · Rob Clark
Quoted 15 lines · Alexander Graf
Quoted 11 lines · Rob Clark
In some cases, it is quite useful to have (for example) EFI on screen but u-boot on serial port.
This adds two new optional environment variables, "efiin" and "efiout",
which can be used to set EFI console input/output independently of u-boot's input/output. If unset, EFI console will default to stdin/ stdout as before.Signed-off-by Rob Clark <[email protected]>Quoted 7 lines
Quoted 4 lines
With this patch, we lose the ability to have the efi in/out go to both graphical and serial console, right? This is critical functionality to have, since we don't necessarily know which output/input a user ends up using.
I'll think about how to support iomux.. but some things like console size are just not going to work properly there. And as long as we fix
Yeah, those probably would need to get special cased.
Quoted 13 lines
the stdout shenanigans (ie. what I was seeing w/ qemu-x86) you can simply not set efiout var and have things working as before, so you don't loose any existing functionality (although, like I said, if the two different consoles have different sizes things aren't going to work properly for anything other than simple cases).
In most cases, the display driver should be able to detect whether a display is connected.. this is what I've done on dragonboard410c, so if no display plugged in, 'efiout=vidconsole' fails and you fall back to serial, else you get efi on screen like you would on a "real" computer. For boards that have a display driver that isn't able to do the basic check of whether a cable is plugged in, just don't set "efiout" (or fix the display driver) ;-)
Quoted 8 lines
Quoted 4 lines
Are you sure that's what happens on a "real" computer? As far as I remember from all ARM servers running edk2 based firmware that I've touched so far, the default is always to display on serial *and* graphical output at the same time.
Well, I suppose some of the arm64 server vendors have done a better job than others on firmware.. you'd hope they would probe EDID, and report correct console dimensions based on display resolution, etc.
Quoted 7 lines
Not sure that's terribly helpful. Most of these servers have built-in BMC chips that just go to a fake video console, so they always get EDID information, but that doesn't mean that it's sensible for what the user ends up seeing.
I think what happens is that in most cases they just assume you have a 80x25 console :).
oh, right.. BMC's.. well, let's not strive to be as horrible as enterprise hardware ;-)
BR,
-R
PATCH 6/11 efi_loader: Decouple EFI input/output from stdin/stdout
In reply to Rob ClarkQuoted 25 lines
From: Rob Clark <[email protected]>
Date: Thu, 12 Oct 2017 08:48:39 -0400Quoted 21 lines · Alexander Graf
Quoted 18 lines · Rob Clark
Quoted 17 lines · Alexander Graf
Quoted 9 lines · Rob Clark
In some cases, it is quite useful to have (for example) EFI on screen but u-boot on serial port.
This adds two new optional environment variables, "efiin" and "efiout", which can be used to set EFI console input/output independently of u-boot's input/output. If unset, EFI console will default to stdin/ stdout as before.
Signed-off-by Rob Clark <[email protected]>With this patch, we lose the ability to have the efi in/out go to both graphical and serial console, right? This is critical functionality to have, since we don't necessarily know which output/input a user ends up using.
Seconded. In many cases I'd want to continue using serial as the console even if a display is connected.
Quoted 11 lines
Quoted 11 lines
Quoted 2 lines
I'll think about how to support iomux.. but some things like console size are just not going to work properly there. And as long as we fix
Yeah, those probably would need to get special cased.
Quoted 6 lines
the stdout shenanigans (ie. what I was seeing w/ qemu-x86) you can simply not set efiout var and have things working as before, so you don't loose any existing functionality (although, like I said, if the two different consoles have different sizes things aren't going to work properly for anything other than simple cases).
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
In most cases, the display driver should be able to detect whether a display is connected.. this is what I've done on dragonboard410c, so if no display plugged in, 'efiout=vidconsole' fails and you fall back to serial, else you get efi on screen like you would on a "real" computer. For boards that have a display driver that isn't able to do the basic check of whether a cable is plugged in, just don't set "efiout" (or fix the display driver) ;-)
Display detection will always be somewhat fragile. The old Sun workstations used to base the decision on whether a keyboard was connected. With no keyboard detected the output would always go to serial.
Quoted 5 lines
Quoted 4 lines
Are you sure that's what happens on a "real" computer? As far as I remember from all ARM servers running edk2 based firmware that I've touched so far, the default is always to display on serial *and* graphical output at the same time.
Quoted 8 lines
Well, I suppose some of the arm64 server vendors have done a better job than others on firmware.. you'd hope they would probe EDID, and report correct console dimensions based on display resolution, etc.
Doing both serial and display works for simple stuff, but it goes badly once the efi payload starts trying to change the cursor position and write to specific parts of the screen (which both Shell.efi and grub try to do).
From my point of view a bootloader should only do "simple stuff". All this fancy display stuff makes a serial console much harder to use.
PATCH 6/11 efi_loader: Decouple EFI input/output from stdin/stdout
Quoted 21 lines · Mark Kettenis
Quoted 21 lines
From: Rob Clark <[email protected]>
Date: Thu, 12 Oct 2017 08:48:39 -0400Quoted 17 lines · Alexander Graf
Quoted 14 lines · Rob Clark
Quoted 13 lines · Alexander Graf
Quoted 9 lines · Rob Clark
In some cases, it is quite useful to have (for example) EFI on screen but u-boot on serial port.
This adds two new optional environment variables, "efiin" and "efiout", which can be used to set EFI console input/output independently of u-boot's input/output. If unset, EFI console will default to stdin/ stdout as before.
Signed-off-by Rob Clark <[email protected]>
Quoted 7 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
With this patch, we lose the ability to have the efi in/out go to both graphical and serial console, right? This is critical functionality to have, since we don't necessarily know which output/input a user ends up using.
Seconded. In many cases I'd want to continue using serial as the console even if a display is connected.
Sure, and this patch isn't preventing that.
Quoted 19 lines
Quoted 11 lines
Quoted 11 lines
Quoted 2 lines
I'll think about how to support iomux.. but some things like console size are just not going to work properly there. And as long as we fix
Yeah, those probably would need to get special cased.
Quoted 6 lines
the stdout shenanigans (ie. what I was seeing w/ qemu-x86) you can simply not set efiout var and have things working as before, so you don't loose any existing functionality (although, like I said, if the two different consoles have different sizes things aren't going to work properly for anything other than simple cases).
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
In most cases, the display driver should be able to detect whether a display is connected.. this is what I've done on dragonboard410c, so if no display plugged in, 'efiout=vidconsole' fails and you fall back to serial, else you get efi on screen like you would on a "real" computer. For boards that have a display driver that isn't able to do the basic check of whether a cable is plugged in, just don't set "efiout" (or fix the display driver) ;-)
Quoted 4 lines
Display detection will always be somewhat fragile. The old Sun workstations used to base the decision on whether a keyboard was connected. With no keyboard detected the output would always go to serial.
s/always/sometimes/
For analog outputs it can be more tricky. For any display technology from this century, it isn't really that hard.
Boards that cannot reliably detect whether a display is connected probably don't want to set efiout.
Quoted 9 lines
Quoted 9 lines
Quoted 4 lines
Are you sure that's what happens on a "real" computer? As far as I remember from all ARM servers running edk2 based firmware that I've touched so far, the default is always to display on serial *and* graphical output at the same time.
Well, I suppose some of the arm64 server vendors have done a better job than others on firmware.. you'd hope they would probe EDID, and report correct console dimensions based on display resolution, etc.
Quoted 7 lines
Quoted 4 lines
Doing both serial and display works for simple stuff, but it goes badly once the efi payload starts trying to change the cursor position and write to specific parts of the screen (which both Shell.efi and grub try to do).
From my point of view a bootloader should only do "simple stuff". All this fancy display stuff makes a serial console much harder to use.
Sure, but people who tinker with u-boot and low level stuff aren't the only target audience here.
This patch provides a (completely optional) way to provide a sane default that doesn't require a serial cable, yet still works with one if you don't have a display connected.. some people expect to be able to just plug in display + keyboard + power and get to a grub boot menu, just like you would on an x86/uefi system.
BR,
-R
PATCH 7/11 efi_loader: fix events
In reply to Rob ClarkAn event can be created with type==0, Shell.efi does this for an event that is set when Ctrl-C is typed. So our current approach of having a fixed set of timer slots, and determining which slots are unused by type==0 doesn't work so well. But we don't have any particularly good reason to have a fixed table of events, so just dynamically allocate them and keep a list.
Also fixes an incorrect implementation of CheckEvent() which was (a) incorrectly returning an error if type==0, and (b) didn't handle the case of an unsignaled event with a notify callback.
With these fixes (plus implementation of SIMPLE_TEXT_INPUT_EX protocol), Ctrl-C works in Shell.efi.
--- include/efi_loader.h | 1 + lib/efi_loader/efi_boottime.c | 217 +++++++++++++++++++++--------------------- 2 files changed, 111 insertions(+), 107 deletions(-)
include/efi_loader.h +1 -0
@@ -154,6 +154,7 @@ struct efi_event {enum efi_timer_delay trigger_type;bool is_queued;bool is_signaled; +struct list_head link; };
lib/efi_loader/efi_boottime.c +110 -107
317 lines not on this page · raw message
Signature · 1 line
2.13.6
PATCH 7/11 efi_loader: fix events
Quoted 356 lines · Rob Clark
An event can be created with type==0, Shell.efi does this for an event that is set when Ctrl-C is typed. So our current approach of having a fixed set of timer slots, and determining which slots are unused by type==0 doesn't work so well. But we don't have any particularly good reason to have a fixed table of events, so just dynamically allocate them and keep a list.
Also fixes an incorrect implementation of
CheckEvent()which was (a) incorrectly returning an error if type==0, and (b) didn't handle the case of an unsignaled event with a notify callback.With these fixes (plus implementation of
SIMPLE_TEXT_INPUT_EXprotocol), Ctrl-C works in Shell.efi.Signed-off-by Rob Clark <[email protected]>--- include/efi_loader.h | 1 + lib/efi_loader/efi_boottime.c | 217 +++++++++++++++++++++--------------------- 2 files changed, 111 insertions(+), 107 deletions(-)include/efi_loader.h +1
-0@@ -154,6 +154,7 @@ struct efi_event {enum efi_timer_delay trigger_type;bool is_queued;bool is_signaled; +struct list_head link; };lib/efi_loader/efi_boottime.c +107
-104@@ -350,11 +350,26 @@ static efi_status_t efi_create_handle(void **handle)return r; } +static LIST_HEAD (efi_events); +/* -* Our event capabilities are very limited. Only a small limited -* number of events is allowed to coexist. +* Check if a pointer is a valid event. +* +* It might be nice at some point to extend this to a more general +* mechanism to check if pointers passed from the EFI world are +* valid objects of a particular type. */ -static struct efi_event efi_events[16 ]; +static bool efi_is_event (const void *obj) +{ +struct efi_event *evt; + +list_for_each_entry (evt, &efi_events, link) { +if (evt == obj) +return true; + } + +return false; +}/* * Create an event. @@ -377,7 +392,7 @@ efi_status_t efi_create_event(uint32_t type, UINTN notify_tpl, void *context), void *notify_context, struct efi_event **event) { - int i; + struct efi_event *evt;if (event ==NULL )return EFI_INVALID_PARAMETER ;@@ -389,21 +404,24 @@ efi_status_t efi_create_event(uint32_t type, UINTN notify_tpl, notify_function == NULL)return EFI_INVALID_PARAMETER ; -for (i =0 ; i <ARRAY_SIZE (efi_events); ++i) { -if (efi_events[i].type) -continue ; - efi_events[i].type = type; - efi_events[i].notify_tpl = notify_tpl; - efi_events[i].notify_function = notify_function; - efi_events[i].notify_context = notify_context; -/* Disable timers on bootup */ - efi_events[i].trigger_next =-1ULL ; - efi_events[i].is_queued = false; - efi_events[i].is_signaled = false; - *event = &efi_events[i]; -return EFI_SUCCESS ; - } -return EFI_OUT_OF_RESOURCES ; + evt =calloc (1 ,sizeof (*evt)); +if (!evt) +return EFI_OUT_OF_RESOURCES ; + + evt->type = type; + evt->notify_tpl = notify_tpl; + evt->notify_function = notify_function; + evt->notify_context = notify_context; +/* Disable timers on bootup */ + evt->trigger_next =-1ULL ; + evt->is_queued = false; + evt->is_signaled = false; + +list_add_tail (&evt->link, &efi_events); + + *event = evt; + +return EFI_SUCCESS ; }/* @@ -443,30 +461,31 @@ static efi_status_t EFIAPI efi_create_event_ext(*/ void efi_timer_check (void ) { -int i; +struct efi_event *evt;u64 now =timer_get_us (); -for (i =0 ; i <ARRAY_SIZE (efi_events); ++i) { -if (!efi_events[i].type) -continue ; -if (efi_events[i].is_queued) -efi_signal_event (&efi_events[i]); -if (!(efi_events[i].type &EVT_TIMER ) || - now < efi_events[i].trigger_next) +/* +* TODO perhaps optimize a bit and track the time of next +* timer to expire? +*/ +list_for_each_entry (evt, &efi_events, link) { +if (evt->is_queued) +efi_signal_event (evt); +if (!(evt->type &EVT_TIMER ) || + now < evt->trigger_next)continue ; -switch (efi_events[i].trigger_type) { +switch (evt->trigger_type) {case EFI_TIMER_RELATIVE : - efi_events[i].trigger_type =EFI_TIMER_STOP ; + evt->trigger_type =EFI_TIMER_STOP ;break ;case EFI_TIMER_PERIODIC : - efi_events[i].trigger_next += - efi_events[i].trigger_time; + evt->trigger_next += evt->trigger_time;break ;default :continue ; } - efi_events[i].is_signaled = true; -efi_signal_event (&efi_events[i]); + evt->is_signaled = true; +efi_signal_event (evt); }WATCHDOG_RESET (); }@@ -485,7 +504,8 @@ void efi_timer_check(void)efi_status_t efi_set_timer (struct efi_event *event,enum efi_timer_delay type,uint64_t trigger_time) { -int i; +if (!efi_is_event (event)) +return EFI_INVALID_PARAMETER ;/* * The parameter defines a multiple of 100ns. @@ -493,30 +513,25 @@ efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type,*/ do_div (trigger_time,10 ); -for (i =0 ; i <ARRAY_SIZE (efi_events); ++i) { -if (event != &efi_events[i]) -continue ; +if (!(event->type &EVT_TIMER )) +return EFI_INVALID_PARAMETER ; -if (!(event->type &EVT_TIMER )) -break ; -switch (type) { -case EFI_TIMER_STOP : - event->trigger_next =-1ULL ; -break ; -case EFI_TIMER_PERIODIC : -case EFI_TIMER_RELATIVE : - event->trigger_next = -timer_get_us () + trigger_time; -break ; -default : -return EFI_INVALID_PARAMETER ; - } - event->trigger_type = type; - event->trigger_time = trigger_time; - event->is_signaled = false; -return EFI_SUCCESS ; +switch (type) { +case EFI_TIMER_STOP : + event->trigger_next =-1ULL ; +break ; +case EFI_TIMER_PERIODIC : +case EFI_TIMER_RELATIVE : + event->trigger_next =timer_get_us () + trigger_time; +break ; +default : +return EFI_INVALID_PARAMETER ; } -return EFI_INVALID_PARAMETER ; + event->trigger_type = type; + event->trigger_time = trigger_time; + event->is_signaled = false; + +return EFI_SUCCESS ; }/* @@ -555,7 +570,7 @@ static efi_status_t EFIAPI efi_wait_for_event(unsigned long num_events,struct efi_event **event, size_t *index) { - int i, j; + int i;EFI_ENTRY ("%ld, %p, %p" , num_events, event, index);@@ -566,12 +581,8 @@ static efi_status_t EFIAPI efi_wait_for_event(unsigned long num_events,if (efi_tpl !=TPL_APPLICATION )return EFI_EXIT (EFI_UNSUPPORTED );for (i =0 ; i < num_events; ++i) { -for (j =0 ; j <ARRAY_SIZE (efi_events); ++j) { -if (event[i] == &efi_events[j]) - goto known_event; - } -return EFI_EXIT (EFI_INVALID_PARAMETER ); -known_event: +if (!efi_is_event (event[i])) +return EFI_EXIT (EFI_INVALID_PARAMETER );if (!event[i]->type || event[i]->type &EVT_NOTIFY_SIGNAL )return EFI_EXIT (EFI_INVALID_PARAMETER );if (!event[i]->is_signaled)@@ -614,19 +625,12 @@ out:*/ static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event) { -int i; -EFI_ENTRY ("%p" , event); -for (i =0 ; i <ARRAY_SIZE (efi_events); ++i) { -if (event != &efi_events[i]) -continue ; -if (event->is_signaled) -break ; - event->is_signaled = true; -if (event->type &EVT_NOTIFY_SIGNAL ) -efi_signal_event (event); -break ; - } +if (!efi_is_event (event)) +return EFI_EXIT (EFI_INVALID_PARAMETER ); + event->is_signaled = true; +if (event->type &EVT_NOTIFY_SIGNAL ) +efi_signal_event (event);return EFI_EXIT (EFI_SUCCESS ); }@@ -642,19 +646,10 @@ static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event)*/ static efi_status_t EFIAPI efi_close_event(struct efi_event *event) { -int i; -EFI_ENTRY ("%p" , event); -for (i =0 ; i <ARRAY_SIZE (efi_events); ++i) { -if (event == &efi_events[i]) { - event->type =0 ; - event->trigger_next =-1ULL ; - event->is_queued = false; - event->is_signaled = false; -return EFI_EXIT (EFI_SUCCESS ); - } - } -return EFI_EXIT (EFI_INVALID_PARAMETER ); +list_del (&event->link); +free (event); +return EFI_EXIT (EFI_SUCCESS ); }/* @@ -664,29 +659,37 @@ static efi_status_t EFIAPI efi_close_event(struct efi_event *event)* See the Unified Extensible Firmware Interface (UEFI) specification * for details. * -* If an event is not signaled yet the notification function is queued. +* - If Event is in the signaled state, it is cleared and EFI_SUCCESS +* is returned. +* +* - If Event is not in the signaled state and has no notification +* function, EFI_NOT_READY is returned. +* +* - If Event is not in the signaled state but does have a notification +* function, the notification function is queued at the event’s +* notification task priority level. If the execution of the +* notification function causes Event to be signaled, then the signaled +* state is cleared and EFI_SUCCESS is returned; if the Event is not +* signaled, then EFI_NOT_READY is returned. * * @event event to check * @return status code */ -static efi_status_t EFIAPI efi_check_event(struct efi_event *event) +/* +*/ +static efi_status_t EFIAPI efi_check_event(struct efi_event *evt) { -int i; - -EFI_ENTRY ("%p" , event); +EFI_ENTRY ("%p" , evt);efi_timer_check (); -for (i =0 ; i <ARRAY_SIZE (efi_events); ++i) { -if (event != &efi_events[i]) -continue ; -if (!event->type || event->type &EVT_NOTIFY_SIGNAL ) -break ; -if (!event->is_signaled) -efi_signal_event (event); -if (event->is_signaled) -return EFI_EXIT (EFI_SUCCESS ); -return EFI_EXIT (EFI_NOT_READY ); +if (!efi_is_event (evt) || (evt->type &EVT_NOTIFY_SIGNAL )) +return EFI_EXIT (EFI_INVALID_PARAMETER ); +if (!evt->is_signaled && evt->notify_function) +EFI_CALL_VOID (evt->notify_function (evt, evt->notify_context)); +if (evt->is_signaled) { + evt->is_signaled = true; +return EFI_EXIT (EFI_SUCCESS ); } -return EFI_EXIT (EFI_INVALID_PARAMETER ); +return EFI_EXIT (EFI_NOT_READY ); }/* @@ -1440,15 +1443,15 @@ static void efi_exit_caches(void) static efi_status_t EFIAPI efi_exit_boot_services(void *image_handle,unsigned long map_key) { -int i; +struct efi_event *evt;EFI_ENTRY ("%p, %ld" , image_handle, map_key);/* Notify that ExitBootServices is invoked. */
lib/efi_loader/efi_boottime.c static void efi_exit_caches(void) · line 1457
Quoted 10 lines
lib/efi_loader/efi_boottime.c +3
-3-for (i =0 ; i <ARRAY_SIZE (efi_events); ++i) { -if (efi_events[i].type !=EVT_SIGNAL_EXIT_BOOT_SERVICES ) +list_for_each_entry (evt, &efi_events, link) { +if (evt->type !=EVT_SIGNAL_EXIT_BOOT_SERVICES )continue ; -efi_signal_event (&efi_events[i]); +efi_signal_event (evt); }/* Make sure that notification functions are not called anymore */ efi_tpl =TPL_HIGH_LEVEL ;
Thanks for adding efi_is_event().
PATCH 7/11 efi_loader: fix events
In reply to Rob ClarkQuoted 305 lines · Rob Clark
An event can be created with type==0, Shell.efi does this for an event that is set when Ctrl-C is typed. So our current approach of having a fixed set of timer slots, and determining which slots are unused by type==0 doesn't work so well. But we don't have any particularly good reason to have a fixed table of events, so just dynamically allocate them and keep a list.
Also fixes an incorrect implementation of
CheckEvent()which was (a) incorrectly returning an error if type==0, and (b) didn't handle the case of an unsignaled event with a notify callback.With these fixes (plus implementation of
SIMPLE_TEXT_INPUT_EXprotocol), Ctrl-C works in Shell.efi.Signed-off-by Rob Clark <[email protected]>--- include/efi_loader.h | 1 + lib/efi_loader/efi_boottime.c | 217 +++++++++++++++++++++--------------------- 2 files changed, 111 insertions(+), 107 deletions(-)include/efi_loader.h +1
-0@@ -154,6 +154,7 @@ struct efi_event {enum efi_timer_delay trigger_type;bool is_queued;bool is_signaled; +struct list_head link; };lib/efi_loader/efi_boottime.c +91
-88@@ -350,11 +350,26 @@ static efi_status_t efi_create_handle(void **handle)return r; } +static LIST_HEAD (efi_events); +/* -* Our event capabilities are very limited. Only a small limited -* number of events is allowed to coexist. +* Check if a pointer is a valid event. +* +* It might be nice at some point to extend this to a more general +* mechanism to check if pointers passed from the EFI world are +* valid objects of a particular type. */ -static struct efi_event efi_events[16 ]; +static bool efi_is_event (const void *obj) +{ +struct efi_event *evt; + +list_for_each_entry (evt, &efi_events, link) { +if (evt == obj) +return true; + } + +return false; +}/* * Create an event. @@ -377,7 +392,7 @@ efi_status_t efi_create_event(uint32_t type, UINTN notify_tpl, void *context), void *notify_context, struct efi_event **event) { - int i; + struct efi_event *evt;if (event ==NULL )return EFI_INVALID_PARAMETER ;@@ -389,21 +404,24 @@ efi_status_t efi_create_event(uint32_t type, UINTN notify_tpl, notify_function == NULL)return EFI_INVALID_PARAMETER ; -for (i =0 ; i <ARRAY_SIZE (efi_events); ++i) { -if (efi_events[i].type) -continue ; - efi_events[i].type = type; - efi_events[i].notify_tpl = notify_tpl; - efi_events[i].notify_function = notify_function; - efi_events[i].notify_context = notify_context; -/* Disable timers on bootup */ - efi_events[i].trigger_next =-1ULL ; - efi_events[i].is_queued = false; - efi_events[i].is_signaled = false; - *event = &efi_events[i]; -return EFI_SUCCESS ; - } -return EFI_OUT_OF_RESOURCES ; + evt =calloc (1 ,sizeof (*evt)); +if (!evt) +return EFI_OUT_OF_RESOURCES ; + + evt->type = type; + evt->notify_tpl = notify_tpl; + evt->notify_function = notify_function; + evt->notify_context = notify_context; +/* Disable timers on bootup */ + evt->trigger_next =-1ULL ; + evt->is_queued = false; + evt->is_signaled = false; + +list_add_tail (&evt->link, &efi_events); + + *event = evt; + +return EFI_SUCCESS ; }/* @@ -443,30 +461,31 @@ static efi_status_t EFIAPI efi_create_event_ext(*/ void efi_timer_check (void ) { -int i; +struct efi_event *evt;u64 now =timer_get_us (); -for (i =0 ; i <ARRAY_SIZE (efi_events); ++i) { -if (!efi_events[i].type) -continue ; -if (efi_events[i].is_queued) -efi_signal_event (&efi_events[i]); -if (!(efi_events[i].type &EVT_TIMER ) || - now < efi_events[i].trigger_next) +/* +* TODO perhaps optimize a bit and track the time of next +* timer to expire? +*/ +list_for_each_entry (evt, &efi_events, link) { +if (evt->is_queued) +efi_signal_event (evt); +if (!(evt->type &EVT_TIMER ) || + now < evt->trigger_next)continue ; -switch (efi_events[i].trigger_type) { +switch (evt->trigger_type) {case EFI_TIMER_RELATIVE : - efi_events[i].trigger_type =EFI_TIMER_STOP ; + evt->trigger_type =EFI_TIMER_STOP ;break ;case EFI_TIMER_PERIODIC : - efi_events[i].trigger_next += - efi_events[i].trigger_time; + evt->trigger_next += evt->trigger_time;break ;default :continue ; } - efi_events[i].is_signaled = true; -efi_signal_event (&efi_events[i]); + evt->is_signaled = true; +efi_signal_event (evt); }WATCHDOG_RESET (); }@@ -485,7 +504,8 @@ void efi_timer_check(void)efi_status_t efi_set_timer (struct efi_event *event,enum efi_timer_delay type,uint64_t trigger_time) { -int i; +if (!efi_is_event (event)) +return EFI_INVALID_PARAMETER ;/* * The parameter defines a multiple of 100ns. @@ -493,30 +513,25 @@ efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type,*/ do_div (trigger_time,10 ); -for (i =0 ; i <ARRAY_SIZE (efi_events); ++i) { -if (event != &efi_events[i]) -continue ; +if (!(event->type &EVT_TIMER )) +return EFI_INVALID_PARAMETER ; -if (!(event->type &EVT_TIMER )) -break ; -switch (type) { -case EFI_TIMER_STOP : - event->trigger_next =-1ULL ; -break ; -case EFI_TIMER_PERIODIC : -case EFI_TIMER_RELATIVE : - event->trigger_next = -timer_get_us () + trigger_time; -break ; -default : -return EFI_INVALID_PARAMETER ; - } - event->trigger_type = type; - event->trigger_time = trigger_time; - event->is_signaled = false; -return EFI_SUCCESS ; +switch (type) { +case EFI_TIMER_STOP : + event->trigger_next =-1ULL ; +break ; +case EFI_TIMER_PERIODIC : +case EFI_TIMER_RELATIVE : + event->trigger_next =timer_get_us () + trigger_time; +break ; +default : +return EFI_INVALID_PARAMETER ; } -return EFI_INVALID_PARAMETER ; + event->trigger_type = type; + event->trigger_time = trigger_time; + event->is_signaled = false; + +return EFI_SUCCESS ; }/* @@ -555,7 +570,7 @@ static efi_status_t EFIAPI efi_wait_for_event(unsigned long num_events,struct efi_event **event, size_t *index) { - int i, j; + int i;EFI_ENTRY ("%ld, %p, %p" , num_events, event, index);@@ -566,12 +581,8 @@ static efi_status_t EFIAPI efi_wait_for_event(unsigned long num_events,if (efi_tpl !=TPL_APPLICATION )return EFI_EXIT (EFI_UNSUPPORTED );for (i =0 ; i < num_events; ++i) { -for (j =0 ; j <ARRAY_SIZE (efi_events); ++j) { -if (event[i] == &efi_events[j]) - goto known_event; - } -return EFI_EXIT (EFI_INVALID_PARAMETER ); -known_event: +if (!efi_is_event (event[i])) +return EFI_EXIT (EFI_INVALID_PARAMETER );if (!event[i]->type || event[i]->type &EVT_NOTIFY_SIGNAL )return EFI_EXIT (EFI_INVALID_PARAMETER );if (!event[i]->is_signaled)@@ -614,19 +625,12 @@ out:*/ static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event) { -int i; -EFI_ENTRY ("%p" , event); -for (i =0 ; i <ARRAY_SIZE (efi_events); ++i) { -if (event != &efi_events[i]) -continue ; -if (event->is_signaled) -break ; - event->is_signaled = true; -if (event->type &EVT_NOTIFY_SIGNAL ) -efi_signal_event (event); -break ; - } +if (!efi_is_event (event)) +return EFI_EXIT (EFI_INVALID_PARAMETER ); + event->is_signaled = true; +if (event->type &EVT_NOTIFY_SIGNAL ) +efi_signal_event (event);return EFI_EXIT (EFI_SUCCESS ); }@@ -642,19 +646,10 @@ static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event)*/ static efi_status_t EFIAPI efi_close_event(struct efi_event *event) { -int i; -EFI_ENTRY ("%p" , event); -for (i =0 ; i <ARRAY_SIZE (efi_events); ++i) { -if (event == &efi_events[i]) { - event->type =0 ; - event->trigger_next =-1ULL ; - event->is_queued = false; - event->is_signaled = false; -return EFI_EXIT (EFI_SUCCESS ); - } - } -return EFI_EXIT (EFI_INVALID_PARAMETER ); +list_del (&event->link); +free (event); +return EFI_EXIT (EFI_SUCCESS ); }/* @@ -664,29 +659,37 @@ static efi_status_t EFIAPI efi_close_event(struct efi_event *event)* See the Unified Extensible Firmware Interface (UEFI) specification * for details. * -* If an event is not signaled yet the notification function is queued. +* - If Event is in the signaled state, it is cleared and EFI_SUCCESS +* is returned. +* +* - If Event is not in the signaled state and has no notification +* function, EFI_NOT_READY is returned. +* +* - If Event is not in the signaled state but does have a notification +* function, the notification function is queued at the event’s +* notification task priority level. If the execution of the
lib/efi_loader/efi_boottime.c static efi_status_t EFIAPI efi_close_event(struct efi_event *event) · line 679
Quoted 10 lines
lib/efi_loader/efi_boottime.c +5
-1+* notification function causes Event to be signaled, then the signaled +* state is cleared and EFI_SUCCESS is returned; if the Event is not +* signaled, then EFI_NOT_READY is returned. * * @event event to check * @return status code */ -static efi_status_t EFIAPI efi_check_event(struct efi_event *event) +/* +*/
I assume this is one comment block too much?
lib/efi_loader/efi_boottime.c static efi_status_t EFIAPI efi_close_event(struct efi_event *event) · line 681
Quoted 2 lines
lib/efi_loader/efi_boottime.c +1
-0+static efi_status_t EFIAPI efi_check_event(struct efi_event *evt) {
Alex
PATCH 7/11 efi_loader: fix events
Quoted 312 lines · Alexander Graf
Quoted 309 lines · Rob Clark
An event can be created with type==0, Shell.efi does this for an event that is set when Ctrl-C is typed. So our current approach of having a fixed set of timer slots, and determining which slots are unused by type==0 doesn't work so well. But we don't have any particularly good reason to have a fixed table of events, so just dynamically allocate them and keep a list.
Also fixes an incorrect implementation of
CheckEvent()which was (a) incorrectly returning an error if type==0, and (b) didn't handle the case of an unsignaled event with a notify callback.With these fixes (plus implementation of
SIMPLE_TEXT_INPUT_EXprotocol), Ctrl-C works in Shell.efi.Signed-off-by Rob Clark <[email protected]>--- include/efi_loader.h | 1 + lib/efi_loader/efi_boottime.c | 217 +++++++++++++++++++++--------------------- 2 files changed, 111 insertions(+), 107 deletions(-)include/efi_loader.h +1
-0@@ -154,6 +154,7 @@ struct efi_event {enum efi_timer_delay trigger_type;bool is_queued;bool is_signaled; +struct list_head link; };lib/efi_loader/efi_boottime.c +94
-88@@ -350,11 +350,26 @@ static efi_status_t efi_create_handle(void **handle)return r; } +static LIST_HEAD (efi_events); +/* -* Our event capabilities are very limited. Only a small limited -* number of events is allowed to coexist. +* Check if a pointer is a valid event. +* +* It might be nice at some point to extend this to a more general +* mechanism to check if pointers passed from the EFI world are +* valid objects of a particular type. */ -static struct efi_event efi_events[16 ]; +static bool efi_is_event (const void *obj) +{ +struct efi_event *evt; + +list_for_each_entry (evt, &efi_events, link) { +if (evt == obj) +return true; + } + +return false; +}/* * Create an event. @@ -377,7 +392,7 @@ efi_status_t efi_create_event(uint32_t type, UINTN notify_tpl, void *context), void *notify_context, struct efi_event **event) { - int i; + struct efi_event *evt;if (event ==NULL )return EFI_INVALID_PARAMETER ;@@ -389,21 +404,24 @@ efi_status_t efi_create_event(uint32_t type, UINTN notify_tpl, notify_function == NULL)return EFI_INVALID_PARAMETER ; -for (i =0 ; i <ARRAY_SIZE (efi_events); ++i) { -if (efi_events[i].type) -continue ; - efi_events[i].type = type; - efi_events[i].notify_tpl = notify_tpl; - efi_events[i].notify_function = notify_function; - efi_events[i].notify_context = notify_context; -/* Disable timers on bootup */ - efi_events[i].trigger_next =-1ULL ; - efi_events[i].is_queued = false; - efi_events[i].is_signaled = false; - *event = &efi_events[i]; -return EFI_SUCCESS ; - } -return EFI_OUT_OF_RESOURCES ; + evt =calloc (1 ,sizeof (*evt)); +if (!evt) +return EFI_OUT_OF_RESOURCES ; + + evt->type = type; + evt->notify_tpl = notify_tpl; + evt->notify_function = notify_function; + evt->notify_context = notify_context; +/* Disable timers on bootup */ + evt->trigger_next =-1ULL ; + evt->is_queued = false; + evt->is_signaled = false; + +list_add_tail (&evt->link, &efi_events); + + *event = evt; + +return EFI_SUCCESS ; }/* @@ -443,30 +461,31 @@ static efi_status_t EFIAPI efi_create_event_ext(*/ void efi_timer_check (void ) { -int i; +struct efi_event *evt;u64 now =timer_get_us (); -for (i =0 ; i <ARRAY_SIZE (efi_events); ++i) { -if (!efi_events[i].type) -continue ; -if (efi_events[i].is_queued) -efi_signal_event (&efi_events[i]); -if (!(efi_events[i].type &EVT_TIMER ) || - now < efi_events[i].trigger_next) +/* +* TODO perhaps optimize a bit and track the time of next +* timer to expire? +*/ +list_for_each_entry (evt, &efi_events, link) { +if (evt->is_queued) +efi_signal_event (evt); +if (!(evt->type &EVT_TIMER ) || + now < evt->trigger_next)continue ; -switch (efi_events[i].trigger_type) { +switch (evt->trigger_type) {case EFI_TIMER_RELATIVE : - efi_events[i].trigger_type =EFI_TIMER_STOP ; + evt->trigger_type =EFI_TIMER_STOP ;break ;case EFI_TIMER_PERIODIC : - efi_events[i].trigger_next += - efi_events[i].trigger_time; + evt->trigger_next += evt->trigger_time;break ;default :continue ; } - efi_events[i].is_signaled = true; -efi_signal_event (&efi_events[i]); + evt->is_signaled = true; +efi_signal_event (evt); }WATCHDOG_RESET (); }@@ -485,7 +504,8 @@ void efi_timer_check(void)efi_status_t efi_set_timer (struct efi_event *event,enum efi_timer_delay type,uint64_t trigger_time) { -int i; +if (!efi_is_event (event)) +return EFI_INVALID_PARAMETER ;/* * The parameter defines a multiple of 100ns. @@ -493,30 +513,25 @@ efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type,*/ do_div (trigger_time,10 ); -for (i =0 ; i <ARRAY_SIZE (efi_events); ++i) { -if (event != &efi_events[i]) -continue ; +if (!(event->type &EVT_TIMER )) +return EFI_INVALID_PARAMETER ; -if (!(event->type &EVT_TIMER )) -break ; -switch (type) { -case EFI_TIMER_STOP : - event->trigger_next =-1ULL ; -break ; -case EFI_TIMER_PERIODIC : -case EFI_TIMER_RELATIVE : - event->trigger_next = -timer_get_us () + trigger_time; -break ; -default : -return EFI_INVALID_PARAMETER ; - } - event->trigger_type = type; - event->trigger_time = trigger_time; - event->is_signaled = false; -return EFI_SUCCESS ; +switch (type) { +case EFI_TIMER_STOP : + event->trigger_next =-1ULL ; +break ; +case EFI_TIMER_PERIODIC : +case EFI_TIMER_RELATIVE : + event->trigger_next =timer_get_us () + trigger_time; +break ; +default : +return EFI_INVALID_PARAMETER ; } -return EFI_INVALID_PARAMETER ; + event->trigger_type = type; + event->trigger_time = trigger_time; + event->is_signaled = false; + +return EFI_SUCCESS ; }/* @@ -555,7 +570,7 @@ static efi_status_t EFIAPI efi_wait_for_event(unsigned long num_events,struct efi_event **event, size_t *index) { - int i, j; + int i;EFI_ENTRY ("%ld, %p, %p" , num_events, event, index);@@ -566,12 +581,8 @@ static efi_status_t EFIAPI efi_wait_for_event(unsigned long num_events,if (efi_tpl !=TPL_APPLICATION )return EFI_EXIT (EFI_UNSUPPORTED );for (i =0 ; i < num_events; ++i) { -for (j =0 ; j <ARRAY_SIZE (efi_events); ++j) { -if (event[i] == &efi_events[j]) - goto known_event; - } -return EFI_EXIT (EFI_INVALID_PARAMETER ); -known_event: +if (!efi_is_event (event[i])) +return EFI_EXIT (EFI_INVALID_PARAMETER );if (!event[i]->type || event[i]->type &EVT_NOTIFY_SIGNAL )return EFI_EXIT (EFI_INVALID_PARAMETER );if (!event[i]->is_signaled)@@ -614,19 +625,12 @@ out:*/ static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event) { -int i; -EFI_ENTRY ("%p" , event); -for (i =0 ; i <ARRAY_SIZE (efi_events); ++i) { -if (event != &efi_events[i]) -continue ; -if (event->is_signaled) -break ; - event->is_signaled = true; -if (event->type &EVT_NOTIFY_SIGNAL ) -efi_signal_event (event); -break ; - } +if (!efi_is_event (event)) +return EFI_EXIT (EFI_INVALID_PARAMETER ); + event->is_signaled = true; +if (event->type &EVT_NOTIFY_SIGNAL ) +efi_signal_event (event);return EFI_EXIT (EFI_SUCCESS ); }@@ -642,19 +646,10 @@ static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event)*/ static efi_status_t EFIAPI efi_close_event(struct efi_event *event) { -int i; -EFI_ENTRY ("%p" , event); -for (i =0 ; i <ARRAY_SIZE (efi_events); ++i) { -if (event == &efi_events[i]) { - event->type =0 ; - event->trigger_next =-1ULL ; - event->is_queued = false; - event->is_signaled = false; -return EFI_EXIT (EFI_SUCCESS ); - } - } -return EFI_EXIT (EFI_INVALID_PARAMETER ); +list_del (&event->link); +free (event); +return EFI_EXIT (EFI_SUCCESS ); }/* @@ -664,29 +659,37 @@ static efi_status_t EFIAPI efi_close_event(struct efi_event *event)* See the Unified Extensible Firmware Interface (UEFI) specification * for details. * -* If an event is not signaled yet the notification function is queued. +* - If Event is in the signaled state, it is cleared and EFI_SUCCESS +* is returned. +* +* - If Event is not in the signaled state and has no notification +* function, EFI_NOT_READY is returned. +* +* - If Event is not in the signaled state but does have a notification +* function, the notification function is queued at the event’s +* notification task priority level. If the execution of the +* notification function causes Event to be signaled, then the signaled +* state is cleared and EFI_SUCCESS is returned; if the Event is not +* signaled, then EFI_NOT_READY is returned. *
Quoted 8 lines
lib/efi_loader/efi_boottime.c static efi_status_t EFIAPI efi_close_event(struct efi_event *event) · line 679
Quoted 6 lines
lib/efi_loader/efi_boottime.c +2
-1* @event event to check * @return status code */ -static efi_status_t EFIAPI efi_check_event(struct efi_event *event) +/* +*/ I assume this is one comment block too much?
ugg, looks like I screwed that up when rebase/mergetool'ing.. can you drop that when applying or do you want me to resend?
BR,
-R
Quoted 7 lines
lib/efi_loader/efi_boottime.c static efi_status_t EFIAPI efi_close_event(struct efi_event *event) · line 681
Quoted 2 lines
lib/efi_loader/efi_boottime.c +1
-0+static efi_status_t EFIAPI efi_check_event(struct efi_event *evt) {Alex
PATCH 7/11 efi_loader: fix events
In reply to Rob ClarkQuoted 326 lines · Rob Clark
An event can be created with type==0, Shell.efi does this for an event that is set when Ctrl-C is typed. So our current approach of having a fixed set of timer slots, and determining which slots are unused by type==0 doesn't work so well. But we don't have any particularly good reason to have a fixed table of events, so just dynamically allocate them and keep a list.
Also fixes an incorrect implementation of
CheckEvent()which was (a) incorrectly returning an error if type==0, and (b) didn't handle the case of an unsignaled event with a notify callback.With these fixes (plus implementation of
SIMPLE_TEXT_INPUT_EXprotocol), Ctrl-C works in Shell.efi.Signed-off-by Rob Clark <[email protected]>--- include/efi_loader.h | 1 + lib/efi_loader/efi_boottime.c | 217 +++++++++++++++++++++--------------------- 2 files changed, 111 insertions(+), 107 deletions(-)include/efi_loader.h +1
-0@@ -154,6 +154,7 @@ struct efi_event {enum efi_timer_delay trigger_type;bool is_queued;bool is_signaled; +struct list_head link; };lib/efi_loader/efi_boottime.c +98
-96@@ -350,11 +350,26 @@ static efi_status_t efi_create_handle(void **handle)return r; } +static LIST_HEAD (efi_events); +/* -* Our event capabilities are very limited. Only a small limited -* number of events is allowed to coexist. +* Check if a pointer is a valid event. +* +* It might be nice at some point to extend this to a more general +* mechanism to check if pointers passed from the EFI world are +* valid objects of a particular type. */ -static struct efi_event efi_events[16 ]; +static bool efi_is_event (const void *obj) +{ +struct efi_event *evt; + +list_for_each_entry (evt, &efi_events, link) { +if (evt == obj) +return true; + } + +return false; +}/* * Create an event. @@ -377,7 +392,7 @@ efi_status_t efi_create_event(uint32_t type, UINTN notify_tpl, void *context), void *notify_context, struct efi_event **event) { - int i; + struct efi_event *evt;if (event ==NULL )return EFI_INVALID_PARAMETER ;@@ -389,21 +404,24 @@ efi_status_t efi_create_event(uint32_t type, UINTN notify_tpl, notify_function == NULL)return EFI_INVALID_PARAMETER ; -for (i =0 ; i <ARRAY_SIZE (efi_events); ++i) { -if (efi_events[i].type) -continue ; - efi_events[i].type = type; - efi_events[i].notify_tpl = notify_tpl; - efi_events[i].notify_function = notify_function; - efi_events[i].notify_context = notify_context; -/* Disable timers on bootup */ - efi_events[i].trigger_next =-1ULL ; - efi_events[i].is_queued = false; - efi_events[i].is_signaled = false; - *event = &efi_events[i]; -return EFI_SUCCESS ; - } -return EFI_OUT_OF_RESOURCES ; + evt =calloc (1 ,sizeof (*evt)); +if (!evt) +return EFI_OUT_OF_RESOURCES ; + + evt->type = type; + evt->notify_tpl = notify_tpl; + evt->notify_function = notify_function; + evt->notify_context = notify_context; +/* Disable timers on bootup */ + evt->trigger_next =-1ULL ; + evt->is_queued = false; + evt->is_signaled = false; + +list_add_tail (&evt->link, &efi_events); + + *event = evt; + +return EFI_SUCCESS ; }/* @@ -443,30 +461,31 @@ static efi_status_t EFIAPI efi_create_event_ext(*/ void efi_timer_check (void ) { -int i; +struct efi_event *evt;u64 now =timer_get_us (); -for (i =0 ; i <ARRAY_SIZE (efi_events); ++i) { -if (!efi_events[i].type) -continue ; -if (efi_events[i].is_queued) -efi_signal_event (&efi_events[i]); -if (!(efi_events[i].type &EVT_TIMER ) || - now < efi_events[i].trigger_next) +/* +* TODO perhaps optimize a bit and track the time of next +* timer to expire? +*/ +list_for_each_entry (evt, &efi_events, link) { +if (evt->is_queued) +efi_signal_event (evt); +if (!(evt->type &EVT_TIMER ) || + now < evt->trigger_next)continue ; -switch (efi_events[i].trigger_type) { +switch (evt->trigger_type) {case EFI_TIMER_RELATIVE : - efi_events[i].trigger_type =EFI_TIMER_STOP ; + evt->trigger_type =EFI_TIMER_STOP ;break ;case EFI_TIMER_PERIODIC : - efi_events[i].trigger_next += - efi_events[i].trigger_time; + evt->trigger_next += evt->trigger_time;break ;default :continue ; } - efi_events[i].is_signaled = true; -efi_signal_event (&efi_events[i]); + evt->is_signaled = true; +efi_signal_event (evt); }WATCHDOG_RESET (); }@@ -485,7 +504,8 @@ void efi_timer_check(void)efi_status_t efi_set_timer (struct efi_event *event,enum efi_timer_delay type,uint64_t trigger_time) { -int i; +if (!efi_is_event (event)) +return EFI_INVALID_PARAMETER ;/* * The parameter defines a multiple of 100ns. @@ -493,30 +513,25 @@ efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type,*/ do_div (trigger_time,10 ); -for (i =0 ; i <ARRAY_SIZE (efi_events); ++i) { -if (event != &efi_events[i]) -continue ; +if (!(event->type &EVT_TIMER )) +return EFI_INVALID_PARAMETER ; -if (!(event->type &EVT_TIMER )) -break ; -switch (type) { -case EFI_TIMER_STOP : - event->trigger_next =-1ULL ; -break ; -case EFI_TIMER_PERIODIC : -case EFI_TIMER_RELATIVE : - event->trigger_next = -timer_get_us () + trigger_time; -break ; -default : -return EFI_INVALID_PARAMETER ; - } - event->trigger_type = type; - event->trigger_time = trigger_time; - event->is_signaled = false; -return EFI_SUCCESS ; +switch (type) { +case EFI_TIMER_STOP : + event->trigger_next =-1ULL ; +break ; +case EFI_TIMER_PERIODIC : +case EFI_TIMER_RELATIVE : + event->trigger_next =timer_get_us () + trigger_time; +break ; +default : +return EFI_INVALID_PARAMETER ; } -return EFI_INVALID_PARAMETER ; + event->trigger_type = type; + event->trigger_time = trigger_time; + event->is_signaled = false; + +return EFI_SUCCESS ; }/* @@ -555,7 +570,7 @@ static efi_status_t EFIAPI efi_wait_for_event(unsigned long num_events,struct efi_event **event, size_t *index) { - int i, j; + int i;EFI_ENTRY ("%ld, %p, %p" , num_events, event, index);@@ -566,12 +581,8 @@ static efi_status_t EFIAPI efi_wait_for_event(unsigned long num_events,if (efi_tpl !=TPL_APPLICATION )return EFI_EXIT (EFI_UNSUPPORTED );for (i =0 ; i < num_events; ++i) { -for (j =0 ; j <ARRAY_SIZE (efi_events); ++j) { -if (event[i] == &efi_events[j]) - goto known_event; - } -return EFI_EXIT (EFI_INVALID_PARAMETER ); -known_event: +if (!efi_is_event (event[i])) +return EFI_EXIT (EFI_INVALID_PARAMETER );if (!event[i]->type || event[i]->type &EVT_NOTIFY_SIGNAL )return EFI_EXIT (EFI_INVALID_PARAMETER );if (!event[i]->is_signaled)@@ -614,19 +625,12 @@ out:*/ static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event) { -int i; -EFI_ENTRY ("%p" , event); -for (i =0 ; i <ARRAY_SIZE (efi_events); ++i) { -if (event != &efi_events[i]) -continue ; -if (event->is_signaled) -break ; - event->is_signaled = true; -if (event->type &EVT_NOTIFY_SIGNAL ) -efi_signal_event (event); -break ; - } +if (!efi_is_event (event)) +return EFI_EXIT (EFI_INVALID_PARAMETER ); + event->is_signaled = true; +if (event->type &EVT_NOTIFY_SIGNAL ) +efi_signal_event (event);return EFI_EXIT (EFI_SUCCESS ); }@@ -642,19 +646,10 @@ static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event)*/ static efi_status_t EFIAPI efi_close_event(struct efi_event *event) { -int i; -EFI_ENTRY ("%p" , event); -for (i =0 ; i <ARRAY_SIZE (efi_events); ++i) { -if (event == &efi_events[i]) { - event->type =0 ; - event->trigger_next =-1ULL ; - event->is_queued = false; - event->is_signaled = false; -return EFI_EXIT (EFI_SUCCESS ); - } - } -return EFI_EXIT (EFI_INVALID_PARAMETER ); +list_del (&event->link); +free (event); +return EFI_EXIT (EFI_SUCCESS ); }/* @@ -664,29 +659,37 @@ static efi_status_t EFIAPI efi_close_event(struct efi_event *event)* See the Unified Extensible Firmware Interface (UEFI) specification * for details. * -* If an event is not signaled yet the notification function is queued. +* - If Event is in the signaled state, it is cleared and EFI_SUCCESS +* is returned. +* +* - If Event is not in the signaled state and has no notification +* function, EFI_NOT_READY is returned. +* +* - If Event is not in the signaled state but does have a notification +* function, the notification function is queued at the event’s +* notification task priority level. If the execution of the +* notification function causes Event to be signaled, then the signaled +* state is cleared and EFI_SUCCESS is returned; if the Event is not +* signaled, then EFI_NOT_READY is returned. * * @event event to check * @return status code */ -static efi_status_t EFIAPI efi_check_event(struct efi_event *event) +/* +*/ +static efi_status_t EFIAPI efi_check_event(struct efi_event *evt) { -int i; - -EFI_ENTRY ("%p" , event); +EFI_ENTRY ("%p" , evt);efi_timer_check (); -for (i =0 ; i <ARRAY_SIZE (efi_events); ++i) { -if (event != &efi_events[i]) -continue ; -if (!event->type || event->type &EVT_NOTIFY_SIGNAL )
lib/efi_loader/efi_boottime.c static efi_status_t EFIAPI efi_close_event(struct efi_event *event) · line 687
Quoted 10 lines
lib/efi_loader/efi_boottime.c +4
-6-break ; -if (!event->is_signaled) -efi_signal_event (event); -if (event->is_signaled) -return EFI_EXIT (EFI_SUCCESS ); -return EFI_EXIT (EFI_NOT_READY ); +if (!efi_is_event (evt) || (evt->type &EVT_NOTIFY_SIGNAL )) +return EFI_EXIT (EFI_INVALID_PARAMETER ); +if (!evt->is_signaled && evt->notify_function) +EFI_CALL_VOID (evt->notify_function (evt, evt->notify_context));
Here you are doing the contrary of what you describe above:
You do not check the task priority level. You call the notification function irrespective of the TPL.
You should queue the notification function if the current TPL is greater or equal to the TPL of the notification functions. This is what the removed call to function efi_signal_event was doing before your patch.
Could you, please, describe the rationale of this change. Where did you get problems with the queuing logic?
Regards
Heinrich
Quoted 30 lines
lib/efi_loader/efi_boottime.c +8
-5+if (evt->is_signaled) { + evt->is_signaled = true; +return EFI_EXIT (EFI_SUCCESS ); } -return EFI_EXIT (EFI_INVALID_PARAMETER ); +return EFI_EXIT (EFI_NOT_READY ); }/* @@ -1440,15 +1443,15 @@ static void efi_exit_caches(void) static efi_status_t EFIAPI efi_exit_boot_services(void *image_handle,unsigned long map_key) { -int i; +struct efi_event *evt;EFI_ENTRY ("%p, %ld" , image_handle, map_key);/* Notify that ExitBootServices is invoked. */ -for (i =0 ; i <ARRAY_SIZE (efi_events); ++i) { -if (efi_events[i].type !=EVT_SIGNAL_EXIT_BOOT_SERVICES ) +list_for_each_entry (evt, &efi_events, link) { +if (evt->type !=EVT_SIGNAL_EXIT_BOOT_SERVICES )continue ; -efi_signal_event (&efi_events[i]); +efi_signal_event (evt); }/* Make sure that notification functions are not called anymore */ efi_tpl =TPL_HIGH_LEVEL ;
PATCH 7/11 efi_loader: fix events
Quoted 343 lines · Heinrich Schuchardt
Quoted 323 lines · Rob Clark
An event can be created with type==0, Shell.efi does this for an event that is set when Ctrl-C is typed. So our current approach of having a fixed set of timer slots, and determining which slots are unused by type==0 doesn't work so well. But we don't have any particularly good reason to have a fixed table of events, so just dynamically allocate them and keep a list.
Also fixes an incorrect implementation of
CheckEvent()which was (a) incorrectly returning an error if type==0, and (b) didn't handle the case of an unsignaled event with a notify callback.With these fixes (plus implementation of
SIMPLE_TEXT_INPUT_EXprotocol), Ctrl-C works in Shell.efi.Signed-off-by Rob Clark <[email protected]>--- include/efi_loader.h | 1 + lib/efi_loader/efi_boottime.c | 217 +++++++++++++++++++++--------------------- 2 files changed, 111 insertions(+), 107 deletions(-)include/efi_loader.h +1
-0@@ -154,6 +154,7 @@ struct efi_event {enum efi_timer_delay trigger_type;bool is_queued;bool is_signaled; +struct list_head link; }; diff --git a/lib/efi_loader/efi_boottime.c
b/lib/efi_loader/efi_boottime.c
index39dcc72648..19fafe546c100644lib/efi_loader/efi_boottime.c +18
-4@@ -350,11 +350,26 @@ static efi_status_t efi_create_handle(void **handle)return r; } +static LIST_HEAD(efi_events); +/* -* Our event capabilities are very limited. Only a small limited -* number of events is allowed to coexist. +* Check if a pointer is a valid event. +* +* It might be nice at some point to extend this to a more general +* mechanism to check if pointers passed from the EFI world are +* valid objects of a particular type. */ -static struct efi_event efi_events[16 ]; +static bool efi_is_event (const void *obj) +{ +struct efi_event *evt; + +list_for_each_entry (evt, &efi_events, link) { +if (evt == obj) +return true; + } + +return false; +}/* * Create an event. @@ -377,7 +392,7 @@ efi_status_t efi_create_event(uint32_t type, UINTN notify_tpl, void *context), void *notify_context, struct efi_event **event) { -int i; +struct efi_event *evt;if (event ==NULL )return EFI_INVALID_PARAMETER;lib/efi_loader/efi_boottime.c +53
-49@@ -389,21 +404,24 @@ efi_status_t efi_create_event(uint32_t type, UINTN notify_tpl, notify_function == NULL)return EFI_INVALID_PARAMETER ; - for (i = 0; i < ARRAY_SIZE(efi_events); ++i) { -if (efi_events[i].type) -continue ; - efi_events[i].type = type; - efi_events[i].notify_tpl = notify_tpl; - efi_events[i].notify_function = notify_function; - efi_events[i].notify_context = notify_context; -/* Disable timers on bootup */ - efi_events[i].trigger_next =-1ULL ; - efi_events[i].is_queued = false; - efi_events[i].is_signaled = false; - *event = &efi_events[i]; -return EFI_SUCCESS ; - } -return EFI_OUT_OF_RESOURCES ; + evt =calloc (1 ,sizeof (*evt)); +if (!evt) +return EFI_OUT_OF_RESOURCES ; + + evt->type = type; + evt->notify_tpl = notify_tpl; + evt->notify_function = notify_function; + evt->notify_context = notify_context; +/* Disable timers on bootup */ + evt->trigger_next =-1ULL ; + evt->is_queued = false; + evt->is_signaled = false; + +list_add_tail (&evt->link, &efi_events); + + *event = evt; + +return EFI_SUCCESS ; }/* @@ -443,30 +461,31 @@ static efi_status_t EFIAPI efi_create_event_ext(*/ void efi_timer_check (void ) { -int i; +struct efi_event *evt;u64 now =timer_get_us (); - for (i = 0; i < ARRAY_SIZE(efi_events); ++i) { -if (!efi_events[i].type) -continue ; -if (efi_events[i].is_queued) -efi_signal_event (&efi_events[i]); -if (!(efi_events[i].type &EVT_TIMER ) || - now < efi_events[i].trigger_next) +/* +* TODO perhaps optimize a bit and track the time of next +* timer to expire? +*/ +list_for_each_entry (evt, &efi_events, link) { +if (evt->is_queued) +efi_signal_event (evt); +if (!(evt->type &EVT_TIMER ) || + now < evt->trigger_next)continue ; -switch (efi_events[i].trigger_type) { +switch (evt->trigger_type) {case EFI_TIMER_RELATIVE : - efi_events[i].trigger_type =EFI_TIMER_STOP ; + evt->trigger_type =EFI_TIMER_STOP ;break ;case EFI_TIMER_PERIODIC : - efi_events[i].trigger_next += - efi_events[i].trigger_time; + evt->trigger_next += evt->trigger_time;break ;default :continue ; } - efi_events[i].is_signaled = true; -efi_signal_event (&efi_events[i]); + evt->is_signaled = true; +efi_signal_event (evt); }WATCHDOG_RESET (); }@@ -485,7 +504,8 @@ void efi_timer_check(void)efi_status_t efi_set_timer (struct efi_event *event,enum efi_timer_delay type,uint64_t trigger_time) { -int i; +if (!efi_is_event (event)) +return EFI_INVALID_PARAMETER ;/* * The parameter defines a multiple of 100ns. @@ -493,30 +513,25 @@ efi_status_t efi_set_timer(struct efi_event *event,enum efi_timer_delay type, */ do_div (trigger_time,10 ); - for (i = 0; i < ARRAY_SIZE(efi_events); ++i) { -if (event != &efi_events[i]) -continue ; +if (!(event->type &EVT_TIMER )) +return EFI_INVALID_PARAMETER ; - if (!(event->type & EVT_TIMER)) - break; -switch (type) { -case EFI_TIMER_STOP : - event->trigger_next =-1ULL ; -break ; -case EFI_TIMER_PERIODIC : -case EFI_TIMER_RELATIVE : - event->trigger_next = -timer_get_us () + trigger_time; -break ; -default : -return EFI_INVALID_PARAMETER ; - } - event->trigger_type = type; - event->trigger_time = trigger_time; - event->is_signaled = false; -return EFI_SUCCESS ; +switch (type) { +case EFI_TIMER_STOP : + event->trigger_next =-1ULL ; +break ; +case EFI_TIMER_PERIODIC : +case EFI_TIMER_RELATIVE : + event->trigger_next =timer_get_us () + trigger_time; +break ; +default : +return EFI_INVALID_PARAMETER ; } -return EFI_INVALID_PARAMETER ; + event->trigger_type = type; + event->trigger_time = trigger_time; + event->is_signaled = false; + +return EFI_SUCCESS ; }/* @@ -555,7 +570,7 @@ static efi_status_t EFIAPI efi_wait_for_event(unsignedlong num_events, struct efi_event **event, size_t *index) { - int i, j; + int i;EFI_ENTRY ("%ld, %p, %p" , num_events, event, index); @@ -566,12 +581,8 @@ static efi_status_t EFIAPIefi_wait_for_event(unsigned long
num_events,if (efi_tpl != TPL_APPLICATION) return EFI_EXIT(EFI_UNSUPPORTED); for (i = 0; i < num_events; ++i) {lib/efi_loader/efi_boottime.c +7
-18-for (j =0 ; j <ARRAY_SIZE (efi_events); ++j) { -if (event[i] == &efi_events[j]) - goto known_event; - } -return EFI_EXIT (EFI_INVALID_PARAMETER ); -known_event: +if (!efi_is_event (event[i])) +return EFI_EXIT (EFI_INVALID_PARAMETER );if (!event[i]->type || event[i]->type &EVT_NOTIFY_SIGNAL )return EFI_EXIT (EFI_INVALID_PARAMETER );if (!event[i]->is_signaled)@@ -614,19 +625,12 @@ out:*/ static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event) { -int i; -EFI_ENTRY ("%p" , event); -for (i =0 ; i <ARRAY_SIZE (efi_events); ++i) { -if (event != &efi_events[i]) -continue ; -if (event->is_signaled) -break ; - event->is_signaled = true; -if (event->type &EVT_NOTIFY_SIGNAL ) -efi_signal_event (event); -break ; - } +if (!efi_is_event (event)) +return EFI_EXIT (EFI_INVALID_PARAMETER ); + event->is_signaled = true; +if (event->type &EVT_NOTIFY_SIGNAL ) +efi_signal_event (event);return EFI_EXIT (EFI_SUCCESS ); } @@ -642,19 +646,10 @@ static efi_status_t EFIAPI
efi_signal_event_ext(struct efi_event *event)
*/
staticefi_status_tEFIAPIefi_close_event(struct efi_event *event){lib/efi_loader/efi_boottime.c +19
-22-int i; -EFI_ENTRY ("%p" , event); -for (i =0 ; i <ARRAY_SIZE (efi_events); ++i) { -if (event == &efi_events[i]) { - event->type =0 ; - event->trigger_next =-1ULL ; - event->is_queued = false; - event->is_signaled = false; -return EFI_EXIT (EFI_SUCCESS ); - } - } -return EFI_EXIT (EFI_INVALID_PARAMETER ); +list_del (&event->link); +free (event); +return EFI_EXIT (EFI_SUCCESS ); }/* @@ -664,29 +659,37 @@ static efi_status_t EFIAPI efi_close_event(structefi_event *event) * See the Unified Extensible Firmware Interface (UEFI) specification * for details. * -* If an event is not signaled yet the notification function is queued. +* - If Event is in the signaled state, it is cleared and EFI_SUCCESS +* is returned. +* +* - If Event is not in the signaled state and has no notification +* function, EFI_NOT_READY is returned. +* +* - If Event is not in the signaled state but does have a notification +* function, the notification function is queued at the event’s +* notification task priority level. If the execution of the +* notification function causes Event to be signaled, then the signaled +* state is cleared and EFI_SUCCESS is returned; if the Event is not +* signaled, then EFI_NOT_READY is returned. * * @event event to check * @return status code */ -static efi_status_t EFIAPI efi_check_event(struct efi_event *event) +/* +*/ +static efi_status_t EFIAPI efi_check_event(struct efi_event *evt) { -int i; - -EFI_ENTRY ("%p" , event); +EFI_ENTRY ("%p" , evt);efi_timer_check (); -for (i =0 ; i <ARRAY_SIZE (efi_events); ++i) { -if (event != &efi_events[i]) -continue ; -if (!event->type || event->type &EVT_NOTIFY_SIGNAL ) -break ;lib/efi_loader/efi_boottime.c static efi_status_t EFIAPI efi_close_event(struct · line 689
Quoted 10 lines
lib/efi_loader/efi_boottime.c +4
-5-if (!event->is_signaled) -efi_signal_event (event); -if (event->is_signaled) -return EFI_EXIT (EFI_SUCCESS ); -return EFI_EXIT (EFI_NOT_READY ); +if (!efi_is_event (evt) || (evt->type &EVT_NOTIFY_SIGNAL )) +return EFI_EXIT (EFI_INVALID_PARAMETER ); +if (!evt->is_signaled && evt->notify_function) +EFI_CALL_VOID (evt->notify_function (evt, evt->notify_context));Here you are doing the contrary of what you describe above:
You do not check the task priority level. You call the notification function irrespective of the TPL.
Quoted 7 lines
You should queue the notification function if the current TPL is greater or equal to the TPL of the notification functions. This is what the removed call to function
efi_signal_eventwas doing before your patch.Could you, please, describe the rationale of this change. Where did you get problems with the queuing logic?
When I originally wrote this patch (prior to your addition of TPL handling), we weren't handling the 3rd case mentioned in the comment I added, IIRC. (We also were running into a problem with an event that shell was creating with type==0 that it would signal when the user hit ctrl-c to interrupt a command, which was what prompted the switch to a list.)
Looks like you fixed the first issue in efi_signal_event(), which I overlooked when rebasing this patch.
BR,
-R
PATCH 8/11 efi_loader: implement SetWatchdogTimer
In reply to Rob ClarkFrom: Heinrich Schuchardt <[email protected]>
The watchdog is initialized with a 5 minute timeout period. It can be reset by SetWatchdogTimer.
It is stopped by ExitBoottimeServices.
--- cmd/bootefi.c | 1 + include/efi_loader.h | 4 ++ lib/efi_loader/Makefile | 2 +- lib/efi_loader/efi_boottime.c | 17 ++------- lib/efi_loader/efi_watchdog.c | 86 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 95 insertions(+), 15 deletions(-) create mode 100644 lib/efi_loader/efi_watchdog.c
cmd/bootefi.c +1 -0
@@ -43,6 +43,7 @@ static void efi_init_obj_list(void)#ifdef CONFIG_GENERATE_SMBIOS_TABLE efi_smbios_register ();#endif +efi_watchdog_register ();/* Initialize EFI runtime services */ efi_reset_system_init ();
include/efi_loader.h +4 -0
@@ -169,6 +169,8 @@ int efi_disk_register(void);int efi_gop_register (void );/* Called by bootefi to make the network interface available */ int efi_net_register (void ); +/* Called by bootefi to make the watchdog available */ +int efi_watchdog_register (void );/* Called by bootefi to make SMBIOS tables available */ void efi_smbios_register (void );
@@ -177,6 +179,8 @@ efi_fs_from_path(struct efi_device_path *fp);/* Called by networking code to memorize the dhcp ack package */ void efi_net_set_dhcp_ack (void *pkt,int len); +/* Called by efi_set_watchdog_timer to reset the timer */ +efi_status_t efi_set_watchdog (unsigned long timeout);/* Called from places to check whether a timer expired */ void efi_timer_check (void );
lib/efi_loader/Makefile +1 -1
@@ -18,7 +18,7 @@ obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o obj-y += efi_device_path_utilities.o efi_hii.o efi_unicode.o -obj-y += efi_file.o efi_variable.o efi_bootmgr.o +obj-y += efi_file.o efi_variable.o efi_bootmgr.o efi_watchdog.o obj-$(CONFIG_LCD) += efi_gop.o obj-$(CONFIG_DM_VIDEO) += efi_gop.o obj-$(CONFIG_PARTITIONS) += efi_disk.o
lib/efi_loader/efi_boottime.c +3 -14
@@ -156,18 +156,6 @@ void efi_signal_event(struct efi_event *event) }/* -* Write a debug message for an EPI API service that is not implemented yet. -* -* @funcname function that is not yet implemented -* @return EFI_UNSUPPORTED -*/ -static efi_status_t efi_unsupported (const char *funcname) -{ -debug ("EFI: App called into unimplemented function %s\n" , funcname); -return EFI_EXIT (EFI_UNSUPPORTED ); -} - -/* * Raise the task priority level. * * This function implements the RaiseTpl service.
@@ -1470,6 +1458,7 @@ static efi_status_t EFIAPI efi_exit_boot_services(void *image_handle,bootm_disable_interrupts ();/* Give the payload some time to boot */ +efi_set_watchdog (0 );WATCHDOG_RESET ();return EFI_EXIT (EFI_SUCCESS );
@@ -1513,7 +1502,7 @@ static efi_status_t EFIAPI efi_stall(unsigned long microseconds)/* * Reset the watchdog timer. * -* This function implements the WatchdogTimer service. +* This function implements the SetWatchdogTimer service. * See the Unified Extensible Firmware Interface (UEFI) specification * for details. *
@@ -1529,7 +1518,7 @@ static efi_status_t EFIAPI efi_set_watchdog_timer(unsigned long timeout, {EFI_ENTRY ("%ld, 0x%" PRIx64", %ld, %p" , timeout, watchdog_code, data_size, watchdog_data); -return efi_unsupported (__func__); +return EFI_EXIT (efi_set_watchdog (timeout)); }/*
lib/efi_loader/efi_watchdog.c new file +86 -0
86 lines not on this page · raw message
Signature · 1 line
2.13.6
PATCH 8/11 efi_loader: implement SetWatchdogTimer
Quoted 7 lines · Rob Clark
From: Heinrich Schuchardt <[email protected]>
The watchdog is initialized with a 5 minute timeout period. It can be reset by SetWatchdogTimer.
It is stopped by ExitBoottimeServices.Signed-off-by Heinrich Schuchardt <[email protected]>
This is missing an SoB line from Rob.
Alex
PATCH 9/11 efi_loader: Fix disk dp's for pre-DM/legacy devices
In reply to Rob ClarkThis fixes an issue with OpenBSD's bootloader, and I think should also fix a similar issue with grub2 on legacy devices. In the legacy case we were creating disk objects for the partitions, but not also the parent device.
--- lib/efi_loader/efi_disk.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
lib/efi_loader/efi_disk.c +11 -0
@@ -340,6 +340,8 @@ int efi_disk_register(void)for (i =0 ; i <4 ; i++) {struct blk_desc *desc;char devname[32 ] = {0 };/* dp->str is u16[32] long */ +disk_partition_t info; +int part =1 ; desc =blk_get_devnum_by_type (if_type, i);if (!desc)
@@ -349,6 +351,15 @@ int efi_disk_register(void)snprintf (devname,sizeof (devname),"%s%d" , if_typename, i); + +/* add devices for each partition: */ +while (!part_get_info (desc, part, &info)) { +efi_disk_add_dev (devname, if_typename, desc, + i,0 , part); + part++; + } + +/* ... and add block device: */ efi_disk_add_dev (devname, if_typename, desc, i,0 ,0 ); disks++;
Signature · 1 line
2.13.6
PATCH 9/11 efi_loader: Fix disk dp's for pre-DM/legacy devices
Quoted 7 lines · Rob Clark
This fixes an issue with OpenBSD's bootloader, and I think should also fix a similar issue with grub2 on legacy devices. In the legacy case we were creating disk objects for the partitions, but not also the parent device.
Reported-by Jonathan Gray <[email protected]>Signed-off-by Rob Clark <[email protected]>
This patch is already in efi-next?
Alex
PATCH 10/11 efi_loader: Add mem-mapped for fallback
In reply to Rob ClarkWhen we don't have a real device/image path, such as 'bootefi hello', construct a mem-mapped device-path.
This fixes 'bootefi hello' after devicepath refactoring.
--- cmd/bootefi.c | 23 +++++++++++++++++++++++ include/efi_api.h | 8 ++++++++ include/efi_loader.h | 3 +++ lib/efi_loader/efi_device_path.c | 24 ++++++++++++++++++++++++ lib/efi_loader/efi_device_path_to_text.c | 9 +++++++++ 5 files changed, 67 insertions(+)
cmd/bootefi.c +23 -0
@@ -128,6 +128,7 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt, {struct efi_loaded_image loaded_image_info = {};struct efi_object loaded_image_info_obj = {}; +struct efi_device_path *memdp =NULL ;ulong ret;ulong (*entry)(void *image_handle,struct efi_system_table *st)
@@ -136,6 +137,20 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt,const efi_guid_t fdt_guid =EFI_FDT_GUID ;bootm_headers_t img = {0 }; +/* +* Special case for efi payload not loaded from disk, such as +* 'bootefi hello' or for example payload loaded directly into +* memory via jtag/etc: +*/ +if (!device_path && !image_path) { +printf ("WARNING: using memory device/image path, this may confuse some payloads!\n" ); +/* actual addresses filled in after efi_load_pe() */ + memdp =efi_dp_from_mem (0 ,0 ,0 ); + device_path = image_path = memdp; + }else { +assert (device_path && image_path); + } +/* Initialize and populate EFI object list */ if (!efi_obj_list_initalized)efi_init_obj_list ();
@@ -182,6 +197,14 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt, goto exit; } +if (memdp) { +struct efi_device_path_memory *mdp = (void *)memdp; + mdp->memory_type = loaded_image_info.image_code_type; + mdp->start_address = (uintptr_t )loaded_image_info.image_base; + mdp->end_address = mdp->start_address + + loaded_image_info.image_size; + } +/* we don't support much: */ env_set ("efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_OsIndicationsSupported" ,"{ro,boot}(blob)0000000000000000" );
include/efi_api.h +8 -0
@@ -299,8 +299,16 @@ struct efi_mac_addr { } __packed;#define DEVICE_PATH_TYPE_HARDWARE_DEVICE 0x01 +# define DEVICE_PATH_SUB_TYPE_MEMORY 0x03# define DEVICE_PATH_SUB_TYPE_VENDOR 0x04 +struct efi_device_path_memory { +struct efi_device_path dp; +u32 memory_type; +u64 start_address; +u64 end_address; +} __packed; +struct efi_device_path_vendor {struct efi_device_path dp;efi_guid_t guid;
include/efi_loader.h +3 -0
@@ -269,6 +269,9 @@ struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part);struct efi_device_path *efi_dp_from_file (struct blk_desc *desc,int part,const char *path);struct efi_device_path *efi_dp_from_eth (void ); +struct efi_device_path *efi_dp_from_mem (uint32_t mem_type, +uint64_t start_address, +uint64_t end_address);void efi_dp_split_file_path (struct efi_device_path *full_path,struct efi_device_path **device_path,struct efi_device_path **file_path);
lib/efi_loader/efi_device_path.c +24 -0
@@ -538,6 +538,30 @@ struct efi_device_path *efi_dp_from_eth(void) }#endif +/* Construct a device-path for memory-mapped image */ +struct efi_device_path *efi_dp_from_mem (uint32_t memory_type, +uint64_t start_address, +uint64_t end_address) +{ +struct efi_device_path_memory *mdp; +void *buf, *start; + + start = buf =dp_alloc (sizeof (*mdp) +sizeof (END )); + + mdp = buf; + mdp->dp.type =DEVICE_PATH_TYPE_HARDWARE_DEVICE ; + mdp->dp.sub_type =DEVICE_PATH_SUB_TYPE_MEMORY ; + mdp->dp.length =sizeof (*mdp); + mdp->memory_type = memory_type; + mdp->start_address = start_address; + mdp->end_address = end_address; + buf = &mdp[1 ]; + + *((struct efi_device_path *)buf) =END ; + +return start; +} +/* * Helper to split a full device path (containing both device and file * parts) into it's constituent parts.
lib/efi_loader/efi_device_path_to_text.c +9 -0
@@ -24,6 +24,15 @@ static char *dp_unknown(char *s, struct efi_device_path *dp)static char *dp_hardware (char *s,struct efi_device_path *dp) {switch (dp->sub_type) { +case DEVICE_PATH_SUB_TYPE_MEMORY : { +struct efi_device_path_memory *mdp = + (struct efi_device_path_memory *)dp; + s +=sprintf (s,"/MemoryMapped(0x%x,0x%llx,0x%llx)" , + mdp->memory_type, + mdp->start_address, + mdp->end_address); +break ; + }case DEVICE_PATH_SUB_TYPE_VENDOR : {struct efi_device_path_vendor *vdp = (struct efi_device_path_vendor *)dp;
Signature · 1 line
2.13.6
PATCH 10/11 efi_loader: Add mem-mapped for fallback
Quoted 144 lines · Rob Clark
When we don't have a real device/image path, such as 'bootefi hello', construct a mem-mapped device-path.
This fixes 'bootefi hello' after devicepath refactoring.
Fixes 95c5553ea2 ("efi_loader: refactor boot device and loaded_image handling")Signed-off-by Rob Clark <[email protected]>--- cmd/bootefi.c | 23 +++++++++++++++++++++++ include/efi_api.h | 8 ++++++++ include/efi_loader.h | 3 +++ lib/efi_loader/efi_device_path.c | 24 ++++++++++++++++++++++++ lib/efi_loader/efi_device_path_to_text.c | 9 +++++++++ 5 files changed, 67 insertions(+)cmd/bootefi.c +23
-0@@ -128,6 +128,7 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt, {struct efi_loaded_image loaded_image_info = {};struct efi_object loaded_image_info_obj = {}; +struct efi_device_path *memdp =NULL ;ulong ret;ulong (*entry)(void *image_handle,struct efi_system_table *st)@@ -136,6 +137,20 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt,const efi_guid_t fdt_guid =EFI_FDT_GUID ;bootm_headers_t img = {0 }; +/* +* Special case for efi payload not loaded from disk, such as +* 'bootefi hello' or for example payload loaded directly into +* memory via jtag/etc: +*/ +if (!device_path && !image_path) { +printf ("WARNING: using memory device/image path, this may confuse some payloads!\n" ); +/* actual addresses filled in after efi_load_pe() */ + memdp =efi_dp_from_mem (0 ,0 ,0 ); + device_path = image_path = memdp; + }else { +assert (device_path && image_path); + } +/* Initialize and populate EFI object list */ if (!efi_obj_list_initalized)efi_init_obj_list ();@@ -182,6 +197,14 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt, goto exit; } +if (memdp) { +struct efi_device_path_memory *mdp = (void *)memdp; + mdp->memory_type = loaded_image_info.image_code_type; + mdp->start_address = (uintptr_t )loaded_image_info.image_base; + mdp->end_address = mdp->start_address + + loaded_image_info.image_size; + } +/* we don't support much: */ env_set ("efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_OsIndicationsSupported" ,"{ro,boot}(blob)0000000000000000" );include/efi_api.h +8
-0@@ -299,8 +299,16 @@ struct efi_mac_addr { } __packed;#define DEVICE_PATH_TYPE_HARDWARE_DEVICE 0x01 +# define DEVICE_PATH_SUB_TYPE_MEMORY 0x03# define DEVICE_PATH_SUB_TYPE_VENDOR 0x04 +struct efi_device_path_memory { +struct efi_device_path dp; +u32 memory_type; +u64 start_address; +u64 end_address; +} __packed; +struct efi_device_path_vendor {struct efi_device_path dp;efi_guid_t guid;include/efi_loader.h +3
-0@@ -269,6 +269,9 @@ struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part);struct efi_device_path *efi_dp_from_file (struct blk_desc *desc,int part,const char *path);struct efi_device_path *efi_dp_from_eth (void ); +struct efi_device_path *efi_dp_from_mem (uint32_t mem_type, +uint64_t start_address, +uint64_t end_address);void efi_dp_split_file_path (struct efi_device_path *full_path,struct efi_device_path **device_path,struct efi_device_path **file_path);lib/efi_loader/efi_device_path.c +24
-0@@ -538,6 +538,30 @@ struct efi_device_path *efi_dp_from_eth(void) }#endif +/* Construct a device-path for memory-mapped image */ +struct efi_device_path *efi_dp_from_mem (uint32_t memory_type, +uint64_t start_address, +uint64_t end_address) +{ +struct efi_device_path_memory *mdp; +void *buf, *start; + + start = buf =dp_alloc (sizeof (*mdp) +sizeof (END )); + + mdp = buf; + mdp->dp.type =DEVICE_PATH_TYPE_HARDWARE_DEVICE ; + mdp->dp.sub_type =DEVICE_PATH_SUB_TYPE_MEMORY ; + mdp->dp.length =sizeof (*mdp); + mdp->memory_type = memory_type; + mdp->start_address = start_address; + mdp->end_address = end_address; + buf = &mdp[1 ]; + + *((struct efi_device_path *)buf) =END ; + +return start; +} +/* * Helper to split a full device path (containing both device and file * parts) into it's constituent parts. lib/efi_loader/efi_device_path_to_text.c +2
-0@@ -24,6 +24,15 @@ static char *dp_unknown(char *s, struct efi_device_path *dp)static char *dp_hardware (char *s,struct efi_device_path *dp) {switch (dp->sub_type) { +case DEVICE_PATH_SUB_TYPE_MEMORY : { + struct efi_device_path_memory *mdp =
lib/efi_loader/efi_device_path_to_text.c static char *dp_unknown(char *s, struct efi_device_path *dp) · line 38
Quoted 10 lines
lib/efi_loader/efi_device_path_to_text.c +7
-0+ (struct efi_device_path_memory *)dp; + s +=sprintf (s,"/MemoryMapped(0x%x,0x%llx,0x%llx)" , + mdp->memory_type, + mdp->start_address, + mdp->end_address); +break ; + }case DEVICE_PATH_SUB_TYPE_VENDOR : {struct efi_device_path_vendor *vdp = (struct efi_device_path_vendor *)dp;
Providing a dummmy device path for bootefi hello and bootefi selftest is reasonable.
PATCH 10/11 efi_loader: Add mem-mapped for fallback
In reply to Rob ClarkQuoted 50 lines · Rob Clark
When we don't have a real device/image path, such as 'bootefi hello', construct a mem-mapped device-path.
This fixes 'bootefi hello' after devicepath refactoring.
Fixes 95c5553ea2 ("efi_loader: refactor boot device and loaded_image handling")Signed-off-by Rob Clark <[email protected]>--- cmd/bootefi.c | 23 +++++++++++++++++++++++ include/efi_api.h | 8 ++++++++ include/efi_loader.h | 3 +++ lib/efi_loader/efi_device_path.c | 24 ++++++++++++++++++++++++ lib/efi_loader/efi_device_path_to_text.c | 9 +++++++++ 5 files changed, 67 insertions(+)cmd/bootefi.c +15
-0@@ -128,6 +128,7 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt, {struct efi_loaded_image loaded_image_info = {};struct efi_object loaded_image_info_obj = {}; +struct efi_device_path *memdp =NULL ;ulong ret;ulong (*entry)(void *image_handle,struct efi_system_table *st)@@ -136,6 +137,20 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt,const efi_guid_t fdt_guid =EFI_FDT_GUID ;bootm_headers_t img = {0 }; +/* +* Special case for efi payload not loaded from disk, such as +* 'bootefi hello' or for example payload loaded directly into +* memory via jtag/etc: +*/ +if (!device_path && !image_path) { +printf ("WARNING: using memory device/image path, this may confuse some payloads!\n" ); +/* actual addresses filled in after efi_load_pe() */ + memdp =efi_dp_from_mem (0 ,0 ,0 ); + device_path = image_path = memdp; + }else { +assert (device_path && image_path); + } +/* Initialize and populate EFI object list */ if (!efi_obj_list_initalized)efi_init_obj_list ();@@ -182,6 +197,14 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt, goto exit;
cmd/bootefi.c static unsigned long do_bootefi_exec(void *efi, void *fdt, · line 207
Quoted 10 lines
cmd/bootefi.c +8
-0} +if (memdp) { +struct efi_device_path_memory *mdp = (void *)memdp; + mdp->memory_type = loaded_image_info.image_code_type; + mdp->start_address = (uintptr_t )loaded_image_info.image_base; + mdp->end_address = mdp->start_address + + loaded_image_info.image_size; + } +
memdp gets leaked after bootefi is done. Putting it on the stack would at least remove that problem ;). We currently expect to only return from bootefi when a payload was successfully quit.
Alex
PATCH 10/11 efi_loader: Add mem-mapped for fallback
Quoted 55 lines · Alexander Graf
Quoted 52 lines · Rob Clark
When we don't have a real device/image path, such as 'bootefi hello', construct a mem-mapped device-path.
This fixes 'bootefi hello' after devicepath refactoring.
Fixes 95c5553ea2 ("efi_loader: refactor boot device and loaded_image handling")Signed-off-by Rob Clark <[email protected]>--- cmd/bootefi.c | 23 +++++++++++++++++++++++ include/efi_api.h | 8 ++++++++ include/efi_loader.h | 3 +++ lib/efi_loader/efi_device_path.c | 24 ++++++++++++++++++++++++ lib/efi_loader/efi_device_path_to_text.c | 9 +++++++++ 5 files changed, 67 insertions(+)cmd/bootefi.c +15
-0@@ -128,6 +128,7 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt, {struct efi_loaded_image loaded_image_info = {};struct efi_object loaded_image_info_obj = {}; +struct efi_device_path *memdp =NULL ;ulong ret;ulong (*entry)(void *image_handle,struct efi_system_table *st)@@ -136,6 +137,20 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt,const efi_guid_t fdt_guid =EFI_FDT_GUID ;bootm_headers_t img = {0 }; +/* +* Special case for efi payload not loaded from disk, such as +* 'bootefi hello' or for example payload loaded directly into +* memory via jtag/etc: +*/ +if (!device_path && !image_path) { +printf ("WARNING: using memory device/image path, this may confuse some payloads!\n" ); +/* actual addresses filled in after efi_load_pe() */ + memdp =efi_dp_from_mem (0 ,0 ,0 ); + device_path = image_path = memdp; + }else { +assert (device_path && image_path); + } +/* Initialize and populate EFI object list */ if (!efi_obj_list_initalized)efi_init_obj_list ();@@ -182,6 +197,14 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt, goto exit; }
Quoted 13 lines
cmd/bootefi.c static unsigned long do_bootefi_exec(void *efi, void *fdt, · line 207
Quoted 8 lines
cmd/bootefi.c +8
-0+if (memdp) { +struct efi_device_path_memory *mdp = (void *)memdp; + mdp->memory_type = loaded_image_info.image_code_type; + mdp->start_address = (uintptr_t )loaded_image_info.image_base; + mdp->end_address = mdp->start_address + + loaded_image_info.image_size; + } +memdp gets leaked after bootefi is done. Putting it on the stack would at least remove that problem ;). We currently expect to only return from bootefi when a payload was successfully quit.
dp's that aren't allocated from pool are a bad idea, in some cases they get free'd by the payload. (Well not really in this particular case but it feels like a bad idea to mix/match how we allocate dp's.. also, it needs an /End node.) I guess it isn't such a critical leak, but the right solution would be to efi_free_pool() it..
BR,
-R
Alexander Graf
AppliedPATCH 10/11 efi_loader: Add mem-mapped for fallback
In reply to Rob ClarkQuoted 8 lines
When we don't have a real device/image path, such as 'bootefi hello', construct a mem-mapped device-path.
This fixes 'bootefi hello' after devicepath refactoring.
Fixes 95c5553ea2 ("efi_loader: refactor boot device and loaded_image handling")Signed-off-by Rob Clark <[email protected]>
Thanks, applied to efi-next
Alex
PATCH 11/11 efi_loader: exclude openrd devices
In reply to Rob ClarkThese devices have small image size limits, so exclude EFI_LOADER to help avoid exceeding limits.
--- lib/efi_loader/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
lib/efi_loader/Kconfig +1 -1
@@ -1,6 +1,6 @@ config EFI_LOADER bool "Support running EFI Applications in U-Boot" - depends on (ARM || X86) && OF_LIBFDT + depends on (ARM || X86) && OF_LIBFDT && !TARGET_OPENRD default y help Select this option if you want to run EFI applications (like grub2)
Signature · 1 line
2.13.6
PATCH 11/11 efi_loader: exclude openrd devices
Quoted 14 lines · Rob Clark
These devices have small image size limits, so exclude
EFI_LOADERto help avoid exceeding limits.Signed-off-by Rob Clark <[email protected]>--- lib/efi_loader/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)lib/efi_loader/Kconfig +0
-0
lib/efi_loader/Kconfig line 6
Quoted 7 lines
lib/efi_loader/Kconfig +1
-1@@ -1,6 +1,6 @@ config EFI_LOADER bool "Support running EFI Applications in U-Boot" - depends on (ARM || X86) && OF_LIBFDT + depends on (ARM || X86) && OF_LIBFDT && !TARGET_OPENRD default y help Select this option if you want to run EFI applications (like grub2)
I understand that with the progress we make on EFI implementation and other parts of U-Boot the U-Boot image size is growing too big for direct loading by the primary boot loader.
The OPENRD boards have abundant memory, e.g. openrd_ultimate_defconfig refers to a board with 512 MB RAM.
So I think completely disabling EFI is not the solution. Instead building an SPL should be enabled for this architecture when the image is becoming too big for direct load.
I am copying in the KIRKWOOD maintainers go get their view.
Best regards
Heinrich
PATCH 11/11 efi_loader: exclude openrd devices
Quoted 29 lines · Heinrich Schuchardt
Quoted 21 lines · Rob Clark
These devices have small image size limits, so exclude
EFI_LOADERto help avoid exceeding limits.Signed-off-by Rob Clark <[email protected]>--- lib/efi_loader/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)lib/efi_loader/Kconfig +1
-1@@ -1,6 +1,6 @@ config EFI_LOADER bool "Support running EFI Applications in U-Boot" - depends on (ARM || X86) && OF_LIBFDT + depends on (ARM || X86) && OF_LIBFDT && !TARGET_OPENRD default y help Select this option if you want to run EFI applications (likeQuoted 2 lines
grub2)
I understand that with the progress we make on EFI implementation and other parts of U-Boot the U-Boot image size is growing too big for direct loading by the primary boot loader.
Quoted 9 lines
The OPENRD boards have abundant memory, e.g.
openrd_ultimate_defconfigrefers to a board with 512 MB RAM.So I think completely disabling EFI is not the solution. Instead building an SPL should be enabled for this architecture when the image is becoming too big for direct load.
I am copying in the KIRKWOOD maintainers go get their view.
I'm defn open to alternatives.. I don't know too much about what the limit was on these boards, other than we were close to it before, and the additional uefi proto's add <4k to the image size, which was enough to push it over the limit. Since this was effecting only a few boards, I went with this.. if it is only a temporary fix that can be removed soon, or if someone can do something better with a separate SPL build in the near term, that would be great.
BR,
-R
PATCH 11/11 efi_loader: exclude openrd devices
(Adding Albert as maintainer again)
Quoted 40 lines · Rob Clark
Quoted 29 lines · Heinrich Schuchardt
Quoted 21 lines · Rob Clark
These devices have small image size limits, so exclude
EFI_LOADERto help avoid exceeding limits.Signed-off-by Rob Clark <[email protected]>--- lib/efi_loader/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)lib/efi_loader/Kconfig +1
-1@@ -1,6 +1,6 @@ config EFI_LOADER bool "Support running EFI Applications in U-Boot" - depends on (ARM || X86) && OF_LIBFDT + depends on (ARM || X86) && OF_LIBFDT && !TARGET_OPENRD default y help Select this option if you want to run EFI applications (likeQuoted 2 lines
grub2)
I understand that with the progress we make on EFI implementation and other parts of U-Boot the U-Boot image size is growing too big for direct loading by the primary boot loader.
Quoted 9 lines
The OPENRD boards have abundant memory, e.g.
openrd_ultimate_defconfigrefers to a board with 512 MB RAM.So I think completely disabling EFI is not the solution. Instead building an SPL should be enabled for this architecture when the image is becoming too big for direct load.
I am copying in the KIRKWOOD maintainers go get their view.
Quoted 7 lines
I'm defn open to alternatives.. I don't know too much about what the limit was on these boards, other than we were close to it before, and the additional uefi proto's add <4k to the image size, which was enough to push it over the limit. Since this was effecting only a few boards, I went with this.. if it is only a temporary fix that can be removed soon, or if someone can do something better with a separate SPL build in the near term, that would be great.
I personally have not used any Kirkwood based platforms in the last few years (and don't have access to one). And I don't see activities here from mother developers either. As adding SPL support is not trivial, frankly I don't see that this will be done anytime soon if at all.
Perhaps the image size can be reduced by removing other features or interfaces from the OPENRD platform instead (CMD_MII, JFFS2, ...)?
Thanks,
Stefan
PATCH 11/11 efi_loader: exclude openrd devices
Quoted 54 lines · Stefan Roese
(Adding Albert as maintainer again)
Quoted 43 lines · Rob Clark
Quoted 31 lines · Heinrich Schuchardt
Quoted 16 lines · Rob Clark
These devices have small image size limits, so exclude
EFI_LOADERto help avoid exceeding limits.Signed-off-by Rob Clark <[email protected]>---
lib/efi_loader/Kconfig| 2 +-1 file changed, 1 insertion(+), 1 deletion(-)lib/efi_loader/Kconfig +0
-0@@ -1,6 +1,6 @@config
EFI_LOADER
bool "Support running EFI Applications in U-Boot"Quoted 7 lines
- depends on (ARM || X86) && OF_LIBFDT + depends on (ARM || X86) && OF_LIBFDT && !TARGET_OPENRDdefault y
help
Select this option if you want to run EFI applications (like grub2)I understand that with the progress we make on EFI implementation and other
parts of U-Boot the U-Boot image size is growing too big for direct loading
by the primary boot loader.Quoted 9 lines
The OPENRD boards have abundant memory, e.g.
openrd_ultimate_defconfigrefers to a board with 512 MB RAM.So I think completely disabling EFI is not the solution. Instead building an SPL should be enabled for this architecture when the image is becoming too big for direct load.
I am copying in the KIRKWOOD maintainers go get their view.
Quoted 7 lines
I'm defn open to alternatives.. I don't know too much about what the limit was on these boards, other than we were close to it before, and the additional uefi proto's add <4k to the image size, which was enough to push it over the limit. Since this was effecting only a few boards, I went with this.. if it is only a temporary fix that can be removed soon, or if someone can do something better with a separate SPL build in the near term, that would be great.
Quoted 7 lines
I personally have not used any Kirkwood based platforms in the last few years (and don't have access to one). And I don't see activities here from mother developers either. As adding SPL support is not trivial, frankly I don't see that this will be done anytime soon if at all.
Perhaps the image size can be reduced by removing other features or interfaces from the OPENRD platform instead (
CMD_MII, JFFS2, ...)?
If it's too much work to make EFI_LOADER work on these platforms, I guess it's ok to disable it just for them. Given how dated they are, chances are pretty slim that enabling EFI_LOADER by default will give us a U-Boot copy on the device that supports it straight from the factory ;).
However, I would ideally prefer to see that happen in the respective defconfigs, not in Kconfig.
Alex
cover efi_loader: patches for Shell.efi
In reply to Rob ClarkQuoted 42 lines · Rob Clark
Re-send of the patch series to get Shell.efi working, and almost get SCT.efi (the UEFI test suite) working.
Since last time, I've updated to Heinrich's latest SetWatchdogTimer patch (as of yesterday evening), and adressed review comments on the three new sets of protocols added. Part of that, to avoid moving changes from my later patch that added implementation on top of Leif's initial stubs was done by simply squashing the patches together.
Heinrich Schuchardt (1):
efi_loader: implement SetWatchdogTimerLeif Lindholm (3):
efi_loader: InitialEFI_DEVICE_PATH_UTILITIES_PROTOCOL
efi_loader: Initial HII protocols
efi_loader: InitialEFI_UNICODE_COLLATION_PROTOCOLRob Clark (7):
efi_loader:SIMPLE_TEXT_INPUT_EXplus wire up objects properly
efi_loader: console support for color attributes
efi_loader: Decouple EFI input/output from stdin/stdout
efi_loader: fix events
efi_loader: Fix disk dp's for pre-DM/legacy devices
efi_loader: Add mem-mapped for fallback
efi_loader: exclude openrd devicescmd/bootefi.c | 24 ++ include/efi_api.h | 438 ++++++++++++++++++++++++- include/efi_loader.h | 29 +- lib/efi_loader/Kconfig | 2 +- lib/efi_loader/Makefile | 3 +- lib/efi_loader/efi_boottime.c | 256 ++++++++------- lib/efi_loader/efi_console.c | 398 +++++++++++++++++++--- lib/efi_loader/efi_device_path.c | 24 ++ lib/efi_loader/efi_device_path_to_text.c | 9 + lib/efi_loader/efi_device_path_utilities.c | 88 +++++ lib/efi_loader/efi_disk.c | 11 + lib/efi_loader/efi_hii.c | 507 +++++++++++++++++++++++++++++ lib/efi_loader/efi_unicode.c | 170 ++++++++++ lib/efi_loader/efi_watchdog.c | 86 +++++ 14 files changed, 1861 insertions(+), 184 deletions(-)
Quoted 5 lines
create mode 100644
lib/efi_loader/efi_device_path_utilities.ccreate mode 100644lib/efi_loader/efi_hii.c
create mode 100644lib/efi_loader/efi_unicode.ccreate mode 100644lib/efi_loader/efi_watchdog.c
Overall the patch series looks in good shape.
One comment I thought could be helpful in
[PATCH 05/11] efi_loader: console support for color attributes
Some minor checkpatch.pl warnings.
One git am problem (may be a missing space) I had.
I hope we can get this merged now.
Thanks to Rob for driving this.
Regards
Heinrich