[U-Boot] [RESEND PATCH v2 0/6] subject: efi_loader: add HII database protocol

HII database protocol is the last missing (major?) piece of code so that we can run unmodified EDKII's shell and UEFI SCT on EFI-enabled u-boot.
The original code was initially written by Leif and Rob a year ago[1], and now I'm reworking it. The implementation has not been much enhanced from the original, but I tried to give it clearer implementation to be able to add more functionality easily later on. I also addressed the comments by Alex[2] and added a self test on request of Heinrich.
HII configuration routing protocol and access protocol have only a skeleton and should be implemented when we need to have *drivers* that require configuration mechanism.
# Please note that a bunch of warnings are generated by checkpatch.pl, # but there are also good reasons for not fixing them.
Concerns (if any): * missing features (see the commit log of patch#2) * unaligned access to *packed* structure in a package list should be cared?
Changes in v2 (Nov 16, 2018) * add some descriptions to newly added functions * rename EFI_HII_PACKAGE_[TYPE|LEN]_* to __EFI_HII_PACKAGE_[TYPE|LEN]_* as they are of internal use only * cast a return value (of efi_status_t) to "unsigned int" for printing
[1] https://lists.denx.de/pipermail/u-boot/2017-October/308999.html [2] https://lists.denx.de/pipermail/u-boot/2017-October/309116.html
AKASHI Takahiro (4): efi: hii: add guid package support efi: hii: add keyboard layout package support efi: hii: add HII config routing/access protocols efi_selftest: add HII database protocols test
Akashi, Takahiro (1): lib: add u16_strcpy/strdup functions
Leif Lindholm (1): efi_loader: Initial HII database protocols
include/charset.h | 23 + include/efi_api.h | 419 +++++++++ include/efi_loader.h | 8 + lib/charset.c | 29 + lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_boottime.c | 18 + lib/efi_loader/efi_hii.c | 1053 ++++++++++++++++++++++ lib/efi_loader/efi_hii_config.c | 146 +++ lib/efi_selftest/Makefile | 1 + lib/efi_selftest/efi_selftest_hii.c | 1046 +++++++++++++++++++++ lib/efi_selftest/efi_selftest_hii_data.c | 452 ++++++++++ 11 files changed, 3196 insertions(+) create mode 100644 lib/efi_loader/efi_hii.c create mode 100644 lib/efi_loader/efi_hii_config.c create mode 100644 lib/efi_selftest/efi_selftest_hii.c create mode 100644 lib/efi_selftest/efi_selftest_hii_data.c

From: "Akashi, Takahiro" takahiro.akashi@linaro.org
Add u16_strcpy() and u16_strdup(). The latter function will be used later in implementing efi HII database protocol.
Signed-off-by: Akashi Takahiro takahiro.akashi@linaro.org --- include/charset.h | 23 +++++++++++++++++++++++ lib/charset.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+)
diff --git a/include/charset.h b/include/charset.h index 4d45e246e515..65087f76d1fc 100644 --- a/include/charset.h +++ b/include/charset.h @@ -191,6 +191,29 @@ size_t u16_strlen(const u16 *in); */ size_t u16_strnlen(const u16 *in, size_t count);
+/** + * u16_strcpy() - copy u16 string + * + * Copy u16 string pointed to by src, including terminating null word, to + * the buffer pointed to by dest. + * + * @dest: destination buffer + * @src: source buffer (null terminated) + * Return: 'dest' address + */ +u16 *u16_strcpy(u16 *dest, const u16 *src); + +/** + * u16_strdup() - duplicate u16 string + * + * Copy u16 string pointed to by src, including terminating null word, to a + * newly allocated buffer. + * + * @src: source buffer (null terminated) + * Return: allocated new buffer on success, NULL on failure + */ +u16 *u16_strdup(const u16 *src); + /** * utf16_to_utf8() - Convert an utf16 string to utf8 * diff --git a/lib/charset.c b/lib/charset.c index 10557b9e753d..5e349ed5ee45 100644 --- a/lib/charset.c +++ b/lib/charset.c @@ -349,6 +349,35 @@ size_t u16_strnlen(const u16 *in, size_t count) return i; }
+u16 *u16_strcpy(u16 *dest, const u16 *src) +{ + u16 *tmp = dest; + + for (;; dest++, src++) { + *dest = *src; + if (!*src) + break; + } + + return tmp; +} + +u16 *u16_strdup(const u16 *src) +{ + u16 *new; + + if (!src) + return NULL; + + new = malloc((u16_strlen(src) + 1) * sizeof(u16)); + if (!new) + return NULL; + + u16_strcpy(new, src); + + return new; +} + /* Convert UTF-16 to UTF-8. */ uint8_t *utf16_to_utf8(uint8_t *dest, const uint16_t *src, size_t size) {

Provide unit tests for u16_strdup() and u16_strcpy().
Cc: AKASHI Takahiro takahiro.akashi@linaro.org Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de --- This patch is a follow up to Takahiro's patch "lib: add u16_strcpy/strdup functions" https://lists.denx.de/pipermail/u-boot/2018-December/352019.html --- test/unicode_ut.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+)
diff --git a/test/unicode_ut.c b/test/unicode_ut.c index b115d18afd3..84fc9a3b537 100644 --- a/test/unicode_ut.c +++ b/test/unicode_ut.c @@ -50,6 +50,29 @@ static const char j1[] = {0x6a, 0x31, 0xa1, 0x6c, 0x00}; static const char j2[] = {0x6a, 0x32, 0xc3, 0xc3, 0x6c, 0x00}; static const char j3[] = {0x6a, 0x33, 0xf0, 0x90, 0xf0, 0x00};
+static int ut_u16_strdup(struct unit_test_state *uts) +{ + u16 *copy = u16_strdup(c4); + + ut_assert(copy != c4); + ut_assert(!memcmp(copy, c4, sizeof(c4))); + free(copy); + return 0; +} +UNICODE_TEST(ut_u16_strdup); + +static int ut_u16_strcpy(struct unit_test_state *uts) +{ + u16 *r; + u16 copy[10]; + + r = u16_strcpy(copy, c1); + ut_assert(r == copy); + ut_assert(!memcmp(copy, c1, sizeof(c1))); + return 0; +} +UNICODE_TEST(ut_u16_strcpy); + /* U-Boot uses UTF-16 strings in the EFI context only. */ #if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD) static int ut_string16(struct unit_test_state *uts)

On 12/14/18 11:10 AM, AKASHI Takahiro wrote:
From: "Akashi, Takahiro" takahiro.akashi@linaro.org
Add u16_strcpy() and u16_strdup(). The latter function will be used later in implementing efi HII database protocol.
Signed-off-by: Akashi Takahiro takahiro.akashi@linaro.org
Reviewed-by: Heinrich Schuchardt xypron.glpk@gmx.de
I just sent a further patch with the missing unit test.
Regards
Heinrich

From: Leif Lindholm leif.lindholm@linaro.org
This patch provides enough implementation of the following protocols to run EDKII's Shell.efi and UEFI SCT:
* EfiHiiDatabaseProtocol * EfiHiiStringProtocol
Not implemented are: * ExportPackageLists() * RegisterPackageNotify()/UnregisterPackageNotify() * SetKeyboardLayout() (i.e. *current* keyboard layout)
HII database protocol can handle only: * GUID package * string package * keyboard layout package (The other packages, except Device path package, will be necessary for interactive and graphical UI.)
We'll fill in the rest once SCT is running properly so we can validate the implementation against the conformance test suite.
Cc: Leif Lindholm leif.lindholm@linaro.org Signed-off-by: Rob Clark robdclark@gmail.com Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org --- include/efi_api.h | 242 ++++++++++ include/efi_loader.h | 4 + lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_boottime.c | 12 + lib/efi_loader/efi_hii.c | 886 ++++++++++++++++++++++++++++++++++ 5 files changed, 1145 insertions(+) create mode 100644 lib/efi_loader/efi_hii.c
diff --git a/include/efi_api.h b/include/efi_api.h index aef77b6319de..c9dbd5a6037d 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -17,6 +17,7 @@ #define _EFI_API_H
#include <efi.h> +#include <charset.h>
#ifdef CONFIG_EFI_LOADER #include <asm/setjmp.h> @@ -697,6 +698,247 @@ struct efi_device_path_utilities_protocol { uint16_t node_length); };
+typedef u16 efi_string_id_t; + +#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; + u16 unicode; + u16 shifted_unicode; + u16 alt_gr_unicode; + u16 shifted_alt_gr_unicode; + u16 modifier; + u16 affected_attribute; +}; + +struct efi_hii_keyboard_layout { + u16 layout_length; + efi_guid_t guid; + u32 layout_descriptor_string_offset; + u8 descriptor_count; + struct efi_key_descriptor descriptors[]; +}; + +struct efi_hii_package_list_header { + efi_guid_t package_list_guid; + u32 package_length; +} __packed; + +/** + * struct efi_hii_package_header - EFI HII package header + * + * @fields: 'fields' replaces the bit-fields defined in the EFI + * specification to to avoid possible compiler incompatibilities:: + * + * u32 length:24; + * u32 type:8; + */ +struct efi_hii_package_header { + u32 fields; +} __packed; + +#define __EFI_HII_PACKAGE_LEN_SHIFT 0 +#define __EFI_HII_PACKAGE_TYPE_SHIFT 24 +#define __EFI_HII_PACKAGE_LEN_MASK 0xffffff +#define __EFI_HII_PACKAGE_TYPE_MASK 0xff + +#define EFI_HII_PACKAGE_HEADER(header, field) \ + (((header)->fields >> __EFI_HII_PACKAGE_##field##_SHIFT) \ + & __EFI_HII_PACKAGE_##field##_MASK) +#define efi_hii_package_len(header) \ + EFI_HII_PACKAGE_HEADER(header, LEN) +#define efi_hii_package_type(header) \ + EFI_HII_PACKAGE_HEADER(header, TYPE) + +#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; + u32 header_size; + u32 string_info_offset; + u16 language_window[16]; + efi_string_id_t language_name; + u8 language[]; +} __packed; + +struct efi_hii_string_block { + u8 block_type; + /* u8 block_body[]; */ +} __packed; + +#define EFI_HII_SIBT_END 0x00 +#define EFI_HII_SIBT_STRING_SCSU 0x10 +#define EFI_HII_SIBT_STRING_SCSU_FONT 0x11 +#define EFI_HII_SIBT_STRINGS_SCSU 0x12 +#define EFI_HII_SIBT_STRINGS_SCSU_FONT 0x13 +#define EFI_HII_SIBT_STRING_UCS2 0x14 +#define EFI_HII_SIBT_STRING_UCS2_FONT 0x15 +#define EFI_HII_SIBT_STRINGS_UCS2 0x16 +#define EFI_HII_SIBT_STRINGS_UCS2_FONT 0x17 +#define EFI_HII_SIBT_DUPLICATE 0x20 +#define EFI_HII_SIBT_SKIP2 0x21 +#define EFI_HII_SIBT_SKIP1 0x22 +#define EFI_HII_SIBT_EXT1 0x30 +#define EFI_HII_SIBT_EXT2 0x31 +#define EFI_HII_SIBT_EXT4 0x32 +#define EFI_HII_SIBT_FONT 0x40 + +struct efi_hii_sibt_string_ucs2_block { + struct efi_hii_string_block header; + u16 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) + + (u16_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, + u8 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, + u8 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, + u16 *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, + u16 *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 u32 efi_hii_font_style_t; + +struct efi_font_info { + efi_hii_font_style_t font_style; + u16 font_size; + u16 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 u8 *language, + const u16 *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 u8 *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 u8 *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, + u8 *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 u8 *primary_language, + u8 *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) diff --git a/include/efi_loader.h b/include/efi_loader.h index 53f08161ab65..d4412d30bf6f 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -106,6 +106,8 @@ extern const struct efi_device_path_utilities_protocol /* Implementation of the EFI_UNICODE_COLLATION_PROTOCOL */ extern const struct efi_unicode_collation_protocol efi_unicode_collation_protocol; +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);
@@ -139,6 +141,8 @@ extern const efi_guid_t efi_file_system_info_guid; extern const efi_guid_t efi_guid_device_path_utilities_protocol; /* GUID of the Unicode collation protocol */ extern const efi_guid_t efi_guid_unicode_collation_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; diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 6703435947f2..e508481fdeeb 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -24,6 +24,7 @@ obj-y += efi_device_path.o obj-y += efi_device_path_to_text.o obj-y += efi_device_path_utilities.o obj-y += efi_file.o +obj-y += efi_hii.o obj-y += efi_image_loader.o obj-y += efi_memory.o obj-y += efi_root_node.o diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index cc9efbb0cbfd..ba2e1f652afe 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1558,6 +1558,18 @@ efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path, if (ret != EFI_SUCCESS) goto failure;
+ ret = efi_add_protocol(&obj->header, + &efi_guid_hii_string_protocol, + (void *)&efi_hii_string); + if (ret != EFI_SUCCESS) + goto failure; + + ret = efi_add_protocol(&obj->header, + &efi_guid_hii_database_protocol, + (void *)&efi_hii_database); + if (ret != EFI_SUCCESS) + goto failure; + return ret; failure: printf("ERROR: Failure to install protocols for loaded image\n"); diff --git a/lib/efi_loader/efi_hii.c b/lib/efi_loader/efi_hii.c new file mode 100644 index 000000000000..40034c27473d --- /dev/null +++ b/lib/efi_loader/efi_hii.c @@ -0,0 +1,886 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * EFI Human Interface Infrastructure ... database and packages + * + * Copyright (c) 2017 Leif Lindholm + * Copyright (c) 2018 AKASHI Takahiro, Linaro Limited + */ + +#include <common.h> +#include <malloc.h> +#include <efi_loader.h> + +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; + +const u32 hii_package_signature = 0x68696770; /* "higp" */ + +static LIST_HEAD(efi_package_lists); + +struct efi_hii_packagelist { + struct list_head link; + u32 signature; + // TODO should there be an associated efi_object? + efi_handle_t driver_handle; + u32 max_string_id; + struct list_head string_tables; /* list of efi_string_table */ + + /* we could also track fonts, images, etc */ +}; + +struct efi_string_info { + efi_string_t string; + /* we could also track font info, etc */ +}; + +struct efi_string_table { + struct list_head link; + efi_string_id_t language_name; + char *language; + u32 nstrings; + /* + * NOTE: + * string id starts at 1 so value is stbl->strings[id-1], + * and strings[] is a array of stbl->nstrings elements + */ + struct efi_string_info *strings; +}; + +static void free_strings_table(struct efi_string_table *stbl) +{ + int i; + + for (i = 0; i < stbl->nstrings; i++) + free(stbl->strings[i].string); + free(stbl->strings); + free(stbl->language); + free(stbl); +} + +static void remove_strings_package(struct efi_hii_packagelist *hii) +{ + while (!list_empty(&hii->string_tables)) { + struct efi_string_table *stbl; + + stbl = list_first_entry(&hii->string_tables, + struct efi_string_table, link); + list_del(&stbl->link); + free_strings_table(stbl); + } +} + +static efi_status_t +add_strings_package(struct efi_hii_packagelist *hii, + struct efi_hii_strings_package *strings_package) +{ + struct efi_hii_string_block *block; + void *end; + u32 nstrings = 0, idx = 0; + struct efi_string_table *stbl = NULL; + efi_status_t ret; + + 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; + end = ((void *)strings_package) + + efi_hii_package_len(&strings_package->header); + while ((void *)block < end) { + switch (block->block_type) { + case EFI_HII_SIBT_STRING_UCS2: { + struct efi_hii_sibt_string_ucs2_block *ucs2; + + 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; + } + } + + stbl = calloc(sizeof(*stbl), 1); + if (!stbl) { + ret = EFI_OUT_OF_RESOURCES; + goto error; + } + stbl->strings = calloc(sizeof(stbl->strings[0]), nstrings); + if (!stbl->strings) { + ret = EFI_OUT_OF_RESOURCES; + goto error; + } + stbl->language_name = strings_package->language_name; + stbl->language = strdup((char *)strings_package->language); + if (!stbl->language) { + ret = EFI_OUT_OF_RESOURCES; + goto error; + } + stbl->nstrings = nstrings; + + /* and now parse string entries and populate efi_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; + + ucs2 = (void *)block; + debug("%4u: "%ls"\n", idx + 1, ucs2->string_text); + stbl->strings[idx].string = + u16_strdup(ucs2->string_text); + if (!stbl->strings[idx].string) { + ret = EFI_OUT_OF_RESOURCES; + goto error; + } + idx++; + block = efi_hii_sibt_string_ucs2_block_next(ucs2); + break; + } + case EFI_HII_SIBT_END: + goto out; + default: + debug("unknown HII string block type: %02x\n", + block->block_type); + ret = EFI_INVALID_PARAMETER; + goto error; + } + } + +out: + list_add(&stbl->link, &hii->string_tables); + if (hii->max_string_id < nstrings) + hii->max_string_id = nstrings; + + return EFI_SUCCESS; + +error: + if (stbl) { + free(stbl->language); + if (idx > 0) + while (--idx >= 0) + free(stbl->strings[idx].string); + free(stbl->strings); + } + free(stbl); + + return ret; +} + +static struct efi_hii_packagelist *new_packagelist(void) +{ + struct efi_hii_packagelist *hii; + + hii = malloc(sizeof(*hii)); + hii->signature = hii_package_signature; + hii->max_string_id = 0; + INIT_LIST_HEAD(&hii->string_tables); + + return hii; +} + +static void free_packagelist(struct efi_hii_packagelist *hii) +{ + remove_strings_package(hii); + + list_del(&hii->link); + free(hii); +} + +static efi_status_t +add_packages(struct efi_hii_packagelist *hii, + const struct efi_hii_package_list_header *package_list) +{ + struct efi_hii_package_header *package; + void *end; + efi_status_t ret = EFI_SUCCESS; + + 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, + efi_hii_package_type(package), + efi_hii_package_len(package)); + + switch (efi_hii_package_type(package)) { + case EFI_HII_PACKAGE_TYPE_GUID: + printf("\tGuid package not supported\n"); + ret = EFI_INVALID_PARAMETER; + break; + case EFI_HII_PACKAGE_FORMS: + printf("\tForm package not supported\n"); + ret = EFI_INVALID_PARAMETER; + break; + case EFI_HII_PACKAGE_STRINGS: + ret = add_strings_package(hii, + (struct efi_hii_strings_package *)package); + break; + case EFI_HII_PACKAGE_FONTS: + printf("\tFont package not supported\n"); + ret = EFI_INVALID_PARAMETER; + break; + case EFI_HII_PACKAGE_IMAGES: + printf("\tImage package not supported\n"); + ret = EFI_INVALID_PARAMETER; + break; + case EFI_HII_PACKAGE_SIMPLE_FONTS: + printf("\tSimple font package not supported\n"); + ret = EFI_INVALID_PARAMETER; + break; + case EFI_HII_PACKAGE_DEVICE_PATH: + printf("\tDevice path package not supported\n"); + ret = EFI_INVALID_PARAMETER; + break; + case EFI_HII_PACKAGE_KEYBOARD_LAYOUT: + printf("\tKeyboard layout package not supported\n"); + ret = EFI_INVALID_PARAMETER; + break; + case EFI_HII_PACKAGE_ANIMATIONS: + printf("\tAnimation package not supported\n"); + ret = EFI_INVALID_PARAMETER; + break; + case EFI_HII_PACKAGE_END: + goto out; + case EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN: + case EFI_HII_PACKAGE_TYPE_SYSTEM_END: + default: + break; + } + + if (ret != EFI_SUCCESS) + return ret; + + package = ((void *)package) + + efi_hii_package_len(package); + } +out: + // TODO in theory there is some notifications that should be sent.. + return EFI_SUCCESS; +} + +/* + * 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) +{ + struct efi_hii_packagelist *hii; + efi_status_t ret; + + EFI_ENTRY("%p, %p, %p, %p", this, package_list, driver_handle, handle); + + if (!package_list || !handle) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + hii = new_packagelist(); + if (!hii) + return EFI_EXIT(EFI_OUT_OF_RESOURCES); + + ret = add_packages(hii, package_list); + if (ret != EFI_SUCCESS) { + free_packagelist(hii); + return EFI_EXIT(ret); + } + + hii->driver_handle = driver_handle; + list_add_tail(&hii->link, &efi_package_lists); + *handle = hii; + + return EFI_EXIT(EFI_SUCCESS); +} + +static efi_status_t EFIAPI +remove_package_list(const struct efi_hii_database_protocol *this, + efi_hii_handle_t handle) +{ + struct efi_hii_packagelist *hii = handle; + + EFI_ENTRY("%p, %p", this, handle); + + if (!hii || hii->signature != hii_package_signature) + return EFI_EXIT(EFI_NOT_FOUND); + + free_packagelist(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) +{ + struct efi_hii_packagelist *hii = handle; + struct efi_hii_package_header *package; + void *end; + efi_status_t ret = EFI_SUCCESS; + + EFI_ENTRY("%p, %p, %p", this, handle, package_list); + + if (!hii || hii->signature != hii_package_signature) + return EFI_EXIT(EFI_NOT_FOUND); + + if (!package_list) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + debug("package_list: %pUl (%u)\n", &package_list->package_list_guid, + package_list->package_length); + + package = ((void *)package_list) + sizeof(*package_list); + end = ((void *)package_list) + package_list->package_length; + + while ((void *)package < end) { + debug("package=%p, package type=%x, length=%u\n", package, + efi_hii_package_type(package), + efi_hii_package_len(package)); + + switch (efi_hii_package_type(package)) { + case EFI_HII_PACKAGE_TYPE_GUID: + printf("\tGuid package not supported\n"); + ret = EFI_INVALID_PARAMETER; + break; + case EFI_HII_PACKAGE_FORMS: + printf("\tForm package not supported\n"); + ret = EFI_INVALID_PARAMETER; + break; + case EFI_HII_PACKAGE_STRINGS: + remove_strings_package(hii); + break; + case EFI_HII_PACKAGE_FONTS: + printf("\tFont package not supported\n"); + ret = EFI_INVALID_PARAMETER; + break; + case EFI_HII_PACKAGE_IMAGES: + printf("\tImage package not supported\n"); + ret = EFI_INVALID_PARAMETER; + break; + case EFI_HII_PACKAGE_SIMPLE_FONTS: + printf("\tSimple font package not supported\n"); + ret = EFI_INVALID_PARAMETER; + break; + case EFI_HII_PACKAGE_DEVICE_PATH: + printf("\tDevice path package not supported\n"); + ret = EFI_INVALID_PARAMETER; + break; + case EFI_HII_PACKAGE_KEYBOARD_LAYOUT: + printf("\tKeyboard layout package not supported\n"); + break; + case EFI_HII_PACKAGE_ANIMATIONS: + printf("\tAnimation package not supported\n"); + ret = EFI_INVALID_PARAMETER; + break; + case EFI_HII_PACKAGE_END: + goto out; + case EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN: + case EFI_HII_PACKAGE_TYPE_SYSTEM_END: + default: + break; + } + + /* TODO: partially destroy a package */ + if (ret != EFI_SUCCESS) + return EFI_EXIT(ret); + + package = ((void *)package) + + efi_hii_package_len(package); + } +out: + ret = add_packages(hii, package_list); + + return EFI_EXIT(ret); +} + +static efi_status_t EFIAPI +list_package_lists(const struct efi_hii_database_protocol *this, + u8 package_type, + const efi_guid_t *package_guid, + efi_uintn_t *handle_buffer_length, + efi_hii_handle_t *handle) +{ + struct efi_hii_packagelist *hii = + (struct efi_hii_packagelist *)handle; + int package_cnt, package_max; + efi_status_t ret = EFI_SUCCESS; + + EFI_ENTRY("%p, %u, %pUl, %p, %p", this, package_type, package_guid, + handle_buffer_length, handle); + + if (!handle_buffer_length || + (*handle_buffer_length && !handle)) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + if ((package_type != EFI_HII_PACKAGE_TYPE_GUID && package_guid) || + (package_type == EFI_HII_PACKAGE_TYPE_GUID && !package_guid)) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + debug("package type=%x, guid=%pUl, length=%lu\n", (int)package_type, + package_guid, *handle_buffer_length); + + package_cnt = 0; + package_max = *handle_buffer_length / sizeof(*handle); + list_for_each_entry(hii, &efi_package_lists, link) { + switch (package_type) { + case EFI_HII_PACKAGE_TYPE_ALL: + break; + case EFI_HII_PACKAGE_TYPE_GUID: + printf("\tGuid package not supported\n"); + ret = EFI_INVALID_PARAMETER; + continue; + case EFI_HII_PACKAGE_FORMS: + printf("\tForm package not supported\n"); + ret = EFI_INVALID_PARAMETER; + continue; + case EFI_HII_PACKAGE_STRINGS: + if (!list_empty(&hii->string_tables)) + break; + continue; + case EFI_HII_PACKAGE_FONTS: + printf("\tFont package not supported\n"); + ret = EFI_INVALID_PARAMETER; + continue; + case EFI_HII_PACKAGE_IMAGES: + printf("\tImage package not supported\n"); + ret = EFI_INVALID_PARAMETER; + continue; + case EFI_HII_PACKAGE_SIMPLE_FONTS: + printf("\tSimple font package not supported\n"); + ret = EFI_INVALID_PARAMETER; + continue; + case EFI_HII_PACKAGE_DEVICE_PATH: + printf("\tDevice path package not supported\n"); + ret = EFI_INVALID_PARAMETER; + continue; + case EFI_HII_PACKAGE_KEYBOARD_LAYOUT: + printf("\tKeyboard layout package not supported\n"); + continue; + case EFI_HII_PACKAGE_ANIMATIONS: + printf("\tAnimation package not supported\n"); + ret = EFI_INVALID_PARAMETER; + continue; + case EFI_HII_PACKAGE_END: + case EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN: + case EFI_HII_PACKAGE_TYPE_SYSTEM_END: + default: + continue; + } + + package_cnt++; + if (package_cnt <= package_max) + *handle++ = hii; + else + ret = EFI_BUFFER_TOO_SMALL; + } + *handle_buffer_length = package_cnt * sizeof(*handle); + + return EFI_EXIT(ret); +} + +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); + + if (!buffer_size || (buffer_size && !buffer)) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + return EFI_EXIT(EFI_NOT_FOUND); +} + +static efi_status_t EFIAPI +register_package_notify(const struct efi_hii_database_protocol *this, + u8 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); + + if (!notify_handle) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + if ((package_type != EFI_HII_PACKAGE_TYPE_GUID && package_guid) || + (package_type == EFI_HII_PACKAGE_TYPE_GUID && !package_guid)) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + 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, + u16 *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); +} + +static efi_status_t EFIAPI +get_keyboard_layout(const struct efi_hii_database_protocol *this, + efi_guid_t *key_guid, + u16 *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) +{ + struct efi_hii_packagelist *hii; + + EFI_ENTRY("%p, %p, %p", this, package_list_handle, driver_handle); + + if (!driver_handle) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + list_for_each_entry(hii, &efi_package_lists, link) { + if (hii == package_list_handle) { + *driver_handle = hii->driver_handle; + return EFI_EXIT(EFI_SUCCESS); + } + } + + return EFI_EXIT(EFI_NOT_FOUND); +} + +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 +}; + +/* + * EFI_HII_STRING_PROTOCOL + */ + +static bool language_match(char *language, char *languages) +{ + char *p, *endp; + + p = languages; + while (*p) { + endp = strchr(p, ';'); + if (!endp) + return !strcmp(language, p); + + if (!strncmp(language, p, endp - p)) + return true; + + p = endp + 1; + } + + return false; +} + +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 u8 *language, + const u16 *language_name, + const efi_string_t string, + const struct efi_font_info *string_font_info) +{ + struct efi_hii_packagelist *hii = package_list; + struct efi_string_table *stbl; + + EFI_ENTRY("%p, %p, %p, "%s", %p, "%ls", %p", this, package_list, + string_id, language, language_name, string, + string_font_info); + + if (!hii || hii->signature != hii_package_signature) + return EFI_EXIT(EFI_NOT_FOUND); + + if (!string_id || !language || !string) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + list_for_each_entry(stbl, &hii->string_tables, link) { + if (language_match((char *)language, stbl->language)) { + efi_string_id_t new_id; + void *buf; + efi_string_t str; + + new_id = ++hii->max_string_id; + if (stbl->nstrings < new_id) { + buf = realloc(stbl->strings, + sizeof(stbl->strings[0]) + * new_id); + if (!buf) + return EFI_EXIT(EFI_OUT_OF_RESOURCES); + + memset(&stbl->strings[stbl->nstrings], 0, + (new_id - stbl->nstrings) + * sizeof(stbl->strings[0])); + stbl->strings = buf; + stbl->nstrings = new_id; + } + + str = u16_strdup(string); + if (!str) + return EFI_EXIT(EFI_OUT_OF_RESOURCES); + + stbl->strings[new_id - 1].string = str; + *string_id = new_id; + + return EFI_EXIT(EFI_SUCCESS); + } + } + + return EFI_EXIT(EFI_NOT_FOUND); +} + +static efi_status_t EFIAPI +get_string(const struct efi_hii_string_protocol *this, + const u8 *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 efi_hii_packagelist *hii = package_list; + struct efi_string_table *stbl; + + EFI_ENTRY("%p, "%s", %p, %u, %p, %p, %p", this, language, + package_list, string_id, string, string_size, + string_font_info); + + if (!hii || hii->signature != hii_package_signature) + return EFI_EXIT(EFI_NOT_FOUND); + + list_for_each_entry(stbl, &hii->string_tables, link) { + if (language_match((char *)language, stbl->language)) { + efi_string_t str; + size_t len; + + if (stbl->nstrings < string_id) + return EFI_EXIT(EFI_NOT_FOUND); + + str = stbl->strings[string_id - 1].string; + if (str) { + len = (u16_strlen(str) + 1) * sizeof(u16); + if (*string_size < len) { + *string_size = len; + + return EFI_EXIT(EFI_BUFFER_TOO_SMALL); + } + memcpy(string, str, len); + *string_size = len; + } else { + return EFI_EXIT(EFI_NOT_FOUND); + } + + 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 u8 *language, + const efi_string_t string, + const struct efi_font_info *string_font_info) +{ + struct efi_hii_packagelist *hii = package_list; + struct efi_string_table *stbl; + + EFI_ENTRY("%p, %p, %u, "%s", "%ls", %p", this, package_list, + string_id, language, string, string_font_info); + + if (!hii || hii->signature != hii_package_signature) + return EFI_EXIT(EFI_NOT_FOUND); + + if (string_id > hii->max_string_id) + return EFI_EXIT(EFI_NOT_FOUND); + + if (!string || !language) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + list_for_each_entry(stbl, &hii->string_tables, link) { + if (language_match((char *)language, stbl->language)) { + efi_string_t str; + + if (hii->max_string_id < string_id) + return EFI_EXIT(EFI_NOT_FOUND); + + if (stbl->nstrings < string_id) { + void *buf; + + buf = realloc(stbl->strings, + string_id + * sizeof(stbl->strings[0])); + if (!buf) + return EFI_EXIT(EFI_OUT_OF_RESOURCES); + + memset(&stbl->strings[string_id - 1], 0, + (string_id - stbl->nstrings) + * sizeof(stbl->strings[0])); + stbl->strings = buf; + } + + str = u16_strdup(string); + if (!str) + return EFI_EXIT(EFI_OUT_OF_RESOURCES); + + free(stbl->strings[string_id - 1].string); + stbl->strings[string_id - 1].string = str; + + return EFI_EXIT(EFI_SUCCESS); + } + } + + 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, + u8 *languages, + efi_uintn_t *languages_size) +{ + struct efi_hii_packagelist *hii = package_list; + struct efi_string_table *stbl; + size_t len = 0; + char *p; + + EFI_ENTRY("%p, %p, %p, %p", this, package_list, languages, + languages_size); + + if (!hii || hii->signature != hii_package_signature) + return EFI_EXIT(EFI_NOT_FOUND); + + if (!languages_size || + (*languages_size && !languages)) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + /* 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); + } + + 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 u8 *primary_language, + u8 *secondary_languages, + efi_uintn_t *secondary_languages_size) +{ + struct efi_hii_packagelist *hii = package_list; + struct efi_string_table *stbl; + bool found = false; + + EFI_ENTRY("%p, %p, "%s", %p, %p", this, package_list, + primary_language, secondary_languages, + secondary_languages_size); + + if (!hii || hii->signature != hii_package_signature) + return EFI_EXIT(EFI_NOT_FOUND); + + if (!secondary_languages_size || + (*secondary_languages_size && !secondary_languages)) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + list_for_each_entry(stbl, &hii->string_tables, link) { + if (language_match((char *)primary_language, stbl->language)) { + found = true; + break; + } + } + if (!found) + return EFI_EXIT(EFI_INVALID_LANGUAGE); + + /* + * TODO: What is secondary language? + * *secondary_languages = '\0'; + * *secondary_languages_size = 0; + */ + + return EFI_EXIT(EFI_NOT_FOUND); +} + +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 +};

On 12/14/18 11:10 AM, AKASHI Takahiro wrote:
From: Leif Lindholm leif.lindholm@linaro.org
This patch provides enough implementation of the following protocols to run EDKII's Shell.efi and UEFI SCT:
- EfiHiiDatabaseProtocol
- EfiHiiStringProtocol
Not implemented are:
- ExportPackageLists()
- RegisterPackageNotify()/UnregisterPackageNotify()
- SetKeyboardLayout() (i.e. *current* keyboard layout)
HII database protocol can handle only:
- GUID package
- string package
- keyboard layout package
(The other packages, except Device path package, will be necessary for interactive and graphical UI.)
We'll fill in the rest once SCT is running properly so we can validate the implementation against the conformance test suite.
Cc: Leif Lindholm leif.lindholm@linaro.org Signed-off-by: Rob Clark robdclark@gmail.com Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
include/efi_api.h | 242 ++++++++++ include/efi_loader.h | 4 + lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_boottime.c | 12 + lib/efi_loader/efi_hii.c | 886 ++++++++++++++++++++++++++++++++++ 5 files changed, 1145 insertions(+) create mode 100644 lib/efi_loader/efi_hii.c
diff --git a/include/efi_api.h b/include/efi_api.h index aef77b6319de..c9dbd5a6037d 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -17,6 +17,7 @@ #define _EFI_API_H
#include <efi.h> +#include <charset.h>
#ifdef CONFIG_EFI_LOADER #include <asm/setjmp.h> @@ -697,6 +698,247 @@ struct efi_device_path_utilities_protocol { uint16_t node_length); };
+typedef u16 efi_string_id_t;
+#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;
The size of enum is not defined in the C standard. Please, use u32 or s32.
- u16 unicode;
- u16 shifted_unicode;
- u16 alt_gr_unicode;
- u16 shifted_alt_gr_unicode;
- u16 modifier;
- u16 affected_attribute;
+};
+struct efi_hii_keyboard_layout {
- u16 layout_length;
- efi_guid_t guid;
This structure is not packed correctly:
The UEFI spec defines EFI_GUID as a 128 bit buffer that is 64 bit aligned if not otherwise specified.
Our efi_guid_t is 8 bit aligned.
EDK2 has in base.h, UefiBaseType.h, and HiiDatabase.h:
/// /// 128 bit buffer containing a unique identifier value. /// Unless otherwise specified, aligned on a 64 bit boundary. /// typedef struct { UINT32 Data1; UINT16 Data2; UINT16 Data3; UINT8 Data4[8]; } GUID; typedef GUID EFI_GUID; typedef struct { UINT16 LayoutLength; EFI_GUID Guid; UINT32 LayoutDescriptorStringOffset; UINT8 DescriptorCount; // EFI_KEY_DESCRIPTOR Descriptors[]; } EFI_HII_KEYBOARD_LAYOUT;
For sure this EDK2 Guid is not 64bit aligned but 32bit aligned.
Same wrong 32bit alignment in GRUB: struct grub_efi_guid { grub_uint32_t data1; grub_uint16_t data2; grub_uint16_t data3; grub_uint8_t data4[8]; } __attribute__ ((aligned(8))); typedef struct grub_efi_guid grub_efi_guid_t;
Linux uses 8bit alignment: typedef struct { Â Â Â Â Â Â Â Â __u8 b[16]; } guid_t; typedef guid_t efi_guid_t;
There are other places where the same problem may hit us, cf. struct efi_configuration_table.
@Leif, Alex: Do you have a suggestion how we should clean up this mess?
Best regards
Heinrich

On Sat, Dec 15, 2018 at 09:48:19PM +0100, Heinrich Schuchardt wrote:
On 12/14/18 11:10 AM, AKASHI Takahiro wrote:
From: Leif Lindholm leif.lindholm@linaro.org
This patch provides enough implementation of the following protocols to run EDKII's Shell.efi and UEFI SCT:
- EfiHiiDatabaseProtocol
- EfiHiiStringProtocol
Not implemented are:
- ExportPackageLists()
- RegisterPackageNotify()/UnregisterPackageNotify()
- SetKeyboardLayout() (i.e. *current* keyboard layout)
HII database protocol can handle only:
- GUID package
- string package
- keyboard layout package
(The other packages, except Device path package, will be necessary for interactive and graphical UI.)
We'll fill in the rest once SCT is running properly so we can validate the implementation against the conformance test suite.
Cc: Leif Lindholm leif.lindholm@linaro.org Signed-off-by: Rob Clark robdclark@gmail.com Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
include/efi_api.h | 242 ++++++++++ include/efi_loader.h | 4 + lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_boottime.c | 12 + lib/efi_loader/efi_hii.c | 886 ++++++++++++++++++++++++++++++++++ 5 files changed, 1145 insertions(+) create mode 100644 lib/efi_loader/efi_hii.c
diff --git a/include/efi_api.h b/include/efi_api.h index aef77b6319de..c9dbd5a6037d 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -17,6 +17,7 @@ #define _EFI_API_H
#include <efi.h> +#include <charset.h>
#ifdef CONFIG_EFI_LOADER #include <asm/setjmp.h> @@ -697,6 +698,247 @@ struct efi_device_path_utilities_protocol { uint16_t node_length); };
+typedef u16 efi_string_id_t;
+#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;
The size of enum is not defined in the C standard. Please, use u32 or s32.
Good catch, thanks. We should not use any enum types in a struct for compatibility across architectures. UEFI spec v2.7a, however, makes definitions as exactly the same above. This could be misleading.
-Takahiro Akashi
- u16 unicode;
- u16 shifted_unicode;
- u16 alt_gr_unicode;
- u16 shifted_alt_gr_unicode;
- u16 modifier;
- u16 affected_attribute;
+};
+struct efi_hii_keyboard_layout {
- u16 layout_length;
- efi_guid_t guid;
This structure is not packed correctly:
The UEFI spec defines EFI_GUID as a 128 bit buffer that is 64 bit aligned if not otherwise specified.
Our efi_guid_t is 8 bit aligned.
EDK2 has in base.h, UefiBaseType.h, and HiiDatabase.h:
/// /// 128 bit buffer containing a unique identifier value. /// Unless otherwise specified, aligned on a 64 bit boundary. /// typedef struct { UINT32 Data1; UINT16 Data2; UINT16 Data3; UINT8 Data4[8]; } GUID; typedef GUID EFI_GUID; typedef struct { UINT16 LayoutLength; EFI_GUID Guid; UINT32 LayoutDescriptorStringOffset; UINT8 DescriptorCount; // EFI_KEY_DESCRIPTOR Descriptors[]; } EFI_HII_KEYBOARD_LAYOUT;
For sure this EDK2 Guid is not 64bit aligned but 32bit aligned.
Same wrong 32bit alignment in GRUB: struct grub_efi_guid { grub_uint32_t data1; grub_uint16_t data2; grub_uint16_t data3; grub_uint8_t data4[8]; } __attribute__ ((aligned(8))); typedef struct grub_efi_guid grub_efi_guid_t;
Linux uses 8bit alignment: typedef struct { Â Â Â Â Â Â Â Â __u8 b[16]; } guid_t; typedef guid_t efi_guid_t;
There are other places where the same problem may hit us, cf. struct efi_configuration_table.
@Leif, Alex: Do you have a suggestion how we should clean up this mess?
Best regards
Heinrich

On 12/14/18 11:10 AM, AKASHI Takahiro wrote:
From: Leif Lindholm leif.lindholm@linaro.org
This patch provides enough implementation of the following protocols to run EDKII's Shell.efi and UEFI SCT:
- EfiHiiDatabaseProtocol
- EfiHiiStringProtocol
Not implemented are:
- ExportPackageLists()
- RegisterPackageNotify()/UnregisterPackageNotify()
- SetKeyboardLayout() (i.e. *current* keyboard layout)
HII database protocol can handle only:
- GUID package
- string package
- keyboard layout package
(The other packages, except Device path package, will be necessary for interactive and graphical UI.)
We'll fill in the rest once SCT is running properly so we can validate the implementation against the conformance test suite.
Cc: Leif Lindholm leif.lindholm@linaro.org Signed-off-by: Rob Clark robdclark@gmail.com Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
include/efi_api.h | 242 ++++++++++ include/efi_loader.h | 4 + lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_boottime.c | 12 + lib/efi_loader/efi_hii.c | 886 ++++++++++++++++++++++++++++++++++ 5 files changed, 1145 insertions(+) create mode 100644 lib/efi_loader/efi_hii.c
diff --git a/include/efi_api.h b/include/efi_api.h index aef77b6319de..c9dbd5a6037d 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -17,6 +17,7 @@ #define _EFI_API_H
#include <efi.h> +#include <charset.h>
#ifdef CONFIG_EFI_LOADER #include <asm/setjmp.h> @@ -697,6 +698,247 @@ struct efi_device_path_utilities_protocol { uint16_t node_length); };
+typedef u16 efi_string_id_t;
+#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;
Hello Takahiro,
with the patch I can start the EFI shell. But I am still trying to check the different definitions in this file.
As mentioned in prior mail the size of enum is not defined in the C spec. So better use u32.
- u16 unicode;
- u16 shifted_unicode;
- u16 alt_gr_unicode;
- u16 shifted_alt_gr_unicode;
- u16 modifier;
- u16 affected_attribute;
+};
+struct efi_hii_keyboard_layout {
- u16 layout_length;
- efi_guid_t guid;
A patch to change the alignment of efi_guid_t to __alinged(8) has been merged into efi-next.
- u32 layout_descriptor_string_offset;
- u8 descriptor_count;
- struct efi_key_descriptor descriptors[];
+};
+struct efi_hii_package_list_header {
- efi_guid_t package_list_guid;
- u32 package_length;
+} __packed;
You are defining several structures as __packed. It is unclear to me where I can find this in the UEFI spec. Looking at EDK2 I could not find the same __packed attributes.
If this packing is necessary a comment in the code would be helpful.
+/**
- struct efi_hii_package_header - EFI HII package header
- @fields: 'fields' replaces the bit-fields defined in the EFI
specification to to avoid possible compiler incompatibilities::
u32 length:24;
u32 type:8;
- */
+struct efi_hii_package_header {
- u32 fields;
+} __packed;
Same here.
+#define __EFI_HII_PACKAGE_LEN_SHIFT 0 +#define __EFI_HII_PACKAGE_TYPE_SHIFT 24 +#define __EFI_HII_PACKAGE_LEN_MASK 0xffffff +#define __EFI_HII_PACKAGE_TYPE_MASK 0xff
+#define EFI_HII_PACKAGE_HEADER(header, field) \
(((header)->fields >> __EFI_HII_PACKAGE_##field##_SHIFT) \
& __EFI_HII_PACKAGE_##field##_MASK)
+#define efi_hii_package_len(header) \
EFI_HII_PACKAGE_HEADER(header, LEN)
+#define efi_hii_package_type(header) \
EFI_HII_PACKAGE_HEADER(header, TYPE)
+#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;
- u32 header_size;
- u32 string_info_offset;
- u16 language_window[16];
- efi_string_id_t language_name;
- u8 language[];
+} __packed;
Same here.
+struct efi_hii_string_block {
- u8 block_type;
- /* u8 block_body[]; */
+} __packed;
Same here.
Best regards
Heinrich

On Sun, Dec 16, 2018 at 09:36:38PM +0100, Heinrich Schuchardt wrote:
On 12/14/18 11:10 AM, AKASHI Takahiro wrote:
From: Leif Lindholm leif.lindholm@linaro.org
This patch provides enough implementation of the following protocols to run EDKII's Shell.efi and UEFI SCT:
- EfiHiiDatabaseProtocol
- EfiHiiStringProtocol
Not implemented are:
- ExportPackageLists()
- RegisterPackageNotify()/UnregisterPackageNotify()
- SetKeyboardLayout() (i.e. *current* keyboard layout)
HII database protocol can handle only:
- GUID package
- string package
- keyboard layout package
(The other packages, except Device path package, will be necessary for interactive and graphical UI.)
We'll fill in the rest once SCT is running properly so we can validate the implementation against the conformance test suite.
Cc: Leif Lindholm leif.lindholm@linaro.org Signed-off-by: Rob Clark robdclark@gmail.com Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
include/efi_api.h | 242 ++++++++++ include/efi_loader.h | 4 + lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_boottime.c | 12 + lib/efi_loader/efi_hii.c | 886 ++++++++++++++++++++++++++++++++++ 5 files changed, 1145 insertions(+) create mode 100644 lib/efi_loader/efi_hii.c
diff --git a/include/efi_api.h b/include/efi_api.h index aef77b6319de..c9dbd5a6037d 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -17,6 +17,7 @@ #define _EFI_API_H
#include <efi.h> +#include <charset.h>
#ifdef CONFIG_EFI_LOADER #include <asm/setjmp.h> @@ -697,6 +698,247 @@ struct efi_device_path_utilities_protocol { uint16_t node_length); };
+typedef u16 efi_string_id_t;
+#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;
Hello Takahiro,
with the patch I can start the EFI shell. But I am still trying to check the different definitions in this file.
As mentioned in prior mail the size of enum is not defined in the C spec. So better use u32.
Sure, but I still wonder whether this should be u32 or u16 (or even u8) as UEFI spec doesn't clearly define this.
- u16 unicode;
- u16 shifted_unicode;
- u16 alt_gr_unicode;
- u16 shifted_alt_gr_unicode;
- u16 modifier;
- u16 affected_attribute;
+};
+struct efi_hii_keyboard_layout {
- u16 layout_length;
- efi_guid_t guid;
A patch to change the alignment of efi_guid_t to __alinged(8) has been merged into efi-next.
I have one concern here; This structure will also be used as a data format/layout in a file, a package list, given the fact that UEFI defines ExportPackageLists(). So extra six bytes after layout_length, for example, may not be very useful in general. I'm not very much sure if UEFI spec intends so.
- u32 layout_descriptor_string_offset;
- u8 descriptor_count;
- struct efi_key_descriptor descriptors[];
+};
+struct efi_hii_package_list_header {
- efi_guid_t package_list_guid;
- u32 package_length;
+} __packed;
You are defining several structures as __packed. It is unclear to me where I can find this in the UEFI spec. Looking at EDK2 I could not find the same __packed attributes.
To be honest, I don't know. I just copied these lines from the original patch from Leif & Rob. My guess here is that such data structures are also used as data formats/layouts as part of a package list in a *file* and that no paddings are necessary. Same as I explained above.
# Same comments to yours below.
I hope that Leif will confirm (or deny) it.
Thanks, -Takahiro Akashi
If this packing is necessary a comment in the code would be helpful.
+/**
- struct efi_hii_package_header - EFI HII package header
- @fields: 'fields' replaces the bit-fields defined in the EFI
specification to to avoid possible compiler incompatibilities::
u32 length:24;
u32 type:8;
- */
+struct efi_hii_package_header {
- u32 fields;
+} __packed;
Same here.
+#define __EFI_HII_PACKAGE_LEN_SHIFT 0 +#define __EFI_HII_PACKAGE_TYPE_SHIFT 24 +#define __EFI_HII_PACKAGE_LEN_MASK 0xffffff +#define __EFI_HII_PACKAGE_TYPE_MASK 0xff
+#define EFI_HII_PACKAGE_HEADER(header, field) \
(((header)->fields >> __EFI_HII_PACKAGE_##field##_SHIFT) \
& __EFI_HII_PACKAGE_##field##_MASK)
+#define efi_hii_package_len(header) \
EFI_HII_PACKAGE_HEADER(header, LEN)
+#define efi_hii_package_type(header) \
EFI_HII_PACKAGE_HEADER(header, TYPE)
+#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;
- u32 header_size;
- u32 string_info_offset;
- u16 language_window[16];
- efi_string_id_t language_name;
- u8 language[];
+} __packed;
Same here.
+struct efi_hii_string_block {
- u8 block_type;
- /* u8 block_body[]; */
+} __packed;
Same here.
Best regards
Heinrich

On 17.12.18 02:16, AKASHI Takahiro wrote:
On Sun, Dec 16, 2018 at 09:36:38PM +0100, Heinrich Schuchardt wrote:
On 12/14/18 11:10 AM, AKASHI Takahiro wrote:
From: Leif Lindholm leif.lindholm@linaro.org
This patch provides enough implementation of the following protocols to run EDKII's Shell.efi and UEFI SCT:
- EfiHiiDatabaseProtocol
- EfiHiiStringProtocol
Not implemented are:
- ExportPackageLists()
- RegisterPackageNotify()/UnregisterPackageNotify()
- SetKeyboardLayout() (i.e. *current* keyboard layout)
HII database protocol can handle only:
- GUID package
- string package
- keyboard layout package
(The other packages, except Device path package, will be necessary for interactive and graphical UI.)
We'll fill in the rest once SCT is running properly so we can validate the implementation against the conformance test suite.
Cc: Leif Lindholm leif.lindholm@linaro.org Signed-off-by: Rob Clark robdclark@gmail.com Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
include/efi_api.h | 242 ++++++++++ include/efi_loader.h | 4 + lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_boottime.c | 12 + lib/efi_loader/efi_hii.c | 886 ++++++++++++++++++++++++++++++++++ 5 files changed, 1145 insertions(+) create mode 100644 lib/efi_loader/efi_hii.c
diff --git a/include/efi_api.h b/include/efi_api.h index aef77b6319de..c9dbd5a6037d 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -17,6 +17,7 @@ #define _EFI_API_H
#include <efi.h> +#include <charset.h>
#ifdef CONFIG_EFI_LOADER #include <asm/setjmp.h> @@ -697,6 +698,247 @@ struct efi_device_path_utilities_protocol { uint16_t node_length); };
+typedef u16 efi_string_id_t;
+#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;
Hello Takahiro,
with the patch I can start the EFI shell. But I am still trying to check the different definitions in this file.
As mentioned in prior mail the size of enum is not defined in the C spec. So better use u32.
Sure, but I still wonder whether this should be u32 or u16 (or even u8) as UEFI spec doesn't clearly define this.
Enums may hold up to INT_MAX, so just make it u32.
- u16 unicode;
- u16 shifted_unicode;
- u16 alt_gr_unicode;
- u16 shifted_alt_gr_unicode;
- u16 modifier;
- u16 affected_attribute;
+};
+struct efi_hii_keyboard_layout {
- u16 layout_length;
- efi_guid_t guid;
A patch to change the alignment of efi_guid_t to __alinged(8) has been merged into efi-next.
I have one concern here; This structure will also be used as a data format/layout in a file, a package list, given the fact that UEFI defines ExportPackageLists(). So extra six bytes after layout_length, for example, may not be very useful in general. I'm not very much sure if UEFI spec intends so.
I'm not sure I fully follow. We ideally should be compatible with edk2, no? So if the spec isn't clear, let's make sure we clarify the spec to the behavior edk2 exposes today.
- u32 layout_descriptor_string_offset;
- u8 descriptor_count;
- struct efi_key_descriptor descriptors[];
+};
+struct efi_hii_package_list_header {
- efi_guid_t package_list_guid;
- u32 package_length;
+} __packed;
You are defining several structures as __packed. It is unclear to me where I can find this in the UEFI spec. Looking at EDK2 I could not find the same __packed attributes.
To be honest, I don't know. I just copied these lines from the original patch from Leif & Rob. My guess here is that such data structures are also used as data formats/layouts as part of a package list in a *file* and that no paddings are necessary. Same as I explained above.
# Same comments to yours below.
I hope that Leif will confirm (or deny) it.
Leif? :)
Alex

