Port from U-Boot its bare minium HII support, so the UEFI shell can be
run.

Signed-off-by: Ahmad Fatoum <[email protected]>
---
 efi/loader/Kconfig                |    2 +
 efi/loader/protocols/Kconfig      |   16 +
 efi/loader/protocols/Makefile     |    1 +
 efi/loader/protocols/hii.c        | 1100 +++++++++++++++++++++++++++++
 efi/loader/protocols/hii_config.c |  157 ++++
 include/efi/protocol/hii.h        |  428 +++++++++++
 6 files changed, 1704 insertions(+)
 create mode 100644 efi/loader/protocols/Kconfig
 create mode 100644 efi/loader/protocols/hii.c
 create mode 100644 efi/loader/protocols/hii_config.c
 create mode 100644 include/efi/protocol/hii.h

diff --git a/efi/loader/Kconfig b/efi/loader/Kconfig
index eaa5087b9ab8..d54783f9a084 100644
--- a/efi/loader/Kconfig
+++ b/efi/loader/Kconfig
@@ -29,3 +29,5 @@ config EFI_LOADER_SET_TIME
          can be used by an EFI application to adjust the real time clock.
 
 endmenu
+
+source "efi/loader/protocols/Kconfig"
diff --git a/efi/loader/protocols/Kconfig b/efi/loader/protocols/Kconfig
new file mode 100644
index 000000000000..4ed7499da4a2
--- /dev/null
+++ b/efi/loader/protocols/Kconfig
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0
+
+menu "UEFI protocol support"
+
+config EFI_LOADER_HII
+       bool "HII protocols"
+       default y
+       help
+         The Human Interface Infrastructure is a complicated framework that
+         allows UEFI applications to draw fancy menus and hook strings using
+         a translation framework.
+
+         barebox implements enough of its features to be able to run the UEFI
+         Shell, but not more than that.
+
+endmenu
diff --git a/efi/loader/protocols/Makefile b/efi/loader/protocols/Makefile
index 472dd54116c5..f4a9c0650fd9 100644
--- a/efi/loader/protocols/Makefile
+++ b/efi/loader/protocols/Makefile
@@ -4,3 +4,4 @@ obj-$(CONFIG_FS) += file.o
 obj-$(CONFIG_DISK) += disk.o
 obj-$(CONFIG_VIDEO) += gop.o
 obj-$(CONFIG_CONSOLE_FULL) += console.o
