[RESEND,v2,2/6] efi_loader: Initial HII database protocols

Message ID 20181214101043.14067-3-takahiro.akashi@linaro.org
State New
Headers show
Series
  • subject: efi_loader: add HII database protocol
Related show

Commit Message

AKASHI Takahiro Dec. 14, 2018, 10:10 a.m.
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

Comments

Heinrich Schuchardt Dec. 15, 2018, 8:48 p.m. | #1
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
Heinrich Schuchardt Dec. 16, 2018, 8:36 p.m. | #2
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
AKASHI Takahiro Dec. 17, 2018, 12:36 a.m. | #3
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
AKASHI Takahiro Dec. 17, 2018, 1:16 a.m. | #4
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
Heinrich Schuchardt Dec. 18, 2018, 5:01 p.m. | #5
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
> +};
>
AKASHI Takahiro Dec. 19, 2018, 1:16 a.m. | #6
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
> > +};
> > 
>
Alexander Graf Dec. 23, 2018, 1:46 a.m. | #7
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
AKASHI Takahiro Dec. 25, 2018, 8:30 a.m. | #8
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
Heinrich Schuchardt Jan. 6, 2019, 3:57 p.m. | #9
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);
> +}
AKASHI Takahiro Jan. 7, 2019, 2:30 a.m. | #10
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);
> > +}
>
Leif Lindholm Jan. 7, 2019, 2:09 p.m. | #11
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
Leif Lindholm Jan. 7, 2019, 7:22 p.m. | #12
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

Patch

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
+};