On Sun, Dec 23, 2018 at 02:46:05AM +0100, Alexander Graf wrote:
On 17.12.18 02:16, AKASHI Takahiro wrote:
On Sun, Dec 16, 2018 at 09:36:38PM +0100, Heinrich Schuchardt wrote:
On 12/14/18 11:10 AM, AKASHI Takahiro wrote:
From: Leif Lindholm leif.lindholm@linaro.org
This patch provides enough implementation of the following protocols to run EDKII's Shell.efi and UEFI SCT:
- EfiHiiDatabaseProtocol
- EfiHiiStringProtocol
Not implemented are:
- ExportPackageLists()
- RegisterPackageNotify()/UnregisterPackageNotify()
- SetKeyboardLayout() (i.e. *current* keyboard layout)
HII database protocol can handle only:
- GUID package
- string package
- keyboard layout package
(The other packages, except Device path package, will be necessary for interactive and graphical UI.)
We'll fill in the rest once SCT is running properly so we can validate the implementation against the conformance test suite.
Cc: Leif Lindholm leif.lindholm@linaro.org Signed-off-by: Rob Clark robdclark@gmail.com Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
include/efi_api.h | 242 ++++++++++ include/efi_loader.h | 4 + lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_boottime.c | 12 + lib/efi_loader/efi_hii.c | 886 ++++++++++++++++++++++++++++++++++ 5 files changed, 1145 insertions(+) create mode 100644 lib/efi_loader/efi_hii.c
diff --git a/include/efi_api.h b/include/efi_api.h index aef77b6319de..c9dbd5a6037d 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -17,6 +17,7 @@ #define _EFI_API_H
#include <efi.h> +#include <charset.h>
#ifdef CONFIG_EFI_LOADER #include <asm/setjmp.h> @@ -697,6 +698,247 @@ struct efi_device_path_utilities_protocol { uint16_t node_length); };
+typedef u16 efi_string_id_t;
+#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;
Hello Takahiro,
with the patch I can start the EFI shell. But I am still trying to check the different definitions in this file.
As mentioned in prior mail the size of enum is not defined in the C spec. So better use u32.
Sure, but I still wonder whether this should be u32 or u16 (or even u8) as UEFI spec doesn't clearly define this.
Enums may hold up to INT_MAX, so just make it u32.
OK.
- u16 unicode;
- u16 shifted_unicode;
- u16 alt_gr_unicode;
- u16 shifted_alt_gr_unicode;
- u16 modifier;
- u16 affected_attribute;
+};
+struct efi_hii_keyboard_layout {
- u16 layout_length;
- efi_guid_t guid;
A patch to change the alignment of efi_guid_t to __alinged(8) has been merged into efi-next.
I have one concern here; This structure will also be used as a data format/layout in a file, a package list, given the fact that UEFI defines ExportPackageLists(). So extra six bytes after layout_length, for example, may not be very useful in general. I'm not very much sure if UEFI spec intends so.
I'm not sure I fully follow. We ideally should be compatible with edk2, no? So if the spec isn't clear, let's make sure we clarify the spec to the behavior edk2 exposes today.
I'm not sure that EDK2 is very careful about data alignment. Regarding guid, in MdePkg/Include/Base.h, /// /// 128 bit buffer containing a unique identifier value. /// Unless otherwise specified, aligned on a 64 bit boundary. /// typedef struct { UINT32 Data1; UINT16 Data2; UINT16 Data3; UINT8 Data4[8]; } GUID; in MdePkg/Include/Uefi/UefiBaseType.h, typedef GUID EFI_GUID;
There is no explicit "aligned()" attribute contrary to Heinrich's patch.
Regarding hii_keyboard_layout, in Include/Uefi/UefiInternalFormRepresentation.h, typedef struct { UINT16 LayoutLength; EFI_GUID Guid; UINT32 LayoutDescriptorStringOffset; UINT8 DescriptorCount; // EFI_KEY_DESCRIPTOR Descriptors[]; } EFI_HII_KEYBOARD_LAYOUT;
No "packed" attribute, so neither in my code.
- u32 layout_descriptor_string_offset;
- u8 descriptor_count;
- struct efi_key_descriptor descriptors[];
+};
+struct efi_hii_package_list_header {
- efi_guid_t package_list_guid;
- u32 package_length;
+} __packed;
You are defining several structures as __packed. It is unclear to me where I can find this in the UEFI spec. Looking at EDK2 I could not find the same __packed attributes.
To be honest, I don't know. I just copied these lines from the original patch from Leif & Rob. My guess here is that such data structures are also used as data formats/layouts as part of a package list in a *file* and that no paddings are necessary. Same as I explained above.
# Same comments to yours below.
I hope that Leif will confirm (or deny) it.
Leif? :)
I'd like to echo, "Leif?"
Thanks, -Takahiro Akashi
Alex