+obj-$(CONFIG_EFI_LOADER_HII) += hii.o hii_config.o
diff --git a/efi/loader/protocols/hii.c b/efi/loader/protocols/hii.c
new file mode 100644
index 000000000000..f35489eba283
--- /dev/null
+++ b/efi/loader/protocols/hii.c
@@ -0,0 +1,1100 @@
+// 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 <charset.h>
+#include <linux/printk.h>
+#include <efi/loader.h>
+#include <efi/guid.h>
+#include <efi/error.h>
+#include <efi/guid.h>
+#include <efi/loader/object.h>
+#include <efi/protocol/hii.h>
+#include <efi/loader/trace.h>
+#include <malloc.h>
+#include <wchar.h>
+#include <asm/unaligned.h>
+#include <init.h>
+
+static LIST_HEAD(efi_package_lists);
+static LIST_HEAD(efi_keyboard_layout_list);
+
+struct efi_hii_packagelist {
+       struct list_head link;
+       // 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 */
+       struct list_head guid_list;
+       struct list_head keyboard_packages;
+
+       /* we could also track fonts, images, etc */
+};
+
+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) +
+               (wcslen(blk->string_text) + 1) * 2;
+}
+
+static int efi_hii_packagelist_exists(efi_hii_handle_t package_list)
+{
+       struct efi_hii_packagelist *hii;
+       int found = 0;
+
+       list_for_each_entry(hii, &efi_package_lists, link) {
+               if (hii == package_list) {
+                       found = 1;
+                       break;
+               }
+       }
+
+       return found;
+}
+
+static u32 efi_hii_package_type(struct efi_hii_package_header *header)
+{
+       u32 fields;
+
+       fields = get_unaligned_le32(&header->fields);
+
+       return (fields >> __EFI_HII_PACKAGE_TYPE_SHIFT)
+               & __EFI_HII_PACKAGE_TYPE_MASK;
+}
+
+static u32 efi_hii_package_len(struct efi_hii_package_header *header)
+{
+       u32 fields;
+
+       fields = get_unaligned_le32(&header->fields);
+
+       return (fields >> __EFI_HII_PACKAGE_LEN_SHIFT)
+               & __EFI_HII_PACKAGE_LEN_MASK;
+}
+
+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;
+};
+
+struct efi_guid_data {
+       struct list_head link;
+       struct efi_hii_guid_package package;
+};
+
+struct efi_keyboard_layout_data {
+       struct list_head link;          /* in package */
+       struct list_head link_sys;      /* in global list */
+       struct efi_hii_keyboard_layout keyboard_layout;
+};
+
+struct efi_keyboard_package_data {
+       struct list_head link;          /* in package_list */
+       struct list_head keyboard_layout_list;
+};
+
+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;
+
+       EFI_PRINT("header_size: %08x\n",
+                 get_unaligned_le32(&strings_package->header_size));
+       EFI_PRINT("string_info_offset: %08x\n",
+                 get_unaligned_le32(&strings_package->string_info_offset));
+       EFI_PRINT("language_name: %u\n",
+                 get_unaligned_le16(&strings_package->language_name));
+       EFI_PRINT("language: %s\n", strings_package->language);
+
+       /* count # of string entries: */
+       end = ((void *)strings_package)
+                       + efi_hii_package_len(&strings_package->header);
+       block = ((void *)strings_package)
+               + get_unaligned_le32(&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;
+                       nstrings++;
+                       block = efi_hii_sibt_string_ucs2_block_next(ucs2);
+                       break;
+               }
+               case EFI_HII_SIBT_END:
+                       block = end;
+                       break;
+               default:
+                       EFI_PRINT("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 =
+                       get_unaligned_le16(&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)
+               + get_unaligned_le32(&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;
+                       EFI_PRINT("%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++;
+                       /* FIXME: accessing u16 * here */
+                       block = efi_hii_sibt_string_ucs2_block_next(ucs2);
+                       break;
+               }
+               case EFI_HII_SIBT_END:
+                       goto out;
+               default:
+                       EFI_PRINT("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);
+               while (idx > 0)
+                       free(stbl->strings[--idx].string);
+               free(stbl->strings);
+       }
+       free(stbl);
+
+       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 void free_keyboard_layouts(struct efi_keyboard_package_data *package)
+{
+       struct efi_keyboard_layout_data *layout_data;
+
+       while (!list_empty(&package->keyboard_layout_list)) {
+               layout_data = list_first_entry(&package->keyboard_layout_list,
+                                              struct efi_keyboard_layout_data,
+                                              link);
+               list_del(&layout_data->link);
+               list_del(&layout_data->link_sys);
+               free(layout_data);
+       }
+}
+
+static void remove_keyboard_package(struct efi_hii_packagelist *hii)
+{
+       struct efi_keyboard_package_data *package;
+
+       while (!list_empty(&hii->keyboard_packages)) {
+               package = list_first_entry(&hii->keyboard_packages,
+                                          struct efi_keyboard_package_data,
+                                          link);
+               free_keyboard_layouts(package);
+               list_del(&package->link);
+               free(package);
+       }
+}
+
+static efi_status_t
+add_keyboard_package(struct efi_hii_packagelist *hii,
+                    struct efi_hii_keyboard_package *keyboard_package)
+{
+       struct efi_keyboard_package_data *package_data;
+       struct efi_hii_keyboard_layout *layout;
+       struct efi_keyboard_layout_data *layout_data;
+       u16 layout_count, layout_length;
+       int i;
+
+       package_data = malloc(sizeof(*package_data));
+       if (!package_data)
+               return EFI_OUT_OF_RESOURCES;
+       INIT_LIST_HEAD(&package_data->link);
+       INIT_LIST_HEAD(&package_data->keyboard_layout_list);
+
+       layout = &keyboard_package->layout[0];
+       layout_count = get_unaligned_le16(&keyboard_package->layout_count);
+       for (i = 0; i < layout_count; i++) {
+               layout_length = get_unaligned_le16(&layout->layout_length);
+               layout_data = malloc(sizeof(*layout_data) + layout_length);
+               if (!layout_data)
+                       goto out;
+
+               memcpy(&layout_data->keyboard_layout, layout, layout_length);
+               list_add_tail(&layout_data->link,
+                             &package_data->keyboard_layout_list);
+               list_add_tail(&layout_data->link_sys,
+                             &efi_keyboard_layout_list);
+
+               layout += layout_length;
+       }
+
+       list_add_tail(&package_data->link, &hii->keyboard_packages);
+
+       return EFI_SUCCESS;
+
+out:
+       free_keyboard_layouts(package_data);
+       free(package_data);
+
+       return EFI_OUT_OF_RESOURCES;
+}
+
+static struct efi_hii_packagelist *new_packagelist(void)
+{
+       struct efi_hii_packagelist *hii;
+
+       hii = malloc(sizeof(*hii));
+       if (!hii)
+               return NULL;
+
+       list_add_tail(&hii->link, &efi_package_lists);
+       hii->max_string_id = 0;
+       INIT_LIST_HEAD(&hii->string_tables);
+       INIT_LIST_HEAD(&hii->guid_list);
+       INIT_LIST_HEAD(&hii->keyboard_packages);
+
+       return hii;
+}
+
+static void free_packagelist(struct efi_hii_packagelist *hii)
+{
+       remove_strings_package(hii);
+       remove_guid_package(hii);
+       remove_keyboard_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)
+               + get_unaligned_le32(&package_list->package_length);
+
+       EFI_PRINT("package_list: %pUs (%u)\n", &package_list->package_list_guid,
+                 get_unaligned_le32(&package_list->package_length));
+
+       package = ((void *)package_list) + sizeof(*package_list);
+       while ((void *)package < end) {
+               EFI_PRINT("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:
+                       ret = add_guid_package(hii,
+                               (struct efi_hii_guid_package *)package);
+                       break;
+               case EFI_HII_PACKAGE_FORMS:
+                       EFI_PRINT("Form 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:
+                       EFI_PRINT("Font package not supported\n");
+                       ret = EFI_INVALID_PARAMETER;
+                       break;
+               case EFI_HII_PACKAGE_IMAGES:
+                       EFI_PRINT("Image package not supported\n");
+                       ret = EFI_INVALID_PARAMETER;
+                       break;
+               case EFI_HII_PACKAGE_SIMPLE_FONTS:
+                       EFI_PRINT("Simple font package not supported\n");
+                       ret = EFI_INVALID_PARAMETER;
+                       break;
+               case EFI_HII_PACKAGE_DEVICE_PATH:
+                       EFI_PRINT("Device path package not supported\n");
+                       ret = EFI_INVALID_PARAMETER;
+                       break;
+               case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
+                       ret = add_keyboard_package(hii,
+                               (struct efi_hii_keyboard_package *)package);
+                       break;
+               case EFI_HII_PACKAGE_ANIMATIONS:
+                       EFI_PRINT("Animation 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;
+       *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 (!handle || !efi_hii_packagelist_exists(handle))
+               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 (!handle || !efi_hii_packagelist_exists(handle))
+               return EFI_EXIT(EFI_NOT_FOUND);
+
+       if (!package_list)
+               return EFI_EXIT(EFI_INVALID_PARAMETER);
+
+       EFI_PRINT("package_list: %pUs (%u)\n", &package_list->package_list_guid,
+                 get_unaligned_le32(&package_list->package_length));
+
+       package = ((void *)package_list) + sizeof(*package_list);
+       end = ((void *)package_list)
+               + get_unaligned_le32(&package_list->package_length);
+
+       while ((void *)package < end) {
+               EFI_PRINT("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:
+                       remove_guid_package(hii);
+                       break;
+               case EFI_HII_PACKAGE_FORMS:
+                       EFI_PRINT("Form package not supported\n");
+                       ret = EFI_INVALID_PARAMETER;
+                       break;
+               case EFI_HII_PACKAGE_STRINGS:
+                       remove_strings_package(hii);
+                       break;
+               case EFI_HII_PACKAGE_FONTS:
+                       EFI_PRINT("Font package not supported\n");
+                       ret = EFI_INVALID_PARAMETER;
+                       break;
+               case EFI_HII_PACKAGE_IMAGES:
+                       EFI_PRINT("Image package not supported\n");
+                       ret = EFI_INVALID_PARAMETER;
+                       break;
+               case EFI_HII_PACKAGE_SIMPLE_FONTS:
+                       EFI_PRINT("Simple font package not supported\n");
+                       ret = EFI_INVALID_PARAMETER;
+                       break;
+               case EFI_HII_PACKAGE_DEVICE_PATH:
+                       EFI_PRINT("Device path package not supported\n");
+                       ret = EFI_INVALID_PARAMETER;
+                       break;
+               case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
+                       remove_keyboard_package(hii);
+                       break;
+               case EFI_HII_PACKAGE_ANIMATIONS:
+                       EFI_PRINT("Animation 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: already removed some packages */
+               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_NOT_FOUND;
+
+       EFI_ENTRY("%p, %u, %pUs, %p, %p", this, package_type, package_guid,
+                 handle_buffer_length, handle);
+
+       if (!handle_buffer_length ||
+           (*handle_buffer_length && !handle)) {
+               ret = EFI_INVALID_PARAMETER;
+               goto out;
+       }
+
+       if ((package_type != EFI_HII_PACKAGE_TYPE_GUID && package_guid) ||
+           (package_type == EFI_HII_PACKAGE_TYPE_GUID && !package_guid)) {
+               ret = EFI_INVALID_PARAMETER;
+               goto out;
+       }
+
+       EFI_PRINT("package type=%x, guid=%pUs, length=%zu\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:
+                       if (!list_empty(&hii->guid_list))
+                               break;
+                       continue;
+               case EFI_HII_PACKAGE_STRINGS:
+                       if (!list_empty(&hii->string_tables))
+                               break;
+                       continue;
+               case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
+                       if (!list_empty(&hii->keyboard_packages))
+                               break;
+                       continue;
+               default:
+                       continue;
+               }
+
+               package_cnt++;
+               if (package_cnt <= package_max) {
+                       *handle++ = hii;
+                       ret = EFI_SUCCESS;
+               } else {
+                       ret = EFI_BUFFER_TOO_SMALL;
+               }
+       }
+       *handle_buffer_length = package_cnt * sizeof(*handle);
+out:
+       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)
+               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, %pUs, %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)
+{
+       struct efi_keyboard_layout_data *layout_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);
+
+       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(layout_data, &efi_keyboard_layout_list, link_sys) {
+               package_cnt++;
+               if (package_cnt <= package_max)
+                       memcpy(key_guid_buffer++,
+                              &layout_data->keyboard_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
+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)
+{
+       struct efi_keyboard_layout_data *layout_data;
+       u16 layout_length;
+
+       EFI_ENTRY("%p, %pUs, %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(layout_data, &efi_keyboard_layout_list, link_sys) {
+               if (!memcmp(layout_data->keyboard_layout.guid, key_guid,
+                           sizeof(efi_guid_t)))
+                       goto found;
+       }
+
+       return EFI_EXIT(EFI_NOT_FOUND);
+
+found:
+       layout_length =
+               get_unaligned_le16(&layout_data->keyboard_layout.layout_length);
+       if (*keyboard_layout_length < layout_length) {
+               *keyboard_layout_length = layout_length;
+               return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
+       }
+
+       memcpy(keyboard_layout, &layout_data->keyboard_layout, layout_length);
+
+       return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI
+set_keyboard_layout(const struct efi_hii_database_protocol *this,
+                   efi_guid_t *key_guid)
+{
+       EFI_ENTRY("%p, %pUs", this, key_guid);
+
+       if (!key_guid)
+               return EFI_EXIT(EFI_INVALID_PARAMETER);
+
+       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_INVALID_PARAMETER);
+}
+
+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)
+{
+       size_t n;
+
+       n = strlen(language);
+       /* match primary language? */
+       if (!strncasecmp(language, languages, n) &&
+           (languages[n] == ';' || languages[n] == '\0'))
+               return true;
+
+       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 (!package_list || !efi_hii_packagelist_exists(package_list))
+               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 (!package_list || !efi_hii_packagelist_exists(package_list))
+               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_strsize(str);
+                               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 (!package_list || !efi_hii_packagelist_exists(package_list))
+               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 (!package_list || !efi_hii_packagelist_exists(package_list))
+               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++ = ';';
+               strcpy(p, stbl->language);
+               p += strlen((char *)stbl->language);
+       }
+       *p = '\0';
+
+       EFI_PRINT("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 (!package_list || !efi_hii_packagelist_exists(package_list))
+               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);
+}
+
+static 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
+};
+
+static int efi_hii_init(void)
+{
+       efi_add_root_node_protocol_deferred(&efi_guid_hii_string_protocol, 
&efi_hii_string);
+       efi_add_root_node_protocol_deferred(&efi_guid_hii_database_protocol, 
&efi_hii_database);
+       return 0;
+}
+device_initcall(efi_hii_init);
diff --git a/efi/loader/protocols/hii_config.c 
b/efi/loader/protocols/hii_config.c
new file mode 100644
index 000000000000..07dce2dae771
--- /dev/null
+++ b/efi/loader/protocols/hii_config.c
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier:     GPL-2.0+
+/*
+ * EFI Human Interface Infrastructure ... Configuration
+ *
+ * Copyright (c) 2017 Leif Lindholm
+ * Copyright (c) 2018 AKASHI Takahiro, Linaro Limited
+ */
+
+#include <linux/printk.h>
+#include <efi/loader.h>
+#include <efi/protocol/hii.h>
+#include <efi/loader/object.h>
+#include <efi/loader/trace.h>
+#include <efi/error.h>
+#include <efi/guid.h>
+#include <init.h>
+
+/*
+ * 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\", %pUs, \"%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
+ */
+
+static 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);
+};
+
+static 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);
+};
+
+static 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%zx, 0x%x, 0x%x, %p, %p", this, action,
+                 question_id, type, value, action_request);
+
+       return EFI_EXIT(EFI_DEVICE_ERROR);
+};
+
+static 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
+};
+
+static 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
+};
+
+static int efi_hii_init(void)
+{
+       
efi_add_root_node_protocol_deferred(&efi_guid_hii_config_routing_protocol,
+                                           &efi_hii_config_routing);
+       
efi_add_root_node_protocol_deferred(&efi_guid_hii_config_access_protocol,
+                                           &efi_hii_config_access);
+       return 0;
+}
+device_initcall(efi_hii_init);
diff --git a/include/efi/protocol/hii.h b/include/efi/protocol/hii.h
new file mode 100644
index 000000000000..d047467a0855
--- /dev/null
+++ b/include/efi/protocol/hii.h
@@ -0,0 +1,428 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Human Interface Infrastructure (HII)
+ */
+
+#ifndef __EFI_PROTOCOL_HII_H_
+#define __EFI_PROTOCOL_HII_H_
+
+#include <efi/types.h>
+
+typedef void *efi_hii_handle_t;
+typedef u16 *efi_string_t;
+typedef u16 efi_string_id_t;
+typedef u32 efi_hii_font_style_t;
+typedef u16 efi_question_id_t;
+typedef u16 efi_image_id_t;
+typedef u16 efi_form_id_t;
+
+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_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
+
+/*
+ * HII GUID package
+ */
+struct efi_hii_guid_package {
+       struct efi_hii_package_header header;
+       efi_guid_t guid;
+       char data[];
+} __packed;
+
+/*
+ * HII string package
+ */
+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;
+
+/*
+ * HII forms package
+ * TODO: full scope of definitions
+ */
+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
+
+/*
+ * HII keyboard package
+ */
+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 {
+       u32 key;
+       u16 unicode;
+       u16 shifted_unicode;
+       u16 alt_gr_unicode;
+       u16 shifted_alt_gr_unicode;
+       u16 modifier;
+       u16 affected_attribute;
+} __packed;
+
+struct efi_hii_keyboard_layout {
+       u16 layout_length;
+       /*
+        * The EFI spec defines this as efi_guid_t.
+        * clang and gcc both report alignment problems here.
+        * clang with -Wunaligned-access
+        * warning: field guid within 'struct efi_hii_keyboard_layout' is less
+        * aligned than 'efi_guid_t' and is usually due to
+        * 'struct efi_hii_keyboard_layout' being packed, which can lead to
+        * unaligned accesses
+        *
+        * GCC with -Wpacked-not-aligned -Waddress-of-packed-member
+        * 'efi_guid_t' offset 2 in 'struct efi_hii_keyboard_layout'
+        * isn't aligned to 4
+        *
+        * Removing the alignment from efi_guid_t is not an option, since
+        * it is also used in non-packed structs and that would break
+        * calculations with offsetof
+        *
+        * This is the only place we get a report for. That happens because
+        * all other declarations of efi_guid_t within a packed struct happens
+        * to be 4-byte aligned.  i.e a u32, a u64 a 2 * u16 or any combination
+        * that ends up landing efi_guid_t on a 4byte boundary precedes.
+        *
+        * Replace this with a 1-byte aligned counterpart of b[16].  This is a
+        * packed struct so the memory  placement of efi_guid_t should not 
change
+        *
+        */
+       u8 guid[16];
+       u32 layout_descriptor_string_offset;
+       u8 descriptor_count;
+       /* struct efi_key_descriptor descriptors[]; follows here */
+} __packed;
+
+struct efi_hii_keyboard_package {
+       struct efi_hii_package_header header;
+       u16 layout_count;
+       struct efi_hii_keyboard_layout layout[];
+} __packed;
+
+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);
+};
+
+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);
+};
+
+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);
+};
+
+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);
+};
+
+#endif
-- 
2.47.3


Reply via email to