Apologies for late reply, back from holidays today.
On Tue, Dec 25, 2018 at 05:30:25PM +0900, AKASHI Takahiro wrote:
+struct efi_key_descriptor {
- efi_key key;
Hello Takahiro,
with the patch I can start the EFI shell. But I am still trying to check the different definitions in this file.
As mentioned in prior mail the size of enum is not defined in the C spec. So better use u32.
Sure, but I still wonder whether this should be u32 or u16 (or even u8) as UEFI spec doesn't clearly define this.
Enums may hold up to INT_MAX, so just make it u32.
OK.
- u16 unicode;
- u16 shifted_unicode;
- u16 alt_gr_unicode;
- u16 shifted_alt_gr_unicode;
- u16 modifier;
- u16 affected_attribute;
+};
+struct efi_hii_keyboard_layout {
- u16 layout_length;
- efi_guid_t guid;
A patch to change the alignment of efi_guid_t to __alinged(8) has been merged into efi-next.
I have one concern here; This structure will also be used as a data format/layout in a file, a package list, given the fact that UEFI defines ExportPackageLists(). So extra six bytes after layout_length, for example, may not be very useful in general. I'm not very much sure if UEFI spec intends so.
I'm not sure I fully follow. We ideally should be compatible with edk2, no? So if the spec isn't clear, let's make sure we clarify the spec to the behavior edk2 exposes today.
The spec cannot simply be changed to be incompatible with a previous version of the spec, regardless of what EDK2 happens to do. (But...)
I'm not sure that EDK2 is very careful about data alignment. Regarding guid, in MdePkg/Include/Base.h, /// /// 128 bit buffer containing a unique identifier value. /// Unless otherwise specified, aligned on a 64 bit boundary. /// typedef struct { UINT32 Data1; UINT16 Data2; UINT16 Data3; UINT8 Data4[8]; } GUID; in MdePkg/Include/Uefi/UefiBaseType.h, typedef GUID EFI_GUID;
There is no explicit "aligned()" attribute contrary to Heinrich's patch.
No, so the alignment when building for (any) ARM architecture will end up being 32-bit. Which I agree does not seem to live up to the specification's requirement on 64-bit alignment where nothing else is said.
Since, obviously, u-boot and edk2 disagreeing about the layout of structs that are exposed to external applications/drivers would defeat this whole exercise, I think we should start by taking this question to edk2-devel (which I have).
Regarding hii_keyboard_layout, in Include/Uefi/UefiInternalFormRepresentation.h, typedef struct { UINT16 LayoutLength; EFI_GUID Guid; UINT32 LayoutDescriptorStringOffset; UINT8 DescriptorCount; // EFI_KEY_DESCRIPTOR Descriptors[]; } EFI_HII_KEYBOARD_LAYOUT;
No "packed" attribute, so neither in my code.
There is a #pragma pack(1) near the start of this file and a #pragma pack() near the end.
Interestingly, UEFI 2.7a describes the EFI_HII_KEYBOARD_LAYOUT struct as containing the EFI_KEY_DESCRIPTOR array at the end, whereas the EDK2 code above has it commented it out. EDK2 itself treats the EFI_HII_KEYBOARD_LAYOUT as a header, which is discarded.
So, continuning the (But...) My understanding is this: - The EDK2 implementation does not conform to the specification; it completely packs the EFI_HII_KEYBOARD_LAYOUT, which the specification does not mention anything about. Since this code is well in the wild, and drivers tested against the current layout need to continuw eorking, I expect the only possible solution is to update the specification to say EFI_HII_KEYBOARD_LAYOUT must be packed. - The default EDK2 definition of GUID (and hence EFI_GUID) gives it a 32-bit alignment requirement also on 64-bit architectures. In practice, I expect this would only affect (some of the) GUIDs that are members of structs used in UEFI interfaces. But that may already be too common an occurrence to audit and address in EDK2. Does the spec need to change on this also?
Can the TianoCore MdeModulePkg Maintainers on cc please comment? (I also cc:d the other stewards as well as Ard, in case they have further input.)
- u32 layout_descriptor_string_offset;
- u8 descriptor_count;
- struct efi_key_descriptor descriptors[];
+};
+struct efi_hii_package_list_header {
- efi_guid_t package_list_guid;
- u32 package_length;
+} __packed;
You are defining several structures as __packed. It is unclear to me where I can find this in the UEFI spec. Looking at EDK2 I could not find the same __packed attributes.
To be honest, I don't know. I just copied these lines from the original patch from Leif & Rob. My guess here is that such data structures are also used as data formats/layouts as part of a package list in a *file* and that no paddings are necessary. Same as I explained above.
# Same comments to yours below.
I hope that Leif will confirm (or deny) it.
Leif? :)
I'd like to echo, "Leif?"
I think the __packed bits were added by Rob, presumably in order to get the Shell (built with EDK2 headers) working.
Regards,
Leif

On 01/07/19 15:09, Leif Lindholm wrote:
Apologies for late reply, back from holidays today.
I'm going to snip a whole lot of context below, since I have no idea what project this is about, and/or what files in that project (no diff hunk headers in the context). Judged from the address list, is this about u-boot perhaps? And adding type definitions to u-boot so they conform to the UEFI spec, and (assuming this "and" is possible) match edk2 practice?
My understanding is this:
- The EDK2 implementation does not conform to the specification; it completely packs the EFI_HII_KEYBOARD_LAYOUT, which the specification does not mention anything about. Since this code is well in the wild, and drivers tested against the current layout need to continuw eorking, I expect the only possible solution is to update the specification to say EFI_HII_KEYBOARD_LAYOUT must be packed.
I'm going to take a pass on this. :)
- The default EDK2 definition of GUID (and hence EFI_GUID) gives it a 32-bit alignment requirement also on 64-bit architectures. In practice, I expect this would only affect (some of the) GUIDs that are members of structs used in UEFI interfaces. But that may already be too common an occurrence to audit and address in EDK2. Does the spec need to change on this also?
The UEFI spec (v2.7) explicitly requires EFI_GUID to be 64-bit aligned, unless specified otherwise. See in "Table 5. Common UEFI Data Types":
EFI_GUID -- 128-bit buffer containing a unique identifier value. Unless otherwise specified, aligned on a 64-bit boundary.
Whether edk2 satisfies that, and if so, how (by chance / by general build flags), I don't know. The code says,
/// /// 128 bit buffer containing a unique identifier value. /// Unless otherwise specified, aligned on a 64 bit boundary. /// typedef struct { UINT32 Data1; UINT16 Data2; UINT16 Data3; UINT8 Data4[8]; } GUID;
I think there may have been an expectation in "MdePkg/Include/Base.h" that the supported compilers would automatically ensure the specified alignment, given the structure definition.
Thanks Laszlo

On Mon, Jan 07, 2019 at 07:29:47PM +0100, Laszlo Ersek wrote:
On 01/07/19 15:09, Leif Lindholm wrote:
Apologies for late reply, back from holidays today.
I'm going to snip a whole lot of context below, since I have no idea what project this is about, and/or what files in that project (no diff hunk headers in the context). Judged from the address list, is this about u-boot perhaps? And adding type definitions to u-boot so they conform to the UEFI spec, and (assuming this "and" is possible) match edk2 practice?
Well, the u-boot UEFI interface is what triggered the questions. And the answer is relevant to the people asking, so I kept the list on cc.
But I'm more concerned with regards to whether EDK2 is compliant, and what impacts this has on the spec if not.
My understanding is this:
- The EDK2 implementation does not conform to the specification; it completely packs the EFI_HII_KEYBOARD_LAYOUT, which the specification does not mention anything about. Since this code is well in the wild, and drivers tested against the current layout need to continuw eorking, I expect the only possible solution is to update the specification to say EFI_HII_KEYBOARD_LAYOUT must be packed.
I'm going to take a pass on this. :)
Be my guest :)
- The default EDK2 definition of GUID (and hence EFI_GUID) gives it a 32-bit alignment requirement also on 64-bit architectures. In practice, I expect this would only affect (some of the) GUIDs that are members of structs used in UEFI interfaces. But that may already be too common an occurrence to audit and address in EDK2. Does the spec need to change on this also?
The UEFI spec (v2.7) explicitly requires EFI_GUID to be 64-bit aligned, unless specified otherwise. See in "Table 5. Common UEFI Data Types":
EFI_GUID -- 128-bit buffer containing a unique identifier value. Unless otherwise specified, aligned on a 64-bit boundary.
Indeed.
Whether edk2 satisfies that, and if so, how (by chance / by general build flags), I don't know. The code says,
/// /// 128 bit buffer containing a unique identifier value. /// Unless otherwise specified, aligned on a 64 bit boundary. /// typedef struct { UINT32 Data1; UINT16 Data2; UINT16 Data3; UINT8 Data4[8]; } GUID;
I think there may have been an expectation in "MdePkg/Include/Base.h" that the supported compilers would automatically ensure the specified alignment, given the structure definition.
But that would be expecting things not only not guaranteed by C, but something there is no semantic information suggesting would be useful for the compiler to do above. C is quite explicit that the above would be given a 32-bit alignment requirement. The most aligned member is Data1, and its alignment is 32 bits.
Now, technically, it would be absolutely fine for this struct to be 32-but aligned, if the EFI_GUID typedef in MdePkg/Include/Uefi/UefiBaseType.h added this constraint. It does not.
/ Leif

On 01/07/19 20:22, Leif Lindholm wrote:
On Mon, Jan 07, 2019 at 07:29:47PM +0100, Laszlo Ersek wrote:
The UEFI spec (v2.7) explicitly requires EFI_GUID to be 64-bit aligned, unless specified otherwise. See in "Table 5. Common UEFI Data Types":
EFI_GUID -- 128-bit buffer containing a unique identifier value. Unless otherwise specified, aligned on a 64-bit boundary.
Indeed.
Whether edk2 satisfies that, and if so, how (by chance / by general build flags), I don't know. The code says,
/// /// 128 bit buffer containing a unique identifier value. /// Unless otherwise specified, aligned on a 64 bit boundary. /// typedef struct { UINT32 Data1; UINT16 Data2; UINT16 Data3; UINT8 Data4[8]; } GUID;
I think there may have been an expectation in "MdePkg/Include/Base.h" that the supported compilers would automatically ensure the specified alignment, given the structure definition.
But that would be expecting things not only not guaranteed by C, but something there is no semantic information suggesting would be useful for the compiler to do above. [...]
Agreed. I'm not saying the edk2 code is right, just guessing why the code might look like it does. This would not be the first silent assumption, I think.
Anyhow, I think it would be better to change the code than the spec.
Thanks, Laszlo

MdePkg/MdeModulePkg maintainers - any comments?
On Tue, Jan 08, 2019 at 01:28:00AM +0100, Laszlo Ersek wrote:
On 01/07/19 20:22, Leif Lindholm wrote:
On Mon, Jan 07, 2019 at 07:29:47PM +0100, Laszlo Ersek wrote:
The UEFI spec (v2.7) explicitly requires EFI_GUID to be 64-bit aligned, unless specified otherwise. See in "Table 5. Common UEFI Data Types":
EFI_GUID -- 128-bit buffer containing a unique identifier value. Unless otherwise specified, aligned on a 64-bit boundary.
Indeed.
Whether edk2 satisfies that, and if so, how (by chance / by general build flags), I don't know. The code says,
/// /// 128 bit buffer containing a unique identifier value. /// Unless otherwise specified, aligned on a 64 bit boundary. /// typedef struct { UINT32 Data1; UINT16 Data2; UINT16 Data3; UINT8 Data4[8]; } GUID;
I think there may have been an expectation in "MdePkg/Include/Base.h" that the supported compilers would automatically ensure the specified alignment, given the structure definition.
But that would be expecting things not only not guaranteed by C, but something there is no semantic information suggesting would be useful for the compiler to do above. [...]
Agreed. I'm not saying the edk2 code is right, just guessing why the code might look like it does. This would not be the first silent assumption, I think.
Anyhow, I think it would be better to change the code than the spec.
Of course it would be better to change the code than the spec.
But as Ard points out off-thread, doing (as a hack, with gcc)
diff --git a/MdePkg/Include/Uefi/UefiBaseType.h b/MdePkg/Include/Uefi/UefiBaseType.h index 8c9d571eb1..75409f3460 100644 --- a/MdePkg/Include/Uefi/UefiBaseType.h +++ b/MdePkg/Include/Uefi/UefiBaseType.h @@ -26,7 +26,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. /// /// 128-bit buffer containing a unique identifier value. /// -typedef GUID EFI_GUID; +typedef GUID EFI_GUID __attribute__((aligned (8))); /// /// Function return status for EFI API. ///
breaks Linux boot on ARM (32-bit), since it inserts 32-bits of padding between ConfigurationTable entries in the system table. So I don't see how that can realistically be fixed in the EDK2 codebase.
And with things like the EFI_HII_KEYBOARD_LAYOUT struct, if there has ever been compatibility between EDK2 and commercial BIOSes, then that struct has always been treated as packed (not just 32-bit aligned GUIDs), and the spec just needs to reflect reality. If there hasn't, then indeed the code change here would be trivial.
(Adding Liming as well, since we're now discussing MdePkg also.)
Yes, this discussion belongs on USWG (UEFI specification working group mailing list), but I want to hear some comment from the package maintainers first.
Either way, I see a bunch of new SCT tests coming up.
/ Leif

On Tue, 8 Jan 2019 at 10:51, Leif Lindholm leif.lindholm@linaro.org wrote:
MdePkg/MdeModulePkg maintainers - any comments?
On Tue, Jan 08, 2019 at 01:28:00AM +0100, Laszlo Ersek wrote:
On 01/07/19 20:22, Leif Lindholm wrote:
On Mon, Jan 07, 2019 at 07:29:47PM +0100, Laszlo Ersek wrote:
The UEFI spec (v2.7) explicitly requires EFI_GUID to be 64-bit aligned, unless specified otherwise. See in "Table 5. Common UEFI Data Types":
EFI_GUID -- 128-bit buffer containing a unique identifier value. Unless otherwise specified, aligned on a 64-bit boundary.
Indeed.
Whether edk2 satisfies that, and if so, how (by chance / by general build flags), I don't know. The code says,
/// /// 128 bit buffer containing a unique identifier value. /// Unless otherwise specified, aligned on a 64 bit boundary. /// typedef struct { UINT32 Data1; UINT16 Data2; UINT16 Data3; UINT8 Data4[8]; } GUID;
I think there may have been an expectation in "MdePkg/Include/Base.h" that the supported compilers would automatically ensure the specified alignment, given the structure definition.
But that would be expecting things not only not guaranteed by C, but something there is no semantic information suggesting would be useful for the compiler to do above. [...]
Agreed. I'm not saying the edk2 code is right, just guessing why the code might look like it does. This would not be the first silent assumption, I think.
Anyhow, I think it would be better to change the code than the spec.
Of course it would be better to change the code than the spec.
But as Ard points out off-thread, doing (as a hack, with gcc)
diff --git a/MdePkg/Include/Uefi/UefiBaseType.h b/MdePkg/Include/Uefi/UefiBaseType.h index 8c9d571eb1..75409f3460 100644 --- a/MdePkg/Include/Uefi/UefiBaseType.h +++ b/MdePkg/Include/Uefi/UefiBaseType.h @@ -26,7 +26,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. /// /// 128-bit buffer containing a unique identifier value. /// -typedef GUID EFI_GUID; +typedef GUID EFI_GUID __attribute__((aligned (8))); /// /// Function return status for EFI API. ///
breaks Linux boot on ARM (32-bit), since it inserts 32-bits of padding between ConfigurationTable entries in the system table. So I don't see how that can realistically be fixed in the EDK2 codebase.
And with things like the EFI_HII_KEYBOARD_LAYOUT struct, if there has ever been compatibility between EDK2 and commercial BIOSes, then that struct has always been treated as packed (not just 32-bit aligned GUIDs), and the spec just needs to reflect reality. If there hasn't, then indeed the code change here would be trivial.
(Adding Liming as well, since we're now discussing MdePkg also.)
Yes, this discussion belongs on USWG (UEFI specification working group mailing list), but I want to hear some comment from the package maintainers first.
Since we don't align EFI_GUIDs to 64 bits anywhere in the EDK2 code base, and given that it is always possible to relax a spec but not to tighten it without breaking backward compatibility, I think the only sane way to deal with this is to update the spec and/or any pertinent comments in the code to say that EFI_GUIDs are 32-bit aligned not 64-bit aligned.
That still leaves us with an issue in Linux, since efi_guid_t there has no minimal alignment, and runtime services code taking EFI_GUID pointers as input (such as Get/SetVariable) may assume they are 32-bit aligned (given the UINT32 member in the EDK2 definition) and thus assume it is safe to use load double/multiple instructions to access them (which will either fault or cause an alignment fixup to trigger if they are invoked with an unaligned memory address). But this is a different issue.

On 01/08/19 10:51, Leif Lindholm wrote:
MdePkg/MdeModulePkg maintainers - any comments?
On Tue, Jan 08, 2019 at 01:28:00AM +0100, Laszlo Ersek wrote:
On 01/07/19 20:22, Leif Lindholm wrote:
On Mon, Jan 07, 2019 at 07:29:47PM +0100, Laszlo Ersek wrote:
The UEFI spec (v2.7) explicitly requires EFI_GUID to be 64-bit aligned, unless specified otherwise. See in "Table 5. Common UEFI Data Types":
EFI_GUID -- 128-bit buffer containing a unique identifier value. Unless otherwise specified, aligned on a 64-bit boundary.
Indeed.
Whether edk2 satisfies that, and if so, how (by chance / by general build flags), I don't know. The code says,
/// /// 128 bit buffer containing a unique identifier value. /// Unless otherwise specified, aligned on a 64 bit boundary. /// typedef struct { UINT32 Data1; UINT16 Data2; UINT16 Data3; UINT8 Data4[8]; } GUID;
I think there may have been an expectation in "MdePkg/Include/Base.h" that the supported compilers would automatically ensure the specified alignment, given the structure definition.
But that would be expecting things not only not guaranteed by C, but something there is no semantic information suggesting would be useful for the compiler to do above. [...]
Agreed. I'm not saying the edk2 code is right, just guessing why the code might look like it does. This would not be the first silent assumption, I think.
Anyhow, I think it would be better to change the code than the spec.
Of course it would be better to change the code than the spec.
But as Ard points out off-thread, doing (as a hack, with gcc)
diff --git a/MdePkg/Include/Uefi/UefiBaseType.h b/MdePkg/Include/Uefi/UefiBaseType.h index 8c9d571eb1..75409f3460 100644 --- a/MdePkg/Include/Uefi/UefiBaseType.h +++ b/MdePkg/Include/Uefi/UefiBaseType.h @@ -26,7 +26,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. /// /// 128-bit buffer containing a unique identifier value. /// -typedef GUID EFI_GUID; +typedef GUID EFI_GUID __attribute__((aligned (8))); /// /// Function return status for EFI API. ///
breaks Linux boot on ARM (32-bit), since it inserts 32-bits of padding between ConfigurationTable entries in the system table.
(
More precisely, it adds padding to EFI_CONFIGURATION_TABLE after "VendorGuid" or after "VendorTable". Padding may not be added at the beginning of structures, and may not be added anywhere to arrays.
The practical effect is the same, so this is just a side comment about C.
)
Thanks Laszlo

EFI_GUID structure definition follows RFC UUID https://www.ietf.org/rfc/rfc4122.txt. This RFC has no 64 bit boundary requirement. I don't know the background why UEFI spec requires to align on 64-bit boundary. This may be true for early IPF arch. UEFI forum can clarify its purpose. If no specific reason, I suggest to follow the industry standard GUID format, and update UEFI spec.
On pack in structure EFI_HII_KEYBOARD_LAYOUT, UEFI2.7 32.3 Code Definitions has one sentence that this chapter describes the binary encoding of the different package types. 32.3.3 Font Package has the additional statement that structures described here are byte packed. Base on those description, we can infer HII package data is the byte packed. I agree to obviously specify that structures described here are byte packed in 32.3 section.
Last, EFI_HII_KEYBOARD_PACKAGE_HDR structure definition doesn't follow UEFI spec. I remember we ever meet with the compiler issue for below style. GCC49 may complaint it. I need to double confirm. typedef struct { EFI_HII_PACKAGE_HEADER Header; UINT16 LayoutCount; EFI_HII_KEYBOARD_LAYOUT Layout[]; } EFI_HII_KEYBOARD_PACKAGE_HDR;
Thanks Liming
-----Original Message----- From: Laszlo Ersek [mailto:lersek@redhat.com] Sent: Tuesday, January 8, 2019 7:56 PM To: Leif Lindholm leif.lindholm@linaro.org Cc: AKASHI Takahiro takahiro.akashi@linaro.org; Alexander Graf agraf@suse.de; Heinrich Schuchardt xypron.glpk@gmx.de; trini@konsulko.com; robdclark@gmail.com; u-boot@lists.denx.de; edk2-devel@lists.01.org; Wang, Jian J jian.j.wang@intel.com; Wu, Hao A hao.a.wu@intel.com; Ni, Ray ray.ni@intel.com; Zeng, Star star.zeng@intel.com; Andrew Fish afish@apple.com; Kinney, Michael D michael.d.kinney@intel.com; Ard Biesheuvel ard.biesheuvel@linaro.org; Gao, Liming liming.gao@intel.com Subject: Re: [RESEND PATCH v2 2/6] efi_loader: Initial HII database protocols
On 01/08/19 10:51, Leif Lindholm wrote:
MdePkg/MdeModulePkg maintainers - any comments?
On Tue, Jan 08, 2019 at 01:28:00AM +0100, Laszlo Ersek wrote:
On 01/07/19 20:22, Leif Lindholm wrote:
On Mon, Jan 07, 2019 at 07:29:47PM +0100, Laszlo Ersek wrote:
The UEFI spec (v2.7) explicitly requires EFI_GUID to be 64-bit aligned, unless specified otherwise. See in "Table 5. Common UEFI Data Types":
EFI_GUID -- 128-bit buffer containing a unique identifier value. Unless otherwise specified, aligned on a 64-bit boundary.
Indeed.
Whether edk2 satisfies that, and if so, how (by chance / by general build flags), I don't know. The code says,
/// /// 128 bit buffer containing a unique identifier value. /// Unless otherwise specified, aligned on a 64 bit boundary. /// typedef struct { UINT32 Data1; UINT16 Data2; UINT16 Data3; UINT8 Data4[8]; } GUID;
I think there may have been an expectation in "MdePkg/Include/Base.h" that the supported compilers would automatically ensure the specified alignment, given the structure definition.
But that would be expecting things not only not guaranteed by C, but something there is no semantic information suggesting would be useful for the compiler to do above. [...]
Agreed. I'm not saying the edk2 code is right, just guessing why the code might look like it does. This would not be the first silent assumption, I think.
Anyhow, I think it would be better to change the code than the spec.
Of course it would be better to change the code than the spec.
But as Ard points out off-thread, doing (as a hack, with gcc)
diff --git a/MdePkg/Include/Uefi/UefiBaseType.h b/MdePkg/Include/Uefi/UefiBaseType.h index 8c9d571eb1..75409f3460 100644 --- a/MdePkg/Include/Uefi/UefiBaseType.h +++ b/MdePkg/Include/Uefi/UefiBaseType.h @@ -26,7 +26,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. /// /// 128-bit buffer containing a unique identifier value. /// -typedef GUID EFI_GUID; +typedef GUID EFI_GUID __attribute__((aligned (8))); /// /// Function return status for EFI API. ///
breaks Linux boot on ARM (32-bit), since it inserts 32-bits of padding between ConfigurationTable entries in the system table.
(
More precisely, it adds padding to EFI_CONFIGURATION_TABLE after "VendorGuid" or after "VendorTable". Padding may not be added at the beginning of structures, and may not be added anywhere to arrays.
The practical effect is the same, so this is just a side comment about C.
)
Thanks Laszlo

Thanks Liming, this exactly the reply I was hoping for.
On Tue, Jan 08, 2019 at 03:12:11PM +0000, Gao, Liming wrote:
EFI_GUID structure definition follows RFC UUID https://www.ietf.org/rfc/rfc4122.txt. This RFC has no 64 bit boundary requirement. I don't know the background why UEFI spec requires to align on 64-bit boundary. This may be true for early IPF arch. UEFI forum can clarify its purpose. If no specific reason, I suggest to follow the industry standard GUID format, and update UEFI spec.
Since there would be no 64-bit alignment requirements for IPF either for correctness reasons, I expect it was added for performance reasons.
On pack in structure EFI_HII_KEYBOARD_LAYOUT, UEFI2.7 32.3 Code Definitions has one sentence that this chapter describes the binary encoding of the different package types. 32.3.3 Font Package has the additional statement that structures described here are byte packed. Base on those description, we can infer HII package data is the byte packed. I agree to obviously specify that structures described here are byte packed in 32.3 section.
That sounds good to me.
Last, EFI_HII_KEYBOARD_PACKAGE_HDR structure definition doesn't follow UEFI spec. I remember we ever meet with the compiler issue for below style. GCC49 may complaint it. I need to double confirm. typedef struct { EFI_HII_PACKAGE_HEADER Header; UINT16 LayoutCount; EFI_HII_KEYBOARD_LAYOUT Layout[]; } EFI_HII_KEYBOARD_PACKAGE_HDR;
I did remark on this to Ard, and he pointed out the old compiler issue. If I delete those comment markers, I cannot reproduce a problem with either GCC48 or GCC49 (on those actual compiler versions) on ARM.
Right, I will put together an email to USWG with you on cc.
Regards,
Leif
Thanks Liming
-----Original Message----- From: Laszlo Ersek [mailto:lersek@redhat.com] Sent: Tuesday, January 8, 2019 7:56 PM To: Leif Lindholm leif.lindholm@linaro.org Cc: AKASHI Takahiro takahiro.akashi@linaro.org; Alexander Graf agraf@suse.de; Heinrich Schuchardt xypron.glpk@gmx.de; trini@konsulko.com; robdclark@gmail.com; u-boot@lists.denx.de; edk2-devel@lists.01.org; Wang, Jian J jian.j.wang@intel.com; Wu, Hao A hao.a.wu@intel.com; Ni, Ray ray.ni@intel.com; Zeng, Star star.zeng@intel.com; Andrew Fish afish@apple.com; Kinney, Michael D michael.d.kinney@intel.com; Ard Biesheuvel ard.biesheuvel@linaro.org; Gao, Liming liming.gao@intel.com Subject: Re: [RESEND PATCH v2 2/6] efi_loader: Initial HII database protocols
On 01/08/19 10:51, Leif Lindholm wrote:
MdePkg/MdeModulePkg maintainers - any comments?
On Tue, Jan 08, 2019 at 01:28:00AM +0100, Laszlo Ersek wrote:
On 01/07/19 20:22, Leif Lindholm wrote:
On Mon, Jan 07, 2019 at 07:29:47PM +0100, Laszlo Ersek wrote:
The UEFI spec (v2.7) explicitly requires EFI_GUID to be 64-bit aligned, unless specified otherwise. See in "Table 5. Common UEFI Data Types":
EFI_GUID -- 128-bit buffer containing a unique identifier value. Unless otherwise specified, aligned on a 64-bit boundary.
Indeed.
Whether edk2 satisfies that, and if so, how (by chance / by general build flags), I don't know. The code says,
/// /// 128 bit buffer containing a unique identifier value. /// Unless otherwise specified, aligned on a 64 bit boundary. /// typedef struct { UINT32 Data1; UINT16 Data2; UINT16 Data3; UINT8 Data4[8]; } GUID;
I think there may have been an expectation in "MdePkg/Include/Base.h" that the supported compilers would automatically ensure the specified alignment, given the structure definition.
But that would be expecting things not only not guaranteed by C, but something there is no semantic information suggesting would be useful for the compiler to do above. [...]
Agreed. I'm not saying the edk2 code is right, just guessing why the code might look like it does. This would not be the first silent assumption, I think.
Anyhow, I think it would be better to change the code than the spec.
Of course it would be better to change the code than the spec.
But as Ard points out off-thread, doing (as a hack, with gcc)
diff --git a/MdePkg/Include/Uefi/UefiBaseType.h b/MdePkg/Include/Uefi/UefiBaseType.h index 8c9d571eb1..75409f3460 100644 --- a/MdePkg/Include/Uefi/UefiBaseType.h +++ b/MdePkg/Include/Uefi/UefiBaseType.h @@ -26,7 +26,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. /// /// 128-bit buffer containing a unique identifier value. /// -typedef GUID EFI_GUID; +typedef GUID EFI_GUID __attribute__((aligned (8))); /// /// Function return status for EFI API. ///
breaks Linux boot on ARM (32-bit), since it inserts 32-bits of padding between ConfigurationTable entries in the system table.
(
More precisely, it adds padding to EFI_CONFIGURATION_TABLE after "VendorGuid" or after "VendorTable". Padding may not be added at the beginning of structures, and may not be added anywhere to arrays.
The practical effect is the same, so this is just a side comment about C.
)
Thanks Laszlo

On 01/08/19 16:12, Gao, Liming wrote:
Last, EFI_HII_KEYBOARD_PACKAGE_HDR structure definition doesn't follow UEFI spec. I remember we ever meet with the compiler issue for below style. GCC49 may complaint it. I need to double confirm. typedef struct { EFI_HII_PACKAGE_HEADER Header; UINT16 LayoutCount; EFI_HII_KEYBOARD_LAYOUT Layout[]; } EFI_HII_KEYBOARD_PACKAGE_HDR;
This is called "flexible array member", and it was introduced in ISO C99. It is not part of the earlier C standards, and I quite expect several of the toolchains currently supported by edk2 to reject it.
Code written against earlier releases of the ISO C standard than C99 would use a construct colloquially called the "struct hack", such as
typedef struct { EFI_HII_PACKAGE_HEADER Header; UINT16 LayoutCount; EFI_HII_KEYBOARD_LAYOUT Layout[1]; } EFI_HII_KEYBOARD_PACKAGE_HDR;
indexing "Layout" with a subscript >= 1. Needless to say, that was always undefined behavior :) C99 introduced the flexible array member precisely for covering the "struct hack" use case with a well-defined construct.
There is no portable, pre-C99 way to actually spell out the Layout field in the structure definition, with the intended use case. The most portable approach I can think of would be:
- explain the trailing (nameless) array in a comment, - instruct programmers to write manual pointer-to-unsigned-char arithmetic, - once the necessary element is located, copy it into an object actually declared with the element type, and access it there.
In edk2 we sometimes do steps #1 and #2, which is OK. But, even in those cases, we almost never do step #3 (because it's both cumbersome and wastes cycles) -- instead, we favor type-punning.
Whenever I see that, I tell myself, "we disable the effective type rules with '-fno-strict-aliasing', so this should be fine, in practice. I hope anyway." :)
Thanks, Laszlo

-----Original Message----- From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of Leif Lindholm Sent: Tuesday, January 08, 2019 5:51 PM To: Laszlo Ersek lersek@redhat.com Cc: Ni, Ray ray.ni@intel.com; trini@konsulko.com; AKASHI Takahiro takahiro.akashi@linaro.org; Wu, Hao A hao.a.wu@intel.com; Heinrich Schuchardt xypron.glpk@gmx.de; edk2-devel@lists.01.org; Alexander Graf agraf@suse.de; Gao, Liming liming.gao@intel.com; u- boot@lists.denx.de; robdclark@gmail.com; Kinney, Michael D michael.d.kinney@intel.com; Zeng, Star star.zeng@intel.com Subject: Re: [edk2] [RESEND PATCH v2 2/6] efi_loader: Initial HII database protocols
MdePkg/MdeModulePkg maintainers - any comments?
On Tue, Jan 08, 2019 at 01:28:00AM +0100, Laszlo Ersek wrote:
On 01/07/19 20:22, Leif Lindholm wrote:
On Mon, Jan 07, 2019 at 07:29:47PM +0100, Laszlo Ersek wrote:
The UEFI spec (v2.7) explicitly requires EFI_GUID to be 64-bit aligned, unless specified otherwise. See in "Table 5. Common UEFI Data
Types":
EFI_GUID -- 128-bit buffer containing a unique identifier value. Unless otherwise specified, aligned on a 64-bit boundary.
Indeed.
Whether edk2 satisfies that, and if so, how (by chance / by general build flags), I don't know. The code says,
/// /// 128 bit buffer containing a unique identifier value. /// Unless otherwise specified, aligned on a 64 bit boundary. /// typedef struct { UINT32 Data1; UINT16 Data2; UINT16 Data3; UINT8 Data4[8]; } GUID;
I think there may have been an expectation in
"MdePkg/Include/Base.h"
that the supported compilers would automatically ensure the specified alignment, given the structure definition.
But that would be expecting things not only not guaranteed by C, but something there is no semantic information suggesting would be useful for the compiler to do above. [...]
Agreed. I'm not saying the edk2 code is right, just guessing why the code might look like it does. This would not be the first silent assumption, I think.
Anyhow, I think it would be better to change the code than the spec.
Of course it would be better to change the code than the spec.
But as Ard points out off-thread, doing (as a hack, with gcc)
diff --git a/MdePkg/Include/Uefi/UefiBaseType.h b/MdePkg/Include/Uefi/UefiBaseType.h index 8c9d571eb1..75409f3460 100644 --- a/MdePkg/Include/Uefi/UefiBaseType.h +++ b/MdePkg/Include/Uefi/UefiBaseType.h @@ -26,7 +26,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. /// /// 128-bit buffer containing a unique identifier value. /// -typedef GUID EFI_GUID; +typedef GUID EFI_GUID __attribute__((aligned (8))); /// /// Function return status for EFI API. ///
breaks Linux boot on ARM (32-bit), since it inserts 32-bits of padding between ConfigurationTable entries in the system table. So I don't see how that can realistically be fixed in the EDK2 codebase.
And with things like the EFI_HII_KEYBOARD_LAYOUT struct, if there has ever been compatibility between EDK2 and commercial BIOSes, then that struct has always been treated as packed (not just 32-bit aligned GUIDs), and the spec just needs to reflect reality. If there hasn't, then indeed the code change here would be trivial.
The structure definitions in Include/Uefi/UefiInternalFormRepresentation.h mainly describe the binary encoding of the different package types. And EFI_HII_KEYBOARD_LAYOUT struct is for the Keyboard Layout Package. Describing the *binary encoding* of the different package type, so I think we should treat them as packed and it also should be the reason why they are packed now. Maybe we can reflect this more clear in Spec.
(Adding Liming as well, since we're now discussing MdePkg also.)
Yes, this discussion belongs on USWG (UEFI specification working group mailing list), but I want to hear some comment from the package maintainers first.
Either way, I see a bunch of new SCT tests coming up.
/ Leif _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel

On 12/14/18 11:10 AM, AKASHI Takahiro wrote:
From: Leif Lindholm leif.lindholm@linaro.org
This patch provides enough implementation of the following protocols to run EDKII's Shell.efi and UEFI SCT:
- EfiHiiDatabaseProtocol
- EfiHiiStringProtocol
Not implemented are:
- ExportPackageLists()
- RegisterPackageNotify()/UnregisterPackageNotify()
- SetKeyboardLayout() (i.e. *current* keyboard layout)
HII database protocol can handle only:
- GUID package
- string package
- keyboard layout package
(The other packages, except Device path package, will be necessary for interactive and graphical UI.)
We'll fill in the rest once SCT is running properly so we can validate the implementation against the conformance test suite.
Cc: Leif Lindholm leif.lindholm@linaro.org Signed-off-by: Rob Clark robdclark@gmail.com Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
include/efi_api.h | 242 ++++++++++ include/efi_loader.h | 4 + lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_boottime.c | 12 + lib/efi_loader/efi_hii.c | 886 ++++++++++++++++++++++++++++++++++ 5 files changed, 1145 insertions(+) create mode 100644 lib/efi_loader/efi_hii.c
diff --git a/include/efi_api.h b/include/efi_api.h index aef77b6319de..c9dbd5a6037d 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -17,6 +17,7 @@ #define _EFI_API_H
#include <efi.h> +#include <charset.h>
#ifdef CONFIG_EFI_LOADER #include <asm/setjmp.h> @@ -697,6 +698,247 @@ struct efi_device_path_utilities_protocol { uint16_t node_length); };
+typedef u16 efi_string_id_t;
+#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;
- u16 unicode;
- u16 shifted_unicode;
- u16 alt_gr_unicode;
- u16 shifted_alt_gr_unicode;
- u16 modifier;
- u16 affected_attribute;
+};
+struct efi_hii_keyboard_layout {
- u16 layout_length;
- efi_guid_t guid;
- u32 layout_descriptor_string_offset;
- u8 descriptor_count;
- struct efi_key_descriptor descriptors[];
+};
+struct efi_hii_package_list_header {
- efi_guid_t package_list_guid;
- u32 package_length;
+} __packed;
+/**
- struct efi_hii_package_header - EFI HII package header
- @fields: 'fields' replaces the bit-fields defined in the EFI
specification to to avoid possible compiler incompatibilities::
u32 length:24;
u32 type:8;
- */
+struct efi_hii_package_header {
- u32 fields;
+} __packed;
+#define __EFI_HII_PACKAGE_LEN_SHIFT 0 +#define __EFI_HII_PACKAGE_TYPE_SHIFT 24 +#define __EFI_HII_PACKAGE_LEN_MASK 0xffffff +#define __EFI_HII_PACKAGE_TYPE_MASK 0xff
+#define EFI_HII_PACKAGE_HEADER(header, field) \
(((header)->fields >> __EFI_HII_PACKAGE_##field##_SHIFT) \
& __EFI_HII_PACKAGE_##field##_MASK)
+#define efi_hii_package_len(header) \
EFI_HII_PACKAGE_HEADER(header, LEN)
+#define efi_hii_package_type(header) \
EFI_HII_PACKAGE_HEADER(header, TYPE)
+#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;
- u32 header_size;
- u32 string_info_offset;
- u16 language_window[16];
- efi_string_id_t language_name;
- u8 language[];
+} __packed;
+struct efi_hii_string_block {
- u8 block_type;
- /* u8 block_body[]; */
+} __packed;
+#define EFI_HII_SIBT_END 0x00 +#define EFI_HII_SIBT_STRING_SCSU 0x10 +#define EFI_HII_SIBT_STRING_SCSU_FONT 0x11 +#define EFI_HII_SIBT_STRINGS_SCSU 0x12 +#define EFI_HII_SIBT_STRINGS_SCSU_FONT 0x13 +#define EFI_HII_SIBT_STRING_UCS2 0x14 +#define EFI_HII_SIBT_STRING_UCS2_FONT 0x15 +#define EFI_HII_SIBT_STRINGS_UCS2 0x16 +#define EFI_HII_SIBT_STRINGS_UCS2_FONT 0x17 +#define EFI_HII_SIBT_DUPLICATE 0x20 +#define EFI_HII_SIBT_SKIP2 0x21 +#define EFI_HII_SIBT_SKIP1 0x22 +#define EFI_HII_SIBT_EXT1 0x30 +#define EFI_HII_SIBT_EXT2 0x31 +#define EFI_HII_SIBT_EXT4 0x32 +#define EFI_HII_SIBT_FONT 0x40
+struct efi_hii_sibt_string_ucs2_block {
- struct efi_hii_string_block header;
- u16 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) +
(u16_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,
u8 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,
u8 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,
u16 *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,
u16 *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 u32 efi_hii_font_style_t;
+struct efi_font_info {
- efi_hii_font_style_t font_style;
- u16 font_size;
- u16 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 u8 *language,
const u16 *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 u8 *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 u8 *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,
u8 *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 u8 *primary_language,
u8 *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) diff --git a/include/efi_loader.h b/include/efi_loader.h index 53f08161ab65..d4412d30bf6f 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -106,6 +106,8 @@ extern const struct efi_device_path_utilities_protocol /* Implementation of the EFI_UNICODE_COLLATION_PROTOCOL */ extern const struct efi_unicode_collation_protocol efi_unicode_collation_protocol; +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);
@@ -139,6 +141,8 @@ extern const efi_guid_t efi_file_system_info_guid; extern const efi_guid_t efi_guid_device_path_utilities_protocol; /* GUID of the Unicode collation protocol */ extern const efi_guid_t efi_guid_unicode_collation_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; diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 6703435947f2..e508481fdeeb 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -24,6 +24,7 @@ obj-y += efi_device_path.o obj-y += efi_device_path_to_text.o obj-y += efi_device_path_utilities.o obj-y += efi_file.o +obj-y += efi_hii.o obj-y += efi_image_loader.o obj-y += efi_memory.o obj-y += efi_root_node.o diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index cc9efbb0cbfd..ba2e1f652afe 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1558,6 +1558,18 @@ efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path, if (ret != EFI_SUCCESS) goto failure;
- ret = efi_add_protocol(&obj->header,
&efi_guid_hii_string_protocol,
(void *)&efi_hii_string);
- if (ret != EFI_SUCCESS)
goto failure;
- ret = efi_add_protocol(&obj->header,
&efi_guid_hii_database_protocol,
(void *)&efi_hii_database);
- if (ret != EFI_SUCCESS)
goto failure;
- return ret;
failure: printf("ERROR: Failure to install protocols for loaded image\n"); diff --git a/lib/efi_loader/efi_hii.c b/lib/efi_loader/efi_hii.c new file mode 100644 index 000000000000..40034c27473d --- /dev/null +++ b/lib/efi_loader/efi_hii.c @@ -0,0 +1,886 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- EFI Human Interface Infrastructure ... database and packages
- Copyright (c) 2017 Leif Lindholm
- Copyright (c) 2018 AKASHI Takahiro, Linaro Limited
- */
+#include <common.h> +#include <malloc.h> +#include <efi_loader.h>
+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;
+const u32 hii_package_signature = 0x68696770; /* "higp" */
+static LIST_HEAD(efi_package_lists);
+struct efi_hii_packagelist {
- struct list_head link;
- u32 signature;
- // TODO should there be an associated efi_object?
- efi_handle_t driver_handle;
- u32 max_string_id;
- struct list_head string_tables; /* list of efi_string_table */
- /* we could also track fonts, images, etc */
+};
+struct efi_string_info {
- efi_string_t string;
- /* we could also track font info, etc */
+};
+struct efi_string_table {
- struct list_head link;
- efi_string_id_t language_name;
- char *language;
- u32 nstrings;
- /*
* NOTE:
* string id starts at 1 so value is stbl->strings[id-1],
* and strings[] is a array of stbl->nstrings elements
*/
- struct efi_string_info *strings;
+};
+static void free_strings_table(struct efi_string_table *stbl) +{
- int i;
- for (i = 0; i < stbl->nstrings; i++)
free(stbl->strings[i].string);
- free(stbl->strings);
- free(stbl->language);
- free(stbl);
+}
+static void remove_strings_package(struct efi_hii_packagelist *hii) +{
- while (!list_empty(&hii->string_tables)) {
struct efi_string_table *stbl;
stbl = list_first_entry(&hii->string_tables,
struct efi_string_table, link);
list_del(&stbl->link);
free_strings_table(stbl);
- }
+}
+static efi_status_t +add_strings_package(struct efi_hii_packagelist *hii,
struct efi_hii_strings_package *strings_package)
+{
- struct efi_hii_string_block *block;
- void *end;
- u32 nstrings = 0, idx = 0;
- struct efi_string_table *stbl = NULL;
- efi_status_t ret;
- 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;
- end = ((void *)strings_package)
+ efi_hii_package_len(&strings_package->header);
- while ((void *)block < end) {
switch (block->block_type) {
case EFI_HII_SIBT_STRING_UCS2: {
struct efi_hii_sibt_string_ucs2_block *ucs2;
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;
}
- }
- stbl = calloc(sizeof(*stbl), 1);
- if (!stbl) {
ret = EFI_OUT_OF_RESOURCES;
goto error;
- }
- stbl->strings = calloc(sizeof(stbl->strings[0]), nstrings);
- if (!stbl->strings) {
ret = EFI_OUT_OF_RESOURCES;
goto error;
- }
- stbl->language_name = strings_package->language_name;
- stbl->language = strdup((char *)strings_package->language);
- if (!stbl->language) {
ret = EFI_OUT_OF_RESOURCES;
goto error;
- }
- stbl->nstrings = nstrings;
- /* and now parse string entries and populate efi_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;
ucs2 = (void *)block;
debug("%4u: \"%ls\"\n", idx + 1, ucs2->string_text);
stbl->strings[idx].string =
u16_strdup(ucs2->string_text);
if (!stbl->strings[idx].string) {
ret = EFI_OUT_OF_RESOURCES;
goto error;
}
idx++;
block = efi_hii_sibt_string_ucs2_block_next(ucs2);
break;
}
case EFI_HII_SIBT_END:
goto out;
default:
debug("unknown HII string block type: %02x\n",
block->block_type);
ret = EFI_INVALID_PARAMETER;
goto error;
}
- }
+out:
- list_add(&stbl->link, &hii->string_tables);
- if (hii->max_string_id < nstrings)
hii->max_string_id = nstrings;
- return EFI_SUCCESS;
+error:
- if (stbl) {
free(stbl->language);
if (idx > 0)
while (--idx >= 0)
free(stbl->strings[idx].string);
free(stbl->strings);
- }
- free(stbl);
- return ret;
+}
+static struct efi_hii_packagelist *new_packagelist(void) +{
- struct efi_hii_packagelist *hii;
- hii = malloc(sizeof(*hii));
- hii->signature = hii_package_signature;
- hii->max_string_id = 0;
- INIT_LIST_HEAD(&hii->string_tables);
- return hii;
+}
+static void free_packagelist(struct efi_hii_packagelist *hii) +{
- remove_strings_package(hii);
- list_del(&hii->link);
- free(hii);
+}
+static efi_status_t +add_packages(struct efi_hii_packagelist *hii,
const struct efi_hii_package_list_header *package_list)
+{
- struct efi_hii_package_header *package;
- void *end;
- efi_status_t ret = EFI_SUCCESS;
- 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,
efi_hii_package_type(package),
efi_hii_package_len(package));
switch (efi_hii_package_type(package)) {
case EFI_HII_PACKAGE_TYPE_GUID:
printf("\tGuid package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_FORMS:
printf("\tForm package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_STRINGS:
ret = add_strings_package(hii,
(struct efi_hii_strings_package *)package);
break;
case EFI_HII_PACKAGE_FONTS:
printf("\tFont package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_IMAGES:
printf("\tImage package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_SIMPLE_FONTS:
printf("\tSimple font package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_DEVICE_PATH:
printf("\tDevice path package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
printf("\tKeyboard layout package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_ANIMATIONS:
printf("\tAnimation package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_END:
goto out;
case EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN:
case EFI_HII_PACKAGE_TYPE_SYSTEM_END:
default:
break;
}
if (ret != EFI_SUCCESS)
return ret;
package = ((void *)package)
+ efi_hii_package_len(package);
- }
+out:
- // TODO in theory there is some notifications that should be sent..
- return EFI_SUCCESS;
+}
+/*
- 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)
+{
- struct efi_hii_packagelist *hii;
- efi_status_t ret;
- EFI_ENTRY("%p, %p, %p, %p", this, package_list, driver_handle, handle);
- if (!package_list || !handle)
return EFI_EXIT(EFI_INVALID_PARAMETER);
- hii = new_packagelist();
- if (!hii)
return EFI_EXIT(EFI_OUT_OF_RESOURCES);
- ret = add_packages(hii, package_list);
- if (ret != EFI_SUCCESS) {
free_packagelist(hii);
return EFI_EXIT(ret);
- }
- hii->driver_handle = driver_handle;
- list_add_tail(&hii->link, &efi_package_lists);
- *handle = hii;
- return EFI_EXIT(EFI_SUCCESS);
+}
+static efi_status_t EFIAPI +remove_package_list(const struct efi_hii_database_protocol *this,
efi_hii_handle_t handle)
+{
- struct efi_hii_packagelist *hii = handle;
- EFI_ENTRY("%p, %p", this, handle);
- if (!hii || hii->signature != hii_package_signature)
return EFI_EXIT(EFI_NOT_FOUND);
- free_packagelist(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)
+{
- struct efi_hii_packagelist *hii = handle;
- struct efi_hii_package_header *package;
- void *end;
- efi_status_t ret = EFI_SUCCESS;
- EFI_ENTRY("%p, %p, %p", this, handle, package_list);
- if (!hii || hii->signature != hii_package_signature)
return EFI_EXIT(EFI_NOT_FOUND);
- if (!package_list)
return EFI_EXIT(EFI_INVALID_PARAMETER);
- debug("package_list: %pUl (%u)\n", &package_list->package_list_guid,
package_list->package_length);
- package = ((void *)package_list) + sizeof(*package_list);
- end = ((void *)package_list) + package_list->package_length;
- while ((void *)package < end) {
debug("package=%p, package type=%x, length=%u\n", package,
efi_hii_package_type(package),
efi_hii_package_len(package));
switch (efi_hii_package_type(package)) {
case EFI_HII_PACKAGE_TYPE_GUID:
printf("\tGuid package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_FORMS:
printf("\tForm package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_STRINGS:
remove_strings_package(hii);
break;
case EFI_HII_PACKAGE_FONTS:
printf("\tFont package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_IMAGES:
printf("\tImage package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_SIMPLE_FONTS:
printf("\tSimple font package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_DEVICE_PATH:
printf("\tDevice path package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
printf("\tKeyboard layout package not supported\n");
break;
case EFI_HII_PACKAGE_ANIMATIONS:
printf("\tAnimation package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_END:
goto out;
case EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN:
case EFI_HII_PACKAGE_TYPE_SYSTEM_END:
default:
break;
}
/* TODO: partially destroy a package */
if (ret != EFI_SUCCESS)
return EFI_EXIT(ret);
package = ((void *)package)
+ efi_hii_package_len(package);
- }
+out:
- ret = add_packages(hii, package_list);
- return EFI_EXIT(ret);
+}
+static efi_status_t EFIAPI +list_package_lists(const struct efi_hii_database_protocol *this,
u8 package_type,
const efi_guid_t *package_guid,
efi_uintn_t *handle_buffer_length,
efi_hii_handle_t *handle)
+{
- struct efi_hii_packagelist *hii =
(struct efi_hii_packagelist *)handle;
- int package_cnt, package_max;
- efi_status_t ret = EFI_SUCCESS;
- EFI_ENTRY("%p, %u, %pUl, %p, %p", this, package_type, package_guid,
handle_buffer_length, handle);
- if (!handle_buffer_length ||
(*handle_buffer_length && !handle))
return EFI_EXIT(EFI_INVALID_PARAMETER);
- if ((package_type != EFI_HII_PACKAGE_TYPE_GUID && package_guid) ||
(package_type == EFI_HII_PACKAGE_TYPE_GUID && !package_guid))
return EFI_EXIT(EFI_INVALID_PARAMETER);
- debug("package type=%x, guid=%pUl, length=%lu\n", (int)package_type,
In file included from include/linux/bug.h:7, from include/common.h:22, from lib/efi_loader/efi_hii.c:9: lib/efi_loader/efi_hii.c: In function ‘list_package_lists’: lib/efi_loader/efi_hii.c:435:8: warning: format ‘%lu’ expects argument of type ‘long unsigned int’, but argument 4 has type ‘size_t’ {aka ‘unsigned int’} [-Wformat=] debug("package type=%x, guid=%pUl, length=%lu\n", (int)package_type, ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ include/linux/printk.h:37:21: note: in definition of macro ‘pr_fmt’ #define pr_fmt(fmt) fmt ^~~
You probably want to use %zu.
Best regards
Heirnich
package_guid, *handle_buffer_length);
- package_cnt = 0;
- package_max = *handle_buffer_length / sizeof(*handle);
- list_for_each_entry(hii, &efi_package_lists, link) {
switch (package_type) {
case EFI_HII_PACKAGE_TYPE_ALL:
break;
case EFI_HII_PACKAGE_TYPE_GUID:
printf("\tGuid package not supported\n");
ret = EFI_INVALID_PARAMETER;
continue;
case EFI_HII_PACKAGE_FORMS:
printf("\tForm package not supported\n");
ret = EFI_INVALID_PARAMETER;
continue;
case EFI_HII_PACKAGE_STRINGS:
if (!list_empty(&hii->string_tables))
break;
continue;
case EFI_HII_PACKAGE_FONTS:
printf("\tFont package not supported\n");
ret = EFI_INVALID_PARAMETER;
continue;
case EFI_HII_PACKAGE_IMAGES:
printf("\tImage package not supported\n");
ret = EFI_INVALID_PARAMETER;
continue;
case EFI_HII_PACKAGE_SIMPLE_FONTS:
printf("\tSimple font package not supported\n");
ret = EFI_INVALID_PARAMETER;
continue;
case EFI_HII_PACKAGE_DEVICE_PATH:
printf("\tDevice path package not supported\n");
ret = EFI_INVALID_PARAMETER;
continue;
case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
printf("\tKeyboard layout package not supported\n");
continue;
case EFI_HII_PACKAGE_ANIMATIONS:
printf("\tAnimation package not supported\n");
ret = EFI_INVALID_PARAMETER;
continue;
case EFI_HII_PACKAGE_END:
case EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN:
case EFI_HII_PACKAGE_TYPE_SYSTEM_END:
default:
continue;
}
package_cnt++;
if (package_cnt <= package_max)
*handle++ = hii;
else
ret = EFI_BUFFER_TOO_SMALL;
- }
- *handle_buffer_length = package_cnt * sizeof(*handle);
- return EFI_EXIT(ret);
+}
+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);
- if (!buffer_size || (buffer_size && !buffer))
return EFI_EXIT(EFI_INVALID_PARAMETER);
- return EFI_EXIT(EFI_NOT_FOUND);
+}
+static efi_status_t EFIAPI +register_package_notify(const struct efi_hii_database_protocol *this,
u8 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);
- if (!notify_handle)
return EFI_EXIT(EFI_INVALID_PARAMETER);
- if ((package_type != EFI_HII_PACKAGE_TYPE_GUID && package_guid) ||
(package_type == EFI_HII_PACKAGE_TYPE_GUID && !package_guid))
return EFI_EXIT(EFI_INVALID_PARAMETER);
- 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,
u16 *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);
+}
+static efi_status_t EFIAPI +get_keyboard_layout(const struct efi_hii_database_protocol *this,
efi_guid_t *key_guid,
u16 *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)
+{
- struct efi_hii_packagelist *hii;
- EFI_ENTRY("%p, %p, %p", this, package_list_handle, driver_handle);
- if (!driver_handle)
return EFI_EXIT(EFI_INVALID_PARAMETER);
- list_for_each_entry(hii, &efi_package_lists, link) {
if (hii == package_list_handle) {
*driver_handle = hii->driver_handle;
return EFI_EXIT(EFI_SUCCESS);
}
- }
- return EFI_EXIT(EFI_NOT_FOUND);
+}
+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
+};
+/*
- EFI_HII_STRING_PROTOCOL
- */
+static bool language_match(char *language, char *languages) +{
- char *p, *endp;
- p = languages;
- while (*p) {
endp = strchr(p, ';');
if (!endp)
return !strcmp(language, p);
if (!strncmp(language, p, endp - p))
return true;
p = endp + 1;
- }
- return false;
+}
+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 u8 *language,
const u16 *language_name,
const efi_string_t string,
const struct efi_font_info *string_font_info)
+{
- struct efi_hii_packagelist *hii = package_list;
- struct efi_string_table *stbl;
- EFI_ENTRY("%p, %p, %p, "%s", %p, "%ls", %p", this, package_list,
string_id, language, language_name, string,
string_font_info);
- if (!hii || hii->signature != hii_package_signature)
return EFI_EXIT(EFI_NOT_FOUND);
- if (!string_id || !language || !string)
return EFI_EXIT(EFI_INVALID_PARAMETER);
- list_for_each_entry(stbl, &hii->string_tables, link) {
if (language_match((char *)language, stbl->language)) {
efi_string_id_t new_id;
void *buf;
efi_string_t str;
new_id = ++hii->max_string_id;
if (stbl->nstrings < new_id) {
buf = realloc(stbl->strings,
sizeof(stbl->strings[0])
* new_id);
if (!buf)
return EFI_EXIT(EFI_OUT_OF_RESOURCES);
memset(&stbl->strings[stbl->nstrings], 0,
(new_id - stbl->nstrings)
* sizeof(stbl->strings[0]));
stbl->strings = buf;
stbl->nstrings = new_id;
}
str = u16_strdup(string);
if (!str)
return EFI_EXIT(EFI_OUT_OF_RESOURCES);
stbl->strings[new_id - 1].string = str;
*string_id = new_id;
return EFI_EXIT(EFI_SUCCESS);
}
- }
- return EFI_EXIT(EFI_NOT_FOUND);
+}
+static efi_status_t EFIAPI +get_string(const struct efi_hii_string_protocol *this,
const u8 *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 efi_hii_packagelist *hii = package_list;
- struct efi_string_table *stbl;
- EFI_ENTRY("%p, "%s", %p, %u, %p, %p, %p", this, language,
package_list, string_id, string, string_size,
string_font_info);
- if (!hii || hii->signature != hii_package_signature)
return EFI_EXIT(EFI_NOT_FOUND);
- list_for_each_entry(stbl, &hii->string_tables, link) {
if (language_match((char *)language, stbl->language)) {
efi_string_t str;
size_t len;
if (stbl->nstrings < string_id)
return EFI_EXIT(EFI_NOT_FOUND);
str = stbl->strings[string_id - 1].string;
if (str) {
len = (u16_strlen(str) + 1) * sizeof(u16);
if (*string_size < len) {
*string_size = len;
return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
}
memcpy(string, str, len);
*string_size = len;
} else {
return EFI_EXIT(EFI_NOT_FOUND);
}
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 u8 *language,
const efi_string_t string,
const struct efi_font_info *string_font_info)
+{
- struct efi_hii_packagelist *hii = package_list;
- struct efi_string_table *stbl;
- EFI_ENTRY("%p, %p, %u, "%s", "%ls", %p", this, package_list,
string_id, language, string, string_font_info);
- if (!hii || hii->signature != hii_package_signature)
return EFI_EXIT(EFI_NOT_FOUND);
- if (string_id > hii->max_string_id)
return EFI_EXIT(EFI_NOT_FOUND);
- if (!string || !language)
return EFI_EXIT(EFI_INVALID_PARAMETER);
- list_for_each_entry(stbl, &hii->string_tables, link) {
if (language_match((char *)language, stbl->language)) {
efi_string_t str;
if (hii->max_string_id < string_id)
return EFI_EXIT(EFI_NOT_FOUND);
if (stbl->nstrings < string_id) {
void *buf;
buf = realloc(stbl->strings,
string_id
* sizeof(stbl->strings[0]));
if (!buf)
return EFI_EXIT(EFI_OUT_OF_RESOURCES);
memset(&stbl->strings[string_id - 1], 0,
(string_id - stbl->nstrings)
* sizeof(stbl->strings[0]));
stbl->strings = buf;
}
str = u16_strdup(string);
if (!str)
return EFI_EXIT(EFI_OUT_OF_RESOURCES);
free(stbl->strings[string_id - 1].string);
stbl->strings[string_id - 1].string = str;
return EFI_EXIT(EFI_SUCCESS);
}
- }
- 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,
u8 *languages,
efi_uintn_t *languages_size)
+{
- struct efi_hii_packagelist *hii = package_list;
- struct efi_string_table *stbl;
- size_t len = 0;
- char *p;
- EFI_ENTRY("%p, %p, %p, %p", this, package_list, languages,
languages_size);
- if (!hii || hii->signature != hii_package_signature)
return EFI_EXIT(EFI_NOT_FOUND);
- if (!languages_size ||
(*languages_size && !languages))
return EFI_EXIT(EFI_INVALID_PARAMETER);
- /* 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);
- }
- 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 u8 *primary_language,
u8 *secondary_languages,
efi_uintn_t *secondary_languages_size)
+{
- struct efi_hii_packagelist *hii = package_list;
- struct efi_string_table *stbl;
- bool found = false;
- EFI_ENTRY("%p, %p, "%s", %p, %p", this, package_list,
primary_language, secondary_languages,
secondary_languages_size);
- if (!hii || hii->signature != hii_package_signature)
return EFI_EXIT(EFI_NOT_FOUND);
- if (!secondary_languages_size ||
(*secondary_languages_size && !secondary_languages))
return EFI_EXIT(EFI_INVALID_PARAMETER);
- list_for_each_entry(stbl, &hii->string_tables, link) {
if (language_match((char *)primary_language, stbl->language)) {
found = true;
break;
}
- }
- if (!found)
return EFI_EXIT(EFI_INVALID_LANGUAGE);
- /*
* TODO: What is secondary language?
* *secondary_languages = '\0';
* *secondary_languages_size = 0;
*/
- return EFI_EXIT(EFI_NOT_FOUND);
+}
+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
+};

On Tue, Dec 18, 2018 at 06:01:01PM +0100, Heinrich Schuchardt wrote:
On 12/14/18 11:10 AM, AKASHI Takahiro wrote:
From: Leif Lindholm leif.lindholm@linaro.org
This patch provides enough implementation of the following protocols to run EDKII's Shell.efi and UEFI SCT:
- EfiHiiDatabaseProtocol
- EfiHiiStringProtocol
Not implemented are:
- ExportPackageLists()
- RegisterPackageNotify()/UnregisterPackageNotify()
- SetKeyboardLayout() (i.e. *current* keyboard layout)
HII database protocol can handle only:
- GUID package
- string package
- keyboard layout package
(The other packages, except Device path package, will be necessary for interactive and graphical UI.)
We'll fill in the rest once SCT is running properly so we can validate the implementation against the conformance test suite.
Cc: Leif Lindholm leif.lindholm@linaro.org Signed-off-by: Rob Clark robdclark@gmail.com Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
include/efi_api.h | 242 ++++++++++ include/efi_loader.h | 4 + lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_boottime.c | 12 + lib/efi_loader/efi_hii.c | 886 ++++++++++++++++++++++++++++++++++ 5 files changed, 1145 insertions(+) create mode 100644 lib/efi_loader/efi_hii.c
diff --git a/include/efi_api.h b/include/efi_api.h index aef77b6319de..c9dbd5a6037d 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -17,6 +17,7 @@ #define _EFI_API_H
#include <efi.h> +#include <charset.h>
#ifdef CONFIG_EFI_LOADER #include <asm/setjmp.h> @@ -697,6 +698,247 @@ struct efi_device_path_utilities_protocol { uint16_t node_length); };
+typedef u16 efi_string_id_t;
+#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;
- u16 unicode;
- u16 shifted_unicode;
- u16 alt_gr_unicode;
- u16 shifted_alt_gr_unicode;
- u16 modifier;
- u16 affected_attribute;
+};
+struct efi_hii_keyboard_layout {
- u16 layout_length;
- efi_guid_t guid;
- u32 layout_descriptor_string_offset;
- u8 descriptor_count;
- struct efi_key_descriptor descriptors[];
+};
+struct efi_hii_package_list_header {
- efi_guid_t package_list_guid;
- u32 package_length;
+} __packed;
+/**
- struct efi_hii_package_header - EFI HII package header
- @fields: 'fields' replaces the bit-fields defined in the EFI
specification to to avoid possible compiler incompatibilities::
u32 length:24;
u32 type:8;
- */
+struct efi_hii_package_header {
- u32 fields;
+} __packed;
+#define __EFI_HII_PACKAGE_LEN_SHIFT 0 +#define __EFI_HII_PACKAGE_TYPE_SHIFT 24 +#define __EFI_HII_PACKAGE_LEN_MASK 0xffffff +#define __EFI_HII_PACKAGE_TYPE_MASK 0xff
+#define EFI_HII_PACKAGE_HEADER(header, field) \
(((header)->fields >> __EFI_HII_PACKAGE_##field##_SHIFT) \
& __EFI_HII_PACKAGE_##field##_MASK)
+#define efi_hii_package_len(header) \
EFI_HII_PACKAGE_HEADER(header, LEN)
+#define efi_hii_package_type(header) \
EFI_HII_PACKAGE_HEADER(header, TYPE)
+#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;
- u32 header_size;
- u32 string_info_offset;
- u16 language_window[16];
- efi_string_id_t language_name;
- u8 language[];
+} __packed;
+struct efi_hii_string_block {
- u8 block_type;
- /* u8 block_body[]; */
+} __packed;
+#define EFI_HII_SIBT_END 0x00 +#define EFI_HII_SIBT_STRING_SCSU 0x10 +#define EFI_HII_SIBT_STRING_SCSU_FONT 0x11 +#define EFI_HII_SIBT_STRINGS_SCSU 0x12 +#define EFI_HII_SIBT_STRINGS_SCSU_FONT 0x13 +#define EFI_HII_SIBT_STRING_UCS2 0x14 +#define EFI_HII_SIBT_STRING_UCS2_FONT 0x15 +#define EFI_HII_SIBT_STRINGS_UCS2 0x16 +#define EFI_HII_SIBT_STRINGS_UCS2_FONT 0x17 +#define EFI_HII_SIBT_DUPLICATE 0x20 +#define EFI_HII_SIBT_SKIP2 0x21 +#define EFI_HII_SIBT_SKIP1 0x22 +#define EFI_HII_SIBT_EXT1 0x30 +#define EFI_HII_SIBT_EXT2 0x31 +#define EFI_HII_SIBT_EXT4 0x32 +#define EFI_HII_SIBT_FONT 0x40
+struct efi_hii_sibt_string_ucs2_block {
- struct efi_hii_string_block header;
- u16 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) +
(u16_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,
u8 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,
u8 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,
u16 *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,
u16 *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 u32 efi_hii_font_style_t;
+struct efi_font_info {
- efi_hii_font_style_t font_style;
- u16 font_size;
- u16 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 u8 *language,
const u16 *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 u8 *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 u8 *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,
u8 *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 u8 *primary_language,
u8 *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) diff --git a/include/efi_loader.h b/include/efi_loader.h index 53f08161ab65..d4412d30bf6f 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -106,6 +106,8 @@ extern const struct efi_device_path_utilities_protocol /* Implementation of the EFI_UNICODE_COLLATION_PROTOCOL */ extern const struct efi_unicode_collation_protocol efi_unicode_collation_protocol; +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);
@@ -139,6 +141,8 @@ extern const efi_guid_t efi_file_system_info_guid; extern const efi_guid_t efi_guid_device_path_utilities_protocol; /* GUID of the Unicode collation protocol */ extern const efi_guid_t efi_guid_unicode_collation_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; diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 6703435947f2..e508481fdeeb 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -24,6 +24,7 @@ obj-y += efi_device_path.o obj-y += efi_device_path_to_text.o obj-y += efi_device_path_utilities.o obj-y += efi_file.o +obj-y += efi_hii.o obj-y += efi_image_loader.o obj-y += efi_memory.o obj-y += efi_root_node.o diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index cc9efbb0cbfd..ba2e1f652afe 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1558,6 +1558,18 @@ efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path, if (ret != EFI_SUCCESS) goto failure;
- ret = efi_add_protocol(&obj->header,
&efi_guid_hii_string_protocol,
(void *)&efi_hii_string);
- if (ret != EFI_SUCCESS)
goto failure;
- ret = efi_add_protocol(&obj->header,
&efi_guid_hii_database_protocol,
(void *)&efi_hii_database);
- if (ret != EFI_SUCCESS)
goto failure;
- return ret;
failure: printf("ERROR: Failure to install protocols for loaded image\n"); diff --git a/lib/efi_loader/efi_hii.c b/lib/efi_loader/efi_hii.c new file mode 100644 index 000000000000..40034c27473d --- /dev/null +++ b/lib/efi_loader/efi_hii.c @@ -0,0 +1,886 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- EFI Human Interface Infrastructure ... database and packages
- Copyright (c) 2017 Leif Lindholm
- Copyright (c) 2018 AKASHI Takahiro, Linaro Limited
- */
+#include <common.h> +#include <malloc.h> +#include <efi_loader.h>
+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;
+const u32 hii_package_signature = 0x68696770; /* "higp" */
+static LIST_HEAD(efi_package_lists);
+struct efi_hii_packagelist {
- struct list_head link;
- u32 signature;
- // TODO should there be an associated efi_object?
- efi_handle_t driver_handle;
- u32 max_string_id;
- struct list_head string_tables; /* list of efi_string_table */
- /* we could also track fonts, images, etc */
+};
+struct efi_string_info {
- efi_string_t string;
- /* we could also track font info, etc */
+};
+struct efi_string_table {
- struct list_head link;
- efi_string_id_t language_name;
- char *language;
- u32 nstrings;
- /*
* NOTE:
* string id starts at 1 so value is stbl->strings[id-1],
* and strings[] is a array of stbl->nstrings elements
*/
- struct efi_string_info *strings;
+};
+static void free_strings_table(struct efi_string_table *stbl) +{
- int i;
- for (i = 0; i < stbl->nstrings; i++)
free(stbl->strings[i].string);
- free(stbl->strings);
- free(stbl->language);
- free(stbl);
+}
+static void remove_strings_package(struct efi_hii_packagelist *hii) +{
- while (!list_empty(&hii->string_tables)) {
struct efi_string_table *stbl;
stbl = list_first_entry(&hii->string_tables,
struct efi_string_table, link);
list_del(&stbl->link);
free_strings_table(stbl);
- }
+}
+static efi_status_t +add_strings_package(struct efi_hii_packagelist *hii,
struct efi_hii_strings_package *strings_package)
+{
- struct efi_hii_string_block *block;
- void *end;
- u32 nstrings = 0, idx = 0;
- struct efi_string_table *stbl = NULL;
- efi_status_t ret;
- 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;
- end = ((void *)strings_package)
+ efi_hii_package_len(&strings_package->header);
- while ((void *)block < end) {
switch (block->block_type) {
case EFI_HII_SIBT_STRING_UCS2: {
struct efi_hii_sibt_string_ucs2_block *ucs2;
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;
}
- }
- stbl = calloc(sizeof(*stbl), 1);
- if (!stbl) {
ret = EFI_OUT_OF_RESOURCES;
goto error;
- }
- stbl->strings = calloc(sizeof(stbl->strings[0]), nstrings);
- if (!stbl->strings) {
ret = EFI_OUT_OF_RESOURCES;
goto error;
- }
- stbl->language_name = strings_package->language_name;
- stbl->language = strdup((char *)strings_package->language);
- if (!stbl->language) {
ret = EFI_OUT_OF_RESOURCES;
goto error;
- }
- stbl->nstrings = nstrings;
- /* and now parse string entries and populate efi_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;
ucs2 = (void *)block;
debug("%4u: \"%ls\"\n", idx + 1, ucs2->string_text);
stbl->strings[idx].string =
u16_strdup(ucs2->string_text);
if (!stbl->strings[idx].string) {
ret = EFI_OUT_OF_RESOURCES;
goto error;
}
idx++;
block = efi_hii_sibt_string_ucs2_block_next(ucs2);
break;
}
case EFI_HII_SIBT_END:
goto out;
default:
debug("unknown HII string block type: %02x\n",
block->block_type);
ret = EFI_INVALID_PARAMETER;
goto error;
}
- }
+out:
- list_add(&stbl->link, &hii->string_tables);
- if (hii->max_string_id < nstrings)
hii->max_string_id = nstrings;
- return EFI_SUCCESS;
+error:
- if (stbl) {
free(stbl->language);
if (idx > 0)
while (--idx >= 0)
free(stbl->strings[idx].string);
free(stbl->strings);
- }
- free(stbl);
- return ret;
+}
+static struct efi_hii_packagelist *new_packagelist(void) +{
- struct efi_hii_packagelist *hii;
- hii = malloc(sizeof(*hii));
- hii->signature = hii_package_signature;
- hii->max_string_id = 0;
- INIT_LIST_HEAD(&hii->string_tables);
- return hii;
+}
+static void free_packagelist(struct efi_hii_packagelist *hii) +{
- remove_strings_package(hii);
- list_del(&hii->link);
- free(hii);
+}
+static efi_status_t +add_packages(struct efi_hii_packagelist *hii,
const struct efi_hii_package_list_header *package_list)
+{
- struct efi_hii_package_header *package;
- void *end;
- efi_status_t ret = EFI_SUCCESS;
- 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,
efi_hii_package_type(package),
efi_hii_package_len(package));
switch (efi_hii_package_type(package)) {
case EFI_HII_PACKAGE_TYPE_GUID:
printf("\tGuid package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_FORMS:
printf("\tForm package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_STRINGS:
ret = add_strings_package(hii,
(struct efi_hii_strings_package *)package);
break;
case EFI_HII_PACKAGE_FONTS:
printf("\tFont package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_IMAGES:
printf("\tImage package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_SIMPLE_FONTS:
printf("\tSimple font package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_DEVICE_PATH:
printf("\tDevice path package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
printf("\tKeyboard layout package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_ANIMATIONS:
printf("\tAnimation package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_END:
goto out;
case EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN:
case EFI_HII_PACKAGE_TYPE_SYSTEM_END:
default:
break;
}
if (ret != EFI_SUCCESS)
return ret;
package = ((void *)package)
+ efi_hii_package_len(package);
- }
+out:
- // TODO in theory there is some notifications that should be sent..
- return EFI_SUCCESS;
+}
+/*
- 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)
+{
- struct efi_hii_packagelist *hii;
- efi_status_t ret;
- EFI_ENTRY("%p, %p, %p, %p", this, package_list, driver_handle, handle);
- if (!package_list || !handle)
return EFI_EXIT(EFI_INVALID_PARAMETER);
- hii = new_packagelist();
- if (!hii)
return EFI_EXIT(EFI_OUT_OF_RESOURCES);
- ret = add_packages(hii, package_list);
- if (ret != EFI_SUCCESS) {
free_packagelist(hii);
return EFI_EXIT(ret);
- }
- hii->driver_handle = driver_handle;
- list_add_tail(&hii->link, &efi_package_lists);
- *handle = hii;
- return EFI_EXIT(EFI_SUCCESS);
+}
+static efi_status_t EFIAPI +remove_package_list(const struct efi_hii_database_protocol *this,
efi_hii_handle_t handle)
+{
- struct efi_hii_packagelist *hii = handle;
- EFI_ENTRY("%p, %p", this, handle);
- if (!hii || hii->signature != hii_package_signature)
return EFI_EXIT(EFI_NOT_FOUND);
- free_packagelist(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)
+{
- struct efi_hii_packagelist *hii = handle;
- struct efi_hii_package_header *package;
- void *end;
- efi_status_t ret = EFI_SUCCESS;
- EFI_ENTRY("%p, %p, %p", this, handle, package_list);
- if (!hii || hii->signature != hii_package_signature)
return EFI_EXIT(EFI_NOT_FOUND);
- if (!package_list)
return EFI_EXIT(EFI_INVALID_PARAMETER);
- debug("package_list: %pUl (%u)\n", &package_list->package_list_guid,
package_list->package_length);
- package = ((void *)package_list) + sizeof(*package_list);
- end = ((void *)package_list) + package_list->package_length;
- while ((void *)package < end) {
debug("package=%p, package type=%x, length=%u\n", package,
efi_hii_package_type(package),
efi_hii_package_len(package));
switch (efi_hii_package_type(package)) {
case EFI_HII_PACKAGE_TYPE_GUID:
printf("\tGuid package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_FORMS:
printf("\tForm package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_STRINGS:
remove_strings_package(hii);
break;
case EFI_HII_PACKAGE_FONTS:
printf("\tFont package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_IMAGES:
printf("\tImage package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_SIMPLE_FONTS:
printf("\tSimple font package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_DEVICE_PATH:
printf("\tDevice path package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
printf("\tKeyboard layout package not supported\n");
break;
case EFI_HII_PACKAGE_ANIMATIONS:
printf("\tAnimation package not supported\n");
ret = EFI_INVALID_PARAMETER;
break;
case EFI_HII_PACKAGE_END:
goto out;
case EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN:
case EFI_HII_PACKAGE_TYPE_SYSTEM_END:
default:
break;
}
/* TODO: partially destroy a package */
if (ret != EFI_SUCCESS)
return EFI_EXIT(ret);
package = ((void *)package)
+ efi_hii_package_len(package);
- }
+out:
- ret = add_packages(hii, package_list);
- return EFI_EXIT(ret);
+}
+static efi_status_t EFIAPI +list_package_lists(const struct efi_hii_database_protocol *this,
u8 package_type,
const efi_guid_t *package_guid,
efi_uintn_t *handle_buffer_length,
efi_hii_handle_t *handle)
+{
- struct efi_hii_packagelist *hii =
(struct efi_hii_packagelist *)handle;
- int package_cnt, package_max;
- efi_status_t ret = EFI_SUCCESS;
- EFI_ENTRY("%p, %u, %pUl, %p, %p", this, package_type, package_guid,
handle_buffer_length, handle);
- if (!handle_buffer_length ||
(*handle_buffer_length && !handle))
return EFI_EXIT(EFI_INVALID_PARAMETER);
- if ((package_type != EFI_HII_PACKAGE_TYPE_GUID && package_guid) ||
(package_type == EFI_HII_PACKAGE_TYPE_GUID && !package_guid))
return EFI_EXIT(EFI_INVALID_PARAMETER);
- debug("package type=%x, guid=%pUl, length=%lu\n", (int)package_type,
In file included from include/linux/bug.h:7, from include/common.h:22, from lib/efi_loader/efi_hii.c:9: lib/efi_loader/efi_hii.c: In function ‘list_package_lists’: lib/efi_loader/efi_hii.c:435:8: warning: format ‘%lu’ expects argument of type ‘long unsigned int’, but argument 4 has type ‘size_t’ {aka ‘unsigned int’} [-Wformat=] debug("package type=%x, guid=%pUl, length=%lu\n", (int)package_type, ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ include/linux/printk.h:37:21: note: in definition of macro ‘pr_fmt’ #define pr_fmt(fmt) fmt ^~~
You probably want to use %zu.
On which architecture? Which version of compiler are you using? I haven't seen this warning before.
-Takahiro Akashi
Best regards
Heirnich
package_guid, *handle_buffer_length);
- package_cnt = 0;
- package_max = *handle_buffer_length / sizeof(*handle);
- list_for_each_entry(hii, &efi_package_lists, link) {
switch (package_type) {
case EFI_HII_PACKAGE_TYPE_ALL:
break;
case EFI_HII_PACKAGE_TYPE_GUID:
printf("\tGuid package not supported\n");
ret = EFI_INVALID_PARAMETER;
continue;
case EFI_HII_PACKAGE_FORMS:
printf("\tForm package not supported\n");
ret = EFI_INVALID_PARAMETER;
continue;
case EFI_HII_PACKAGE_STRINGS:
if (!list_empty(&hii->string_tables))
break;
continue;
case EFI_HII_PACKAGE_FONTS:
printf("\tFont package not supported\n");
ret = EFI_INVALID_PARAMETER;
continue;
case EFI_HII_PACKAGE_IMAGES:
printf("\tImage package not supported\n");
ret = EFI_INVALID_PARAMETER;
continue;
case EFI_HII_PACKAGE_SIMPLE_FONTS:
printf("\tSimple font package not supported\n");
ret = EFI_INVALID_PARAMETER;
continue;
case EFI_HII_PACKAGE_DEVICE_PATH:
printf("\tDevice path package not supported\n");
ret = EFI_INVALID_PARAMETER;
continue;
case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
printf("\tKeyboard layout package not supported\n");
continue;
case EFI_HII_PACKAGE_ANIMATIONS:
printf("\tAnimation package not supported\n");
ret = EFI_INVALID_PARAMETER;
continue;
case EFI_HII_PACKAGE_END:
case EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN:
case EFI_HII_PACKAGE_TYPE_SYSTEM_END:
default:
continue;
}
package_cnt++;
if (package_cnt <= package_max)
*handle++ = hii;
else
ret = EFI_BUFFER_TOO_SMALL;
- }
- *handle_buffer_length = package_cnt * sizeof(*handle);
- return EFI_EXIT(ret);
+}
+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);
- if (!buffer_size || (buffer_size && !buffer))
return EFI_EXIT(EFI_INVALID_PARAMETER);
- return EFI_EXIT(EFI_NOT_FOUND);
+}
+static efi_status_t EFIAPI +register_package_notify(const struct efi_hii_database_protocol *this,
u8 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);
- if (!notify_handle)
return EFI_EXIT(EFI_INVALID_PARAMETER);
- if ((package_type != EFI_HII_PACKAGE_TYPE_GUID && package_guid) ||
(package_type == EFI_HII_PACKAGE_TYPE_GUID && !package_guid))
return EFI_EXIT(EFI_INVALID_PARAMETER);
- 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,
u16 *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);
+}
+static efi_status_t EFIAPI +get_keyboard_layout(const struct efi_hii_database_protocol *this,
efi_guid_t *key_guid,
u16 *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)
+{
- struct efi_hii_packagelist *hii;
- EFI_ENTRY("%p, %p, %p", this, package_list_handle, driver_handle);
- if (!driver_handle)
return EFI_EXIT(EFI_INVALID_PARAMETER);
- list_for_each_entry(hii, &efi_package_lists, link) {
if (hii == package_list_handle) {
*driver_handle = hii->driver_handle;
return EFI_EXIT(EFI_SUCCESS);
}
- }
- return EFI_EXIT(EFI_NOT_FOUND);
+}
+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
+};
+/*
- EFI_HII_STRING_PROTOCOL
- */
+static bool language_match(char *language, char *languages) +{
- char *p, *endp;
- p = languages;
- while (*p) {
endp = strchr(p, ';');
if (!endp)
return !strcmp(language, p);
if (!strncmp(language, p, endp - p))
return true;
p = endp + 1;
- }
- return false;
+}
+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 u8 *language,
const u16 *language_name,
const efi_string_t string,
const struct efi_font_info *string_font_info)
+{
- struct efi_hii_packagelist *hii = package_list;
- struct efi_string_table *stbl;
- EFI_ENTRY("%p, %p, %p, "%s", %p, "%ls", %p", this, package_list,
string_id, language, language_name, string,
string_font_info);
- if (!hii || hii->signature != hii_package_signature)
return EFI_EXIT(EFI_NOT_FOUND);
- if (!string_id || !language || !string)
return EFI_EXIT(EFI_INVALID_PARAMETER);
- list_for_each_entry(stbl, &hii->string_tables, link) {
if (language_match((char *)language, stbl->language)) {
efi_string_id_t new_id;
void *buf;
efi_string_t str;
new_id = ++hii->max_string_id;
if (stbl->nstrings < new_id) {
buf = realloc(stbl->strings,
sizeof(stbl->strings[0])
* new_id);
if (!buf)
return EFI_EXIT(EFI_OUT_OF_RESOURCES);
memset(&stbl->strings[stbl->nstrings], 0,
(new_id - stbl->nstrings)
* sizeof(stbl->strings[0]));
stbl->strings = buf;
stbl->nstrings = new_id;
}
str = u16_strdup(string);
if (!str)
return EFI_EXIT(EFI_OUT_OF_RESOURCES);
stbl->strings[new_id - 1].string = str;
*string_id = new_id;
return EFI_EXIT(EFI_SUCCESS);
}
- }
- return EFI_EXIT(EFI_NOT_FOUND);
+}
+static efi_status_t EFIAPI +get_string(const struct efi_hii_string_protocol *this,
const u8 *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 efi_hii_packagelist *hii = package_list;
- struct efi_string_table *stbl;
- EFI_ENTRY("%p, "%s", %p, %u, %p, %p, %p", this, language,
package_list, string_id, string, string_size,
string_font_info);
- if (!hii || hii->signature != hii_package_signature)
return EFI_EXIT(EFI_NOT_FOUND);
- list_for_each_entry(stbl, &hii->string_tables, link) {
if (language_match((char *)language, stbl->language)) {
efi_string_t str;
size_t len;
if (stbl->nstrings < string_id)
return EFI_EXIT(EFI_NOT_FOUND);
str = stbl->strings[string_id - 1].string;
if (str) {
len = (u16_strlen(str) + 1) * sizeof(u16);
if (*string_size < len) {
*string_size = len;
return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
}
memcpy(string, str, len);
*string_size = len;
} else {
return EFI_EXIT(EFI_NOT_FOUND);
}
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 u8 *language,
const efi_string_t string,
const struct efi_font_info *string_font_info)
+{
- struct efi_hii_packagelist *hii = package_list;
- struct efi_string_table *stbl;
- EFI_ENTRY("%p, %p, %u, "%s", "%ls", %p", this, package_list,
string_id, language, string, string_font_info);
- if (!hii || hii->signature != hii_package_signature)
return EFI_EXIT(EFI_NOT_FOUND);
- if (string_id > hii->max_string_id)
return EFI_EXIT(EFI_NOT_FOUND);
- if (!string || !language)
return EFI_EXIT(EFI_INVALID_PARAMETER);
- list_for_each_entry(stbl, &hii->string_tables, link) {
if (language_match((char *)language, stbl->language)) {
efi_string_t str;
if (hii->max_string_id < string_id)
return EFI_EXIT(EFI_NOT_FOUND);
if (stbl->nstrings < string_id) {
void *buf;
buf = realloc(stbl->strings,
string_id
* sizeof(stbl->strings[0]));
if (!buf)
return EFI_EXIT(EFI_OUT_OF_RESOURCES);
memset(&stbl->strings[string_id - 1], 0,
(string_id - stbl->nstrings)
* sizeof(stbl->strings[0]));
stbl->strings = buf;
}
str = u16_strdup(string);
if (!str)
return EFI_EXIT(EFI_OUT_OF_RESOURCES);
free(stbl->strings[string_id - 1].string);
stbl->strings[string_id - 1].string = str;
return EFI_EXIT(EFI_SUCCESS);
}
- }
- 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,
u8 *languages,
efi_uintn_t *languages_size)
+{
- struct efi_hii_packagelist *hii = package_list;
- struct efi_string_table *stbl;
- size_t len = 0;
- char *p;
- EFI_ENTRY("%p, %p, %p, %p", this, package_list, languages,
languages_size);
- if (!hii || hii->signature != hii_package_signature)
return EFI_EXIT(EFI_NOT_FOUND);
- if (!languages_size ||
(*languages_size && !languages))
return EFI_EXIT(EFI_INVALID_PARAMETER);
- /* 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);
- }
- 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 u8 *primary_language,
u8 *secondary_languages,
efi_uintn_t *secondary_languages_size)
+{
- struct efi_hii_packagelist *hii = package_list;
- struct efi_string_table *stbl;
- bool found = false;
- EFI_ENTRY("%p, %p, "%s", %p, %p", this, package_list,
primary_language, secondary_languages,
secondary_languages_size);
- if (!hii || hii->signature != hii_package_signature)
return EFI_EXIT(EFI_NOT_FOUND);
- if (!secondary_languages_size ||
(*secondary_languages_size && !secondary_languages))
return EFI_EXIT(EFI_INVALID_PARAMETER);
- list_for_each_entry(stbl, &hii->string_tables, link) {
if (language_match((char *)primary_language, stbl->language)) {
found = true;
break;
}
- }
- if (!found)
return EFI_EXIT(EFI_INVALID_LANGUAGE);
- /*
* TODO: What is secondary language?
* *secondary_languages = '\0';
* *secondary_languages_size = 0;
*/
- return EFI_EXIT(EFI_NOT_FOUND);
+}
+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
+};

On 12/14/18 11:10 AM, AKASHI Takahiro wrote:
From: Leif Lindholm leif.lindholm@linaro.org
This patch provides enough implementation of the following protocols to run EDKII's Shell.efi and UEFI SCT:
- EfiHiiDatabaseProtocol
- EfiHiiStringProtocol
<snip>
+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);
- if (!buffer_size || (buffer_size && !buffer))
This can be simplified:
if (!buffer_size || !buffer))
Regards
Heinrich
return EFI_EXIT(EFI_INVALID_PARAMETER);
- return EFI_EXIT(EFI_NOT_FOUND);
+}

On Sun, Jan 06, 2019 at 04:57:49PM +0100, Heinrich Schuchardt wrote:
On 12/14/18 11:10 AM, AKASHI Takahiro wrote:
From: Leif Lindholm leif.lindholm@linaro.org
This patch provides enough implementation of the following protocols to run EDKII's Shell.efi and UEFI SCT:
- EfiHiiDatabaseProtocol
- EfiHiiStringProtocol
<snip>
+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);
- if (!buffer_size || (buffer_size && !buffer))
This can be simplified:
if (!buffer_size || !buffer))
OK.
-Takahiro Akashi
Regards
Heinrich
return EFI_EXIT(EFI_INVALID_PARAMETER);
- return EFI_EXIT(EFI_NOT_FOUND);
+}

Allow for handling GUID package in HII database protocol.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org --- include/efi_api.h | 9 ++++++++ lib/efi_loader/efi_hii.c | 48 +++++++++++++++++++++++++++++++++++----- 2 files changed, 51 insertions(+), 6 deletions(-)
diff --git a/include/efi_api.h b/include/efi_api.h index c9dbd5a6037d..7209f268c78f 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -835,6 +835,15 @@ efi_hii_sibt_string_ucs2_block_next(struct efi_hii_sibt_string_ucs2_block *blk) (u16_strlen(blk->string_text) + 1) * 2; }
+/* + * Guid package + */ +struct efi_hii_guid_package { + struct efi_hii_package_header header; + efi_guid_t guid; + char data[]; +} __packed; + typedef void *efi_hii_handle_t;
struct efi_hii_database_protocol { diff --git a/lib/efi_loader/efi_hii.c b/lib/efi_loader/efi_hii.c index 40034c27473d..036aa8eac956 100644 --- a/lib/efi_loader/efi_hii.c +++ b/lib/efi_loader/efi_hii.c @@ -25,6 +25,7 @@ struct efi_hii_packagelist { efi_handle_t driver_handle; u32 max_string_id; struct list_head string_tables; /* list of efi_string_table */ + struct list_head guid_list;
/* we could also track fonts, images, etc */ }; @@ -47,6 +48,11 @@ struct efi_string_table { struct efi_string_info *strings; };
+struct efi_guid_data { + struct list_head link; + struct efi_hii_guid_package package; +}; + static void free_strings_table(struct efi_string_table *stbl) { int i; @@ -178,6 +184,35 @@ error: return ret; }
+static void remove_guid_package(struct efi_hii_packagelist *hii) +{ + struct efi_guid_data *data; + + while (!list_empty(&hii->guid_list)) { + data = list_first_entry(&hii->guid_list, + struct efi_guid_data, link); + list_del(&data->link); + free(data); + } +} + +static efi_status_t +add_guid_package(struct efi_hii_packagelist *hii, + struct efi_hii_guid_package *package) +{ + struct efi_guid_data *data; + + data = calloc(sizeof(*data), 1); + if (!data) + return EFI_OUT_OF_RESOURCES; + + /* TODO: we don't know any about data field */ + memcpy(&data->package, package, sizeof(*package)); + list_add_tail(&data->link, &hii->guid_list); + + return EFI_SUCCESS; +} + static struct efi_hii_packagelist *new_packagelist(void) { struct efi_hii_packagelist *hii; @@ -186,6 +221,7 @@ static struct efi_hii_packagelist *new_packagelist(void) hii->signature = hii_package_signature; hii->max_string_id = 0; INIT_LIST_HEAD(&hii->string_tables); + INIT_LIST_HEAD(&hii->guid_list);
return hii; } @@ -193,6 +229,7 @@ static struct efi_hii_packagelist *new_packagelist(void) static void free_packagelist(struct efi_hii_packagelist *hii) { remove_strings_package(hii); + remove_guid_package(hii);
list_del(&hii->link); free(hii); @@ -219,8 +256,8 @@ add_packages(struct efi_hii_packagelist *hii,
switch (efi_hii_package_type(package)) { case EFI_HII_PACKAGE_TYPE_GUID: - printf("\tGuid package not supported\n"); - ret = EFI_INVALID_PARAMETER; + ret = add_guid_package(hii, + (struct efi_hii_guid_package *)package); break; case EFI_HII_PACKAGE_FORMS: printf("\tForm package not supported\n"); @@ -355,8 +392,7 @@ update_package_list(const struct efi_hii_database_protocol *this,
switch (efi_hii_package_type(package)) { case EFI_HII_PACKAGE_TYPE_GUID: - printf("\tGuid package not supported\n"); - ret = EFI_INVALID_PARAMETER; + remove_guid_package(hii); break; case EFI_HII_PACKAGE_FORMS: printf("\tForm package not supported\n"); @@ -442,8 +478,8 @@ list_package_lists(const struct efi_hii_database_protocol *this, case EFI_HII_PACKAGE_TYPE_ALL: break; case EFI_HII_PACKAGE_TYPE_GUID: - printf("\tGuid package not supported\n"); - ret = EFI_INVALID_PARAMETER; + if (!list_empty(&hii->guid_list)) + break; continue; case EFI_HII_PACKAGE_FORMS: printf("\tForm package not supported\n");

Allow for handling keyboard layout package in HII database protocol.
A package can be added or deleted in HII database protocol, but we don't set 'current' keyboard layout as there is no driver that requests a keyboard layout.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org --- include/efi_api.h | 11 +++ lib/efi_loader/efi_hii.c | 141 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 147 insertions(+), 5 deletions(-)
diff --git a/include/efi_api.h b/include/efi_api.h index 7209f268c78f..954d2414c5c7 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -844,6 +844,17 @@ struct efi_hii_guid_package { char data[]; } __packed;
+/* + * Keyboard layout package + */ + +struct efi_hii_keyboard_layout_package { + struct efi_hii_package_header header; + u8 layout_count; + u8 __pad; + struct efi_hii_keyboard_layout layout[]; +} __packed; + typedef void *efi_hii_handle_t;
struct efi_hii_database_protocol { diff --git a/lib/efi_loader/efi_hii.c b/lib/efi_loader/efi_hii.c index 036aa8eac956..fefe3a861387 100644 --- a/lib/efi_loader/efi_hii.c +++ b/lib/efi_loader/efi_hii.c @@ -17,6 +17,7 @@ const efi_guid_t efi_guid_hii_string_protocol = EFI_HII_STRING_PROTOCOL_GUID; const u32 hii_package_signature = 0x68696770; /* "higp" */
static LIST_HEAD(efi_package_lists); +static LIST_HEAD(efi_kb_layout_list);
struct efi_hii_packagelist { struct list_head link; @@ -26,6 +27,7 @@ struct efi_hii_packagelist { u32 max_string_id; struct list_head string_tables; /* list of efi_string_table */ struct list_head guid_list; + struct list_head kb_layout_packages;
/* we could also track fonts, images, etc */ }; @@ -53,6 +55,17 @@ struct efi_guid_data { struct efi_hii_guid_package package; };
+struct efi_kb_layout_data { + struct list_head link; /* in package */ + struct list_head link_sys; /* in global list */ + struct efi_hii_keyboard_layout kb_layout; +}; + +struct efi_kb_layout_package_data { + struct list_head link; /* in package_list */ + struct list_head kb_layout_list; +}; + static void free_strings_table(struct efi_string_table *stbl) { int i; @@ -213,6 +226,74 @@ add_guid_package(struct efi_hii_packagelist *hii, return EFI_SUCCESS; }
+static void free_keyboard_layouts(struct efi_kb_layout_package_data *package) +{ + struct efi_kb_layout_data *data; + + while (!list_empty(&package->kb_layout_list)) { + data = list_first_entry(&package->kb_layout_list, + struct efi_kb_layout_data, + link); + list_del(&data->link); + list_del(&data->link_sys); + free(data); + } +} + +static void remove_keyboard_layout_package(struct efi_hii_packagelist *hii) +{ + struct efi_kb_layout_package_data *package; + + while (!list_empty(&hii->kb_layout_packages)) { + package = list_first_entry(&hii->kb_layout_packages, + struct efi_kb_layout_package_data, + link); + free_keyboard_layouts(package); + list_del(&package->link); + free(package); + } +} + +static efi_status_t +add_keyboard_layout_package(struct efi_hii_packagelist *hii, + struct efi_hii_keyboard_layout_package + *kb_layout_package) +{ + struct efi_kb_layout_package_data *package; + struct efi_hii_keyboard_layout *layout; + struct efi_kb_layout_data *data; + int i; + + package = malloc(sizeof(*package)); + if (!package) + return EFI_OUT_OF_RESOURCES; + INIT_LIST_HEAD(&package->link); + INIT_LIST_HEAD(&package->kb_layout_list); + + layout = &kb_layout_package->layout[0]; + for (i = 0; i < kb_layout_package->layout_count; i++) { + data = malloc(sizeof(*data) + layout->layout_length); + if (!data) + goto out; + + memcpy(&data->kb_layout, layout, layout->layout_length); + list_add_tail(&data->link, &package->kb_layout_list); + list_add_tail(&data->link_sys, &efi_kb_layout_list); + + layout += layout->layout_length; + } + + list_add_tail(&package->link, &hii->kb_layout_packages); + + return EFI_SUCCESS; + +out: + free_keyboard_layouts(package); + free(package); + + return EFI_OUT_OF_RESOURCES; +} + static struct efi_hii_packagelist *new_packagelist(void) { struct efi_hii_packagelist *hii; @@ -222,6 +303,7 @@ static struct efi_hii_packagelist *new_packagelist(void) hii->max_string_id = 0; INIT_LIST_HEAD(&hii->string_tables); INIT_LIST_HEAD(&hii->guid_list); + INIT_LIST_HEAD(&hii->kb_layout_packages);
return hii; } @@ -230,6 +312,7 @@ static void free_packagelist(struct efi_hii_packagelist *hii) { remove_strings_package(hii); remove_guid_package(hii); + remove_keyboard_layout_package(hii);
list_del(&hii->link); free(hii); @@ -284,8 +367,9 @@ add_packages(struct efi_hii_packagelist *hii, ret = EFI_INVALID_PARAMETER; break; case EFI_HII_PACKAGE_KEYBOARD_LAYOUT: - printf("\tKeyboard layout package not supported\n"); - ret = EFI_INVALID_PARAMETER; + ret = add_keyboard_layout_package(hii, + (struct efi_hii_keyboard_layout_package *) + package); break; case EFI_HII_PACKAGE_ANIMATIONS: printf("\tAnimation package not supported\n"); @@ -418,7 +502,7 @@ update_package_list(const struct efi_hii_database_protocol *this, ret = EFI_INVALID_PARAMETER; break; case EFI_HII_PACKAGE_KEYBOARD_LAYOUT: - printf("\tKeyboard layout package not supported\n"); + remove_keyboard_layout_package(hii); break; case EFI_HII_PACKAGE_ANIMATIONS: printf("\tAnimation package not supported\n"); @@ -506,7 +590,8 @@ list_package_lists(const struct efi_hii_database_protocol *this, ret = EFI_INVALID_PARAMETER; continue; case EFI_HII_PACKAGE_KEYBOARD_LAYOUT: - printf("\tKeyboard layout package not supported\n"); + if (!list_empty(&hii->kb_layout_packages)) + break; continue; case EFI_HII_PACKAGE_ANIMATIONS: printf("\tAnimation package not supported\n"); @@ -580,9 +665,29 @@ find_keyboard_layouts(const struct efi_hii_database_protocol *this, u16 *key_guid_buffer_length, efi_guid_t *key_guid_buffer) { + struct efi_kb_layout_data *data; + int package_cnt, package_max; + efi_status_t ret = EFI_SUCCESS; + EFI_ENTRY("%p, %p, %p", this, key_guid_buffer_length, key_guid_buffer);
- return EFI_EXIT(EFI_NOT_FOUND); + if (!key_guid_buffer_length || + (*key_guid_buffer_length && !key_guid_buffer)) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + package_cnt = 0; + package_max = *key_guid_buffer_length / sizeof(*key_guid_buffer); + list_for_each_entry(data, &efi_kb_layout_list, link_sys) { + package_cnt++; + if (package_cnt <= package_max) + memcpy(key_guid_buffer++, &data->kb_layout.guid, + sizeof(*key_guid_buffer)); + else + ret = EFI_BUFFER_TOO_SMALL; + } + *key_guid_buffer_length = package_cnt * sizeof(*key_guid_buffer); + + return EFI_EXIT(ret); }
static efi_status_t EFIAPI @@ -591,10 +696,36 @@ get_keyboard_layout(const struct efi_hii_database_protocol *this, u16 *keyboard_layout_length, struct efi_hii_keyboard_layout *keyboard_layout) { + struct efi_kb_layout_data *data; + EFI_ENTRY("%p, %pUl, %p, %p", this, key_guid, keyboard_layout_length, keyboard_layout);
+ if (!keyboard_layout_length || + (*keyboard_layout_length && !keyboard_layout)) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + /* TODO: no notion of current keyboard layout */ + if (!key_guid) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + list_for_each_entry(data, &efi_kb_layout_list, link_sys) { + if (!guidcmp(&data->kb_layout.guid, key_guid)) + goto found; + } + return EFI_EXIT(EFI_NOT_FOUND); + +found: + if (*keyboard_layout_length < data->kb_layout.layout_length) { + *keyboard_layout_length = data->kb_layout.layout_length; + return EFI_EXIT(EFI_BUFFER_TOO_SMALL); + } + + memcpy(keyboard_layout, &data->kb_layout, + sizeof(data->kb_layout.layout_length)); + + return EFI_EXIT(EFI_SUCCESS); }
static efi_status_t EFIAPI

This patch is a place holder for HII configuration routing protocol and HII configuration access protocol.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org --- include/efi_api.h | 157 ++++++++++++++++++++++++++++++++ include/efi_loader.h | 4 + lib/efi_loader/Makefile | 2 +- lib/efi_loader/efi_boottime.c | 6 ++ lib/efi_loader/efi_hii_config.c | 146 +++++++++++++++++++++++++++++ 5 files changed, 314 insertions(+), 1 deletion(-) create mode 100644 lib/efi_loader/efi_hii_config.c
diff --git a/include/efi_api.h b/include/efi_api.h index 954d2414c5c7..9e929a58abf0 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -699,6 +699,163 @@ struct efi_device_path_utilities_protocol { };
typedef u16 efi_string_id_t; +typedef u16 efi_question_id_t; +typedef u16 efi_image_id_t; +typedef u16 efi_form_id_t; + +#define EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID \ + EFI_GUID(0x587e72d7, 0xcc50, 0x4f79, \ + 0x82, 0x09, 0xca, 0x29, 0x1f, 0xc1, 0xa1, 0x0f) + +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_CONFIG_ACCESS_PROTOCOL_GUID \ + EFI_GUID(0x330d4706, 0xf2a0, 0x4e4f, \ + 0xa3, 0x69, 0xb6, 0x6f, 0xa8, 0xd5, 0x43, 0x85) + +struct efi_hii_time { + u8 hour; + u8 minute; + u8 second; +}; + +struct efi_hii_date { + u16 year; + u8 month; + u8 day; +}; + +struct efi_hii_ref { + efi_question_id_t question_id; + efi_form_id_t form_id; + efi_guid_t form_set_guid; + efi_string_id_t device_path; +}; + +union efi_ifr_type_value { + u8 u8; // EFI_IFR_TYPE_NUM_SIZE_8 + u16 u16; // EFI_IFR_TYPE_NUM_SIZE_16 + u32 u32; // EFI_IFR_TYPE_NUM_SIZE_32 + u64 u64; // EFI_IFR_TYPE_NUM_SIZE_64 + bool b; // EFI_IFR_TYPE_BOOLEAN + struct efi_hii_time time; // EFI_IFR_TYPE_TIME + struct efi_hii_date date; // EFI_IFR_TYPE_DATE + efi_string_id_t string; // EFI_IFR_TYPE_STRING, EFI_IFR_TYPE_ACTION + struct efi_hii_ref ref; // EFI_IFR_TYPE_REF + // u8 buffer[]; // EFI_IFR_TYPE_BUFFER +}; + +#define EFI_IFR_TYPE_NUM_SIZE_8 0x00 +#define EFI_IFR_TYPE_NUM_SIZE_16 0x01 +#define EFI_IFR_TYPE_NUM_SIZE_32 0x02 +#define EFI_IFR_TYPE_NUM_SIZE_64 0x03 +#define EFI_IFR_TYPE_BOOLEAN 0x04 +#define EFI_IFR_TYPE_TIME 0x05 +#define EFI_IFR_TYPE_DATE 0x06 +#define EFI_IFR_TYPE_STRING 0x07 +#define EFI_IFR_TYPE_OTHER 0x08 +#define EFI_IFR_TYPE_UNDEFINED 0x09 +#define EFI_IFR_TYPE_ACTION 0x0A +#define EFI_IFR_TYPE_BUFFER 0x0B +#define EFI_IFR_TYPE_REF 0x0C +#define EFI_IFR_OPTION_DEFAULT 0x10 +#define EFI_IFR_OPTION_DEFAULT_MFG 0x20 + +#define EFI_IFR_ONE_OF_OPTION_OP 0x09 + +struct efi_ifr_op_header { + u8 opCode; + u8 length:7; + u8 scope:1; +}; + +struct efi_ifr_one_of_option { + struct efi_ifr_op_header header; + efi_string_id_t option; + u8 flags; + u8 type; + union efi_ifr_type_value value; +}; + +typedef efi_uintn_t efi_browser_action_t; + +#define EFI_BROWSER_ACTION_REQUEST_NONE 0 +#define EFI_BROWSER_ACTION_REQUEST_RESET 1 +#define EFI_BROWSER_ACTION_REQUEST_SUBMIT 2 +#define EFI_BROWSER_ACTION_REQUEST_EXIT 3 +#define EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT 4 +#define EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT 5 +#define EFI_BROWSER_ACTION_REQUEST_FORM_APPLY 6 +#define EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD 7 +#define EFI_BROWSER_ACTION_REQUEST_RECONNECT 8 + +typedef efi_uintn_t efi_browser_action_request_t; + +#define EFI_BROWSER_ACTION_CHANGING 0 +#define EFI_BROWSER_ACTION_CHANGED 1 +#define EFI_BROWSER_ACTION_RETRIEVE 2 +#define EFI_BROWSER_ACTION_FORM_OPEN 3 +#define EFI_BROWSER_ACTION_FORM_CLOSE 4 +#define EFI_BROWSER_ACTION_SUBMITTED 5 +#define EFI_BROWSER_ACTION_DEFAULT_STANDARD 0x1000 +#define EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING 0x1001 +#define EFI_BROWSER_ACTION_DEFAULT_SAFE 0x1002 +#define EFI_BROWSER_ACTION_DEFAULT_PLATFORM 0x2000 +#define EFI_BROWSER_ACTION_DEFAULT_HARDWARE 0x3000 +#define EFI_BROWSER_ACTION_DEFAULT_FIRMWARE 0x4000 + +struct efi_hii_config_access_protocol { + efi_status_t(EFIAPI *extract_config_access)( + const struct efi_hii_config_access_protocol *this, + const efi_string_t request, + efi_string_t *progress, + efi_string_t *results); + efi_status_t(EFIAPI *route_config_access)( + const struct efi_hii_config_access_protocol *this, + const efi_string_t configuration, + efi_string_t *progress); + efi_status_t(EFIAPI *form_callback)( + const struct efi_hii_config_access_protocol *this, + efi_browser_action_t action, + efi_question_id_t question_id, + u8 type, + union efi_ifr_type_value *value, + efi_browser_action_request_t *action_request); +};
#define EFI_HII_DATABASE_PROTOCOL_GUID \ EFI_GUID(0xef9fc172, 0xa1b2, 0x4693, \ diff --git a/include/efi_loader.h b/include/efi_loader.h index d4412d30bf6f..16633d6da0d5 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -106,6 +106,8 @@ extern const struct efi_device_path_utilities_protocol /* Implementation of the EFI_UNICODE_COLLATION_PROTOCOL */ extern const struct efi_unicode_collation_protocol efi_unicode_collation_protocol; +extern const struct efi_hii_config_routing_protocol efi_hii_config_routing; +extern const struct efi_hii_config_access_protocol efi_hii_config_access; extern const struct efi_hii_database_protocol efi_hii_database; extern const struct efi_hii_string_protocol efi_hii_string;
@@ -141,6 +143,8 @@ extern const efi_guid_t efi_file_system_info_guid; extern const efi_guid_t efi_guid_device_path_utilities_protocol; /* GUID of the Unicode collation protocol */ extern const efi_guid_t efi_guid_unicode_collation_protocol; +extern const efi_guid_t efi_guid_hii_config_routing_protocol; +extern const efi_guid_t efi_guid_hii_config_access_protocol; extern const efi_guid_t efi_guid_hii_database_protocol; extern const efi_guid_t efi_guid_hii_string_protocol;
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index e508481fdeeb..26b999bf7c51 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -24,7 +24,7 @@ obj-y += efi_device_path.o obj-y += efi_device_path_to_text.o obj-y += efi_device_path_utilities.o obj-y += efi_file.o -obj-y += efi_hii.o +obj-y += efi_hii.o efi_hii_config.o obj-y += efi_image_loader.o obj-y += efi_memory.o obj-y += efi_root_node.o diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index ba2e1f652afe..291bc1bd35f9 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1570,6 +1570,12 @@ efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path, if (ret != EFI_SUCCESS) goto failure;
+ ret = efi_add_protocol(&obj->header, + &efi_guid_hii_config_routing_protocol, + (void *)&efi_hii_config_routing); + if (ret != EFI_SUCCESS) + goto failure; + return ret; failure: printf("ERROR: Failure to install protocols for loaded image\n"); diff --git a/lib/efi_loader/efi_hii_config.c b/lib/efi_loader/efi_hii_config.c new file mode 100644 index 000000000000..f4b1f026c1bd --- /dev/null +++ b/lib/efi_loader/efi_hii_config.c @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * EFI Human Interface Infrastructure ... Configuration + * + * Copyright (c) 2017 Leif Lindholm + * Copyright (c) 2018 AKASHI Takahiro, Linaro Limited + */ + +#include <common.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_config_access_protocol + = EFI_HII_CONFIG_ACCESS_PROTOCOL_GUID; + +/* + * 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 u8 *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 u8 *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_ACCESS_PROTOCOL + */ + +efi_status_t EFIAPI +extract_config_access(const struct efi_hii_config_access_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); +}; + +efi_status_t EFIAPI +route_config_access(const struct efi_hii_config_access_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); +}; + +efi_status_t EFIAPI +form_callback(const struct efi_hii_config_access_protocol *this, + efi_browser_action_t action, + efi_question_id_t question_id, + u8 type, + union efi_ifr_type_value *value, + efi_browser_action_request_t *action_request) +{ + EFI_ENTRY("%p, 0x%lx, 0x%x, 0x%x, %p, %p", this, action, + question_id, type, value, action_request); + + return EFI_EXIT(EFI_DEVICE_ERROR); +}; + +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_config_access_protocol efi_hii_config_access = { + .extract_config_access = extract_config_access, + .route_config_access = route_config_access, + .form_callback = form_callback +};

This efi_selftest tests HII database protocol and HII string protocol.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org --- lib/efi_selftest/Makefile | 1 + lib/efi_selftest/efi_selftest_hii.c | 1046 ++++++++++++++++++++++ lib/efi_selftest/efi_selftest_hii_data.c | 452 ++++++++++ 3 files changed, 1499 insertions(+) create mode 100644 lib/efi_selftest/efi_selftest_hii.c create mode 100644 lib/efi_selftest/efi_selftest_hii_data.c
diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 743b48204493..5cd8a757a3eb 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -25,6 +25,7 @@ efi_selftest_exception.o \ efi_selftest_exitbootservices.o \ efi_selftest_fdt.o \ efi_selftest_gop.o \ +efi_selftest_hii.o \ efi_selftest_loaded_image.o \ efi_selftest_manageprotocols.o \ efi_selftest_memory.o \ diff --git a/lib/efi_selftest/efi_selftest_hii.c b/lib/efi_selftest/efi_selftest_hii.c new file mode 100644 index 000000000000..16d7b608297e --- /dev/null +++ b/lib/efi_selftest/efi_selftest_hii.c @@ -0,0 +1,1046 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_hii + * + * Copyright (c) 2018 AKASHI Takahiro, Linaro Limited + * + * Test HII database protocols + */ + +#include <efi_selftest.h> +#include <malloc.h> +#include "efi_selftest_hii_data.c" + +#define PRINT_TESTNAME efi_st_printf("%s:\n", __func__) + +static struct efi_boot_services *boottime; + +static const efi_guid_t hii_database_protocol_guid = + EFI_HII_DATABASE_PROTOCOL_GUID; +static const efi_guid_t hii_string_protocol_guid = + EFI_HII_STRING_PROTOCOL_GUID; + +static struct efi_hii_database_protocol *hii_database_protocol; +static struct efi_hii_string_protocol *hii_string_protocol; + +/* + * Setup unit test. + * + * @handle: handle of the loaded image + * @systable: system table + * + * @return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + efi_status_t ret; + + boottime = systable->boottime; + + /* HII database protocol */ + ret = boottime->locate_protocol(&hii_database_protocol_guid, NULL, + (void **)&hii_database_protocol); + if (ret != EFI_SUCCESS) { + hii_database_protocol = NULL; + efi_st_error("HII database protocol is not available.\n"); + return EFI_ST_FAILURE; + } + + /* HII string protocol */ + ret = boottime->locate_protocol(&hii_string_protocol_guid, NULL, + (void **)&hii_string_protocol); + if (ret != EFI_SUCCESS) { + hii_string_protocol = NULL; + efi_st_error("HII string protocol is not available.\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +/* + * HII database protocol tests + */ + +/** + * test_hii_database_new_package_list() - test creation and removal of + * package list + * + * This test adds a new package list and then tries to remove it using + * the provided handle. + * + * @Return: status code + */ +static int test_hii_database_new_package_list(void) +{ + efi_hii_handle_t handle; + efi_status_t ret; + + PRINT_TESTNAME; + ret = hii_database_protocol->new_package_list(hii_database_protocol, + (struct efi_hii_package_list_header *)packagelist1, + NULL, &handle); + if (ret != EFI_SUCCESS || !handle) { + efi_st_error("new_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; + } + + ret = hii_database_protocol->remove_package_list(hii_database_protocol, + handle); + if (ret != EFI_SUCCESS) { + efi_st_error("remove_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +/** + * test_hii_database_update_package_list() - test update of package list + * + * This test adds a new package list and then tries to update it using + * another package list. + * + * @Return: status code + */ +static int test_hii_database_update_package_list(void) +{ + efi_hii_handle_t handle = NULL; + efi_status_t ret; + int result = EFI_ST_FAILURE; + + PRINT_TESTNAME; + ret = hii_database_protocol->new_package_list(hii_database_protocol, + (struct efi_hii_package_list_header *)packagelist1, + NULL, &handle); + if (ret != EFI_SUCCESS || !handle) { + efi_st_error("new_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; + } + + ret = hii_database_protocol->update_package_list(hii_database_protocol, + handle, + (struct efi_hii_package_list_header *)packagelist2); + if (ret != EFI_SUCCESS || !handle) { + efi_st_error("new_package_list returned %u\n", + (unsigned int)ret); + goto out; + } + + result = EFI_ST_SUCCESS; + +out: + if (handle) { + ret = hii_database_protocol->remove_package_list( + hii_database_protocol, handle); + if (ret != EFI_SUCCESS) { + efi_st_error("remove_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; + } + } + + return result; +} + +/** + * test_hii_database_list_package_lists() - test listing of package lists + * + * This test adds two package lists and then tries to enumerate them + * against different package types. We will get an array of handles. + * + * @Return: status code + */ +static int test_hii_database_list_package_lists(void) +{ + efi_hii_handle_t handle1 = NULL, handle2 = NULL, *handles; + efi_uintn_t handles_size; + efi_status_t ret; + int result = EFI_ST_FAILURE; + + PRINT_TESTNAME; + ret = hii_database_protocol->new_package_list(hii_database_protocol, + (struct efi_hii_package_list_header *)packagelist1, + NULL, &handle1); + if (ret != EFI_SUCCESS || !handle1) { + efi_st_error("new_package_list returned %u\n", + (unsigned int)ret); + goto out; + } + + ret = hii_database_protocol->new_package_list(hii_database_protocol, + (struct efi_hii_package_list_header *)packagelist2, + NULL, &handle2); + if (ret != EFI_SUCCESS || !handle2) { + efi_st_error("new_package_list returned %u\n", + (unsigned int)ret); + goto out; + } + + /* TYPE_ALL */ + handles = NULL; + handles_size = 0; + ret = hii_database_protocol->list_package_lists(hii_database_protocol, + EFI_HII_PACKAGE_TYPE_ALL, NULL, + &handles_size, handles); + if (ret != EFI_BUFFER_TOO_SMALL) { + efi_st_error("list_package_lists returned %u\n", + (unsigned int)ret); + goto out; + } + handles = malloc(handles_size); + if (!handles) { + efi_st_error("malloc failed\n"); + goto out; + } + ret = hii_database_protocol->list_package_lists(hii_database_protocol, + EFI_HII_PACKAGE_TYPE_ALL, NULL, + &handles_size, handles); + if (ret != EFI_SUCCESS) { + efi_st_error("list_package_lists returned %u\n", + (unsigned int)ret); + goto out; + } + efi_st_printf("list_package_lists returned %ld handles\n", + handles_size / sizeof(*handles)); + free(handles); + + /* STRINGS */ + handles = NULL; + handles_size = 0; + ret = hii_database_protocol->list_package_lists(hii_database_protocol, + EFI_HII_PACKAGE_STRINGS, NULL, + &handles_size, handles); + if (ret != EFI_BUFFER_TOO_SMALL) { + efi_st_error("list_package_lists returned %u\n", + (unsigned int)ret); + ret = EFI_ST_FAILURE; + goto out; + } + handles = malloc(handles_size); + if (!handles) { + efi_st_error("malloc failed\n"); + ret = EFI_ST_FAILURE; + goto out; + } + ret = hii_database_protocol->list_package_lists(hii_database_protocol, + EFI_HII_PACKAGE_STRINGS, NULL, + &handles_size, handles); + if (ret != EFI_SUCCESS) { + efi_st_error("list_package_lists returned %u\n", + (unsigned int)ret); + ret = EFI_ST_FAILURE; + goto out; + } + efi_st_printf("list_package_lists returned %ld strings handles\n", + handles_size / sizeof(*handles)); + free(handles); + + /* GUID */ + handles = NULL; + handles_size = 0; + ret = hii_database_protocol->list_package_lists(hii_database_protocol, + EFI_HII_PACKAGE_TYPE_GUID, &package_guid, + &handles_size, handles); + if (ret != EFI_BUFFER_TOO_SMALL) { + efi_st_error("list_package_lists returned %u\n", + (unsigned int)ret); + ret = EFI_ST_FAILURE; + goto out; + } + handles = malloc(handles_size); + if (!handles) { + efi_st_error("malloc failed\n"); + ret = EFI_ST_FAILURE; + goto out; + } + ret = hii_database_protocol->list_package_lists(hii_database_protocol, + EFI_HII_PACKAGE_TYPE_GUID, &package_guid, + &handles_size, handles); + if (ret != EFI_SUCCESS) { + efi_st_error("list_package_lists returned %u\n", + (unsigned int)ret); + ret = EFI_ST_FAILURE; + goto out; + } + efi_st_printf("list_package_lists returned %ld guid handles\n", + handles_size / sizeof(*handles)); + free(handles); + + /* KEYBOARD_LAYOUT */ + handles = NULL; + handles_size = 0; + ret = hii_database_protocol->list_package_lists(hii_database_protocol, + EFI_HII_PACKAGE_KEYBOARD_LAYOUT, NULL, + &handles_size, handles); + if (ret != EFI_BUFFER_TOO_SMALL) { + efi_st_error("list_package_lists returned %u\n", + (unsigned int)ret); + ret = EFI_ST_FAILURE; + goto out; + } + handles = malloc(handles_size); + if (!handles) { + efi_st_error("malloc failed\n"); + ret = EFI_ST_FAILURE; + goto out; + } + ret = hii_database_protocol->list_package_lists(hii_database_protocol, + EFI_HII_PACKAGE_KEYBOARD_LAYOUT, NULL, + &handles_size, handles); + if (ret != EFI_SUCCESS) { + efi_st_error("list_package_lists returned %u\n", + (unsigned int)ret); + ret = EFI_ST_FAILURE; + goto out; + } + efi_st_printf("list_package_lists returned %ld keyboard layout handles\n", + handles_size / sizeof(*handles)); + free(handles); + + result = EFI_ST_SUCCESS; + +out: + if (handle1) { + ret = hii_database_protocol->remove_package_list( + hii_database_protocol, handle1); + if (ret != EFI_SUCCESS) + efi_st_error("remove_package_list returned %u\n", + (unsigned int)ret); + } + if (handle2) { + ret = hii_database_protocol->remove_package_list( + hii_database_protocol, handle2); + if (ret != EFI_SUCCESS) + efi_st_error("remove_package_list returned %u\n", + (unsigned int)ret); + } + + return result; +} + +/** + * test_hii_database_export_package_lists() - test export of package lists + * + * @Return: status code + */ +static int test_hii_database_export_package_lists(void) +{ + PRINT_TESTNAME; + /* export_package_lists() not implemented yet */ + return EFI_ST_SUCCESS; +} + +/** + * test_hii_database_register_package_notify() - test registration of + * notification function + * + * @Return: status code + */ +static int test_hii_database_register_package_notify(void) +{ + PRINT_TESTNAME; + /* register_package_notify() not implemented yet */ + return EFI_ST_SUCCESS; +} + +/** + * test_hii_database_unregister_package_notify() - test removal of + * notification function + * + * @Return: status code + */ +static int test_hii_database_unregister_package_notify(void) +{ + PRINT_TESTNAME; + /* unregsiter_package_notify() not implemented yet */ + return EFI_ST_SUCCESS; +} + +/** + * test_hii_database_find_keyboard_layouts() - test listing of + * all the keyboard layouts in the system + * + * This test adds two package lists, each of which has two keyboard layouts + * and then tries to enumerate them. We will get an array of handles. + * + * @Return: status code + */ +static int test_hii_database_find_keyboard_layouts(void) +{ + efi_hii_handle_t handle1 = NULL, handle2 = NULL; + efi_guid_t *guids; + u16 guids_size; + efi_status_t ret; + int result = EFI_ST_FAILURE; + + PRINT_TESTNAME; + ret = hii_database_protocol->new_package_list(hii_database_protocol, + (struct efi_hii_package_list_header *)packagelist1, + NULL, &handle1); + if (ret != EFI_SUCCESS || !handle1) { + efi_st_error("new_package_list returned %u\n", + (unsigned int)ret); + goto out; + } + + ret = hii_database_protocol->new_package_list(hii_database_protocol, + (struct efi_hii_package_list_header *)packagelist2, + NULL, &handle2); + if (ret != EFI_SUCCESS || !handle2) { + efi_st_error("new_package_list returned %u\n", + (unsigned int)ret); + goto out; + } + + guids = NULL; + guids_size = 0; + ret = hii_database_protocol->find_keyboard_layouts( + hii_database_protocol, &guids_size, guids); + if (ret != EFI_BUFFER_TOO_SMALL) { + efi_st_error("find_keyboard_layouts returned %u\n", + (unsigned int)ret); + goto out; + } + guids = malloc(guids_size); + if (!guids) { + efi_st_error("malloc failed\n"); + goto out; + } + ret = hii_database_protocol->find_keyboard_layouts( + hii_database_protocol, &guids_size, guids); + if (ret != EFI_SUCCESS) { + efi_st_error("find_keyboard_layouts returned %u\n", + (unsigned int)ret); + goto out; + } + free(guids); + + efi_st_printf("find_keyboard_layouts returned %ld guids\n", + guids_size / sizeof(*guids)); + + result = EFI_ST_SUCCESS; + +out: + if (handle1) { + ret = hii_database_protocol->remove_package_list( + hii_database_protocol, handle1); + if (ret != EFI_SUCCESS) + efi_st_error("remove_package_list returned %u\n", + (unsigned int)ret); + } + if (handle2) { + ret = hii_database_protocol->remove_package_list( + hii_database_protocol, handle2); + if (ret != EFI_SUCCESS) + efi_st_error("remove_package_list returned %u\n", + (unsigned int)ret); + } + + return result; +} + +/** + * test_hii_database_get_keyboard_layout() - test retrieval of keyboard layout + * + * This test adds two package lists, each of which has two keyboard layouts + * and then tries to get a handle to keyboard layout with a specific guid + * and the current one. + * + * @Return: status code + */ +static int test_hii_database_get_keyboard_layout(void) +{ + efi_hii_handle_t handle1 = NULL, handle2 = NULL; + struct efi_hii_keyboard_layout *kb_layout; + u16 kb_layout_size; + efi_status_t ret; + int result = EFI_ST_FAILURE; + + PRINT_TESTNAME; + ret = hii_database_protocol->new_package_list(hii_database_protocol, + (struct efi_hii_package_list_header *)packagelist1, + NULL, &handle1); + if (ret != EFI_SUCCESS || !handle1) { + efi_st_error("new_package_list returned %u\n", + (unsigned int)ret); + goto out; + } + + ret = hii_database_protocol->new_package_list(hii_database_protocol, + (struct efi_hii_package_list_header *)packagelist2, + NULL, &handle2); + if (ret != EFI_SUCCESS || !handle2) { + efi_st_error("new_package_list returned %u\n", + (unsigned int)ret); + goto out; + } + + /* specific keyboard_layout(guid11) */ + kb_layout = NULL; + kb_layout_size = 0; + ret = hii_database_protocol->get_keyboard_layout(hii_database_protocol, + &kb_layout_guid11, &kb_layout_size, kb_layout); + if (ret != EFI_BUFFER_TOO_SMALL) { + efi_st_error("get_keyboard_layout returned %u\n", + (unsigned int)ret); + goto out; + } + kb_layout = malloc(kb_layout_size); + if (!kb_layout) { + efi_st_error("malloc failed\n"); + goto out; + } + ret = hii_database_protocol->get_keyboard_layout(hii_database_protocol, + &kb_layout_guid11, &kb_layout_size, kb_layout); + if (ret != EFI_SUCCESS) { + efi_st_error("get_keyboard_layout returned %u\n", + (unsigned int)ret); + goto out; + } + free(kb_layout); + + /* current */ + kb_layout = NULL; + kb_layout_size = 0; + ret = hii_database_protocol->get_keyboard_layout(hii_database_protocol, + NULL, &kb_layout_size, kb_layout); + if (ret != EFI_INVALID_PARAMETER) { + efi_st_error("get_keyboard_layout returned %u\n", + (unsigned int)ret); + goto out; + } + + result = EFI_ST_SUCCESS; + +out: + if (handle1) { + ret = hii_database_protocol->remove_package_list( + hii_database_protocol, handle1); + if (ret != EFI_SUCCESS) + efi_st_error("remove_package_list returned %u\n", + (unsigned int)ret); + } + if (handle2) { + ret = hii_database_protocol->remove_package_list( + hii_database_protocol, handle2); + if (ret != EFI_SUCCESS) + efi_st_error("remove_package_list returned %u\n", + (unsigned int)ret); + } + + return result; +} + +/** + * test_hii_database_set_keyboard_layout() - test change of + * current keyboard layout + * + * @Return: status code + */ +static int test_hii_database_set_keyboard_layout(void) +{ + PRINT_TESTNAME; + /* set_keyboard_layout() not implemented yet */ + return EFI_ST_SUCCESS; +} + +/** + * test_hii_database_get_package_list_handle() - test retrieval of + * driver associated with a package list + * + * This test adds a package list, and then tries to get a handle to driver + * which is associated with a package list. + * + * @Return: status code + */ +static int test_hii_database_get_package_list_handle(void) +{ + efi_hii_handle_t handle = NULL; + efi_handle_t driver_handle; + efi_status_t ret; + int result = EFI_ST_FAILURE; + + PRINT_TESTNAME; + driver_handle = (efi_handle_t)0x12345678; /* dummy */ + ret = hii_database_protocol->new_package_list(hii_database_protocol, + (struct efi_hii_package_list_header *)packagelist1, + driver_handle, &handle); + if (ret != EFI_SUCCESS || !handle) { + efi_st_error("new_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; + } + + driver_handle = NULL; + ret = hii_database_protocol->get_package_list_handle( + hii_database_protocol, handle, &driver_handle); + if (ret != EFI_SUCCESS || driver_handle != (efi_handle_t)0x12345678) { + efi_st_error("get_package_list_handle returned %u, driver:%p\n", + (unsigned int)ret, driver_handle); + goto out; + } + + result = EFI_ST_SUCCESS; + +out: + if (handle) { + ret = hii_database_protocol->remove_package_list( + hii_database_protocol, handle); + if (ret != EFI_SUCCESS) { + efi_st_error("remove_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; + } + } + + return result; +} + +static int test_hii_database_protocol(void) +{ + int ret; + + ret = test_hii_database_new_package_list(); + if (ret != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + ret = test_hii_database_update_package_list(); + if (ret != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + ret = test_hii_database_list_package_lists(); + if (ret != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + ret = test_hii_database_export_package_lists(); + if (ret != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + ret = test_hii_database_register_package_notify(); + if (ret != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + ret = test_hii_database_unregister_package_notify(); + if (ret != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + ret = test_hii_database_find_keyboard_layouts(); + if (ret != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + ret = test_hii_database_get_keyboard_layout(); + if (ret != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + ret = test_hii_database_set_keyboard_layout(); + if (ret != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + ret = test_hii_database_get_package_list_handle(); + if (ret != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + return EFI_ST_SUCCESS; +} + +/* + * HII string protocol tests + */ + +/** + * test_hii_string_new_string() - test creation of a new string entry + * + * This test adds a package list, and then tries to add a new string + * entry for a specific language. + * + * @Return: status code + */ +static int test_hii_string_new_string(void) +{ + efi_hii_handle_t handle = NULL; + efi_string_id_t id; + efi_status_t ret; + int result = EFI_ST_FAILURE; + + PRINT_TESTNAME; + ret = hii_database_protocol->new_package_list(hii_database_protocol, + (struct efi_hii_package_list_header *)packagelist1, + NULL, &handle); + if (ret != EFI_SUCCESS || !handle) { + efi_st_error("new_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; + } + + ret = hii_string_protocol->new_string(hii_string_protocol, handle, + &id, (u8 *)"en-US", + L"Japanese", L"Japanese", NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("new_string returned %u\n", + (unsigned int)ret); + goto out; + } + efi_st_printf("new string id is %u\n", id); + + result = EFI_ST_SUCCESS; + +out: + if (handle) { + ret = hii_database_protocol->remove_package_list( + hii_database_protocol, handle); + if (ret != EFI_SUCCESS) { + efi_st_error("remove_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; + } + } + + return result; +} + +/** + * test_hii_string_get_string() - test retrieval of a string entry + * + * This test adds a package list, create a new string entry and then tries + * to get it with its string id. + * + * @Return: status code + */ +static int test_hii_string_get_string(void) +{ + efi_hii_handle_t handle = NULL; + efi_string_id_t id; + efi_string_t string; + efi_uintn_t string_len; + efi_status_t ret; + int result = EFI_ST_FAILURE; + + PRINT_TESTNAME; + ret = hii_database_protocol->new_package_list(hii_database_protocol, + (struct efi_hii_package_list_header *)packagelist1, + NULL, &handle); + if (ret != EFI_SUCCESS || !handle) { + efi_st_error("new_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; + } + + ret = hii_string_protocol->new_string(hii_string_protocol, handle, + &id, (u8 *)"en-US", + L"Japanese", L"Japanese", NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("new_string returned %u\n", + (unsigned int)ret); + goto out; + } + + string = NULL; + string_len = 0; + ret = hii_string_protocol->get_string(hii_string_protocol, + (u8 *)"en-US", handle, id, string, &string_len, NULL); + if (ret != EFI_BUFFER_TOO_SMALL) { + efi_st_error("get_string returned %u\n", + (unsigned int)ret); + goto out; + } + string_len += sizeof(u16); + string = malloc(string_len); + if (!string) { + efi_st_error("malloc failed\n"); + goto out; + } + ret = hii_string_protocol->get_string(hii_string_protocol, + (u8 *)"en-US", handle, id, string, &string_len, NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("get_string returned %u\n", + (unsigned int)ret); + goto out; + } + +#if 1 + u16 *c1, *c2; + + for (c1 = string, c2 = L"Japanese"; *c1 == *c2; c1++, c2++) + ; + if (!*c1 && !*c2) + result = EFI_ST_SUCCESS; + else + result = EFI_ST_FAILURE; +#else + /* TODO: %ls */ + efi_st_printf("got string is %s (can be wrong)\n", string); +#endif + + result = EFI_ST_SUCCESS; + +out: + if (handle) { + ret = hii_database_protocol->remove_package_list( + hii_database_protocol, handle); + if (ret != EFI_SUCCESS) { + efi_st_error("remove_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; + } + } + + return result; +} + +/** + * test_hii_string_set_string() - test change of a string entry + * + * This test adds a package list, create a new string entry and then tries + * to modify it. + * + * @Return: status code + */ +static int test_hii_string_set_string(void) +{ + efi_hii_handle_t handle = NULL; + efi_string_id_t id; + efi_status_t ret; + int result = EFI_ST_FAILURE; + + PRINT_TESTNAME; + ret = hii_database_protocol->new_package_list(hii_database_protocol, + (struct efi_hii_package_list_header *)packagelist1, + NULL, &handle); + if (ret != EFI_SUCCESS || !handle) { + efi_st_error("new_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; + } + + ret = hii_string_protocol->new_string(hii_string_protocol, handle, + &id, (u8 *)"en-US", + L"Japanese", L"Japanese", NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("new_string returned %u\n", + (unsigned int)ret); + goto out; + } + + ret = hii_string_protocol->set_string(hii_string_protocol, handle, + id, (u8 *)"en-US", + L"Nihongo", NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("set_string returned %u\n", + (unsigned int)ret); + goto out; + } + + result = EFI_ST_SUCCESS; + +out: + if (handle) { + ret = hii_database_protocol->remove_package_list( + hii_database_protocol, handle); + if (ret != EFI_SUCCESS) { + efi_st_error("remove_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; + } + } + + return result; +} + +/** + * test_hii_string_get_languages() - test listing of languages + * + * This test adds a package list, and then tries to enumerate languages + * in it. We will get an string of language names. + * + * @Return: status code + */ +static int test_hii_string_get_languages(void) +{ + efi_hii_handle_t handle = NULL; + u8 *languages; + efi_uintn_t languages_len; + efi_status_t ret; + int result = EFI_ST_FAILURE; + + PRINT_TESTNAME; + ret = hii_database_protocol->new_package_list(hii_database_protocol, + (struct efi_hii_package_list_header *)packagelist1, + NULL, &handle); + if (ret != EFI_SUCCESS || !handle) { + efi_st_error("new_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; + } + + languages = NULL; + languages_len = 0; + ret = hii_string_protocol->get_languages(hii_string_protocol, handle, + languages, &languages_len); + if (ret != EFI_BUFFER_TOO_SMALL) { + efi_st_error("get_languages returned %u\n", + (unsigned int)ret); + goto out; + } + languages = malloc(languages_len); + if (!languages) { + efi_st_error("malloc failed\n"); + goto out; + } + ret = hii_string_protocol->get_languages(hii_string_protocol, handle, + languages, &languages_len); + if (ret != EFI_SUCCESS) { + efi_st_error("get_languages returned %u\n", + (unsigned int)ret); + goto out; + } + + efi_st_printf("got languages are %s\n", languages); + + result = EFI_ST_SUCCESS; + +out: + if (handle) { + ret = hii_database_protocol->remove_package_list( + hii_database_protocol, handle); + if (ret != EFI_SUCCESS) { + efi_st_error("remove_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; + } + } + + return result; +} + +/** + * test_hii_string_get_secondary_languages() - test listing of secondary + * languages + * + * This test adds a package list, and then tries to enumerate secondary + * languages with a specific language. We will get an string of language names. + * + * @Return: status code + */ +static int test_hii_string_get_secondary_languages(void) +{ + efi_hii_handle_t handle = NULL; + u8 *languages; + efi_uintn_t languages_len; + efi_status_t ret; + int result = EFI_ST_FAILURE; + + PRINT_TESTNAME; + ret = hii_database_protocol->new_package_list(hii_database_protocol, + (struct efi_hii_package_list_header *)packagelist1, + NULL, &handle); + if (ret != EFI_SUCCESS || !handle) { + efi_st_error("new_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; + } + + languages = NULL; + languages_len = 0; + ret = hii_string_protocol->get_secondary_languages(hii_string_protocol, + handle, (u8 *)"en-US", languages, &languages_len); + if (ret == EFI_NOT_FOUND) { + efi_st_printf("no secondary languages\n"); + result = EFI_ST_SUCCESS; + goto out; + } + if (ret != EFI_BUFFER_TOO_SMALL) { + efi_st_error("get_secondary_languages returned %u\n", + (unsigned int)ret); + goto out; + } + languages = malloc(languages_len); + if (!languages) { + efi_st_error("malloc failed\n"); + goto out; + } + ret = hii_string_protocol->get_secondary_languages(hii_string_protocol, + handle, (u8 *)"en-US", languages, &languages_len); + if (ret != EFI_SUCCESS) { + efi_st_error("get_secondary_languages returned %u\n", + (unsigned int)ret); + goto out; + } + + efi_st_printf("got secondary languages are %s\n", languages); + + result = EFI_ST_SUCCESS; + +out: + if (handle) { + ret = hii_database_protocol->remove_package_list( + hii_database_protocol, handle); + if (ret != EFI_SUCCESS) { + efi_st_error("remove_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; + } + } + + return result; +} + +static int test_hii_string_protocol(void) +{ + int ret; + + ret = test_hii_string_new_string(); + if (ret != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + ret = test_hii_string_get_string(); + if (ret != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + ret = test_hii_string_set_string(); + if (ret != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + ret = test_hii_string_get_languages(); + if (ret != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + ret = test_hii_string_get_secondary_languages(); + if (ret != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * @return: EFI_ST_SUCCESS for success, EFI_ST_FAILURE for failure + */ +static int execute(void) +{ + int ret; + + /* HII database protocol */ + ret = test_hii_database_protocol(); + if (ret != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + /* HII string protocol */ + ret = test_hii_string_protocol(); + if (ret != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(hii) = { + .name = "HII database protocols", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, +}; diff --git a/lib/efi_selftest/efi_selftest_hii_data.c b/lib/efi_selftest/efi_selftest_hii_data.c new file mode 100644 index 000000000000..fad1465ac17c --- /dev/null +++ b/lib/efi_selftest/efi_selftest_hii_data.c @@ -0,0 +1,452 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * This file's test data is derived from UEFI SCT. + * The original copyright is attached below. + */ + +/* + * Copyright 2006 - 2016 Unified EFI, Inc.<BR> + * Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR> + * + * This program and the accompanying materials + * are licensed and made available under the terms and conditions of the BSD + * License which accompanies this distribution. The full text of the license + * may be found at + * http://opensource.org/licenses/bsd-license.php + * + * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + */ + +#include <efi.h> + +/* + * TODO: These macro's are not used as they appear only in + * "#if 0" clauses. In the future, define them elsewhere. + */ +#if 0 +/* HII form */ +#define EFI_IFR_AND_OP 0x15 +#define EFI_IFR_END_OP 0x29 +#define EFI_IFR_BITWISE_AND_OP 0x35 + +/* HII image */ +#define EFI_HII_IIBT_END 0x00 +#define EFI_HII_IIBT_IMAGE_1BIT 0x10 +#endif + +/* HII keyboard layout */ +#define EFI_NULL_MODIFIER 0x0000 + +u8 packagelist1[] = { + // EFI_HII_PACKAGE_LIST_HEADER, length = 20 + // SimpleFont, Font, GUID, Form, String, Image, DevicePath, + // (74) (110) 20 (8) 78 (67) (8) + // KeyboardLayout, End + // 192 4 + + 0x89, 0xcd, 0xab, 0x03, 0xf4, 0x03, 0x44, 0x70, + 0x81, 0xde, 0x99, 0xb1, 0x81, 0x20, 0xf7, 0x68, //16: guid + 0x3a, 0x01, 0x00, 0x00, // 4: total 314(0x13a) +#if 0 /* TODO: simple font package not implemented yet */ + // + // Simple Font Package 1, length = 74 + // + 0x4A, 0x00, 0x00, + EFI_HII_PACKAGE_SIMPLE_FONTS, + 1, 0, + 1, 0, + 0x55, 0x0, 0x1, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 0x77, 0x0, 0x2, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 0, 0, 0, + // + // Font Package 1, length = 110 + // + 0x6e, 0x00, 0x00, // 3 + EFI_HII_PACKAGE_FONTS, // 1 + 0x5c, 0x00, 0x00, 0x00, // 4: size of header + 0x5c, 0x00, 0x00, 0x00, // 4: offset + 0xf1, 0x00, 0xf2, 0x00, 0xf3, 0x00, 0xf4, 0x00, + 0xf5, 0x00, 0xec, 0xec, //10+2(pads) + 0xff, 0x33, 0xff, 0x44, // 4: font style + 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, //64 + // + // Glyph block 1, length = 18 + // + EFI_HII_GIBT_GLYPH_DEFAULT, // 1 + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x99, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, //16: BitMapData + EFI_HII_GIBT_END, // 1 +#endif + // + // Guid Package 1, length = 20 + // + 0x14, 0x00, 0x00, // 3 + EFI_HII_PACKAGE_TYPE_GUID, // 1 + 0x5a, 0xc9, 0x87, 0x03, 0x3, 0xd7, 0x46, 0x23, + 0xb2, 0xab, 0xd0, 0xc7, 0xdd, 0x90, 0x44, 0xf8, //16: guid +#if 0 /* TODO: form package not implemented yet */ + // + // EFI_HII_PACKAGE_FORMS, length = 8 + // + 0x08, 0x00, 0x00, // 3 + EFI_HII_PACKAGE_FORMS, // 1 + // + // Opcode 1, length = 4 + // + EFI_IFR_AND_OP, + 0x82, + EFI_IFR_END_OP, + 0x02, + // +#endif + // EFI_HII_PACKAGE_STRINGS, length = 78 + // + 0x4e, 0x00, 0x00, // 3: length(header) + EFI_HII_PACKAGE_STRINGS, // 1: type(header) + 0x3c, 0x00, 0x00, 0x00, // 4: header_size + 0x3c, 0x00, 0x00, 0x00, // 4: string_offset + 0x00, 0x00, 0x11, 0x22, 0x44, 0x55, 0x77, 0x89, //32: language_window + 0x11, 0x00, 0x11, 0x22, 0x44, 0x55, 0x87, 0x89, + 0x22, 0x00, 0x11, 0x22, 0x44, 0x55, 0x77, 0x89, + 0x33, 0x00, 0x11, 0x22, 0x44, 0x55, 0x77, 0x89, + 0x01, 0x00, // 2: language name + 0x65, 0x6e, 0x2d, 0x55, 0x53, 0x3b, 0x7a, 0x68, //14: language + 0x2d, 0x48, 0x61, 0x6e, 0x74, 0x00, // "en-US;zh-Hant" + EFI_HII_SIBT_STRING_UCS2, // 1 + 0x45, 0x00, 0x6E, 0x00, 0x67, 0x00, 0x6C, 0x00, + 0x69, 0x00, 0x73, 0x00, 0x68, 0x00, 0x00, 0x00, //16: "English" + EFI_HII_SIBT_END, // 1 +#if 0 /* TODO: image package not implemented yet */ + // + // EFI_HII_PACKAGE_IMAGES, length = 67 + // + 0x43, 0x00, 0x00, // 3 + EFI_HII_PACKAGE_IMAGES, // 1 + 0x0c, 0x00, 0x00, 0x00, // 4: image info offset + 0x39, 0x00, 0x00, 0x00, // 4: palette info offset + EFI_HII_IIBT_IMAGE_1BIT, // 1 + 0x01, + 0x0b, 0x00, + 0x13, 0x00, + 0x80, 0x00, + 0xc0, 0x00, + 0xe0, 0x00, + 0xf0, 0x00, + 0xf8, 0x00, + 0xfc, 0x00, + 0xfe, 0x00, + 0xff, 0x00, + 0xff, 0x80, + 0xff, 0xc0, + 0xff, 0xe0, + 0xfe, 0x00, + 0xef, 0x00, + 0xcf, 0x00, + 0x87, 0x80, + 0x07, 0x80, + 0x03, 0xc0, + 0x03, 0xc0, + 0x01, 0x80, //43 + EFI_HII_IIBT_END, // 1 + 0x01, 0x00, + 0x06, 0x00, + 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, //10 + // + // EFI_HII_PACKAGE_DEVICE_PATH, length = 8 + // + 0x08, 0x00, 0x00, // 3 + EFI_HII_PACKAGE_DEVICE_PATH, // 1 + 0x01, 0x23, 0x45, 0x66, // 4: dummy device path protocol + // instance address +#endif + // + // Keyboard layout package 1, length = 192 + 0xc0, 0x00, 0x00, // 3: length(header) + EFI_HII_PACKAGE_KEYBOARD_LAYOUT, // 1: type(header) + 0x02, 0x00, // 2: LayoutCount + // + // Layout 1, length = 93 + // + 0x5d, 0x00, // 2: layout_length + 0x95, 0xe4, 0x40, 0x8d, 0xaa, 0xe2, 0x6f, 0x4c, + 0x89, 0x70, 0x68, 0x85, 0x09, 0xee, 0xc7, 0xd2, //16: guid + 0x37, 0x00, 0x00, 0x00, // 4: layout_descriptor_ + // string_offset + 0x02, // 1: descriptor_count + // + // Descriptor 1, length = 16 + // + 49, 0x00, 0x00, 0x00, // 4: key (EfiKeyD1) + 'q', 0x00, // 2: unicode + 'Q', 0x00, // 2: shifted_unicode + 0x00, 0x00, // 2: alt_gr_unicode + 0x00, 0x00, // 2: shifted_alt_gr_unicode + EFI_NULL_MODIFIER, 0x00, // 2: modifier + 0x03, 0x00, // 2: affected_attribute + // + // Descriptor 2, length = 16 + // + 50, 0x00, 0x00, 0x00, // 4: key (EfiKeyD2) + 'w', 0x00, // 2: unicode + 'W', 0x00, // 2: shifted_unicode + 0x00, 0x00, // 2: alt_gr_unicode + 0x00, 0x00, // 2: shifted_alt_gr_unicode + EFI_NULL_MODIFIER, 0x00, // 2: modifier + 0x3, 0x0, // 2: affected_attribute + // + // EFI_DESCRIPTOR_STRING_BUNDLE, length = 38 + // + 0x01, 0x00, // 2: DescriptionCount + 'e', 0x0, 'n', 0x0, '-', 0x0, 'U', 0x0, 'S', 0x0, + //10: RFC3066 language code + ' ', 0x0, // 2: Space + 'S', 0x0, 'i', 0x0, 'm', 0x0, 'p', 0x0, 'l', 0x0, 'e', 0x0, + '1', 0x0, 'o', 0x0, 'n', 0x0, 'l', 0x0, 'y', 0x0, '\0', 0x0, + //24: DescriptionString + // + // Layout 2, length = 93 + // + 0x5d, 0x00, // 2: layout_length + 0x3e, 0x0b, 0xe6, 0x2a, 0xd6, 0xb9, 0xd8, 0x49, + 0x9a, 0x16, 0xc2, 0x48, 0xf1, 0xeb, 0xa8, 0xdb, //16: guid + 0x37, 0x00, 0x00, 0x00, // 4: layout_descriptor_ + // string_offset + 0x02, // 1 Descriptor count + // + // Descriptor 1, length = 16 + // + 51, 0x0, 0x0, 0x0, // 4: key (EfiKeyD3) + 'e', 0x00, // 2: unicode + 'E', 0x00, // 2: shifted_unicode + 0x00, 0x00, // 2: alt_gr_unicode + 0x00, 0x00, // 2: shifted_alt_gr_unicode + EFI_NULL_MODIFIER, 0x0, // 2: modifier + 0x3, 0x0, // 2: affected_attribute + // + // Descriptor 2, length = 16 + // + 52, 0x0, 0x0, 0x0, // 4: key (EfiKeyD4) + 'r', 0x00, // 2: unicode + 'R', 0x00, // 2: shifted_unicode + 0x00, 0x00, // 2: alt_gr_unicode + 0x00, 0x00, // 2: shifted_alt_gr_unicode + EFI_NULL_MODIFIER, 0x0, // 2: modifier + 0x3, 0x0, // 2: affected_attribute + // + // EFI_DESCRIPTOR_STRING_BUNDLE, length = 38 + // + 0x01, 0x00, // 2: DescriptionCount + 'e', 0x0, 'n', 0x0, '-', 0x0, 'U', 0x0, 'S', 0x0, + //10: RFC3066 language code + ' ', 0x0, // 2: Space + 'S', 0x0, 'i', 0x0, 'm', 0x0, 'p', 0x0, 'l', 0x0, 'e', 0x0, + '2', 0x0, 'o', 0x0, 'n', 0x0, 'l', 0x0, 'y', 0x0, '\0', 0x0, + //24: DescriptionString + // + // End of package list, length = 4 + // + 0x4, 0x00, 0x00, + EFI_HII_PACKAGE_END +}; + +u8 packagelist2[] = { + // EFI_HII_PACKAGE_LIST_HEADER, length = 20 + // SimpleFont, Font, GUID, KeyboardLayout, Form, End + // (74) (122) 20 192 (8) 4 + 0xd3, 0xde, 0x85, 0x86, 0xce, 0x1b, 0xf3, 0x43, + 0xa2, 0x0c, 0xa3, 0x06, 0xec, 0x69, 0x72, 0xdd, //16 + 0xec, 0x00, 0x00, 0x00, // 4: total 236(0xec) + +#if 0 /* TODO: simple font package not implemented yet */ + // + // Simple Font Package 2, length = 74 + // + 0x4A, 0x00, 0x00, // 3 + EFI_HII_PACKAGE_SIMPLE_FONTS, // 1 + 1, 0, // 2 + 1, 0, // 2 + 0x33, 0x0, 0, 1, 2, 3, 4, 5, 0, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, //22 + 0x44, 0x0, 0x2, 2, 3, 4, 5, 6, 0, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, //22 + 3, 4, 5, 6, 7, 8, 9, 10, 11, 9, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 0, 0, 0, //22 + // + // Font Package 2, length = 122 + // + 0x7A, 0x00, 0x00, // 3 + EFI_HII_PACKAGE_FONTS, // 1 + 0x5C, 0x00, 0x00, 0x00, // 4: size of header + 0x5C, 0x00, 0x00, 0x00, // 4: dummy offset + 0xf1, 0x00, 0xf2, 0x00, 0xf3, 0x00, 0xf4, 0x00, + 0xf5, 0x00, 0xec, 0xec, //10+2(pads) + 0xff, 0x11, 0xff, 0x22, // 4: font style + 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, //64 + // + // Glyph block 1, length = 30 + // + EFI_HII_GIBT_GLYPH, // 1 + 0xf1, 0x00, 0xf2, 0x00, 0xf3, 0x00, 0xf4, 0x00, + 0xf5, 0x00, //10 + 0xff, 0x01, // 2 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, //16: BitMapData + EFI_HII_GIBT_END, // 1 +#endif + // + // Guid Package 1, length = 20 + // + 0x14, 0x00, 0x00, // 3 + EFI_HII_PACKAGE_TYPE_GUID, // 1 + 0x5a, 0xc9, 0x87, 0x03, 0x3, 0xd7, 0x46, 0x23, + 0xb2, 0xab, 0xd0, 0xc7, 0xdd, 0x90, 0x44, 0xf8, //16: guid + // + // Keyboard layout package 2, length = 192 + 0xc0, 0x00, 0x00, // 3 + EFI_HII_PACKAGE_KEYBOARD_LAYOUT, // 1 + 0x02, 0x00, //0xec, 0xec, // 2: LayoutCount + // + // Layout 1, length = 93 + // + 0x5d, 0x00, // 2: layout_length + 0x1f, 0x6a, 0xf5, 0xe0, 0x6b, 0xdf, 0x7e, 0x4a, + 0xa3, 0x9a, 0xe7, 0xa5, 0x19, 0x15, 0x45, 0xd6,//16: guid + 0x37, 0x00, 0x00, 0x00, // 4: layout_descriptor + // string offset + 0x02, // 1: descriptor_count + // + // Descriptor 1, length = 16 + // + 32, 0x00, 0x00, 0x00, // 4: key (EfiKeyC1) + 'a', 0x00, // 2: unicode + 'A', 0x00, // 2: shifted_unicode + 0x00, 0x00, // 2: alt_gr_unicode + 0x00, 0x00, // 2: shifted_alt_gr_unic + EFI_NULL_MODIFIER, 0x00, // 2: modifier + 0x03, 0x00, // 2: affected_attribute + // + // Descriptor 2, length = 16 + // + 33 /*EfiKeyC2*/, 0x00, 0x00, 0x00, + 's', 0x00, + 'S', 0x00, + 0x00, 0x00, + 0x00, 0x00, + EFI_NULL_MODIFIER, 0x00, + 0x3, 0x0, + // + // EFI_DESCRIPTOR_STRING_BUNDLE, length = 38 + // + 0x01, 0x00, // 2: DescriptionCount + 'e', 0x0, 'n', 0x0, '-', 0x0, 'U', 0x0, 'S', 0x0, + //10: RFC3066 language code + ' ', 0x0, // 2: Space + 'S', 0x0, 'i', 0x0, 'm', 0x0, 'p', 0x0, 'l', 0x0, 'e', 0x0, + '3', 0x0, 'o', 0x0, 'n', 0x0, 'l', 0x0, 'y', 0x0, '\0', 0x0, + //24: DescriptionString + // + // Layout 2, length = 93 + // + 0x5d, 0x00, // 2: layout_length + 0xc9, 0x6a, 0xbe, 0x47, 0xcc, 0x54, 0xf9, 0x46, + 0xa2, 0x62, 0xd5, 0x3b, 0x25, 0x6a, 0xc, 0x34, //16: guid + 0x37, 0x00, 0x00, 0x00, // 4: layout_descriptor + // string_offset + 0x02, // 1: descriptor_count + // + // Descriptor 1, length = 16 + // + 34 /*EfiKeyC3*/, 0x0, 0x0, 0x0, + 'd', 0x00, + 'D', 0x00, + 0x00, 0x00, + 0x00, 0x00, + EFI_NULL_MODIFIER, 0x0, + 0x3, 0x0, + // + // Descriptor 2, length = 16 + // + 35 /*EfiKeyC4*/, 0x0, 0x0, 0x0, + 'e', 0x00, + 'E', 0x00, + 0x00, 0x00, + 0x00, 0x00, + EFI_NULL_MODIFIER, 0x0, + 0x3, 0x0, + // + // EFI_DESCRIPTOR_STRING_BUNDLE, length = 38 + // + 0x01, 0x00, // 2: DescriptionCount + 'e', 0x0, 'n', 0x0, '-', 0x0, 'U', 0x0, 'S', 0x0, + //10: RFC3066 language code + ' ', 0x0, // 2: Space + 'S', 0x0, 'i', 0x0, 'm', 0x0, 'p', 0x0, 'l', 0x0, 'e', 0x0, + '4', 0x0, 'o', 0x0, 'n', 0x0, 'l', 0x0, 'y', 0x0, '\0', 0x0, + //24: DescriptionString +#if 0 /* TODO: form package not implemented yet */ + // + // EFI_HII_PACKAGE_FORMS, length = 8 + // + 0x08, 0x00, 0x00, // 3 + EFI_HII_PACKAGE_FORMS, // 1 + // + // Opcode 1 + // + EFI_IFR_BITWISE_AND_OP, // 1 + 0x02, // 1 + EFI_IFR_END_OP, // 1 + 0x02, // 1 +#endif + // + // End of package list, length = 4 + // + 0x4, 0x00, 0x00, // 3 + EFI_HII_PACKAGE_END // 1 +}; + +efi_guid_t packagelist_guid1 = + EFI_GUID(0x03abcd89, 0x03f4, 0x7044, + 0x81, 0xde, 0x99, 0xb1, 0x81, 0x20, 0xf7, 0x68); + +efi_guid_t packagelist_guid2 = + EFI_GUID(0x8685ded3, 0x1bce, 0x43f3, + 0xa2, 0x0c, 0xa3, 0x06, 0xec, 0x69, 0x72, 0xdd); + +efi_guid_t kb_layout_guid11 = + EFI_GUID(0x8d40e495, 0xe2aa, 0x4c6f, + 0x89, 0x70, 0x68, 0x85, 0x09, 0xee, 0xc7, 0xd2); + +efi_guid_t kb_layout_guid12 = + EFI_GUID(0x2ae60b3e, 0xb9d6, 0x49d8, + 0x9a, 0x16, 0xc2, 0x48, 0xf1, 0xeb, 0xa8, 0xdb); + +efi_guid_t kb_layout_guid21 = + EFI_GUID(0xe0f56a1f, 0xdf6b, 0x4a7e, + 0xa3, 0x9a, 0xe7, 0xa5, 0x19, 0x15, 0x45, 0xd6); + +efi_guid_t kb_layout_guid22 = + EFI_GUID(0x47be6ac9, 0x54cc, 0x46f9, + 0xa2, 0x62, 0xd5, 0x3b, 0x25, 0x6a, 0x0c, 0x34); + +efi_guid_t package_guid = + EFI_GUID(0x0387c95a, 0xd703, 0x2346, + 0xb2, 0xab, 0xd0, 0xc7, 0xdd, 0x90, 0x44, 0xf8);
participants (8)
-
AKASHI Takahiro
-
Alexander Graf
-
Ard Biesheuvel
-
Bi, Dandan
-
Gao, Liming
-
Heinrich Schuchardt
-
Laszlo Ersek
-
Leif Lindholm