All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH 00/11] efi_loader: patches for Shell.efi
@ 2017-10-10 12:22 Rob Clark
  2017-10-10 12:22 ` [U-Boot] [PATCH 01/11] efi_loader: Initial EFI_DEVICE_PATH_UTILITIES_PROTOCOL Rob Clark
                   ` (11 more replies)
  0 siblings, 12 replies; 75+ messages in thread
From: Rob Clark @ 2017-10-10 12:22 UTC (permalink / raw)
  To: u-boot

Re-send of the patch series to get Shell.efi working, and almost get
SCT.efi (the UEFI test suite) working.

Since last time, I've updated to Heinrich's latest SetWatchdogTimer
patch (as of yesterday evening), and adressed review comments on the
three new sets of protocols added.  Part of that, to avoid moving
changes from my later patch that added implementation on top of Leif's
initial stubs was done by simply squashing the patches together.


Heinrich Schuchardt (1):
  efi_loader: implement SetWatchdogTimer

Leif Lindholm (3):
  efi_loader: Initial EFI_DEVICE_PATH_UTILITIES_PROTOCOL
  efi_loader: Initial HII protocols
  efi_loader: Initial EFI_UNICODE_COLLATION_PROTOCOL

Rob Clark (7):
  efi_loader: SIMPLE_TEXT_INPUT_EX plus wire up objects properly
  efi_loader: console support for color attributes
  efi_loader: Decouple EFI input/output from stdin/stdout
  efi_loader: fix events
  efi_loader: Fix disk dp's for pre-DM/legacy devices
  efi_loader: Add mem-mapped for fallback
  efi_loader: exclude openrd devices

 cmd/bootefi.c                              |  24 ++
 include/efi_api.h                          | 438 ++++++++++++++++++++++++-
 include/efi_loader.h                       |  29 +-
 lib/efi_loader/Kconfig                     |   2 +-
 lib/efi_loader/Makefile                    |   3 +-
 lib/efi_loader/efi_boottime.c              | 256 ++++++++-------
 lib/efi_loader/efi_console.c               | 398 +++++++++++++++++++---
 lib/efi_loader/efi_device_path.c           |  24 ++
 lib/efi_loader/efi_device_path_to_text.c   |   9 +
 lib/efi_loader/efi_device_path_utilities.c |  88 +++++
 lib/efi_loader/efi_disk.c                  |  11 +
 lib/efi_loader/efi_hii.c                   | 507 +++++++++++++++++++++++++++++
 lib/efi_loader/efi_unicode.c               | 170 ++++++++++
 lib/efi_loader/efi_watchdog.c              |  86 +++++
 14 files changed, 1861 insertions(+), 184 deletions(-)
 create mode 100644 lib/efi_loader/efi_device_path_utilities.c
 create mode 100644 lib/efi_loader/efi_hii.c
 create mode 100644 lib/efi_loader/efi_unicode.c
 create mode 100644 lib/efi_loader/efi_watchdog.c

-- 
2.13.6

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 01/11] efi_loader: Initial EFI_DEVICE_PATH_UTILITIES_PROTOCOL
  2017-10-10 12:22 [U-Boot] [PATCH 00/11] efi_loader: patches for Shell.efi Rob Clark
@ 2017-10-10 12:22 ` Rob Clark
  2017-10-11  0:03   ` Heinrich Schuchardt
  2017-10-11 14:07   ` Alexander Graf
  2017-10-10 12:22 ` [U-Boot] [PATCH 02/11] efi_loader: Initial HII protocols Rob Clark
                   ` (10 subsequent siblings)
  11 siblings, 2 replies; 75+ messages in thread
From: Rob Clark @ 2017-10-10 12:22 UTC (permalink / raw)
  To: u-boot

From: Leif Lindholm <leif.lindholm@linaro.org>

Not complete, but enough for Shell.efi and SCT.efi.  We'll implement the
rest as needed or once we have SCT running properly so there is a way to
validate the interface against the conformance test suite.

Initial skeleton written by Leif, and then implementation by myself.

Cc: Leif Lindholm <leif.lindholm@linaro.org>
Signed-off-by: Rob Clark <robdclark@gmail.com>
---
 include/efi_api.h                          | 34 +++++++++++-
 include/efi_loader.h                       |  2 +
 lib/efi_loader/Makefile                    |  1 +
 lib/efi_loader/efi_boottime.c              |  4 ++
 lib/efi_loader/efi_device_path_utilities.c | 88 ++++++++++++++++++++++++++++++
 5 files changed, 127 insertions(+), 2 deletions(-)
 create mode 100644 lib/efi_loader/efi_device_path_utilities.c

diff --git a/include/efi_api.h b/include/efi_api.h
index a9a6494afe..ffdba7fe1a 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -28,8 +28,9 @@ enum efi_timer_delay {
 	EFI_TIMER_RELATIVE = 2
 };
 
-#define UINTN size_t
-typedef long INTN;
+#define UINTN size_t   /* TODO this should be removed in a future patch */
+typedef size_t efi_uintn_t;
+typedef ssize_t efi_intn_t;
 typedef uint16_t *efi_string_t;
 
 #define EVT_TIMER				0x80000000
@@ -506,6 +507,35 @@ struct efi_device_path_to_text_protocol
 			bool allow_shortcuts);
 };
 
+#define EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID \
+	EFI_GUID(0x0379be4e, 0xd706, 0x437d, \
+		 0xb0, 0x37, 0xed, 0xb8, 0x2f, 0xb7, 0x72, 0xa4)
+
+struct efi_device_path_utilities_protocol {
+	efi_uintn_t (EFIAPI *get_device_path_size)(
+		const struct efi_device_path *device_path);
+	struct efi_device_path *(EFIAPI *duplicate_device_path)(
+		const struct efi_device_path *device_path);
+	struct efi_device_path *(EFIAPI *append_device_path)(
+		const struct efi_device_path *src1,
+		const struct efi_device_path *src2);
+	struct efi_device_path *(EFIAPI *append_device_node)(
+		const struct efi_device_path *device_path,
+		const struct efi_device_path *device_node);
+	struct efi_device_path *(EFIAPI *append_device_path_instance)(
+		const struct efi_device_path *device_path,
+		const struct efi_device_path *device_path_instance);
+	struct efi_device_path *(EFIAPI *get_next_device_path_instance)(
+		struct efi_device_path **device_path_instance,
+		efi_uintn_t *device_path_instance_size);
+	bool (EFIAPI *is_device_path_multi_instance)(
+		const struct efi_device_path *device_path);
+	struct efi_device_path *(EFIAPI *create_device_node)(
+		uint8_t node_type,
+		uint8_t node_sub_type,
+		uint16_t node_length);
+};
+
 #define EFI_GOP_GUID \
 	EFI_GUID(0x9042a9de, 0x23dc, 0x4a38, \
 		 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a)
diff --git a/include/efi_loader.h b/include/efi_loader.h
index e1179b7dcd..5d37c1d75f 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -79,6 +79,7 @@ extern const struct efi_simple_text_output_protocol efi_con_out;
 extern struct efi_simple_input_interface efi_con_in;
 extern const struct efi_console_control_protocol efi_console_control;
 extern const struct efi_device_path_to_text_protocol efi_device_path_to_text;
+extern const struct efi_device_path_utilities_protocol efi_device_path_utilities;
 
 uint16_t *efi_dp_str(struct efi_device_path *dp);
 
@@ -89,6 +90,7 @@ extern const efi_guid_t efi_guid_loaded_image;
 extern const efi_guid_t efi_guid_device_path_to_text_protocol;
 extern const efi_guid_t efi_simple_file_system_protocol_guid;
 extern const efi_guid_t efi_file_info_guid;
+extern const efi_guid_t efi_guid_device_path_utilities_protocol;
 
 extern unsigned int __efi_runtime_start, __efi_runtime_stop;
 extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
index ddb978f650..b6927b3b84 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -17,6 +17,7 @@ endif
 obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o
 obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o
 obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o
+obj-y += efi_device_path_utilities.o
 obj-y += efi_file.o efi_variable.o efi_bootmgr.o
 obj-$(CONFIG_LCD) += efi_gop.o
 obj-$(CONFIG_DM_VIDEO) += efi_gop.o
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index 976d5822f7..92c778fcca 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -1153,6 +1153,10 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob
 	obj->protocols[3].protocol_interface =
 		(void *)&efi_device_path_to_text;
 
+	obj->protocols[4].guid = &efi_guid_device_path_utilities_protocol;
+	obj->protocols[4].protocol_interface =
+		(void *)&efi_device_path_utilities;
+
 	info->file_path = file_path;
 	info->device_handle = efi_dp_find_obj(device_path, NULL);
 
diff --git a/lib/efi_loader/efi_device_path_utilities.c b/lib/efi_loader/efi_device_path_utilities.c
new file mode 100644
index 0000000000..9d90f14ee4
--- /dev/null
+++ b/lib/efi_loader/efi_device_path_utilities.c
@@ -0,0 +1,88 @@
+/*
+ *  EFI device path interface
+ *
+ *  Copyright (c) 2017 Leif Lindholm
+ *
+ *  SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <efi_loader.h>
+
+const efi_guid_t efi_guid_device_path_utilities_protocol =
+		EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID;
+
+static efi_uintn_t EFIAPI get_device_path_size(
+	const struct efi_device_path *device_path)
+{
+	efi_uintn_t sz = 0;
+	EFI_ENTRY("%p", device_path);
+	/* size includes the END node: */
+	if (device_path)
+		sz = efi_dp_size(device_path) + sizeof(struct efi_device_path);
+	return EFI_EXIT(sz);
+}
+
+static struct efi_device_path * EFIAPI duplicate_device_path(
+	const struct efi_device_path *device_path)
+{
+	EFI_ENTRY("%p", device_path);
+	return EFI_EXIT(efi_dp_dup(device_path));
+}
+
+static struct efi_device_path * EFIAPI append_device_path(
+	const struct efi_device_path *src1,
+	const struct efi_device_path *src2)
+{
+	EFI_ENTRY("%p, %p", src1, src2);
+	return EFI_EXIT(efi_dp_append(src1, src2));
+}
+
+static struct efi_device_path * EFIAPI append_device_node(
+	const struct efi_device_path *device_path,
+	const struct efi_device_path *device_node)
+{
+	EFI_ENTRY("%p, %p", device_path, device_node);
+	return EFI_EXIT(efi_dp_append_node(device_path, device_node));
+}
+
+static struct efi_device_path * EFIAPI append_device_path_instance(
+	const struct efi_device_path *device_path,
+	const struct efi_device_path *device_path_instance)
+{
+	EFI_ENTRY("%p, %p", device_path, device_path_instance);
+	return EFI_EXIT(NULL);
+}
+
+static struct efi_device_path * EFIAPI get_next_device_path_instance(
+	struct efi_device_path **device_path_instance,
+	efi_uintn_t *device_path_instance_size)
+{
+	EFI_ENTRY("%p, %p", device_path_instance, device_path_instance_size);
+	return EFI_EXIT(NULL);
+}
+
+static bool EFIAPI is_device_path_multi_instance(
+	const struct efi_device_path *device_path)
+{
+	EFI_ENTRY("%p", device_path);
+	return EFI_EXIT(false);
+}
+
+static struct efi_device_path * EFIAPI create_device_node(
+	uint8_t node_type, uint8_t node_sub_type, uint16_t node_length)
+{
+	EFI_ENTRY("%u, %u, %u", node_type, node_sub_type, node_length);
+	return EFI_EXIT(NULL);
+}
+
+const struct efi_device_path_utilities_protocol efi_device_path_utilities = {
+	.get_device_path_size = get_device_path_size,
+	.duplicate_device_path = duplicate_device_path,
+	.append_device_path = append_device_path,
+	.append_device_node = append_device_node,
+	.append_device_path_instance = append_device_path_instance,
+	.get_next_device_path_instance = get_next_device_path_instance,
+	.is_device_path_multi_instance = is_device_path_multi_instance,
+	.create_device_node = create_device_node,
+};
-- 
2.13.6

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 02/11] efi_loader: Initial HII protocols
  2017-10-10 12:22 [U-Boot] [PATCH 00/11] efi_loader: patches for Shell.efi Rob Clark
  2017-10-10 12:22 ` [U-Boot] [PATCH 01/11] efi_loader: Initial EFI_DEVICE_PATH_UTILITIES_PROTOCOL Rob Clark
@ 2017-10-10 12:22 ` Rob Clark
  2017-10-11 14:30   ` Alexander Graf
  2018-09-22 10:34   ` Heinrich Schuchardt
  2017-10-10 12:22 ` [U-Boot] [PATCH 03/11] efi_loader: Initial EFI_UNICODE_COLLATION_PROTOCOL Rob Clark
                   ` (9 subsequent siblings)
  11 siblings, 2 replies; 75+ messages in thread
From: Rob Clark @ 2017-10-10 12:22 UTC (permalink / raw)
  To: u-boot

From: Leif Lindholm <leif.lindholm@linaro.org>

Enough implementation of the following protocols to run Shell.efi and
SCT.efi:

  EfiHiiConfigRoutingProtocolGuid
  EfiHiiDatabaseProtocol
  EfiHiiStringProtocol

We'll fill in the rest once SCT is running properly so we can validate
the implementation against the conformance test suite.

Initial skeleton written by Leif, and then implementation by myself.

Cc: Leif Lindholm <leif.lindholm@linaro.org>
Signed-off-by: Rob Clark <robdclark@gmail.com>
---
 include/efi_api.h             | 261 ++++++++++++++++++++++
 include/efi_loader.h          |   6 +
 lib/efi_loader/Makefile       |   2 +-
 lib/efi_loader/efi_boottime.c |   9 +
 lib/efi_loader/efi_hii.c      | 507 ++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 784 insertions(+), 1 deletion(-)
 create mode 100644 lib/efi_loader/efi_hii.c

diff --git a/include/efi_api.h b/include/efi_api.h
index ffdba7fe1a..164147dc87 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -16,6 +16,7 @@
 #define _EFI_API_H
 
 #include <efi.h>
+#include <charset.h>
 
 #ifdef CONFIG_EFI_LOADER
 #include <asm/setjmp.h>
@@ -536,6 +537,266 @@ struct efi_device_path_utilities_protocol {
 		uint16_t node_length);
 };
 
+#define EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID \
+	EFI_GUID(0x587e72d7, 0xcc50, 0x4f79, \
+		 0x82, 0x09, 0xca, 0x29, 0x1f, 0xc1, 0xa1, 0x0f)
+
+typedef uint16_t efi_string_id_t;
+
+struct efi_hii_config_routing_protocol {
+	efi_status_t(EFIAPI *extract_config)(
+		const struct efi_hii_config_routing_protocol *this,
+		const efi_string_t request,
+		efi_string_t *progress,
+		efi_string_t *results);
+	efi_status_t(EFIAPI *export_config)(
+		const struct efi_hii_config_routing_protocol *this,
+		efi_string_t *results);
+	efi_status_t(EFIAPI *route_config)(
+		const struct efi_hii_config_routing_protocol *this,
+		const efi_string_t configuration,
+		efi_string_t *progress);
+	efi_status_t(EFIAPI *block_to_config)(
+		const struct efi_hii_config_routing_protocol *this,
+		const efi_string_t config_request,
+		const uint8_t *block,
+		const efi_uintn_t block_size,
+		efi_string_t *config,
+		efi_string_t *progress);
+	efi_status_t(EFIAPI *config_to_block)(
+		const struct efi_hii_config_routing_protocol *this,
+		const efi_string_t config_resp,
+		const uint8_t *block,
+		const efi_uintn_t *block_size,
+		efi_string_t *progress);
+	efi_status_t(EFIAPI *get_alt_config)(
+		const struct efi_hii_config_routing_protocol *this,
+		const efi_string_t config_resp,
+		const efi_guid_t *guid,
+		const efi_string_t name,
+		const struct efi_device_path *device_path,
+		const efi_string_t alt_cfg_id,
+		efi_string_t *alt_cfg_resp);
+};
+
+#define EFI_HII_DATABASE_PROTOCOL_GUID	     \
+	EFI_GUID(0xef9fc172, 0xa1b2, 0x4693, \
+		 0xb3, 0x27, 0x6d, 0x32, 0xfc, 0x41, 0x60, 0x42)
+
+typedef enum {
+	EFI_KEY_LCTRL, EFI_KEY_A0, EFI_KEY_LALT, EFI_KEY_SPACE_BAR,
+	EFI_KEY_A2, EFI_KEY_A3, EFI_KEY_A4, EFI_KEY_RCTRL, EFI_KEY_LEFT_ARROW,
+	EFI_KEY_DOWN_ARROW, EFI_KEY_RIGHT_ARROW, EFI_KEY_ZERO,
+	EFI_KEY_PERIOD, EFI_KEY_ENTER, EFI_KEY_LSHIFT, EFI_KEY_B0,
+	EFI_KEY_B1, EFI_KEY_B2, EFI_KEY_B3, EFI_KEY_B4, EFI_KEY_B5, EFI_KEY_B6,
+	EFI_KEY_B7, EFI_KEY_B8, EFI_KEY_B9, EFI_KEY_B10, EFI_KEY_RSHIFT,
+	EFI_KEY_UP_ARROW, EFI_KEY_ONE, EFI_KEY_TWO, EFI_KEY_THREE,
+	EFI_KEY_CAPS_LOCK, EFI_KEY_C1, EFI_KEY_C2, EFI_KEY_C3, EFI_KEY_C4,
+	EFI_KEY_C5, EFI_KEY_C6, EFI_KEY_C7, EFI_KEY_C8, EFI_KEY_C9,
+	EFI_KEY_C10, EFI_KEY_C11, EFI_KEY_C12, EFI_KEY_FOUR, EFI_KEY_FIVE,
+	EFI_KEY_SIX, EFI_KEY_PLUS, EFI_KEY_TAB, EFI_KEY_D1, EFI_KEY_D2,
+	EFI_KEY_D3, EFI_KEY_D4, EFI_KEY_D5, EFI_KEY_D6, EFI_KEY_D7, EFI_KEY_D8,
+	EFI_KEY_D9, EFI_KEY_D10, EFI_KEY_D11, EFI_KEY_D12, EFI_KEY_D13,
+	EFI_KEY_DEL, EFI_KEY_END, EFI_KEY_PG_DN, EFI_KEY_SEVEN, EFI_KEY_EIGHT,
+	EFI_KEY_NINE, EFI_KEY_E0, EFI_KEY_E1, EFI_KEY_E2, EFI_KEY_E3,
+	EFI_KEY_E4, EFI_KEY_E5, EFI_KEY_E6, EFI_KEY_E7, EFI_KEY_E8, EFI_KEY_E9,
+	EFI_KEY_E10, EFI_KEY_E11, EFI_KEY_E12, EFI_KEY_BACK_SPACE,
+	EFI_KEY_INS, EFI_KEY_HOME, EFI_KEY_PG_UP, EFI_KEY_NLCK, EFI_KEY_SLASH,
+	EFI_KEY_ASTERISK, EFI_KEY_MINUS, EFI_KEY_ESC, EFI_KEY_F1, EFI_KEY_F2,
+	EFI_KEY_F3, EFI_KEY_F4, EFI_KEY_F5, EFI_KEY_F6, EFI_KEY_F7, EFI_KEY_F8,
+	EFI_KEY_F9, EFI_KEY_F10, EFI_KEY_F11, EFI_KEY_F12, EFI_KEY_PRINT,
+	EFI_KEY_SLCK, EFI_KEY_PAUSE,
+} efi_key;
+
+struct efi_key_descriptor {
+	efi_key key;
+	uint16_t unicode;
+	uint16_t shifted_unicode;
+	uint16_t alt_gr_unicode;
+	uint16_t shifted_alt_gr_unicode;
+	uint16_t modifier;
+	uint16_t affected_attribute;
+};
+
+struct efi_hii_keyboard_layout {
+	uint16_t layout_length;
+	efi_guid_t guid;
+	uint32_t layout_descriptor_string_offset;
+	uint8_t descriptor_count;
+	struct efi_key_descriptor descriptors[];
+};
+
+struct efi_hii_package_list_header {
+	efi_guid_t package_list_guid;
+	uint32_t package_length;
+} __packed;
+
+struct efi_hii_package_header {
+	uint32_t length : 24;
+	uint32_t type : 8;
+} __packed;
+
+#define EFI_HII_PACKAGE_TYPE_ALL          0x00
+#define EFI_HII_PACKAGE_TYPE_GUID         0x01
+#define EFI_HII_PACKAGE_FORMS             0x02
+#define EFI_HII_PACKAGE_STRINGS           0x04
+#define EFI_HII_PACKAGE_FONTS             0x05
+#define EFI_HII_PACKAGE_IMAGES            0x06
+#define EFI_HII_PACKAGE_SIMPLE_FONTS      0x07
+#define EFI_HII_PACKAGE_DEVICE_PATH       0x08
+#define EFI_HII_PACKAGE_KEYBOARD_LAYOUT   0x09
+#define EFI_HII_PACKAGE_ANIMATIONS        0x0A
+#define EFI_HII_PACKAGE_END               0xDF
+#define EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN 0xE0
+#define EFI_HII_PACKAGE_TYPE_SYSTEM_END   0xFF
+
+struct efi_hii_strings_package {
+	struct efi_hii_package_header header;
+	uint32_t header_size;
+	uint32_t string_info_offset;
+	uint16_t language_window[16];
+	efi_string_id_t language_name;
+	uint8_t  language[];
+} __packed;
+
+struct efi_hii_string_block {
+	uint8_t block_type;
+	/*uint8_t block_body[];*/
+} __packed;
+
+#define EFI_HII_SIBT_END               0x00 // The end of the string information.
+#define EFI_HII_SIBT_STRING_SCSU       0x10 // Single string using default font information.
+#define EFI_HII_SIBT_STRING_SCSU_FONT  0x11 // Single string with font information.
+#define EFI_HII_SIBT_STRINGS_SCSU      0x12 // Multiple strings using default font information.
+#define EFI_HII_SIBT_STRINGS_SCSU_FONT 0x13 // Multiple strings with font information.
+#define EFI_HII_SIBT_STRING_UCS2       0x14 // Single UCS-2 string using default font information.
+#define EFI_HII_SIBT_STRING_UCS2_FONT  0x15 // Single UCS-2 string with font information
+#define EFI_HII_SIBT_STRINGS_UCS2      0x16 // Multiple UCS-2 strings using default font information.
+#define EFI_HII_SIBT_STRINGS_UCS2_FONT 0x17 // Multiple UCS-2 strings with font information.
+#define EFI_HII_SIBT_DUPLICATE         0x20 // Create a duplicate of an existing string.
+#define EFI_HII_SIBT_SKIP2             0x21 // Skip a certain number of string identifiers.
+#define EFI_HII_SIBT_SKIP1             0x22 // Skip a certain number of string identifiers.
+#define EFI_HII_SIBT_EXT1              0x30 // For future expansion (one byte length field)
+#define EFI_HII_SIBT_EXT2              0x31 // For future expansion (two byte length field)
+#define EFI_HII_SIBT_EXT4              0x32 // For future expansion (four byte length field)
+#define EFI_HII_SIBT_FONT              0x40 // Font information.
+
+struct efi_hii_sibt_string_ucs2_block {
+	struct efi_hii_string_block header;
+	uint16_t string_text[];
+} __packed;
+
+static inline struct efi_hii_string_block *efi_hii_sibt_string_ucs2_block_next(
+	struct efi_hii_sibt_string_ucs2_block *blk)
+{
+	return ((void *)blk) + sizeof(*blk) +
+		(utf16_strlen(blk->string_text) + 1) * 2;
+}
+
+typedef void *efi_hii_handle_t;
+
+struct efi_hii_database_protocol {
+	efi_status_t(EFIAPI *new_package_list)(
+		const struct efi_hii_database_protocol *this,
+		const struct efi_hii_package_list_header *package_list,
+		const efi_handle_t driver_handle,
+		efi_hii_handle_t *handle);
+	efi_status_t(EFIAPI *remove_package_list)(
+		const struct efi_hii_database_protocol *this,
+		efi_hii_handle_t handle);
+	efi_status_t(EFIAPI *update_package_list)(
+		const struct efi_hii_database_protocol *this,
+		efi_hii_handle_t handle,
+		const struct efi_hii_package_list_header *package_list);
+	efi_status_t(EFIAPI *list_package_lists)(
+		const struct efi_hii_database_protocol *this,
+		uint8_t package_type,
+		const efi_guid_t *package_guid,
+		efi_uintn_t *handle_buffer_length,
+		efi_hii_handle_t *handle);
+	efi_status_t(EFIAPI *export_package_lists)(
+		const struct efi_hii_database_protocol *this,
+		efi_hii_handle_t handle,
+		efi_uintn_t *buffer_size,
+		struct efi_hii_package_list_header *buffer);
+	efi_status_t(EFIAPI *register_package_notify)(
+		const struct efi_hii_database_protocol *this,
+		uint8_t package_type,
+		const efi_guid_t *package_guid,
+		const void *package_notify_fn,
+		efi_uintn_t notify_type,
+		efi_handle_t *notify_handle);
+	efi_status_t(EFIAPI *unregister_package_notify)(
+		const struct efi_hii_database_protocol *this,
+		efi_handle_t notification_handle
+		);
+	efi_status_t(EFIAPI *find_keyboard_layouts)(
+		const struct efi_hii_database_protocol *this,
+		uint16_t *key_guid_buffer_length,
+		efi_guid_t *key_guid_buffer);
+	efi_status_t(EFIAPI *get_keyboard_layout)(
+		const struct efi_hii_database_protocol *this,
+		efi_guid_t *key_guid,
+		uint16_t *keyboard_layout_length,
+		struct efi_hii_keyboard_layout *keyboard_layout);
+	efi_status_t(EFIAPI *set_keyboard_layout)(
+		const struct efi_hii_database_protocol *this,
+		efi_guid_t *key_guid);
+	efi_status_t(EFIAPI *get_package_list_handle)(
+		const struct efi_hii_database_protocol *this,
+		efi_hii_handle_t package_list_handle,
+		efi_handle_t *driver_handle);
+};
+
+#define EFI_HII_STRING_PROTOCOL_GUID \
+	EFI_GUID(0x0fd96974, 0x23aa, 0x4cdc, \
+		 0xb9, 0xcb, 0x98, 0xd1, 0x77, 0x50, 0x32, 0x2a)
+
+typedef uint32_t efi_hii_font_style_t;
+
+struct efi_font_info {
+	efi_hii_font_style_t font_style;
+	uint16_t font_size;
+	uint16_t font_name[1];
+};
+
+struct efi_hii_string_protocol {
+	efi_status_t(EFIAPI *new_string)(
+		const struct efi_hii_string_protocol *this,
+		efi_hii_handle_t package_list,
+		efi_string_id_t *string_id,
+		const uint8_t *language,
+		const uint16_t *language_name,
+		const efi_string_t string,
+		const struct efi_font_info *string_font_info);
+	efi_status_t(EFIAPI *get_string)(
+		const struct efi_hii_string_protocol *this,
+		const uint8_t *language,
+		efi_hii_handle_t package_list,
+		efi_string_id_t string_id,
+		efi_string_t string,
+		efi_uintn_t *string_size,
+		struct efi_font_info **string_font_info);
+	efi_status_t(EFIAPI *set_string)(
+		const struct efi_hii_string_protocol *this,
+		efi_hii_handle_t package_list,
+		efi_string_id_t string_id,
+		const uint8_t *language,
+		const efi_string_t string,
+		const struct efi_font_info *string_font_info);
+	efi_status_t(EFIAPI *get_languages)(
+		const struct efi_hii_string_protocol *this,
+		efi_hii_handle_t package_list,
+		uint8_t *languages,
+		efi_uintn_t *languages_size);
+	efi_status_t(EFIAPI *get_secondary_languages)(
+		const struct efi_hii_string_protocol *this,
+		efi_hii_handle_t package_list,
+		const uint8_t *primary_language,
+		uint8_t *secondary_languages,
+		efi_uintn_t *secondary_languages_size);
+};
+
 #define EFI_GOP_GUID \
 	EFI_GUID(0x9042a9de, 0x23dc, 0x4a38, \
 		 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a)
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 5d37c1d75f..591bf07e7a 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -80,6 +80,9 @@ extern struct efi_simple_input_interface efi_con_in;
 extern const struct efi_console_control_protocol efi_console_control;
 extern const struct efi_device_path_to_text_protocol efi_device_path_to_text;
 extern const struct efi_device_path_utilities_protocol efi_device_path_utilities;
+extern const struct efi_hii_config_routing_protocol efi_hii_config_routing;
+extern const struct efi_hii_database_protocol efi_hii_database;
+extern const struct efi_hii_string_protocol efi_hii_string;
 
 uint16_t *efi_dp_str(struct efi_device_path *dp);
 
@@ -91,6 +94,9 @@ extern const efi_guid_t efi_guid_device_path_to_text_protocol;
 extern const efi_guid_t efi_simple_file_system_protocol_guid;
 extern const efi_guid_t efi_file_info_guid;
 extern const efi_guid_t efi_guid_device_path_utilities_protocol;
+extern const efi_guid_t efi_guid_hii_config_routing_protocol;
+extern const efi_guid_t efi_guid_hii_database_protocol;
+extern const efi_guid_t efi_guid_hii_string_protocol;
 
 extern unsigned int __efi_runtime_start, __efi_runtime_stop;
 extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
index b6927b3b84..725e0cba85 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -17,7 +17,7 @@ endif
 obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o
 obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o
 obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o
-obj-y += efi_device_path_utilities.o
+obj-y += efi_device_path_utilities.o efi_hii.o
 obj-y += efi_file.o efi_variable.o efi_bootmgr.o
 obj-$(CONFIG_LCD) += efi_gop.o
 obj-$(CONFIG_DM_VIDEO) += efi_gop.o
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index 92c778fcca..c179afc25a 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -1157,6 +1157,15 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob
 	obj->protocols[4].protocol_interface =
 		(void *)&efi_device_path_utilities;
 
+	obj->protocols[5].guid = &efi_guid_hii_string_protocol;
+	obj->protocols[5].protocol_interface = (void *)&efi_hii_string;
+
+	obj->protocols[6].guid = &efi_guid_hii_database_protocol;
+	obj->protocols[6].protocol_interface = (void *)&efi_hii_database;
+
+	obj->protocols[7].guid = &efi_guid_hii_config_routing_protocol;
+	obj->protocols[7].protocol_interface = (void *)&efi_hii_config_routing;
+
 	info->file_path = file_path;
 	info->device_handle = efi_dp_find_obj(device_path, NULL);
 
diff --git a/lib/efi_loader/efi_hii.c b/lib/efi_loader/efi_hii.c
new file mode 100644
index 0000000000..25c8e88a60
--- /dev/null
+++ b/lib/efi_loader/efi_hii.c
@@ -0,0 +1,507 @@
+/*
+ *  EFI Human Interface Infrastructure ... interface
+ *
+ *  Copyright (c) 2017 Leif Lindholm
+ *
+ *  SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <efi_loader.h>
+
+const efi_guid_t efi_guid_hii_config_routing_protocol =
+	EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID;
+const efi_guid_t efi_guid_hii_database_protocol = EFI_HII_DATABASE_PROTOCOL_GUID;
+const efi_guid_t efi_guid_hii_string_protocol = EFI_HII_STRING_PROTOCOL_GUID;
+
+struct hii_package {
+	// TODO should there be an associated efi_object?
+	struct list_head string_tables;     /* list of string_table */
+	/* we could also track fonts, images, etc */
+};
+
+struct string_table {
+	struct list_head link;
+	efi_string_id_t language_name;
+	char *language;
+	uint32_t nstrings;
+	/* NOTE: string id starts at 1 so value is stbl->strings[id-1] */
+	struct {
+		efi_string_t string;
+		/* we could also track font info, etc */
+	} strings[];
+};
+
+static void free_strings_table(struct string_table *stbl)
+{
+	int i;
+
+	for (i = 0; i < stbl->nstrings; i++)
+		free(stbl->strings[i].string);
+	free(stbl->language);
+	free(stbl);
+}
+
+static struct hii_package *new_package(void)
+{
+	struct hii_package *hii = malloc(sizeof(*hii));
+	INIT_LIST_HEAD(&hii->string_tables);
+	return hii;
+}
+
+static void free_package(struct hii_package *hii)
+{
+
+	while (!list_empty(&hii->string_tables)) {
+		struct string_table *stbl;
+
+		stbl = list_first_entry(&hii->string_tables,
+					struct string_table, link);
+		list_del(&stbl->link);
+		free_strings_table(stbl);
+	}
+
+	free(hii);
+}
+
+static efi_status_t add_strings_package(struct hii_package *hii,
+	struct efi_hii_strings_package *strings_package)
+{
+	struct efi_hii_string_block *block;
+	void *end = ((void *)strings_package) + strings_package->header.length;
+	uint32_t nstrings = 0;
+	unsigned id = 0;
+
+	debug("header_size: %08x\n", strings_package->header_size);
+	debug("string_info_offset: %08x\n", strings_package->string_info_offset);
+	debug("language_name: %u\n", strings_package->language_name);
+	debug("language: %s\n", strings_package->language);
+
+	/* count # of string entries: */
+	block = ((void *)strings_package) + strings_package->string_info_offset;
+	while ((void *)block < end) {
+		switch (block->block_type) {
+		case EFI_HII_SIBT_STRING_UCS2: {
+			struct efi_hii_sibt_string_ucs2_block *ucs2 =
+				(void *)block;
+			nstrings++;
+			block = efi_hii_sibt_string_ucs2_block_next(ucs2);
+			break;
+		}
+		case EFI_HII_SIBT_END:
+			block = end;
+			break;
+		default:
+			debug("unknown HII string block type: %02x\n",
+			      block->block_type);
+			return EFI_INVALID_PARAMETER;
+		}
+	}
+
+	struct string_table *stbl = malloc(sizeof(*stbl) +
+			(nstrings * sizeof(stbl->strings[0])));
+	stbl->language_name = strings_package->language_name;
+	stbl->language = strdup((char *)strings_package->language);
+	stbl->nstrings = nstrings;
+
+	list_add(&stbl->link, &hii->string_tables);
+
+	/* and now parse string entries and populate string_table */
+	block = ((void *)strings_package) + strings_package->string_info_offset;
+
+	while ((void *)block < end) {
+		switch (block->block_type) {
+		case EFI_HII_SIBT_STRING_UCS2: {
+			struct efi_hii_sibt_string_ucs2_block *ucs2 =
+				(void *)block;
+			id++;
+			debug("%4u: \"%ls\"\n", id, ucs2->string_text);
+			stbl->strings[id-1].string =
+				utf16_strdup(ucs2->string_text);
+			block = efi_hii_sibt_string_ucs2_block_next(ucs2);
+			break;
+		}
+		case EFI_HII_SIBT_END:
+			return EFI_SUCCESS;
+		default:
+			debug("unknown HII string block type: %02x\n",
+			      block->block_type);
+			return EFI_INVALID_PARAMETER;
+		}
+	}
+
+	return EFI_SUCCESS;
+}
+
+/*
+ * EFI_HII_CONFIG_ROUTING_PROTOCOL
+ */
+
+static efi_status_t EFIAPI extract_config(
+	const struct efi_hii_config_routing_protocol *this,
+	const efi_string_t request,
+	efi_string_t *progress,
+	efi_string_t *results)
+{
+	EFI_ENTRY("%p, \"%ls\", %p, %p", this, request, progress, results);
+	return EFI_EXIT(EFI_OUT_OF_RESOURCES);
+}
+
+static efi_status_t EFIAPI export_config(
+	const struct efi_hii_config_routing_protocol *this,
+	efi_string_t *results)
+{
+	EFI_ENTRY("%p, %p", this, results);
+	return EFI_EXIT(EFI_OUT_OF_RESOURCES);
+}
+
+static efi_status_t EFIAPI route_config(
+	const struct efi_hii_config_routing_protocol *this,
+	const efi_string_t configuration,
+	efi_string_t *progress)
+{
+	EFI_ENTRY("%p, \"%ls\", %p", this, configuration, progress);
+	return EFI_EXIT(EFI_OUT_OF_RESOURCES);
+}
+
+static efi_status_t EFIAPI block_to_config(
+	const struct efi_hii_config_routing_protocol *this,
+	const efi_string_t config_request,
+	const uint8_t *block,
+	const efi_uintn_t block_size,
+	efi_string_t *config,
+	efi_string_t *progress)
+{
+	EFI_ENTRY("%p, \"%ls\", %p, %zu, %p, %p", this, config_request, block,
+		  block_size, config, progress);
+	return EFI_EXIT(EFI_OUT_OF_RESOURCES);
+}
+
+static efi_status_t EFIAPI config_to_block(
+	const struct efi_hii_config_routing_protocol *this,
+	const efi_string_t config_resp,
+	const uint8_t *block,
+	const efi_uintn_t *block_size,
+	efi_string_t *progress)
+{
+	EFI_ENTRY("%p, \"%ls\", %p, %p, %p", this, config_resp, block,
+		  block_size, progress);
+	return EFI_EXIT(EFI_OUT_OF_RESOURCES);
+}
+
+static efi_status_t EFIAPI get_alt_config(
+	const struct efi_hii_config_routing_protocol *this,
+	const efi_string_t config_resp,
+	const efi_guid_t *guid,
+	const efi_string_t name,
+	const struct efi_device_path *device_path,
+	const efi_string_t alt_cfg_id,
+	efi_string_t *alt_cfg_resp)
+{
+	EFI_ENTRY("%p, \"%ls\", %pUl, \"%ls\", %p, \"%ls\", %p", this,
+		  config_resp, guid, name, device_path, alt_cfg_id,
+		  alt_cfg_resp);
+	return EFI_EXIT(EFI_OUT_OF_RESOURCES);
+}
+
+
+/*
+ * EFI_HII_DATABASE_PROTOCOL
+ */
+
+static efi_status_t EFIAPI new_package_list(
+	const struct efi_hii_database_protocol *this,
+	const struct efi_hii_package_list_header *package_list,
+	const efi_handle_t driver_handle,
+	efi_hii_handle_t *handle)
+{
+	efi_status_t ret = EFI_SUCCESS;
+
+	EFI_ENTRY("%p, %p, %p, %p", this, package_list, driver_handle, handle);
+
+	if (!package_list || !driver_handle)
+		return EFI_EXIT(EFI_INVALID_PARAMETER);
+
+	struct hii_package *hii = new_package();
+	struct efi_hii_package_header *package;
+	void *end = ((void *)package_list) + package_list->package_length;
+
+	debug("package_list: %pUl (%u)\n", &package_list->package_list_guid,
+	      package_list->package_length);
+
+	package = ((void *)package_list) + sizeof(*package_list);
+	while ((void *)package < end) {
+		debug("package=%p, package type=%x, length=%u\n", package,
+		      package->type, package->length);
+		switch (package->type) {
+		case EFI_HII_PACKAGE_STRINGS:
+			ret = add_strings_package(hii,
+				(struct efi_hii_strings_package *)package);
+			break;
+		default:
+			break;
+		}
+
+		if (ret != EFI_SUCCESS)
+			goto error;
+
+		package = ((void *)package) + package->length;
+	}
+
+	// TODO in theory there is some notifications that should be sent..
+
+	*handle = hii;
+
+	return EFI_EXIT(EFI_SUCCESS);
+
+error:
+	free_package(hii);
+	return EFI_EXIT(ret);
+}
+
+static efi_status_t EFIAPI remove_package_list(
+	const struct efi_hii_database_protocol *this,
+	efi_hii_handle_t handle)
+{
+	struct hii_package *hii = handle;
+	EFI_ENTRY("%p, %p", this, handle);
+	free_package(hii);
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI update_package_list(
+	const struct efi_hii_database_protocol *this,
+	efi_hii_handle_t handle,
+	const struct efi_hii_package_list_header *package_list)
+{
+	EFI_ENTRY("%p, %p, %p", this, handle, package_list);
+	return EFI_EXIT(EFI_NOT_FOUND);
+}
+
+static efi_status_t EFIAPI list_package_lists(
+	const struct efi_hii_database_protocol *this,
+	uint8_t package_type,
+	const efi_guid_t *package_guid,
+	efi_uintn_t *handle_buffer_length,
+	efi_hii_handle_t *handle)
+{
+	EFI_ENTRY("%p, %u, %pUl, %p, %p", this, package_type, package_guid,
+		  handle_buffer_length, handle);
+	return EFI_EXIT(EFI_NOT_FOUND);
+}
+
+static efi_status_t EFIAPI export_package_lists(
+	const struct efi_hii_database_protocol *this,
+	efi_hii_handle_t handle,
+	efi_uintn_t *buffer_size,
+	struct efi_hii_package_list_header *buffer)
+{
+	EFI_ENTRY("%p, %p, %p, %p", this, handle, buffer_size, buffer);
+	return EFI_EXIT(EFI_NOT_FOUND);
+}
+
+static efi_status_t EFIAPI register_package_notify(
+	const struct efi_hii_database_protocol *this,
+	uint8_t package_type,
+	const efi_guid_t *package_guid,
+	const void *package_notify_fn,
+	efi_uintn_t notify_type,
+	efi_handle_t *notify_handle)
+{
+	EFI_ENTRY("%p, %u, %pUl, %p, %zu, %p", this, package_type,
+		  package_guid, package_notify_fn, notify_type,
+		  notify_handle);
+	return EFI_EXIT(EFI_OUT_OF_RESOURCES);
+}
+
+static efi_status_t EFIAPI unregister_package_notify(
+	const struct efi_hii_database_protocol *this,
+	efi_handle_t notification_handle)
+{
+	EFI_ENTRY("%p, %p", this, notification_handle);
+	return EFI_EXIT(EFI_NOT_FOUND);
+}
+
+static efi_status_t EFIAPI find_keyboard_layouts(
+	const struct efi_hii_database_protocol *this,
+	uint16_t *key_guid_buffer_length,
+	efi_guid_t *key_guid_buffer)
+{
+	EFI_ENTRY("%p, %p, %p", this, key_guid_buffer_length, key_guid_buffer);
+	return EFI_EXIT(EFI_NOT_FOUND); /* Invalid */
+}
+
+static efi_status_t EFIAPI get_keyboard_layout(
+	const struct efi_hii_database_protocol *this,
+	efi_guid_t *key_guid,
+	uint16_t *keyboard_layout_length,
+	struct efi_hii_keyboard_layout *keyboard_layout)
+{
+	EFI_ENTRY("%p, %pUl, %p, %p", this, key_guid, keyboard_layout_length,
+		  keyboard_layout);
+	return EFI_EXIT(EFI_NOT_FOUND);
+}
+
+static efi_status_t EFIAPI set_keyboard_layout(
+	const struct efi_hii_database_protocol *this,
+	efi_guid_t *key_guid)
+{
+	EFI_ENTRY("%p, %pUl", this, key_guid);
+	return EFI_EXIT(EFI_NOT_FOUND);
+}
+
+static efi_status_t EFIAPI get_package_list_handle(
+	const struct efi_hii_database_protocol *this,
+	efi_hii_handle_t package_list_handle,
+	efi_handle_t *driver_handle)
+{
+	EFI_ENTRY("%p, %p, %p", this, package_list_handle, driver_handle);
+	return EFI_EXIT(EFI_INVALID_PARAMETER);
+}
+
+
+/*
+ * EFI_HII_STRING_PROTOCOL
+ */
+
+static efi_status_t EFIAPI new_string(
+	const struct efi_hii_string_protocol *this,
+	efi_hii_handle_t package_list,
+	efi_string_id_t *string_id,
+	const uint8_t *language,
+	const uint16_t *language_name,
+	const efi_string_t string,
+	const struct efi_font_info *string_font_info)
+{
+	EFI_ENTRY("%p, %p, %p, \"%s\", %p, \"%ls\", %p", this, package_list,
+		  string_id, language, language_name, string,
+		  string_font_info);
+	return EFI_EXIT(EFI_NOT_FOUND);
+}
+
+static efi_status_t EFIAPI get_string(
+	const struct efi_hii_string_protocol *this,
+	const uint8_t *language,
+	efi_hii_handle_t package_list,
+	efi_string_id_t string_id,
+	efi_string_t string,
+	efi_uintn_t *string_size,
+	struct efi_font_info **string_font_info)
+{
+	struct hii_package *hii = package_list;
+	struct string_table *stbl;
+
+	EFI_ENTRY("%p, \"%s\", %p, %u, %p, %p, %p", this, language,
+		  package_list, string_id, string, string_size,
+		  string_font_info);
+
+	list_for_each_entry(stbl, &hii->string_tables, link) {
+		if (!strcmp((char *)language, (char *)stbl->language)) {
+			unsigned idx = string_id - 1;
+			if (idx > stbl->nstrings)
+				return EFI_EXIT(EFI_NOT_FOUND);
+			efi_string_t str = stbl->strings[idx].string;
+			size_t len = utf16_strlen(str) + 1;
+			if (*string_size < len * 2) {
+				*string_size = len * 2;
+				return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
+			}
+			memcpy(string, str, len * 2);
+			*string_size = len * 2;
+			return EFI_EXIT(EFI_SUCCESS);
+		}
+	}
+
+	return EFI_EXIT(EFI_NOT_FOUND);
+}
+
+static efi_status_t EFIAPI set_string(
+	const struct efi_hii_string_protocol *this,
+	efi_hii_handle_t package_list,
+	efi_string_id_t string_id,
+	const uint8_t *language,
+	const efi_string_t string,
+	const struct efi_font_info *string_font_info)
+{
+	EFI_ENTRY("%p, %p, %u, \"%s\", \"%ls\", %p", this, package_list,
+		  string_id, language, string, string_font_info);
+	return EFI_EXIT(EFI_NOT_FOUND);
+}
+
+static efi_status_t EFIAPI get_languages(
+	const struct efi_hii_string_protocol *this,
+	efi_hii_handle_t package_list,
+	uint8_t *languages,
+	efi_uintn_t *languages_size)
+{
+	struct hii_package *hii = package_list;
+	struct string_table *stbl;
+	size_t len = 0;
+
+	EFI_ENTRY("%p, %p, %p, %p", this, package_list, languages,
+		  languages_size);
+
+	/* figure out required size: */
+	list_for_each_entry(stbl, &hii->string_tables, link) {
+		len += strlen((char *)stbl->language) + 1;
+	}
+
+	if (*languages_size < len) {
+		*languages_size = len;
+		return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
+	}
+
+	char *p = (char *)languages;
+	list_for_each_entry(stbl, &hii->string_tables, link) {
+		if (p != (char *)languages)
+			p += sprintf(p, ";");
+		p += sprintf(p, "%s", stbl->language);
+	}
+
+	debug("languages: %s\n", languages);
+
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI get_secondary_languages(
+	const struct efi_hii_string_protocol *this,
+	efi_hii_handle_t package_list,
+	const uint8_t *primary_language,
+	uint8_t *secondary_languages,
+	efi_uintn_t *secondary_languages_size)
+{
+	EFI_ENTRY("%p, %p, \"%s\", %p, %p", this, package_list,
+		  primary_language, secondary_languages,
+		  secondary_languages_size);
+	return EFI_EXIT(EFI_NOT_FOUND);
+}
+
+const struct efi_hii_config_routing_protocol efi_hii_config_routing = {
+	.extract_config = extract_config,
+	.export_config = export_config,
+	.route_config = route_config,
+	.block_to_config = block_to_config,
+	.config_to_block = config_to_block,
+	.get_alt_config = get_alt_config
+};
+const struct efi_hii_database_protocol efi_hii_database = {
+	.new_package_list = new_package_list,
+	.remove_package_list = remove_package_list,
+	.update_package_list = update_package_list,
+	.list_package_lists = list_package_lists,
+	.export_package_lists = export_package_lists,
+	.register_package_notify = register_package_notify,
+	.unregister_package_notify = unregister_package_notify,
+	.find_keyboard_layouts = find_keyboard_layouts,
+	.get_keyboard_layout = get_keyboard_layout,
+	.set_keyboard_layout = set_keyboard_layout,
+	.get_package_list_handle = get_package_list_handle
+};
+const struct efi_hii_string_protocol efi_hii_string = {
+	.new_string = new_string,
+	.get_string = get_string,
+	.set_string = set_string,
+	.get_languages = get_languages,
+	.get_secondary_languages = get_secondary_languages
+};
-- 
2.13.6

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 03/11] efi_loader: Initial EFI_UNICODE_COLLATION_PROTOCOL
  2017-10-10 12:22 [U-Boot] [PATCH 00/11] efi_loader: patches for Shell.efi Rob Clark
  2017-10-10 12:22 ` [U-Boot] [PATCH 01/11] efi_loader: Initial EFI_DEVICE_PATH_UTILITIES_PROTOCOL Rob Clark
  2017-10-10 12:22 ` [U-Boot] [PATCH 02/11] efi_loader: Initial HII protocols Rob Clark
@ 2017-10-10 12:22 ` Rob Clark
  2017-10-11 14:36   ` Alexander Graf
  2017-10-10 12:23 ` [U-Boot] [PATCH 04/11] efi_loader: SIMPLE_TEXT_INPUT_EX plus wire up objects properly Rob Clark
                   ` (8 subsequent siblings)
  11 siblings, 1 reply; 75+ messages in thread
From: Rob Clark @ 2017-10-10 12:22 UTC (permalink / raw)
  To: u-boot

From: Leif Lindholm <leif.lindholm@linaro.org>

Not complete, but enough for Shell.efi and SCT.efi.

Initial skeleton written by Leif, and then implementation by myself.

Cc: Leif Lindholm <leif.lindholm@linaro.org>
Signed-off-by: Rob Clark <robdclark@gmail.com>
---
 include/efi_api.h             |  41 ++++++++++
 include/efi_loader.h          |   3 +
 lib/efi_loader/Makefile       |   2 +-
 lib/efi_loader/efi_boottime.c |   6 ++
 lib/efi_loader/efi_unicode.c  | 170 ++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 221 insertions(+), 1 deletion(-)
 create mode 100644 lib/efi_loader/efi_unicode.c

diff --git a/include/efi_api.h b/include/efi_api.h
index 164147dc87..38dd1240c1 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -797,6 +797,47 @@ struct efi_hii_string_protocol {
 		efi_uintn_t *secondary_languages_size);
 };
 
+/*
+ * Both UNICODE_COLLATION protocols seem to be the same thing, but
+ * advertised with two different GUID's because, why not?
+ */
+
+#define EFI_UNICODE_COLLATION_PROTOCOL_GUID \
+	EFI_GUID(0x1d85cd7f, 0xf43d, 0x11d2, \
+		 0x9a, 0x0c, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
+
+#define EFI_UNICODE_COLLATION_PROTOCOL2_GUID \
+	EFI_GUID(0xa4c751fc, 0x23ae, 0x4c3e, \
+		 0x92, 0xe9, 0x49, 0x64, 0xcf, 0x63, 0xf3, 0x49)
+
+struct efi_unicode_collation_protocol {
+	efi_intn_t (EFIAPI *stri_coll)(
+		struct efi_unicode_collation_protocol *this,
+		efi_string_t s1,
+		efi_string_t s2);
+	bool (EFIAPI *metai_match)(
+		struct efi_unicode_collation_protocol *this,
+		efi_string_t string,
+		efi_string_t pattern);
+	void (EFIAPI *str_lwr)(
+		struct efi_unicode_collation_protocol *this,
+		efi_string_t string);
+	void (EFIAPI *str_upr)(
+		struct efi_unicode_collation_protocol *this,
+		efi_string_t string);
+	void (EFIAPI *fat_to_str)(
+		struct efi_unicode_collation_protocol *this,
+		efi_uintn_t fat_size,
+		uint8_t *fat,
+		efi_string_t string);
+	bool (EFIAPI *str_to_fat)(
+		struct efi_unicode_collation_protocol *this,
+		efi_string_t string,
+		efi_uintn_t fat_size,
+		uint8_t *fat);
+	uint8_t *supported_languages;
+};
+
 #define EFI_GOP_GUID \
 	EFI_GUID(0x9042a9de, 0x23dc, 0x4a38, \
 		 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a)
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 591bf07e7a..af6812b2b4 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -83,6 +83,7 @@ extern const struct efi_device_path_utilities_protocol efi_device_path_utilities
 extern const struct efi_hii_config_routing_protocol efi_hii_config_routing;
 extern const struct efi_hii_database_protocol efi_hii_database;
 extern const struct efi_hii_string_protocol efi_hii_string;
+extern const struct efi_unicode_collation_protocol efi_unicode_collation;
 
 uint16_t *efi_dp_str(struct efi_device_path *dp);
 
@@ -97,6 +98,8 @@ extern const efi_guid_t efi_guid_device_path_utilities_protocol;
 extern const efi_guid_t efi_guid_hii_config_routing_protocol;
 extern const efi_guid_t efi_guid_hii_database_protocol;
 extern const efi_guid_t efi_guid_hii_string_protocol;
+extern const efi_guid_t efi_guid_unicode_collation_protocol;
+extern const efi_guid_t efi_guid_unicode_collation_protocol2;
 
 extern unsigned int __efi_runtime_start, __efi_runtime_stop;
 extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
index 725e0cba85..7ea96a4f1c 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -17,7 +17,7 @@ endif
 obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o
 obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o
 obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o
-obj-y += efi_device_path_utilities.o efi_hii.o
+obj-y += efi_device_path_utilities.o efi_hii.o efi_unicode.o
 obj-y += efi_file.o efi_variable.o efi_bootmgr.o
 obj-$(CONFIG_LCD) += efi_gop.o
 obj-$(CONFIG_DM_VIDEO) += efi_gop.o
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index c179afc25a..b568f3f162 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -1166,6 +1166,12 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob
 	obj->protocols[7].guid = &efi_guid_hii_config_routing_protocol;
 	obj->protocols[7].protocol_interface = (void *)&efi_hii_config_routing;
 
+	obj->protocols[8].guid = &efi_guid_unicode_collation_protocol;
+	obj->protocols[8].protocol_interface = (void *)&efi_unicode_collation;
+
+	obj->protocols[9].guid = &efi_guid_unicode_collation_protocol2;
+	obj->protocols[9].protocol_interface = (void *)&efi_unicode_collation;
+
 	info->file_path = file_path;
 	info->device_handle = efi_dp_find_obj(device_path, NULL);
 
diff --git a/lib/efi_loader/efi_unicode.c b/lib/efi_loader/efi_unicode.c
new file mode 100644
index 0000000000..2c6302df25
--- /dev/null
+++ b/lib/efi_loader/efi_unicode.c
@@ -0,0 +1,170 @@
+/*
+*  EFI Unicode interface
+ *
+ *  Copyright (c) 2017 Leif Lindholm
+ *
+ *  SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <charset.h>
+#include <linux/ctype.h>
+#include <efi_loader.h>
+
+const efi_guid_t efi_guid_unicode_collation_protocol =
+	EFI_UNICODE_COLLATION_PROTOCOL_GUID;
+
+const efi_guid_t efi_guid_unicode_collation_protocol2 =
+	EFI_UNICODE_COLLATION_PROTOCOL2_GUID;
+
+static int matchn(efi_string_t s1, unsigned n1, efi_string_t s2, unsigned n2)
+{
+	char u1[MAX_UTF8_PER_UTF16 * n1 + 1];
+	char u2[MAX_UTF8_PER_UTF16 * n2 + 1];
+
+	*utf16_to_utf8((u8 *)u1, s1, n1) = '\0';
+	*utf16_to_utf8((u8 *)u2, s2, n2) = '\0';
+
+	return strcasecmp(u1, u2);
+}
+
+static efi_intn_t EFIAPI stri_coll(struct efi_unicode_collation_protocol *this,
+				   efi_string_t s1,
+				   efi_string_t s2)
+{
+	EFI_ENTRY("%p, \"%ls\", \"%ls\"", this, s1, s2);
+
+	unsigned n1 = utf16_strlen(s1);
+	unsigned n2 = utf16_strlen(s2);
+
+	return EFI_EXIT(matchn(s1, n1, s2, n2));
+}
+
+static bool match(efi_string_t string, efi_string_t pattern)
+{
+	while (true) {
+		uint16_t p = *pattern++;
+		bool matches = false;
+
+		if (p == '\0' || *string == '\0') {
+			/*
+			 * End of pattern or string, succeed if
+			 * end of both:
+			 */
+			return *string == p;
+		}
+
+		switch (p) {
+		case '*':
+			/* Match zero or more chars: */
+			while (*string != '\0') {
+				if (match(string, pattern))
+					return true;
+				string++;
+			}
+			return match(string, pattern);
+		case '?':
+			/* Match any one char: */
+			string++;
+			break;
+		case '[':
+			/* Match char set, either [abc] or [a-c]: */
+
+			if (pattern[0] == '\0' || pattern[0] == ']') {
+				/* invalid pattern */
+				return false;
+			}
+
+			if (pattern[1] == '-') {
+				uint16_t lo, hi, c;
+
+				/* range: [a-c] */
+				lo = pattern[0];
+				hi = pattern[2];
+
+				if (hi == '\0' || hi == ']' || pattern[3] != ']') {
+					/* invalid pattern */
+					return false;
+				}
+
+				c  = tolower(*string);
+				lo = tolower(lo);
+				hi = tolower(hi);
+
+				if (lo <= c && c <= hi)
+					matches = true;
+
+				pattern += 4;
+			} else {
+				/* set: [abc] */
+				while ((p = *pattern++) && p != ']')
+					if (matchn(string, 1, &p, 1))
+						matches = true;
+			}
+
+			if (!matches)
+				return false;
+
+			string++;
+			break;
+		default:
+			if (matchn(string, 1, &p, 1))
+				return false;
+			string++;
+			break;
+		}
+	}
+}
+
+static bool EFIAPI metai_match(struct efi_unicode_collation_protocol *this,
+			       efi_string_t string,
+			       efi_string_t pattern)
+{
+	EFI_ENTRY("%p, \"%ls\", \"%ls\"", this, string, pattern);
+	return EFI_EXIT(match(string, pattern));
+}
+
+static void EFIAPI str_lwr(struct efi_unicode_collation_protocol *this,
+			   efi_string_t string)
+{
+	EFI_ENTRY("%p, \"%ls\"", this, string);
+	EFI_EXIT(EFI_SUCCESS);
+	return;
+}
+
+static void EFIAPI str_upr(struct efi_unicode_collation_protocol *this,
+			   efi_string_t string)
+{
+	EFI_ENTRY("%p, \"%ls\"", this, string);
+	EFI_EXIT(EFI_SUCCESS);
+	return;
+}
+
+static void EFIAPI fat_to_str(struct efi_unicode_collation_protocol *this,
+			      efi_uintn_t fat_size,
+			      uint8_t *fat,
+			      efi_string_t string)
+{
+	EFI_ENTRY("%p, %zu, \"%s\", %p", this, fat_size, fat, string);
+	EFI_EXIT(EFI_SUCCESS);
+	return;
+}
+
+static bool EFIAPI str_to_fat(struct efi_unicode_collation_protocol *this,
+			      efi_string_t string,
+			      efi_uintn_t fat_size,
+			      uint8_t *fat)
+{
+	EFI_ENTRY("%p, \"%ls\", %zu, %p", this, string, fat_size, fat);
+	return EFI_EXIT(false);
+}
+
+const struct efi_unicode_collation_protocol efi_unicode_collation = {
+	.stri_coll = stri_coll,
+	.metai_match = metai_match,
+	.str_lwr = str_lwr,
+	.str_upr = str_upr,
+	.fat_to_str = fat_to_str,
+	.str_to_fat = str_to_fat,
+	.supported_languages = (uint8_t *)"eng",
+};
-- 
2.13.6

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 04/11] efi_loader: SIMPLE_TEXT_INPUT_EX plus wire up objects properly
  2017-10-10 12:22 [U-Boot] [PATCH 00/11] efi_loader: patches for Shell.efi Rob Clark
                   ` (2 preceding siblings ...)
  2017-10-10 12:22 ` [U-Boot] [PATCH 03/11] efi_loader: Initial EFI_UNICODE_COLLATION_PROTOCOL Rob Clark
@ 2017-10-10 12:23 ` Rob Clark
  2017-10-11 14:39   ` Alexander Graf
  2018-09-04 14:07   ` [U-Boot] [U-Boot, " Alexander Graf
  2017-10-10 12:23 ` [U-Boot] [PATCH 05/11] efi_loader: console support for color attributes Rob Clark
                   ` (7 subsequent siblings)
  11 siblings, 2 replies; 75+ messages in thread
From: Rob Clark @ 2017-10-10 12:23 UTC (permalink / raw)
  To: u-boot

We need the _EX version for SCT.. and we need to wire up the
corresponding objects in the systab properly, as well as dealing
with the console_in object advertising multiple protocols.

Signed-off-by: Rob Clark <robdclark@gmail.com>
---
 include/efi_api.h             |  61 +++++++++-
 include/efi_loader.h          |  10 +-
 lib/efi_loader/efi_boottime.c |   3 +
 lib/efi_loader/efi_console.c  | 264 +++++++++++++++++++++++++++++++++++++++---
 4 files changed, 308 insertions(+), 30 deletions(-)

diff --git a/include/efi_api.h b/include/efi_api.h
index 38dd1240c1..58bf15b8e6 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -243,11 +243,11 @@ struct efi_system_table {
 	struct efi_table_hdr hdr;
 	unsigned long fw_vendor;   /* physical addr of wchar_t vendor string */
 	u32 fw_revision;
-	unsigned long con_in_handle;
+	efi_handle_t con_in_handle;
 	struct efi_simple_input_interface *con_in;
-	unsigned long con_out_handle;
+	efi_handle_t con_out_handle;
 	struct efi_simple_text_output_protocol *con_out;
-	unsigned long stderr_handle;
+	efi_handle_t stderr_handle;
 	struct efi_simple_text_output_protocol *std_err;
 	struct efi_runtime_services *runtime;
 	struct efi_boot_services *boottime;
@@ -474,6 +474,61 @@ struct efi_simple_input_interface {
 	struct efi_event *wait_for_key;
 };
 
+
+#define EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID \
+	EFI_GUID(0xdd9e7534, 0x7762, 0x4698, \
+		 0x8c, 0x14, 0xf5, 0x85, 0x17, 0xa6, 0x25, 0xaa)
+
+/* key-shift state: */
+#define EFI_SHIFT_STATE_VALID     0x80000000
+#define EFI_RIGHT_SHIFT_PRESSED   0x00000001
+#define EFI_LEFT_SHIFT_PRESSED    0x00000002
+#define EFI_RIGHT_CONTROL_PRESSED 0x00000004
+#define EFI_LEFT_CONTROL_PRESSED  0x00000008
+#define EFI_RIGHT_ALT_PRESSED     0x00000010
+#define EFI_EFI_LEFT_ALT_PRESSED  0x00000020
+#define EFI_RIGHT_LOGO_PRESSED    0x00000040
+#define EFI_LEFT_LOGO_PRESSED     0x00000080
+#define EFI_MENU_KEY_PRESSED      0x00000100
+#define EFI_SYS_REQ_PRESSED       0x00000200
+
+/* key-toggle state: */
+#define EFI_TOGGLE_STATE_VALID 0x80
+#define EFI_SCROLL_LOCK_ACTIVE 0x01
+#define EFI_NUM_LOCK_ACTIVE    0x02
+#define EFI_CAPS_LOCK_ACTIVE   0x04
+
+struct efi_key_state {
+	uint32_t key_shift_state;
+	uint8_t  key_toggle_state;
+};
+
+struct efi_key_data {
+	struct efi_input_key key;
+	struct efi_key_state key_state;
+};
+
+struct efi_simple_text_input_ex_interface {
+	efi_status_t (EFIAPI *reset)(
+			struct efi_simple_text_input_ex_interface *this,
+			bool ExtendedVerification);
+	efi_status_t (EFIAPI *read_key_stroke)(
+			struct efi_simple_text_input_ex_interface *this,
+			struct efi_key_data *key_data);
+	struct efi_event *wait_for_key;
+	efi_status_t (EFIAPI *set_state)(
+			struct efi_simple_text_input_ex_interface *this,
+			uint8_t key_toggle_state);
+	efi_status_t (EFIAPI *register_key_notify)(
+			struct efi_simple_text_input_ex_interface *this,
+			struct efi_key_data *key_data,
+			efi_status_t (EFIAPI *notify_fn)(struct efi_key_data *key_data),
+			efi_handle_t *notify_handle);
+	efi_status_t (EFIAPI *unregister_key_notify)(
+			struct efi_simple_text_input_ex_interface *this,
+			efi_handle_t notify_handle);
+};
+
 #define CONSOLE_CONTROL_GUID \
 	EFI_GUID(0xf42f7782, 0x12e, 0x4c12, \
 		 0x99, 0x56, 0x49, 0xf9, 0x43, 0x4, 0xf7, 0x21)
diff --git a/include/efi_loader.h b/include/efi_loader.h
index af6812b2b4..e6e55d2cb4 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -75,7 +75,9 @@ const char *__efi_nesting_dec(void);
 extern struct efi_runtime_services efi_runtime_services;
 extern struct efi_system_table systab;
 
+extern struct efi_object efi_console_output_obj;
 extern const struct efi_simple_text_output_protocol efi_con_out;
+extern struct efi_object efi_console_input_obj;
 extern struct efi_simple_input_interface efi_con_in;
 extern const struct efi_console_control_protocol efi_console_control;
 extern const struct efi_device_path_to_text_protocol efi_device_path_to_text;
@@ -129,14 +131,6 @@ struct efi_object {
 	void *handle;
 };
 
-#define EFI_PROTOCOL_OBJECT(_guid, _protocol) (struct efi_object){	\
-	.protocols = {{							\
-		.guid = &(_guid),	 				\
-		.protocol_interface = (void *)(_protocol), 		\
-	}},								\
-	.handle = (void *)(_protocol),					\
-}
-
 /**
  * struct efi_event
  *
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index b568f3f162..39dcc72648 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -2077,8 +2077,11 @@ struct efi_system_table __efi_runtime_data systab = {
 		.headersize = sizeof(struct efi_table_hdr),
 	},
 	.fw_vendor = (long)firmware_vendor,
+	.con_in_handle = &efi_console_input_obj,
 	.con_in = (void*)&efi_con_in,
+	.con_out_handle = &efi_console_output_obj,
 	.con_out = (void*)&efi_con_out,
+	.stderr_handle = &efi_console_output_obj,
 	.std_err = (void*)&efi_con_out,
 	.runtime = (void*)&efi_runtime_services,
 	.boottime = (void*)&efi_boot_services,
diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
index 1bdf36b4ae..f508b79ab8 100644
--- a/lib/efi_loader/efi_console.c
+++ b/lib/efi_loader/efi_console.c
@@ -50,6 +50,10 @@ const efi_guid_t efi_guid_console_control = CONSOLE_CONTROL_GUID;
 #define cESC '\x1b'
 #define ESC "\x1b"
 
+/*
+ * EFI_CONSOLE_CONTROL:
+ */
+
 static efi_status_t EFIAPI efi_cin_get_mode(
 			struct efi_console_control_protocol *this,
 			int *mode, char *uga_exists, char *std_in_locked)
@@ -97,6 +101,11 @@ static struct simple_text_output_mode efi_con_mode = {
 	.cursor_visible = 1,
 };
 
+
+/*
+ * EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL:
+ */
+
 static int term_read_reply(int *n, int maxnum, char end_char)
 {
 	char c;
@@ -364,32 +373,77 @@ const struct efi_simple_text_output_protocol efi_con_out = {
 	.mode = (void*)&efi_con_mode,
 };
 
+
+/*
+ * EFI_SIMPLE_TEXT_INPUT_PROTOCOL:
+ */
+
+/*
+ * FIFO to buffer up key-strokes, to allow dispatching key event
+ * notifications in advance of someone calling ReadKeyStroke().
+ */
+
+struct key_fifo {
+	unsigned rd, wr;
+	struct efi_key_data key[32]; /* use PoT size */
+};
+
+/* number of item's queued in fifo: */
+static unsigned fifo_count(struct key_fifo *fifo)
+{
+	return (ARRAY_SIZE(fifo->key) + fifo->wr - fifo->rd) % ARRAY_SIZE(fifo->key);
+}
+
+/* remaining space to queue items in fifo: */
+static unsigned fifo_space(struct key_fifo *fifo)
+{
+	return ARRAY_SIZE(fifo->key) - 1 - fifo_count(fifo);
+}
+
+/* push an item onto the tail of the fifo: */
+static void fifo_push(struct key_fifo *fifo, struct efi_key_data *key)
+{
+	assert(fifo_space(fifo) >= 1);
+	fifo->key[fifo->wr] = *key;
+	fifo->wr = (fifo->wr + 1) % ARRAY_SIZE(fifo->key);
+}
+
+/* pop an item from the head of the fifo: */
+static void fifo_pop(struct key_fifo *fifo, struct efi_key_data *key)
+{
+	assert(fifo_count(fifo) >= 1);
+	*key = fifo->key[fifo->rd];
+	fifo->rd = (fifo->rd + 1) % ARRAY_SIZE(fifo->key);
+}
+
+static struct key_fifo fifo;
+
+static void notify_key(struct efi_key_data *key);
+
 static efi_status_t EFIAPI efi_cin_reset(
 			struct efi_simple_input_interface *this,
 			bool extended_verification)
 {
 	EFI_ENTRY("%p, %d", this, extended_verification);
+	fifo.rd = fifo.wr = 0;
 	return EFI_EXIT(EFI_UNSUPPORTED);
 }
 
-static efi_status_t EFIAPI efi_cin_read_key_stroke(
-			struct efi_simple_input_interface *this,
-			struct efi_input_key *key)
+static efi_status_t read_key_stroke(struct efi_key_data *key_data)
 {
 	struct efi_input_key pressed_key = {
 		.scan_code = 0,
 		.unicode_char = 0,
 	};
+	struct efi_key_state key_state = {
+		.key_shift_state = 0,
+		.key_toggle_state = 0,
+	};
 	char ch;
 
-	EFI_ENTRY("%p, %p", this, key);
-
-	/* We don't do interrupts, so check for timers cooperatively */
-	efi_timer_check();
-
 	if (!tstc()) {
 		/* No key pressed */
-		return EFI_EXIT(EFI_NOT_READY);
+		return EFI_NOT_READY;
 	}
 
 	ch = getc();
@@ -404,7 +458,8 @@ static efi_status_t EFIAPI efi_cin_read_key_stroke(
 			pressed_key.scan_code = getc() - 'P' + 11;
 			break;
 		case 'a'...'z':
-			ch = ch - 'a';
+			key_state.key_shift_state =
+				EFI_SHIFT_STATE_VALID | EFI_EFI_LEFT_ALT_PRESSED;
 			break;
 		case '[':
 			ch = getc();
@@ -433,14 +488,61 @@ static efi_status_t EFIAPI efi_cin_read_key_stroke(
 			}
 			break;
 		}
+	} else if (0x01 <= ch && ch <= 0x1a && ch != '\t' && ch != '\b' &&
+		   ch != '\n' && ch != '\r') {
+		/*
+		 * Ctrl + <letter>.. except for a few cases that conflict
+		 * with unmodified chars
+		 */
+		ch = ch + 'a' - 1;
+		key_state.key_shift_state =
+			EFI_SHIFT_STATE_VALID | EFI_LEFT_CONTROL_PRESSED;
 	} else if (ch == 0x7f) {
 		/* Backspace */
 		ch = 0x08;
 	}
 	pressed_key.unicode_char = ch;
-	*key = pressed_key;
+	key_data->key = pressed_key;
+	key_data->key_state = key_state;
 
-	return EFI_EXIT(EFI_SUCCESS);
+	return EFI_SUCCESS;
+}
+
+static void read_keys(void)
+{
+	struct efi_key_data key;
+
+	while (fifo_space(&fifo) > 0 && read_key_stroke(&key) == EFI_SUCCESS) {
+		notify_key(&key);
+		fifo_push(&fifo, &key);
+	}
+}
+
+static efi_status_t EFIAPI efi_cin_read_key_stroke(
+			struct efi_simple_input_interface *this,
+			struct efi_input_key *key)
+{
+	struct efi_key_data key_data;
+
+	EFI_ENTRY("%p, %p", this, key);
+
+	while (true) {
+		efi_timer_check();
+		read_keys();
+
+		if (fifo_count(&fifo) == 0)
+			return EFI_EXIT(EFI_NOT_READY);
+
+		fifo_pop(&fifo, &key_data);
+
+		/* ignore ctrl/alt/etc */
+		if (key_data.key_state.key_shift_state)
+			continue;
+
+		*key = key_data.key;
+
+		return EFI_EXIT(EFI_SUCCESS);
+	}
 }
 
 struct efi_simple_input_interface efi_con_in = {
@@ -460,19 +562,143 @@ static void EFIAPI efi_console_timer_notify(struct efi_event *event,
 {
 	EFI_ENTRY("%p, %p", event, context);
 	if (tstc()) {
+		read_keys();
 		efi_con_in.wait_for_key->is_signaled = true;
 		efi_signal_event(efi_con_in.wait_for_key);
-		}
+	}
 	EFI_EXIT(EFI_SUCCESS);
 }
 
 
-static struct efi_object efi_console_control_obj =
-	EFI_PROTOCOL_OBJECT(efi_guid_console_control, &efi_console_control);
-static struct efi_object efi_console_output_obj =
-	EFI_PROTOCOL_OBJECT(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID, &efi_con_out);
-static struct efi_object efi_console_input_obj =
-	EFI_PROTOCOL_OBJECT(EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID, &efi_con_in);
+/*
+ * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
+ */
+
+struct key_notifier {
+	struct list_head link;
+	struct efi_key_data key;
+	efi_status_t (EFIAPI *notify)(struct efi_key_data *key);
+};
+
+static LIST_HEAD(key_notifiers);  /* list of key_notifier */
+
+static bool match_key(struct efi_key_data *a, struct efi_key_data *b)
+{
+	return (a->key.scan_code == b->key.scan_code) &&
+	       (a->key.unicode_char == b->key.unicode_char) &&
+	       (a->key_state.key_shift_state == b->key_state.key_shift_state) &&
+	       (a->key_state.key_toggle_state == b->key_state.key_toggle_state);
+}
+
+static void notify_key(struct efi_key_data *key)
+{
+	struct key_notifier *notifier;
+
+	list_for_each_entry(notifier, &key_notifiers, link)
+		if (match_key(&notifier->key, key))
+			EFI_CALL(notifier->notify(key));
+}
+
+static efi_status_t EFIAPI efi_cin_ex_reset(
+		struct efi_simple_text_input_ex_interface *this,
+		bool extended_verification)
+{
+	EFI_ENTRY("%p, %d", this, extended_verification);
+	fifo.rd = fifo.wr = 0;
+	return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+static efi_status_t EFIAPI efi_cin_ex_read_key_stroke(
+		struct efi_simple_text_input_ex_interface *this,
+		struct efi_key_data *key_data)
+{
+	EFI_ENTRY("%p, %p", this, key_data);
+
+	/* We don't do interrupts, so check for timers cooperatively */
+	efi_timer_check();
+	read_keys();
+
+	if (fifo_count(&fifo) == 0)
+		return EFI_EXIT(EFI_NOT_READY);
+
+	fifo_pop(&fifo, key_data);
+
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_cin_ex_set_state(
+		struct efi_simple_text_input_ex_interface *this,
+		uint8_t key_toggle_state)
+{
+	EFI_ENTRY("%p, %x", this, key_toggle_state);
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_cin_ex_register_key_notify(
+		struct efi_simple_text_input_ex_interface *this,
+		struct efi_key_data *key_data,
+		efi_status_t (EFIAPI *notify_fn)(struct efi_key_data *key_data),
+		efi_handle_t *notify_handle)
+{
+	struct key_notifier *notifier;
+
+	EFI_ENTRY("%p, %p, %p", this, notify_fn, notify_handle);
+	notifier = calloc(1, sizeof(*notifier));
+	if (!notifier)
+		return EFI_EXIT(EFI_OUT_OF_RESOURCES);
+
+	notifier->notify = notify_fn;
+	notifier->key = *key_data;
+
+	list_add_tail(&notifier->link, &key_notifiers);
+
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_cin_ex_unregister_key_notify(
+		struct efi_simple_text_input_ex_interface *this,
+		efi_handle_t notify_handle)
+{
+	struct key_notifier *notifier = notify_handle;
+
+	EFI_ENTRY("%p, %p", this, notify_handle);
+
+	list_del(&notifier->link);
+	free(notifier);
+
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+static struct efi_simple_text_input_ex_interface efi_con_in_ex = {
+	.reset = efi_cin_ex_reset,
+	.read_key_stroke = efi_cin_ex_read_key_stroke,
+	.wait_for_key = NULL,
+	.set_state = efi_cin_ex_set_state,
+	.register_key_notify = efi_cin_ex_register_key_notify,
+	.unregister_key_notify = efi_cin_ex_unregister_key_notify,
+};
+
+static struct efi_object efi_console_control_obj = {
+	.protocols =  {
+		{ &efi_guid_console_control, (void *)&efi_console_control },
+	},
+	.handle = &efi_console_control_obj,
+};
+
+struct efi_object efi_console_output_obj = {
+	.protocols = {
+		{&EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID, (void *)&efi_con_out},
+	},
+	.handle = &efi_console_output_obj,
+};
+
+struct efi_object efi_console_input_obj = {
+	.protocols = {
+		{&EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID,    (void *)&efi_con_in},
+		{&EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID, (void *)&efi_con_in_ex},
+	},
+	.handle = &efi_console_input_obj,
+};
 
 /* This gets called from do_bootefi_exec(). */
 int efi_console_register(void)
-- 
2.13.6

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 05/11] efi_loader: console support for color attributes
  2017-10-10 12:22 [U-Boot] [PATCH 00/11] efi_loader: patches for Shell.efi Rob Clark
                   ` (3 preceding siblings ...)
  2017-10-10 12:23 ` [U-Boot] [PATCH 04/11] efi_loader: SIMPLE_TEXT_INPUT_EX plus wire up objects properly Rob Clark
@ 2017-10-10 12:23 ` Rob Clark
  2017-10-10 23:41   ` Heinrich Schuchardt
                     ` (2 more replies)
  2017-10-10 12:23 ` [U-Boot] [PATCH 06/11] efi_loader: Decouple EFI input/output from stdin/stdout Rob Clark
                   ` (6 subsequent siblings)
  11 siblings, 3 replies; 75+ messages in thread
From: Rob Clark @ 2017-10-10 12:23 UTC (permalink / raw)
  To: u-boot

Shell.efi uses this, and supporting color attributes makes things look
nicer.  Map the EFI fg/bg color attributes to ANSI escape sequences.
Not all colors have a perfect match, but spec just says "Devices
supporting a different number of text colors are required to emulate the
above colors to the best of the device’s capabilities".

Signed-off-by: Rob Clark <robdclark@gmail.com>
---
 include/efi_api.h            | 33 +++++++++++++++++++++++++++++++++
 lib/efi_loader/efi_console.c | 27 +++++++++++++++++++++++++--
 2 files changed, 58 insertions(+), 2 deletions(-)

diff --git a/include/efi_api.h b/include/efi_api.h
index 58bf15b8e6..9610d03d47 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -427,6 +427,39 @@ struct simple_text_output_mode {
 	EFI_GUID(0x387477c2, 0x69c7, 0x11d2, \
 		 0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
 
+#define EFI_BLACK                0x00
+#define EFI_BLUE                 0x01
+#define EFI_GREEN                0x02
+#define EFI_CYAN                 0x03
+#define EFI_RED                  0x04
+#define EFI_MAGENTA              0x05
+#define EFI_BROWN                0x06
+#define EFI_LIGHTGRAY            0x07
+#define EFI_BRIGHT               0x08
+#define EFI_DARKGRAY             0x08
+#define EFI_LIGHTBLUE            0x09
+#define EFI_LIGHTGREEN           0x0a
+#define EFI_LIGHTCYAN            0x0b
+#define EFI_LIGHTRED             0x0c
+#define EFI_LIGHTMAGENTA         0x0d
+#define EFI_YELLOW               0x0e
+#define EFI_WHITE                0x0f
+#define EFI_BACKGROUND_BLACK     0x00
+#define EFI_BACKGROUND_BLUE      0x10
+#define EFI_BACKGROUND_GREEN     0x20
+#define EFI_BACKGROUND_CYAN      0x30
+#define EFI_BACKGROUND_RED       0x40
+#define EFI_BACKGROUND_MAGENTA   0x50
+#define EFI_BACKGROUND_BROWN     0x60
+#define EFI_BACKGROUND_LIGHTGRAY 0x70
+
+/* extract foreground color from EFI attribute */
+#define EFI_ATTR_FG(attr)        ((attr) & 0x07)
+/* treat high bit of FG as bright/bold (similar to edk2) */
+#define EFI_ATTR_BOLD(attr)      (((attr) >> 3) & 0x01)
+/* extract background color from EFI attribute */
+#define EFI_ATTR_BG(attr)        (((attr) >> 4) & 0x7)
+
 struct efi_simple_text_output_protocol {
 	void *reset;
 	efi_status_t (EFIAPI *output_string)(
diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
index f508b79ab8..c25d6b16f2 100644
--- a/lib/efi_loader/efi_console.c
+++ b/lib/efi_loader/efi_console.c
@@ -316,14 +316,37 @@ static efi_status_t EFIAPI efi_cout_set_mode(
 	return EFI_EXIT(EFI_SUCCESS);
 }
 
+static const struct {
+	unsigned fg;
+	unsigned bg;
+} color[] = {
+	{ 30, 40 },     /* 0: black */
+	{ 34, 44 },     /* 1: blue */
+	{ 32, 42 },     /* 2: green */
+	{ 36, 46 },     /* 3: cyan */
+	{ 31, 41 },     /* 4: red */
+	{ 35, 45 },     /* 5: magenta */
+	{ 33, 43 },     /* 6: brown, map to yellow as edk2 does*/
+	{ 37, 47 },     /* 7: light grey, map to white */
+};
+
+/* See EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetAttribute(). */
 static efi_status_t EFIAPI efi_cout_set_attribute(
 			struct efi_simple_text_output_protocol *this,
 			unsigned long attribute)
 {
+	unsigned int bold = EFI_ATTR_BOLD(attribute);
+	unsigned int fg = EFI_ATTR_FG(attribute);
+	unsigned int bg = EFI_ATTR_BG(attribute);
+
 	EFI_ENTRY("%p, %lx", this, attribute);
 
-	/* Just ignore attributes (colors) for now */
-	return EFI_EXIT(EFI_UNSUPPORTED);
+	if (attribute)
+		printf(ESC"[%u;%u;%um", bold, color[fg].fg, color[bg].bg);
+	else
+		printf(ESC"[0;37;40m");
+
+	return EFI_EXIT(EFI_SUCCESS);
 }
 
 static efi_status_t EFIAPI efi_cout_clear_screen(
-- 
2.13.6

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 06/11] efi_loader: Decouple EFI input/output from stdin/stdout
  2017-10-10 12:22 [U-Boot] [PATCH 00/11] efi_loader: patches for Shell.efi Rob Clark
                   ` (4 preceding siblings ...)
  2017-10-10 12:23 ` [U-Boot] [PATCH 05/11] efi_loader: console support for color attributes Rob Clark
@ 2017-10-10 12:23 ` Rob Clark
  2017-10-11 14:45   ` Alexander Graf
  2017-10-10 12:23 ` [U-Boot] [PATCH 07/11] efi_loader: fix events Rob Clark
                   ` (5 subsequent siblings)
  11 siblings, 1 reply; 75+ messages in thread
From: Rob Clark @ 2017-10-10 12:23 UTC (permalink / raw)
  To: u-boot

In some cases, it is quite useful to have (for example) EFI on screen
but u-boot on serial port.

This adds two new optional environment variables, "efiin" and "efiout",
which can be used to set EFI console input/output independently of
u-boot's input/output.  If unset, EFI console will default to stdin/
stdout as before.

Signed-off-by: Rob Clark <robdclark@gmail.com>
---
As mentioned yesterday, this triggers some problems w/ qemu + 'bootefi
hello' since puts() != fputs(stdout).  So you can hold off applying
this one for now if you want until we figure out a solution.  It is
not strictly required, only nice-to-have (and nice for enabling debug
traces on serial without interfering with Shell.efi output on screen)

 lib/efi_loader/efi_console.c | 111 ++++++++++++++++++++++++++++++++-----------
 1 file changed, 82 insertions(+), 29 deletions(-)

diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
index c25d6b16f2..1333f9cb71 100644
--- a/lib/efi_loader/efi_console.c
+++ b/lib/efi_loader/efi_console.c
@@ -47,6 +47,38 @@ static struct cout_mode efi_cout_modes[] = {
 
 const efi_guid_t efi_guid_console_control = CONSOLE_CONTROL_GUID;
 
+static struct stdio_dev *efiin, *efiout;
+
+static int efi_tstc(void)
+{
+	return efiin->tstc(efiin);
+}
+
+static int efi_getc(void)
+{
+	return efiin->getc(efiin);
+}
+
+static int efi_printf(const char *fmt, ...)
+{
+	va_list args;
+	uint i;
+	char printbuffer[CONFIG_SYS_PBSIZE];
+
+	va_start(args, fmt);
+
+	/*
+	 * For this to work, printbuffer must be larger than
+	 * anything we ever want to print.
+	 */
+	i = vsnprintf(printbuffer, sizeof(printbuffer), fmt, args);
+	va_end(args);
+
+	/* Print the string */
+	efiout->puts(efiout, printbuffer);
+	return i;
+}
+
 #define cESC '\x1b'
 #define ESC "\x1b"
 
@@ -111,16 +143,16 @@ static int term_read_reply(int *n, int maxnum, char end_char)
 	char c;
 	int i = 0;
 
-	c = getc();
+	c = efi_getc();
 	if (c != cESC)
 		return -1;
-	c = getc();
+	c = efi_getc();
 	if (c != '[')
 		return -1;
 
 	n[0] = 0;
 	while (1) {
-		c = getc();
+		c = efi_getc();
 		if (c == ';') {
 			i++;
 			if (i >= maxnum)
@@ -164,7 +196,7 @@ static efi_status_t EFIAPI efi_cout_output_string(
 
 	*utf16_to_utf8((u8 *)buf, string, n16) = '\0';
 
-	fputs(stdout, buf);
+	efiout->puts(efiout, buf);
 
 	for (p = buf; *p; p++) {
 		switch (*p) {
@@ -217,14 +249,14 @@ static int query_console_serial(int *rows, int *cols)
 	u64 timeout;
 
 	/* Empty input buffer */
-	while (tstc())
-		getc();
+	while (efi_tstc())
+		efi_getc();
 
-	printf(ESC"[18t");
+	efi_printf(ESC"[18t");
 
 	/* Check if we have a terminal that understands */
 	timeout = timer_get_us() + 1000000;
-	while (!tstc())
+	while (!efi_tstc())
 		if (timer_get_us() > timeout)
 			return -1;
 
@@ -246,16 +278,13 @@ static efi_status_t EFIAPI efi_cout_query_mode(
 	EFI_ENTRY("%p, %ld, %p, %p", this, mode_number, columns, rows);
 
 	if (!console_size_queried) {
-		const char *stdout_name = env_get("stdout");
 		int rows, cols;
 
 		console_size_queried = true;
 
-		if (stdout_name && !strcmp(stdout_name, "vidconsole") &&
+		if (!strcmp(efiout->name, "vidconsole") &&
 		    IS_ENABLED(CONFIG_DM_VIDEO)) {
-			struct stdio_dev *stdout_dev =
-				stdio_get_by_name("vidconsole");
-			struct udevice *dev = stdout_dev->priv;
+			struct udevice *dev = efiout->priv;
 			struct vidconsole_priv *priv =
 				dev_get_uclass_priv(dev);
 			rows = priv->rows;
@@ -342,9 +371,9 @@ static efi_status_t EFIAPI efi_cout_set_attribute(
 	EFI_ENTRY("%p, %lx", this, attribute);
 
 	if (attribute)
-		printf(ESC"[%u;%u;%um", bold, color[fg].fg, color[bg].bg);
+		efi_printf(ESC"[%u;%u;%um", bold, color[fg].fg, color[bg].bg);
 	else
-		printf(ESC"[0;37;40m");
+		efi_printf(ESC"[0;37;40m");
 
 	return EFI_EXIT(EFI_SUCCESS);
 }
@@ -354,7 +383,7 @@ static efi_status_t EFIAPI efi_cout_clear_screen(
 {
 	EFI_ENTRY("%p", this);
 
-	printf(ESC"[2J");
+	efi_printf(ESC"[2J");
 
 	return EFI_EXIT(EFI_SUCCESS);
 }
@@ -365,7 +394,7 @@ static efi_status_t EFIAPI efi_cout_set_cursor_position(
 {
 	EFI_ENTRY("%p, %ld, %ld", this, column, row);
 
-	printf(ESC"[%d;%df", (int)row, (int)column);
+	efi_printf(ESC"[%d;%df", (int)row, (int)column);
 	efi_con_mode.cursor_column = column;
 	efi_con_mode.cursor_row = row;
 
@@ -378,7 +407,7 @@ static efi_status_t EFIAPI efi_cout_enable_cursor(
 {
 	EFI_ENTRY("%p, %d", this, enable);
 
-	printf(ESC"[?25%c", enable ? 'h' : 'l');
+	efi_printf(ESC"[?25%c", enable ? 'h' : 'l');
 
 	return EFI_EXIT(EFI_SUCCESS);
 }
@@ -464,28 +493,28 @@ static efi_status_t read_key_stroke(struct efi_key_data *key_data)
 	};
 	char ch;
 
-	if (!tstc()) {
+	if (!efi_tstc()) {
 		/* No key pressed */
 		return EFI_NOT_READY;
 	}
 
-	ch = getc();
+	ch = efi_getc();
 	if (ch == cESC) {
 		/* Escape Sequence */
-		ch = getc();
+		ch = efi_getc();
 		switch (ch) {
 		case cESC: /* ESC */
 			pressed_key.scan_code = 23;
 			break;
 		case 'O': /* F1 - F4 */
-			pressed_key.scan_code = getc() - 'P' + 11;
+			pressed_key.scan_code = efi_getc() - 'P' + 11;
 			break;
 		case 'a'...'z':
 			key_state.key_shift_state =
 				EFI_SHIFT_STATE_VALID | EFI_EFI_LEFT_ALT_PRESSED;
 			break;
 		case '[':
-			ch = getc();
+			ch = efi_getc();
 			switch (ch) {
 			case 'A'...'D': /* up, down right, left */
 				pressed_key.scan_code = ch - 'A' + 1;
@@ -497,16 +526,16 @@ static efi_status_t read_key_stroke(struct efi_key_data *key_data)
 				pressed_key.scan_code = 5;
 				break;
 			case '1': /* F5 - F8 */
-				pressed_key.scan_code = getc() - '0' + 11;
-				getc();
+				pressed_key.scan_code = efi_getc() - '0' + 11;
+				efi_getc();
 				break;
 			case '2': /* F9 - F12 */
-				pressed_key.scan_code = getc() - '0' + 19;
-				getc();
+				pressed_key.scan_code = efi_getc() - '0' + 19;
+				efi_getc();
 				break;
 			case '3': /* DEL */
 				pressed_key.scan_code = 8;
-				getc();
+				efi_getc();
 				break;
 			}
 			break;
@@ -584,7 +613,7 @@ static void EFIAPI efi_console_timer_notify(struct efi_event *event,
 					    void *context)
 {
 	EFI_ENTRY("%p, %p", event, context);
-	if (tstc()) {
+	if (efi_tstc()) {
 		read_keys();
 		efi_con_in.wait_for_key->is_signaled = true;
 		efi_signal_event(efi_con_in.wait_for_key);
@@ -723,6 +752,27 @@ struct efi_object efi_console_input_obj = {
 	.handle = &efi_console_input_obj,
 };
 
+static struct stdio_dev *get_stdio_dev(const char *envname, int default_dev)
+{
+	const char *name;
+	struct stdio_dev *dev = NULL;
+
+	name = env_get(envname);
+	if (name) {
+		dev = stdio_get_by_name(name);
+		if (dev && dev->start) {
+			int ret = dev->start(dev);
+			if (ret < 0)
+				dev = NULL;
+		}
+	}
+
+	if (!dev)
+		dev = stdio_devices[default_dev];
+
+	return dev;
+}
+
 /* This gets called from do_bootefi_exec(). */
 int efi_console_register(void)
 {
@@ -733,6 +783,9 @@ int efi_console_register(void)
 	list_add_tail(&efi_console_output_obj.link, &efi_obj_list);
 	list_add_tail(&efi_console_input_obj.link, &efi_obj_list);
 
+	efiout = get_stdio_dev("efiout", stdout);
+	efiin  = get_stdio_dev("efiin",  stdin);
+
 	r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK,
 			     efi_key_notify, NULL, &efi_con_in.wait_for_key);
 	if (r != EFI_SUCCESS) {
-- 
2.13.6

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 07/11] efi_loader: fix events
  2017-10-10 12:22 [U-Boot] [PATCH 00/11] efi_loader: patches for Shell.efi Rob Clark
                   ` (5 preceding siblings ...)
  2017-10-10 12:23 ` [U-Boot] [PATCH 06/11] efi_loader: Decouple EFI input/output from stdin/stdout Rob Clark
@ 2017-10-10 12:23 ` Rob Clark
  2017-10-10 22:40   ` Heinrich Schuchardt
                     ` (2 more replies)
  2017-10-10 12:23 ` [U-Boot] [PATCH 08/11] efi_loader: implement SetWatchdogTimer Rob Clark
                   ` (4 subsequent siblings)
  11 siblings, 3 replies; 75+ messages in thread
From: Rob Clark @ 2017-10-10 12:23 UTC (permalink / raw)
  To: u-boot

An event can be created with type==0, Shell.efi does this for an event
that is set when Ctrl-C is typed.  So our current approach of having a
fixed set of timer slots, and determining which slots are unused by
type==0 doesn't work so well.  But we don't have any particularly good
reason to have a fixed table of events, so just dynamically allocate
them and keep a list.

Also fixes an incorrect implementation of CheckEvent() which was (a)
incorrectly returning an error if type==0, and (b) didn't handle the
case of an unsignaled event with a notify callback.

With these fixes (plus implementation of SIMPLE_TEXT_INPUT_EX protocol),
Ctrl-C works in Shell.efi.

Signed-off-by: Rob Clark <robdclark@gmail.com>
---
 include/efi_loader.h          |   1 +
 lib/efi_loader/efi_boottime.c | 217 +++++++++++++++++++++---------------------
 2 files changed, 111 insertions(+), 107 deletions(-)

diff --git a/include/efi_loader.h b/include/efi_loader.h
index e6e55d2cb4..2232caca44 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -154,6 +154,7 @@ struct efi_event {
 	enum efi_timer_delay trigger_type;
 	bool is_queued;
 	bool is_signaled;
+	struct list_head link;
 };
 
 
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index 39dcc72648..19fafe546c 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -350,11 +350,26 @@ static efi_status_t efi_create_handle(void **handle)
 	return r;
 }
 
+static LIST_HEAD(efi_events);
+
 /*
- * Our event capabilities are very limited. Only a small limited
- * number of events is allowed to coexist.
+ * Check if a pointer is a valid event.
+ *
+ * It might be nice at some point to extend this to a more general
+ * mechanism to check if pointers passed from the EFI world are
+ * valid objects of a particular type.
  */
-static struct efi_event efi_events[16];
+static bool efi_is_event(const void *obj)
+{
+	struct efi_event *evt;
+
+	list_for_each_entry(evt, &efi_events, link) {
+		if (evt == obj)
+			return true;
+	}
+
+	return false;
+}
 
 /*
  * Create an event.
@@ -377,7 +392,7 @@ efi_status_t efi_create_event(uint32_t type, UINTN notify_tpl,
 					void *context),
 			      void *notify_context, struct efi_event **event)
 {
-	int i;
+	struct efi_event *evt;
 
 	if (event == NULL)
 		return EFI_INVALID_PARAMETER;
@@ -389,21 +404,24 @@ efi_status_t efi_create_event(uint32_t type, UINTN notify_tpl,
 	    notify_function == NULL)
 		return EFI_INVALID_PARAMETER;
 
-	for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
-		if (efi_events[i].type)
-			continue;
-		efi_events[i].type = type;
-		efi_events[i].notify_tpl = notify_tpl;
-		efi_events[i].notify_function = notify_function;
-		efi_events[i].notify_context = notify_context;
-		/* Disable timers on bootup */
-		efi_events[i].trigger_next = -1ULL;
-		efi_events[i].is_queued = false;
-		efi_events[i].is_signaled = false;
-		*event = &efi_events[i];
-		return EFI_SUCCESS;
-	}
-	return EFI_OUT_OF_RESOURCES;
+	evt = calloc(1, sizeof(*evt));
+	if (!evt)
+		return EFI_OUT_OF_RESOURCES;
+
+	evt->type = type;
+	evt->notify_tpl = notify_tpl;
+	evt->notify_function = notify_function;
+	evt->notify_context = notify_context;
+	/* Disable timers on bootup */
+	evt->trigger_next = -1ULL;
+	evt->is_queued = false;
+	evt->is_signaled = false;
+
+	list_add_tail(&evt->link, &efi_events);
+
+	*event = evt;
+
+	return EFI_SUCCESS;
 }
 
 /*
@@ -443,30 +461,31 @@ static efi_status_t EFIAPI efi_create_event_ext(
  */
 void efi_timer_check(void)
 {
-	int i;
+	struct efi_event *evt;
 	u64 now = timer_get_us();
 
-	for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
-		if (!efi_events[i].type)
-			continue;
-		if (efi_events[i].is_queued)
-			efi_signal_event(&efi_events[i]);
-		if (!(efi_events[i].type & EVT_TIMER) ||
-		    now < efi_events[i].trigger_next)
+	/*
+	 * TODO perhaps optimize a bit and track the time of next
+	 * timer to expire?
+	 */
+	list_for_each_entry(evt, &efi_events, link) {
+		if (evt->is_queued)
+			efi_signal_event(evt);
+		if (!(evt->type & EVT_TIMER) ||
+		    now < evt->trigger_next)
 			continue;
-		switch (efi_events[i].trigger_type) {
+		switch (evt->trigger_type) {
 		case EFI_TIMER_RELATIVE:
-			efi_events[i].trigger_type = EFI_TIMER_STOP;
+			evt->trigger_type = EFI_TIMER_STOP;
 			break;
 		case EFI_TIMER_PERIODIC:
-			efi_events[i].trigger_next +=
-				efi_events[i].trigger_time;
+			evt->trigger_next += evt->trigger_time;
 			break;
 		default:
 			continue;
 		}
-		efi_events[i].is_signaled = true;
-		efi_signal_event(&efi_events[i]);
+		evt->is_signaled = true;
+		efi_signal_event(evt);
 	}
 	WATCHDOG_RESET();
 }
@@ -485,7 +504,8 @@ void efi_timer_check(void)
 efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type,
 			   uint64_t trigger_time)
 {
-	int i;
+	if (!efi_is_event(event))
+		return EFI_INVALID_PARAMETER;
 
 	/*
 	 * The parameter defines a multiple of 100ns.
@@ -493,30 +513,25 @@ efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type,
 	 */
 	do_div(trigger_time, 10);
 
-	for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
-		if (event != &efi_events[i])
-			continue;
+	if (!(event->type & EVT_TIMER))
+		return EFI_INVALID_PARAMETER;
 
-		if (!(event->type & EVT_TIMER))
-			break;
-		switch (type) {
-		case EFI_TIMER_STOP:
-			event->trigger_next = -1ULL;
-			break;
-		case EFI_TIMER_PERIODIC:
-		case EFI_TIMER_RELATIVE:
-			event->trigger_next =
-				timer_get_us() + trigger_time;
-			break;
-		default:
-			return EFI_INVALID_PARAMETER;
-		}
-		event->trigger_type = type;
-		event->trigger_time = trigger_time;
-		event->is_signaled = false;
-		return EFI_SUCCESS;
+	switch (type) {
+	case EFI_TIMER_STOP:
+		event->trigger_next = -1ULL;
+		break;
+	case EFI_TIMER_PERIODIC:
+	case EFI_TIMER_RELATIVE:
+		event->trigger_next = timer_get_us() + trigger_time;
+		break;
+	default:
+		return EFI_INVALID_PARAMETER;
 	}
-	return EFI_INVALID_PARAMETER;
+	event->trigger_type = type;
+	event->trigger_time = trigger_time;
+	event->is_signaled = false;
+
+	return EFI_SUCCESS;
 }
 
 /*
@@ -555,7 +570,7 @@ static efi_status_t EFIAPI efi_wait_for_event(unsigned long num_events,
 					      struct efi_event **event,
 					      size_t *index)
 {
-	int i, j;
+	int i;
 
 	EFI_ENTRY("%ld, %p, %p", num_events, event, index);
 
@@ -566,12 +581,8 @@ static efi_status_t EFIAPI efi_wait_for_event(unsigned long num_events,
 	if (efi_tpl != TPL_APPLICATION)
 		return EFI_EXIT(EFI_UNSUPPORTED);
 	for (i = 0; i < num_events; ++i) {
-		for (j = 0; j < ARRAY_SIZE(efi_events); ++j) {
-			if (event[i] == &efi_events[j])
-				goto known_event;
-		}
-		return EFI_EXIT(EFI_INVALID_PARAMETER);
-known_event:
+		if (!efi_is_event(event[i]))
+			return EFI_EXIT(EFI_INVALID_PARAMETER);
 		if (!event[i]->type || event[i]->type & EVT_NOTIFY_SIGNAL)
 			return EFI_EXIT(EFI_INVALID_PARAMETER);
 		if (!event[i]->is_signaled)
@@ -614,19 +625,12 @@ out:
  */
 static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event)
 {
-	int i;
-
 	EFI_ENTRY("%p", event);
-	for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
-		if (event != &efi_events[i])
-			continue;
-		if (event->is_signaled)
-			break;
-		event->is_signaled = true;
-		if (event->type & EVT_NOTIFY_SIGNAL)
-			efi_signal_event(event);
-		break;
-	}
+	if (!efi_is_event(event))
+		return EFI_EXIT(EFI_INVALID_PARAMETER);
+	event->is_signaled = true;
+	if (event->type & EVT_NOTIFY_SIGNAL)
+		efi_signal_event(event);
 	return EFI_EXIT(EFI_SUCCESS);
 }
 
@@ -642,19 +646,10 @@ static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event)
  */
 static efi_status_t EFIAPI efi_close_event(struct efi_event *event)
 {
-	int i;
-
 	EFI_ENTRY("%p", event);
-	for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
-		if (event == &efi_events[i]) {
-			event->type = 0;
-			event->trigger_next = -1ULL;
-			event->is_queued = false;
-			event->is_signaled = false;
-			return EFI_EXIT(EFI_SUCCESS);
-		}
-	}
-	return EFI_EXIT(EFI_INVALID_PARAMETER);
+	list_del(&event->link);
+	free(event);
+	return EFI_EXIT(EFI_SUCCESS);
 }
 
 /*
@@ -664,29 +659,37 @@ static efi_status_t EFIAPI efi_close_event(struct efi_event *event)
  * See the Unified Extensible Firmware Interface (UEFI) specification
  * for details.
  *
- * If an event is not signaled yet the notification function is queued.
+ * - If Event is in the signaled state, it is cleared and EFI_SUCCESS
+ *   is returned.
+ *
+ * - If Event is not in the signaled state and has no notification
+ *   function, EFI_NOT_READY is returned.
+ *
+ * - If Event is not in the signaled state but does have a notification
+ *   function, the notification function is queued at the event’s
+ *   notification task priority level. If the execution of the
+ *   notification function causes Event to be signaled, then the signaled
+ *   state is cleared and EFI_SUCCESS is returned; if the Event is not
+ *   signaled, then EFI_NOT_READY is returned.
  *
  * @event	event to check
  * @return	status code
  */
-static efi_status_t EFIAPI efi_check_event(struct efi_event *event)
+/*
+ */
+static efi_status_t EFIAPI efi_check_event(struct efi_event *evt)
 {
-	int i;
-
-	EFI_ENTRY("%p", event);
+	EFI_ENTRY("%p", evt);
 	efi_timer_check();
-	for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
-		if (event != &efi_events[i])
-			continue;
-		if (!event->type || event->type & EVT_NOTIFY_SIGNAL)
-			break;
-		if (!event->is_signaled)
-			efi_signal_event(event);
-		if (event->is_signaled)
-			return EFI_EXIT(EFI_SUCCESS);
-		return EFI_EXIT(EFI_NOT_READY);
+	if (!efi_is_event(evt) || (evt->type & EVT_NOTIFY_SIGNAL))
+		return EFI_EXIT(EFI_INVALID_PARAMETER);
+	if (!evt->is_signaled && evt->notify_function)
+		EFI_CALL_VOID(evt->notify_function(evt, evt->notify_context));
+	if (evt->is_signaled) {
+		evt->is_signaled = true;
+		return EFI_EXIT(EFI_SUCCESS);
 	}
-	return EFI_EXIT(EFI_INVALID_PARAMETER);
+	return EFI_EXIT(EFI_NOT_READY);
 }
 
 /*
@@ -1440,15 +1443,15 @@ static void efi_exit_caches(void)
 static efi_status_t EFIAPI efi_exit_boot_services(void *image_handle,
 						  unsigned long map_key)
 {
-	int i;
+	struct efi_event *evt;
 
 	EFI_ENTRY("%p, %ld", image_handle, map_key);
 
 	/* Notify that ExitBootServices is invoked. */
-	for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
-		if (efi_events[i].type != EVT_SIGNAL_EXIT_BOOT_SERVICES)
+	list_for_each_entry(evt, &efi_events, link) {
+		if (evt->type != EVT_SIGNAL_EXIT_BOOT_SERVICES)
 			continue;
-		efi_signal_event(&efi_events[i]);
+		efi_signal_event(evt);
 	}
 	/* Make sure that notification functions are not called anymore */
 	efi_tpl = TPL_HIGH_LEVEL;
-- 
2.13.6

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 08/11] efi_loader: implement SetWatchdogTimer
  2017-10-10 12:22 [U-Boot] [PATCH 00/11] efi_loader: patches for Shell.efi Rob Clark
                   ` (6 preceding siblings ...)
  2017-10-10 12:23 ` [U-Boot] [PATCH 07/11] efi_loader: fix events Rob Clark
@ 2017-10-10 12:23 ` Rob Clark
  2017-10-11 14:55   ` Alexander Graf
  2017-10-10 12:23 ` [U-Boot] [PATCH 09/11] efi_loader: Fix disk dp's for pre-DM/legacy devices Rob Clark
                   ` (3 subsequent siblings)
  11 siblings, 1 reply; 75+ messages in thread
From: Rob Clark @ 2017-10-10 12:23 UTC (permalink / raw)
  To: u-boot

From: Heinrich Schuchardt <xypron.glpk@gmx.de>

The watchdog is initialized with a 5 minute timeout period.
It can be reset by SetWatchdogTimer.
It is stopped by ExitBoottimeServices.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
---
 cmd/bootefi.c                 |  1 +
 include/efi_loader.h          |  4 ++
 lib/efi_loader/Makefile       |  2 +-
 lib/efi_loader/efi_boottime.c | 17 ++-------
 lib/efi_loader/efi_watchdog.c | 86 +++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 95 insertions(+), 15 deletions(-)
 create mode 100644 lib/efi_loader/efi_watchdog.c

diff --git a/cmd/bootefi.c b/cmd/bootefi.c
index b7087e3da8..24958ada46 100644
--- a/cmd/bootefi.c
+++ b/cmd/bootefi.c
@@ -43,6 +43,7 @@ static void efi_init_obj_list(void)
 #ifdef CONFIG_GENERATE_SMBIOS_TABLE
 	efi_smbios_register();
 #endif
+	efi_watchdog_register();
 
 	/* Initialize EFI runtime services */
 	efi_reset_system_init();
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 2232caca44..fa4e1cdb1c 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -169,6 +169,8 @@ int efi_disk_register(void);
 int efi_gop_register(void);
 /* Called by bootefi to make the network interface available */
 int efi_net_register(void);
+/* Called by bootefi to make the watchdog available */
+int efi_watchdog_register(void);
 /* Called by bootefi to make SMBIOS tables available */
 void efi_smbios_register(void);
 
@@ -177,6 +179,8 @@ efi_fs_from_path(struct efi_device_path *fp);
 
 /* Called by networking code to memorize the dhcp ack package */
 void efi_net_set_dhcp_ack(void *pkt, int len);
+/* Called by efi_set_watchdog_timer to reset the timer */
+efi_status_t efi_set_watchdog(unsigned long timeout);
 
 /* Called from places to check whether a timer expired */
 void efi_timer_check(void);
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
index 7ea96a4f1c..4238cf9f9b 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -18,7 +18,7 @@ obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o
 obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o
 obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o
 obj-y += efi_device_path_utilities.o efi_hii.o efi_unicode.o
-obj-y += efi_file.o efi_variable.o efi_bootmgr.o
+obj-y += efi_file.o efi_variable.o efi_bootmgr.o efi_watchdog.o
 obj-$(CONFIG_LCD) += efi_gop.o
 obj-$(CONFIG_DM_VIDEO) += efi_gop.o
 obj-$(CONFIG_PARTITIONS) += efi_disk.o
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index 19fafe546c..310f0a3b62 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -156,18 +156,6 @@ void efi_signal_event(struct efi_event *event)
 }
 
 /*
- * Write a debug message for an EPI API service that is not implemented yet.
- *
- * @funcname	function that is not yet implemented
- * @return	EFI_UNSUPPORTED
- */
-static efi_status_t efi_unsupported(const char *funcname)
-{
-	debug("EFI: App called into unimplemented function %s\n", funcname);
-	return EFI_EXIT(EFI_UNSUPPORTED);
-}
-
-/*
  * Raise the task priority level.
  *
  * This function implements the RaiseTpl service.
@@ -1470,6 +1458,7 @@ static efi_status_t EFIAPI efi_exit_boot_services(void *image_handle,
 	bootm_disable_interrupts();
 
 	/* Give the payload some time to boot */
+	efi_set_watchdog(0);
 	WATCHDOG_RESET();
 
 	return EFI_EXIT(EFI_SUCCESS);
@@ -1513,7 +1502,7 @@ static efi_status_t EFIAPI efi_stall(unsigned long microseconds)
 /*
  * Reset the watchdog timer.
  *
- * This function implements the WatchdogTimer service.
+ * This function implements the SetWatchdogTimer service.
  * See the Unified Extensible Firmware Interface (UEFI) specification
  * for details.
  *
@@ -1529,7 +1518,7 @@ static efi_status_t EFIAPI efi_set_watchdog_timer(unsigned long timeout,
 {
 	EFI_ENTRY("%ld, 0x%"PRIx64", %ld, %p", timeout, watchdog_code,
 		  data_size, watchdog_data);
-	return efi_unsupported(__func__);
+	return EFI_EXIT(efi_set_watchdog(timeout));
 }
 
 /*
diff --git a/lib/efi_loader/efi_watchdog.c b/lib/efi_loader/efi_watchdog.c
new file mode 100644
index 0000000000..eb437faf4b
--- /dev/null
+++ b/lib/efi_loader/efi_watchdog.c
@@ -0,0 +1,86 @@
+/*
+ *  EFI watchdog
+ *
+ *  Copyright (c) 2017 Heinrich Schuchardt
+ *
+ *  SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <efi_loader.h>
+
+static struct efi_event *watchdog_timer_event;
+
+/*
+ * Reset the system when the watchdog event is notified.
+ *
+ * @event:	the watchdog event
+ * @context:	not used
+ */
+static void EFIAPI efi_watchdog_timer_notify(struct efi_event *event,
+					     void *context)
+{
+	EFI_ENTRY("%p, %p", event, context);
+
+	printf("\nEFI: Watchdog timeout\n");
+	EFI_CALL_VOID(efi_runtime_services.reset_system(EFI_RESET_COLD,
+							EFI_SUCCESS, 0, NULL));
+
+	EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+/*
+ * Reset the watchdog timer.
+ *
+ * This function is used by the SetWatchdogTimer service.
+ *
+ * @timeout:		seconds before reset by watchdog
+ * @return:		status code
+ */
+efi_status_t efi_set_watchdog(unsigned long timeout)
+{
+	efi_status_t r;
+
+	if (timeout)
+		/* Reset watchdog */
+		r = efi_set_timer(watchdog_timer_event, EFI_TIMER_RELATIVE,
+				  10000000 * timeout);
+	else
+		/* Deactivate watchdog */
+		r = efi_set_timer(watchdog_timer_event, EFI_TIMER_STOP, 0);
+	return r;
+}
+
+/*
+ * Initialize the EFI watchdog.
+ *
+ * This function is called by efi_init_obj_list()
+ */
+int efi_watchdog_register(void)
+{
+	efi_status_t r;
+
+	/*
+	 * Create a timer event.
+	 */
+	r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
+			     efi_watchdog_timer_notify, NULL,
+			     &watchdog_timer_event);
+	if (r != EFI_SUCCESS) {
+		printf("ERROR: Failed to register watchdog event\n");
+		return r;
+	}
+	/*
+	 * The UEFI standard requires that the watchdog timer is set to five
+	 * minutes when invoking an EFI boot option.
+	 *
+	 * Unified Extensible Firmware Interface (UEFI), version 2.7 Errata A
+	 * 7.5. Miscellaneous Boot Services - EFI_BOOT_SERVICES.SetWatchdogTimer
+	 */
+	r = efi_set_watchdog(300);
+	if (r != EFI_SUCCESS) {
+		printf("ERROR: Failed to set watchdog timer\n");
+		return r;
+	}
+	return 0;
+}
-- 
2.13.6

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 09/11] efi_loader: Fix disk dp's for pre-DM/legacy devices
  2017-10-10 12:22 [U-Boot] [PATCH 00/11] efi_loader: patches for Shell.efi Rob Clark
                   ` (7 preceding siblings ...)
  2017-10-10 12:23 ` [U-Boot] [PATCH 08/11] efi_loader: implement SetWatchdogTimer Rob Clark
@ 2017-10-10 12:23 ` Rob Clark
  2017-10-11 14:56   ` Alexander Graf
  2017-10-10 12:23 ` [U-Boot] [PATCH 10/11] efi_loader: Add mem-mapped for fallback Rob Clark
                   ` (2 subsequent siblings)
  11 siblings, 1 reply; 75+ messages in thread
From: Rob Clark @ 2017-10-10 12:23 UTC (permalink / raw)
  To: u-boot

This fixes an issue with OpenBSD's bootloader, and I think should also
fix a similar issue with grub2 on legacy devices.  In the legacy case
we were creating disk objects for the partitions, but not also the
parent device.

Reported-by: Jonathan Gray <jsg@jsg.id.au>
Signed-off-by: Rob Clark <robdclark@gmail.com>
---
 lib/efi_loader/efi_disk.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
index eb9ce772d1..47b487aa30 100644
--- a/lib/efi_loader/efi_disk.c
+++ b/lib/efi_loader/efi_disk.c
@@ -340,6 +340,8 @@ int efi_disk_register(void)
 		for (i = 0; i < 4; i++) {
 			struct blk_desc *desc;
 			char devname[32] = { 0 }; /* dp->str is u16[32] long */
+			disk_partition_t info;
+			int part = 1;
 
 			desc = blk_get_devnum_by_type(if_type, i);
 			if (!desc)
@@ -349,6 +351,15 @@ int efi_disk_register(void)
 
 			snprintf(devname, sizeof(devname), "%s%d",
 				 if_typename, i);
+
+			/* add devices for each partition: */
+			while (!part_get_info(desc, part, &info)) {
+				efi_disk_add_dev(devname, if_typename, desc,
+						 i, 0, part);
+				part++;
+			}
+
+			/* ... and add block device: */
 			efi_disk_add_dev(devname, if_typename, desc, i, 0, 0);
 			disks++;
 
-- 
2.13.6

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 10/11] efi_loader: Add mem-mapped for fallback
  2017-10-10 12:22 [U-Boot] [PATCH 00/11] efi_loader: patches for Shell.efi Rob Clark
                   ` (8 preceding siblings ...)
  2017-10-10 12:23 ` [U-Boot] [PATCH 09/11] efi_loader: Fix disk dp's for pre-DM/legacy devices Rob Clark
@ 2017-10-10 12:23 ` Rob Clark
  2017-10-10 22:31   ` Heinrich Schuchardt
                     ` (2 more replies)
  2017-10-10 12:23 ` [U-Boot] [PATCH 11/11] efi_loader: exclude openrd devices Rob Clark
  2017-10-11  0:24 ` [U-Boot] [PATCH 00/11] efi_loader: patches for Shell.efi Heinrich Schuchardt
  11 siblings, 3 replies; 75+ messages in thread
From: Rob Clark @ 2017-10-10 12:23 UTC (permalink / raw)
  To: u-boot

When we don't have a real device/image path, such as 'bootefi hello',
construct a mem-mapped device-path.

This fixes 'bootefi hello' after devicepath refactoring.

Fixes: 95c5553ea2 ("efi_loader: refactor boot device and loaded_image handling")
Signed-off-by: Rob Clark <robdclark@gmail.com>
---
 cmd/bootefi.c                            | 23 +++++++++++++++++++++++
 include/efi_api.h                        |  8 ++++++++
 include/efi_loader.h                     |  3 +++
 lib/efi_loader/efi_device_path.c         | 24 ++++++++++++++++++++++++
 lib/efi_loader/efi_device_path_to_text.c |  9 +++++++++
 5 files changed, 67 insertions(+)

diff --git a/cmd/bootefi.c b/cmd/bootefi.c
index 24958ada46..18176a1266 100644
--- a/cmd/bootefi.c
+++ b/cmd/bootefi.c
@@ -128,6 +128,7 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt,
 {
 	struct efi_loaded_image loaded_image_info = {};
 	struct efi_object loaded_image_info_obj = {};
+	struct efi_device_path *memdp = NULL;
 	ulong ret;
 
 	ulong (*entry)(void *image_handle, struct efi_system_table *st)
@@ -136,6 +137,20 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt,
 	const efi_guid_t fdt_guid = EFI_FDT_GUID;
 	bootm_headers_t img = { 0 };
 
+	/*
+	 * Special case for efi payload not loaded from disk, such as
+	 * 'bootefi hello' or for example payload loaded directly into
+	 * memory via jtag/etc:
+	 */
+	if (!device_path && !image_path) {
+		printf("WARNING: using memory device/image path, this may confuse some payloads!\n");
+		/* actual addresses filled in after efi_load_pe() */
+		memdp = efi_dp_from_mem(0, 0, 0);
+		device_path = image_path = memdp;
+	} else {
+		assert(device_path && image_path);
+	}
+
 	/* Initialize and populate EFI object list */
 	if (!efi_obj_list_initalized)
 		efi_init_obj_list();
@@ -182,6 +197,14 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt,
 		goto exit;
 	}
 
+	if (memdp) {
+		struct efi_device_path_memory *mdp = (void *)memdp;
+		mdp->memory_type = loaded_image_info.image_code_type;
+		mdp->start_address = (uintptr_t)loaded_image_info.image_base;
+		mdp->end_address = mdp->start_address +
+				loaded_image_info.image_size;
+	}
+
 	/* we don't support much: */
 	env_set("efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_OsIndicationsSupported",
 		"{ro,boot}(blob)0000000000000000");
diff --git a/include/efi_api.h b/include/efi_api.h
index 9610d03d47..07b2af7020 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -299,8 +299,16 @@ struct efi_mac_addr {
 } __packed;
 
 #define DEVICE_PATH_TYPE_HARDWARE_DEVICE	0x01
+#  define DEVICE_PATH_SUB_TYPE_MEMORY		0x03
 #  define DEVICE_PATH_SUB_TYPE_VENDOR		0x04
 
+struct efi_device_path_memory {
+	struct efi_device_path dp;
+	u32 memory_type;
+	u64 start_address;
+	u64 end_address;
+} __packed;
+
 struct efi_device_path_vendor {
 	struct efi_device_path dp;
 	efi_guid_t guid;
diff --git a/include/efi_loader.h b/include/efi_loader.h
index fa4e1cdb1c..db805e898f 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -269,6 +269,9 @@ struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part);
 struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part,
 					 const char *path);
 struct efi_device_path *efi_dp_from_eth(void);
+struct efi_device_path *efi_dp_from_mem(uint32_t mem_type,
+					uint64_t start_address,
+					uint64_t end_address);
 void efi_dp_split_file_path(struct efi_device_path *full_path,
 			    struct efi_device_path **device_path,
 			    struct efi_device_path **file_path);
diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
index 5d5c3b3464..f6e368e029 100644
--- a/lib/efi_loader/efi_device_path.c
+++ b/lib/efi_loader/efi_device_path.c
@@ -538,6 +538,30 @@ struct efi_device_path *efi_dp_from_eth(void)
 }
 #endif
 
+/* Construct a device-path for memory-mapped image */
+struct efi_device_path *efi_dp_from_mem(uint32_t memory_type,
+					uint64_t start_address,
+					uint64_t end_address)
+{
+	struct efi_device_path_memory *mdp;
+	void *buf, *start;
+
+	start = buf = dp_alloc(sizeof(*mdp) + sizeof(END));
+
+	mdp = buf;
+	mdp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
+	mdp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MEMORY;
+	mdp->dp.length = sizeof(*mdp);
+	mdp->memory_type = memory_type;
+	mdp->start_address = start_address;
+	mdp->end_address = end_address;
+	buf = &mdp[1];
+
+	*((struct efi_device_path *)buf) = END;
+
+	return start;
+}
+
 /*
  * Helper to split a full device path (containing both device and file
  * parts) into it's constituent parts.
diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c
index 1a5ef3919b..62771338f0 100644
--- a/lib/efi_loader/efi_device_path_to_text.c
+++ b/lib/efi_loader/efi_device_path_to_text.c
@@ -24,6 +24,15 @@ static char *dp_unknown(char *s, struct efi_device_path *dp)
 static char *dp_hardware(char *s, struct efi_device_path *dp)
 {
 	switch (dp->sub_type) {
+	case DEVICE_PATH_SUB_TYPE_MEMORY: {
+		struct efi_device_path_memory *mdp =
+			(struct efi_device_path_memory *)dp;
+		s += sprintf(s, "/MemoryMapped(0x%x,0x%llx,0x%llx)",
+			     mdp->memory_type,
+			     mdp->start_address,
+			     mdp->end_address);
+		break;
+	}
 	case DEVICE_PATH_SUB_TYPE_VENDOR: {
 		struct efi_device_path_vendor *vdp =
 			(struct efi_device_path_vendor *)dp;
-- 
2.13.6

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 11/11] efi_loader: exclude openrd devices
  2017-10-10 12:22 [U-Boot] [PATCH 00/11] efi_loader: patches for Shell.efi Rob Clark
                   ` (9 preceding siblings ...)
  2017-10-10 12:23 ` [U-Boot] [PATCH 10/11] efi_loader: Add mem-mapped for fallback Rob Clark
@ 2017-10-10 12:23 ` Rob Clark
  2017-10-10 22:28   ` Heinrich Schuchardt
  2017-10-11  0:24 ` [U-Boot] [PATCH 00/11] efi_loader: patches for Shell.efi Heinrich Schuchardt
  11 siblings, 1 reply; 75+ messages in thread
From: Rob Clark @ 2017-10-10 12:23 UTC (permalink / raw)
  To: u-boot

These devices have small image size limits, so exclude EFI_LOADER to
help avoid exceeding limits.

Signed-off-by: Rob Clark <robdclark@gmail.com>
---
 lib/efi_loader/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index d2b6327119..6e22940da5 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -1,6 +1,6 @@
 config EFI_LOADER
 	bool "Support running EFI Applications in U-Boot"
-	depends on (ARM || X86) && OF_LIBFDT
+	depends on (ARM || X86) && OF_LIBFDT && !TARGET_OPENRD
 	default y
 	help
 	  Select this option if you want to run EFI applications (like grub2)
-- 
2.13.6

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 11/11] efi_loader: exclude openrd devices
  2017-10-10 12:23 ` [U-Boot] [PATCH 11/11] efi_loader: exclude openrd devices Rob Clark
@ 2017-10-10 22:28   ` Heinrich Schuchardt
  2017-10-10 22:50     ` Rob Clark
  0 siblings, 1 reply; 75+ messages in thread
From: Heinrich Schuchardt @ 2017-10-10 22:28 UTC (permalink / raw)
  To: u-boot

On 10/10/2017 02:23 PM, Rob Clark wrote:
> These devices have small image size limits, so exclude EFI_LOADER to
> help avoid exceeding limits.
> 
> Signed-off-by: Rob Clark <robdclark@gmail.com>
> ---
>   lib/efi_loader/Kconfig | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
> index d2b6327119..6e22940da5 100644
> --- a/lib/efi_loader/Kconfig
> +++ b/lib/efi_loader/Kconfig
> @@ -1,6 +1,6 @@
>   config EFI_LOADER
>   	bool "Support running EFI Applications in U-Boot"
> -	depends on (ARM || X86) && OF_LIBFDT
> +	depends on (ARM || X86) && OF_LIBFDT && !TARGET_OPENRD
>   	default y
>   	help
>   	  Select this option if you want to run EFI applications (like grub2)
> 

I understand that with the progress we make on EFI implementation and 
other parts of U-Boot the U-Boot image size is growing too big for 
direct loading by the primary boot loader.

The OPENRD boards have abundant memory, e.g. openrd_ultimate_defconfig 
refers to a board with 512 MB RAM.

So I think completely disabling EFI is not the solution.
Instead building an SPL should be enabled for this architecture when the 
image is becoming too big for direct load.

I am copying in the KIRKWOOD maintainers go get their view.

Best regards

Heinrich

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 10/11] efi_loader: Add mem-mapped for fallback
  2017-10-10 12:23 ` [U-Boot] [PATCH 10/11] efi_loader: Add mem-mapped for fallback Rob Clark
@ 2017-10-10 22:31   ` Heinrich Schuchardt
  2017-10-11 14:59   ` Alexander Graf
  2017-10-12 15:24   ` [U-Boot] [U-Boot, " Alexander Graf
  2 siblings, 0 replies; 75+ messages in thread
From: Heinrich Schuchardt @ 2017-10-10 22:31 UTC (permalink / raw)
  To: u-boot



On 10/10/2017 02:23 PM, Rob Clark wrote:
> When we don't have a real device/image path, such as 'bootefi hello',
> construct a mem-mapped device-path.
> 
> This fixes 'bootefi hello' after devicepath refactoring.
> 
> Fixes: 95c5553ea2 ("efi_loader: refactor boot device and loaded_image handling")
> Signed-off-by: Rob Clark <robdclark@gmail.com>
> ---
>   cmd/bootefi.c                            | 23 +++++++++++++++++++++++
>   include/efi_api.h                        |  8 ++++++++
>   include/efi_loader.h                     |  3 +++
>   lib/efi_loader/efi_device_path.c         | 24 ++++++++++++++++++++++++
>   lib/efi_loader/efi_device_path_to_text.c |  9 +++++++++
>   5 files changed, 67 insertions(+)
> 
> diff --git a/cmd/bootefi.c b/cmd/bootefi.c
> index 24958ada46..18176a1266 100644
> --- a/cmd/bootefi.c
> +++ b/cmd/bootefi.c
> @@ -128,6 +128,7 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt,
>   {
>   	struct efi_loaded_image loaded_image_info = {};
>   	struct efi_object loaded_image_info_obj = {};
> +	struct efi_device_path *memdp = NULL;
>   	ulong ret;
>   
>   	ulong (*entry)(void *image_handle, struct efi_system_table *st)
> @@ -136,6 +137,20 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt,
>   	const efi_guid_t fdt_guid = EFI_FDT_GUID;
>   	bootm_headers_t img = { 0 };
>   
> +	/*
> +	 * Special case for efi payload not loaded from disk, such as
> +	 * 'bootefi hello' or for example payload loaded directly into
> +	 * memory via jtag/etc:
> +	 */
> +	if (!device_path && !image_path) {
> +		printf("WARNING: using memory device/image path, this may confuse some payloads!\n");
> +		/* actual addresses filled in after efi_load_pe() */
> +		memdp = efi_dp_from_mem(0, 0, 0);
> +		device_path = image_path = memdp;
> +	} else {
> +		assert(device_path && image_path);
> +	}
> +
>   	/* Initialize and populate EFI object list */
>   	if (!efi_obj_list_initalized)
>   		efi_init_obj_list();
> @@ -182,6 +197,14 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt,
>   		goto exit;
>   	}
>   
> +	if (memdp) {
> +		struct efi_device_path_memory *mdp = (void *)memdp;
> +		mdp->memory_type = loaded_image_info.image_code_type;
> +		mdp->start_address = (uintptr_t)loaded_image_info.image_base;
> +		mdp->end_address = mdp->start_address +
> +				loaded_image_info.image_size;
> +	}
> +
>   	/* we don't support much: */
>   	env_set("efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_OsIndicationsSupported",
>   		"{ro,boot}(blob)0000000000000000");
> diff --git a/include/efi_api.h b/include/efi_api.h
> index 9610d03d47..07b2af7020 100644
> --- a/include/efi_api.h
> +++ b/include/efi_api.h
> @@ -299,8 +299,16 @@ struct efi_mac_addr {
>   } __packed;
>   
>   #define DEVICE_PATH_TYPE_HARDWARE_DEVICE	0x01
> +#  define DEVICE_PATH_SUB_TYPE_MEMORY		0x03
>   #  define DEVICE_PATH_SUB_TYPE_VENDOR		0x04
>   
> +struct efi_device_path_memory {
> +	struct efi_device_path dp;
> +	u32 memory_type;
> +	u64 start_address;
> +	u64 end_address;
> +} __packed;
> +
>   struct efi_device_path_vendor {
>   	struct efi_device_path dp;
>   	efi_guid_t guid;
> diff --git a/include/efi_loader.h b/include/efi_loader.h
> index fa4e1cdb1c..db805e898f 100644
> --- a/include/efi_loader.h
> +++ b/include/efi_loader.h
> @@ -269,6 +269,9 @@ struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part);
>   struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part,
>   					 const char *path);
>   struct efi_device_path *efi_dp_from_eth(void);
> +struct efi_device_path *efi_dp_from_mem(uint32_t mem_type,
> +					uint64_t start_address,
> +					uint64_t end_address);
>   void efi_dp_split_file_path(struct efi_device_path *full_path,
>   			    struct efi_device_path **device_path,
>   			    struct efi_device_path **file_path);
> diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
> index 5d5c3b3464..f6e368e029 100644
> --- a/lib/efi_loader/efi_device_path.c
> +++ b/lib/efi_loader/efi_device_path.c
> @@ -538,6 +538,30 @@ struct efi_device_path *efi_dp_from_eth(void)
>   }
>   #endif
>   
> +/* Construct a device-path for memory-mapped image */
> +struct efi_device_path *efi_dp_from_mem(uint32_t memory_type,
> +					uint64_t start_address,
> +					uint64_t end_address)
> +{
> +	struct efi_device_path_memory *mdp;
> +	void *buf, *start;
> +
> +	start = buf = dp_alloc(sizeof(*mdp) + sizeof(END));
> +
> +	mdp = buf;
> +	mdp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
> +	mdp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MEMORY;
> +	mdp->dp.length = sizeof(*mdp);
> +	mdp->memory_type = memory_type;
> +	mdp->start_address = start_address;
> +	mdp->end_address = end_address;
> +	buf = &mdp[1];
> +
> +	*((struct efi_device_path *)buf) = END;
> +
> +	return start;
> +}
> +
>   /*
>    * Helper to split a full device path (containing both device and file
>    * parts) into it's constituent parts.
> diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c
> index 1a5ef3919b..62771338f0 100644
> --- a/lib/efi_loader/efi_device_path_to_text.c
> +++ b/lib/efi_loader/efi_device_path_to_text.c
> @@ -24,6 +24,15 @@ static char *dp_unknown(char *s, struct efi_device_path *dp)
>   static char *dp_hardware(char *s, struct efi_device_path *dp)
>   {
>   	switch (dp->sub_type) {
> +	case DEVICE_PATH_SUB_TYPE_MEMORY: {
> +		struct efi_device_path_memory *mdp =
> +			(struct efi_device_path_memory *)dp;
> +		s += sprintf(s, "/MemoryMapped(0x%x,0x%llx,0x%llx)",
> +			     mdp->memory_type,
> +			     mdp->start_address,
> +			     mdp->end_address);
> +		break;
> +	}
>   	case DEVICE_PATH_SUB_TYPE_VENDOR: {
>   		struct efi_device_path_vendor *vdp =
>   			(struct efi_device_path_vendor *)dp;
> 

Providing a dummmy device path for bootefi hello and bootefi selftest is 
reasonable.

Acked-by: Heinrich Schuchardt <xypron.glpk@gmx.de>

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 07/11] efi_loader: fix events
  2017-10-10 12:23 ` [U-Boot] [PATCH 07/11] efi_loader: fix events Rob Clark
@ 2017-10-10 22:40   ` Heinrich Schuchardt
  2017-10-11 14:49   ` Alexander Graf
  2017-10-13  5:24   ` Heinrich Schuchardt
  2 siblings, 0 replies; 75+ messages in thread
From: Heinrich Schuchardt @ 2017-10-10 22:40 UTC (permalink / raw)
  To: u-boot

On 10/10/2017 02:23 PM, Rob Clark wrote:
> An event can be created with type==0, Shell.efi does this for an event
> that is set when Ctrl-C is typed.  So our current approach of having a
> fixed set of timer slots, and determining which slots are unused by
> type==0 doesn't work so well.  But we don't have any particularly good
> reason to have a fixed table of events, so just dynamically allocate
> them and keep a list.
> 
> Also fixes an incorrect implementation of CheckEvent() which was (a)
> incorrectly returning an error if type==0, and (b) didn't handle the
> case of an unsignaled event with a notify callback.
> 
> With these fixes (plus implementation of SIMPLE_TEXT_INPUT_EX protocol),
> Ctrl-C works in Shell.efi.
> 
> Signed-off-by: Rob Clark <robdclark@gmail.com>
> ---
>   include/efi_loader.h          |   1 +
>   lib/efi_loader/efi_boottime.c | 217 +++++++++++++++++++++---------------------
>   2 files changed, 111 insertions(+), 107 deletions(-)
> 
> diff --git a/include/efi_loader.h b/include/efi_loader.h
> index e6e55d2cb4..2232caca44 100644
> --- a/include/efi_loader.h
> +++ b/include/efi_loader.h
> @@ -154,6 +154,7 @@ struct efi_event {
>   	enum efi_timer_delay trigger_type;
>   	bool is_queued;
>   	bool is_signaled;
> +	struct list_head link;
>   };
>   
>   
> diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
> index 39dcc72648..19fafe546c 100644
> --- a/lib/efi_loader/efi_boottime.c
> +++ b/lib/efi_loader/efi_boottime.c
> @@ -350,11 +350,26 @@ static efi_status_t efi_create_handle(void **handle)
>   	return r;
>   }
>   
> +static LIST_HEAD(efi_events);
> +
>   /*
> - * Our event capabilities are very limited. Only a small limited
> - * number of events is allowed to coexist.
> + * Check if a pointer is a valid event.
> + *
> + * It might be nice at some point to extend this to a more general
> + * mechanism to check if pointers passed from the EFI world are
> + * valid objects of a particular type.
>    */
> -static struct efi_event efi_events[16];
> +static bool efi_is_event(const void *obj)
> +{
> +	struct efi_event *evt;
> +
> +	list_for_each_entry(evt, &efi_events, link) {
> +		if (evt == obj)
> +			return true;
> +	}
> +
> +	return false;
> +}
>   
>   /*
>    * Create an event.
> @@ -377,7 +392,7 @@ efi_status_t efi_create_event(uint32_t type, UINTN notify_tpl,
>   					void *context),
>   			      void *notify_context, struct efi_event **event)
>   {
> -	int i;
> +	struct efi_event *evt;
>   
>   	if (event == NULL)
>   		return EFI_INVALID_PARAMETER;
> @@ -389,21 +404,24 @@ efi_status_t efi_create_event(uint32_t type, UINTN notify_tpl,
>   	    notify_function == NULL)
>   		return EFI_INVALID_PARAMETER;
>   
> -	for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
> -		if (efi_events[i].type)
> -			continue;
> -		efi_events[i].type = type;
> -		efi_events[i].notify_tpl = notify_tpl;
> -		efi_events[i].notify_function = notify_function;
> -		efi_events[i].notify_context = notify_context;
> -		/* Disable timers on bootup */
> -		efi_events[i].trigger_next = -1ULL;
> -		efi_events[i].is_queued = false;
> -		efi_events[i].is_signaled = false;
> -		*event = &efi_events[i];
> -		return EFI_SUCCESS;
> -	}
> -	return EFI_OUT_OF_RESOURCES;
> +	evt = calloc(1, sizeof(*evt));
> +	if (!evt)
> +		return EFI_OUT_OF_RESOURCES;
> +
> +	evt->type = type;
> +	evt->notify_tpl = notify_tpl;
> +	evt->notify_function = notify_function;
> +	evt->notify_context = notify_context;
> +	/* Disable timers on bootup */
> +	evt->trigger_next = -1ULL;
> +	evt->is_queued = false;
> +	evt->is_signaled = false;
> +
> +	list_add_tail(&evt->link, &efi_events);
> +
> +	*event = evt;
> +
> +	return EFI_SUCCESS;
>   }
>   
>   /*
> @@ -443,30 +461,31 @@ static efi_status_t EFIAPI efi_create_event_ext(
>    */
>   void efi_timer_check(void)
>   {
> -	int i;
> +	struct efi_event *evt;
>   	u64 now = timer_get_us();
>   
> -	for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
> -		if (!efi_events[i].type)
> -			continue;
> -		if (efi_events[i].is_queued)
> -			efi_signal_event(&efi_events[i]);
> -		if (!(efi_events[i].type & EVT_TIMER) ||
> -		    now < efi_events[i].trigger_next)
> +	/*
> +	 * TODO perhaps optimize a bit and track the time of next
> +	 * timer to expire?
> +	 */
> +	list_for_each_entry(evt, &efi_events, link) {
> +		if (evt->is_queued)
> +			efi_signal_event(evt);
> +		if (!(evt->type & EVT_TIMER) ||
> +		    now < evt->trigger_next)
>   			continue;
> -		switch (efi_events[i].trigger_type) {
> +		switch (evt->trigger_type) {
>   		case EFI_TIMER_RELATIVE:
> -			efi_events[i].trigger_type = EFI_TIMER_STOP;
> +			evt->trigger_type = EFI_TIMER_STOP;
>   			break;
>   		case EFI_TIMER_PERIODIC:
> -			efi_events[i].trigger_next +=
> -				efi_events[i].trigger_time;
> +			evt->trigger_next += evt->trigger_time;
>   			break;
>   		default:
>   			continue;
>   		}
> -		efi_events[i].is_signaled = true;
> -		efi_signal_event(&efi_events[i]);
> +		evt->is_signaled = true;
> +		efi_signal_event(evt);
>   	}
>   	WATCHDOG_RESET();
>   }
> @@ -485,7 +504,8 @@ void efi_timer_check(void)
>   efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type,
>   			   uint64_t trigger_time)
>   {
> -	int i;
> +	if (!efi_is_event(event))
> +		return EFI_INVALID_PARAMETER;
>   
>   	/*
>   	 * The parameter defines a multiple of 100ns.
> @@ -493,30 +513,25 @@ efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type,
>   	 */
>   	do_div(trigger_time, 10);
>   
> -	for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
> -		if (event != &efi_events[i])
> -			continue;
> +	if (!(event->type & EVT_TIMER))
> +		return EFI_INVALID_PARAMETER;
>   
> -		if (!(event->type & EVT_TIMER))
> -			break;
> -		switch (type) {
> -		case EFI_TIMER_STOP:
> -			event->trigger_next = -1ULL;
> -			break;
> -		case EFI_TIMER_PERIODIC:
> -		case EFI_TIMER_RELATIVE:
> -			event->trigger_next =
> -				timer_get_us() + trigger_time;
> -			break;
> -		default:
> -			return EFI_INVALID_PARAMETER;
> -		}
> -		event->trigger_type = type;
> -		event->trigger_time = trigger_time;
> -		event->is_signaled = false;
> -		return EFI_SUCCESS;
> +	switch (type) {
> +	case EFI_TIMER_STOP:
> +		event->trigger_next = -1ULL;
> +		break;
> +	case EFI_TIMER_PERIODIC:
> +	case EFI_TIMER_RELATIVE:
> +		event->trigger_next = timer_get_us() + trigger_time;
> +		break;
> +	default:
> +		return EFI_INVALID_PARAMETER;
>   	}
> -	return EFI_INVALID_PARAMETER;
> +	event->trigger_type = type;
> +	event->trigger_time = trigger_time;
> +	event->is_signaled = false;
> +
> +	return EFI_SUCCESS;
>   }
>   
>   /*
> @@ -555,7 +570,7 @@ static efi_status_t EFIAPI efi_wait_for_event(unsigned long num_events,
>   					      struct efi_event **event,
>   					      size_t *index)
>   {
> -	int i, j;
> +	int i;
>   
>   	EFI_ENTRY("%ld, %p, %p", num_events, event, index);
>   
> @@ -566,12 +581,8 @@ static efi_status_t EFIAPI efi_wait_for_event(unsigned long num_events,
>   	if (efi_tpl != TPL_APPLICATION)
>   		return EFI_EXIT(EFI_UNSUPPORTED);
>   	for (i = 0; i < num_events; ++i) {
> -		for (j = 0; j < ARRAY_SIZE(efi_events); ++j) {
> -			if (event[i] == &efi_events[j])
> -				goto known_event;
> -		}
> -		return EFI_EXIT(EFI_INVALID_PARAMETER);
> -known_event:
> +		if (!efi_is_event(event[i]))
> +			return EFI_EXIT(EFI_INVALID_PARAMETER);
>   		if (!event[i]->type || event[i]->type & EVT_NOTIFY_SIGNAL)
>   			return EFI_EXIT(EFI_INVALID_PARAMETER);
>   		if (!event[i]->is_signaled)
> @@ -614,19 +625,12 @@ out:
>    */
>   static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event)
>   {
> -	int i;
> -
>   	EFI_ENTRY("%p", event);
> -	for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
> -		if (event != &efi_events[i])
> -			continue;
> -		if (event->is_signaled)
> -			break;
> -		event->is_signaled = true;
> -		if (event->type & EVT_NOTIFY_SIGNAL)
> -			efi_signal_event(event);
> -		break;
> -	}
> +	if (!efi_is_event(event))
> +		return EFI_EXIT(EFI_INVALID_PARAMETER);
> +	event->is_signaled = true;
> +	if (event->type & EVT_NOTIFY_SIGNAL)
> +		efi_signal_event(event);
>   	return EFI_EXIT(EFI_SUCCESS);
>   }
>   
> @@ -642,19 +646,10 @@ static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event)
>    */
>   static efi_status_t EFIAPI efi_close_event(struct efi_event *event)
>   {
> -	int i;
> -
>   	EFI_ENTRY("%p", event);
> -	for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
> -		if (event == &efi_events[i]) {
> -			event->type = 0;
> -			event->trigger_next = -1ULL;
> -			event->is_queued = false;
> -			event->is_signaled = false;
> -			return EFI_EXIT(EFI_SUCCESS);
> -		}
> -	}
> -	return EFI_EXIT(EFI_INVALID_PARAMETER);
> +	list_del(&event->link);
> +	free(event);
> +	return EFI_EXIT(EFI_SUCCESS);
>   }
>   
>   /*
> @@ -664,29 +659,37 @@ static efi_status_t EFIAPI efi_close_event(struct efi_event *event)
>    * See the Unified Extensible Firmware Interface (UEFI) specification
>    * for details.
>    *
> - * If an event is not signaled yet the notification function is queued.
> + * - If Event is in the signaled state, it is cleared and EFI_SUCCESS
> + *   is returned.
> + *
> + * - If Event is not in the signaled state and has no notification
> + *   function, EFI_NOT_READY is returned.
> + *
> + * - If Event is not in the signaled state but does have a notification
> + *   function, the notification function is queued at the event’s
> + *   notification task priority level. If the execution of the
> + *   notification function causes Event to be signaled, then the signaled
> + *   state is cleared and EFI_SUCCESS is returned; if the Event is not
> + *   signaled, then EFI_NOT_READY is returned.
>    *
>    * @event	event to check
>    * @return	status code
>    */
> -static efi_status_t EFIAPI efi_check_event(struct efi_event *event)
> +/*
> + */
> +static efi_status_t EFIAPI efi_check_event(struct efi_event *evt)
>   {
> -	int i;
> -
> -	EFI_ENTRY("%p", event);
> +	EFI_ENTRY("%p", evt);
>   	efi_timer_check();
> -	for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
> -		if (event != &efi_events[i])
> -			continue;
> -		if (!event->type || event->type & EVT_NOTIFY_SIGNAL)
> -			break;
> -		if (!event->is_signaled)
> -			efi_signal_event(event);
> -		if (event->is_signaled)
> -			return EFI_EXIT(EFI_SUCCESS);
> -		return EFI_EXIT(EFI_NOT_READY);
> +	if (!efi_is_event(evt) || (evt->type & EVT_NOTIFY_SIGNAL))
> +		return EFI_EXIT(EFI_INVALID_PARAMETER);
> +	if (!evt->is_signaled && evt->notify_function)
> +		EFI_CALL_VOID(evt->notify_function(evt, evt->notify_context));
> +	if (evt->is_signaled) {
> +		evt->is_signaled = true;
> +		return EFI_EXIT(EFI_SUCCESS);
>   	}
> -	return EFI_EXIT(EFI_INVALID_PARAMETER);
> +	return EFI_EXIT(EFI_NOT_READY);
>   }
>   
>   /*
> @@ -1440,15 +1443,15 @@ static void efi_exit_caches(void)
>   static efi_status_t EFIAPI efi_exit_boot_services(void *image_handle,
>   						  unsigned long map_key)
>   {
> -	int i;
> +	struct efi_event *evt;
>   
>   	EFI_ENTRY("%p, %ld", image_handle, map_key);
>   
>   	/* Notify that ExitBootServices is invoked. */
> -	for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
> -		if (efi_events[i].type != EVT_SIGNAL_EXIT_BOOT_SERVICES)
> +	list_for_each_entry(evt, &efi_events, link) {
> +		if (evt->type != EVT_SIGNAL_EXIT_BOOT_SERVICES)
>   			continue;
> -		efi_signal_event(&efi_events[i]);
> +		efi_signal_event(evt);
>   	}
>   	/* Make sure that notification functions are not called anymore */
>   	efi_tpl = TPL_HIGH_LEVEL;
> 

Thanks for adding efi_is_event().

Tested-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Acked-by: Heinrich Schuchardt <xypron.glpk@gmx.de>

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 11/11] efi_loader: exclude openrd devices
  2017-10-10 22:28   ` Heinrich Schuchardt
@ 2017-10-10 22:50     ` Rob Clark
  2017-10-11  7:07       ` Stefan Roese
  0 siblings, 1 reply; 75+ messages in thread
From: Rob Clark @ 2017-10-10 22:50 UTC (permalink / raw)
  To: u-boot

On Tue, Oct 10, 2017 at 6:28 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
> On 10/10/2017 02:23 PM, Rob Clark wrote:
>>
>> These devices have small image size limits, so exclude EFI_LOADER to
>> help avoid exceeding limits.
>>
>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>> ---
>>   lib/efi_loader/Kconfig | 2 +-
>>   1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
>> index d2b6327119..6e22940da5 100644
>> --- a/lib/efi_loader/Kconfig
>> +++ b/lib/efi_loader/Kconfig
>> @@ -1,6 +1,6 @@
>>   config EFI_LOADER
>>         bool "Support running EFI Applications in U-Boot"
>> -       depends on (ARM || X86) && OF_LIBFDT
>> +       depends on (ARM || X86) && OF_LIBFDT && !TARGET_OPENRD
>>         default y
>>         help
>>           Select this option if you want to run EFI applications (like
>> grub2)
>>
>
> I understand that with the progress we make on EFI implementation and other
> parts of U-Boot the U-Boot image size is growing too big for direct loading
> by the primary boot loader.
>
> The OPENRD boards have abundant memory, e.g. openrd_ultimate_defconfig
> refers to a board with 512 MB RAM.
>
> So I think completely disabling EFI is not the solution.
> Instead building an SPL should be enabled for this architecture when the
> image is becoming too big for direct load.
>
> I am copying in the KIRKWOOD maintainers go get their view.
>

I'm defn open to alternatives..  I don't know too much about what the
limit was on these boards, other than we were close to it before, and
the additional uefi proto's add <4k to the image size, which was
enough to push it over the limit.  Since this was effecting only a few
boards, I went with this.. if it is only a temporary fix that can be
removed soon, or if someone can do something better with a separate
SPL build in the near term, that would be great.

BR,
-R

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 05/11] efi_loader: console support for color attributes
  2017-10-10 12:23 ` [U-Boot] [PATCH 05/11] efi_loader: console support for color attributes Rob Clark
@ 2017-10-10 23:41   ` Heinrich Schuchardt
  2017-10-11 14:41   ` Alexander Graf
  2017-10-12 15:24   ` [U-Boot] [U-Boot, " Alexander Graf
  2 siblings, 0 replies; 75+ messages in thread
From: Heinrich Schuchardt @ 2017-10-10 23:41 UTC (permalink / raw)
  To: u-boot



On 10/10/2017 02:23 PM, Rob Clark wrote:
> Shell.efi uses this, and supporting color attributes makes things look
> nicer.  Map the EFI fg/bg color attributes to ANSI escape sequences.
> Not all colors have a perfect match, but spec just says "Devices
> supporting a different number of text colors are required to emulate the
> above colors to the best of the device’s capabilities".
> 
> Signed-off-by: Rob Clark <robdclark@gmail.com>
> ---
>   include/efi_api.h            | 33 +++++++++++++++++++++++++++++++++
>   lib/efi_loader/efi_console.c | 27 +++++++++++++++++++++++++--
>   2 files changed, 58 insertions(+), 2 deletions(-)
> 
> diff --git a/include/efi_api.h b/include/efi_api.h
> index 58bf15b8e6..9610d03d47 100644
> --- a/include/efi_api.h
> +++ b/include/efi_api.h
> @@ -427,6 +427,39 @@ struct simple_text_output_mode {
>   	EFI_GUID(0x387477c2, 0x69c7, 0x11d2, \
>   		 0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
>   
> +#define EFI_BLACK                0x00
> +#define EFI_BLUE                 0x01
> +#define EFI_GREEN                0x02
> +#define EFI_CYAN                 0x03
> +#define EFI_RED                  0x04
> +#define EFI_MAGENTA              0x05
> +#define EFI_BROWN                0x06
> +#define EFI_LIGHTGRAY            0x07
> +#define EFI_BRIGHT               0x08
> +#define EFI_DARKGRAY             0x08
> +#define EFI_LIGHTBLUE            0x09
> +#define EFI_LIGHTGREEN           0x0a
> +#define EFI_LIGHTCYAN            0x0b
> +#define EFI_LIGHTRED             0x0c
> +#define EFI_LIGHTMAGENTA         0x0d
> +#define EFI_YELLOW               0x0e
> +#define EFI_WHITE                0x0f
> +#define EFI_BACKGROUND_BLACK     0x00
> +#define EFI_BACKGROUND_BLUE      0x10
> +#define EFI_BACKGROUND_GREEN     0x20
> +#define EFI_BACKGROUND_CYAN      0x30
> +#define EFI_BACKGROUND_RED       0x40
> +#define EFI_BACKGROUND_MAGENTA   0x50
> +#define EFI_BACKGROUND_BROWN     0x60
> +#define EFI_BACKGROUND_LIGHTGRAY 0x70
> +
> +/* extract foreground color from EFI attribute */
> +#define EFI_ATTR_FG(attr)        ((attr) & 0x07)
> +/* treat high bit of FG as bright/bold (similar to edk2) */
> +#define EFI_ATTR_BOLD(attr)      (((attr) >> 3) & 0x01)
> +/* extract background color from EFI attribute */
> +#define EFI_ATTR_BG(attr)        (((attr) >> 4) & 0x7)
> +
>   struct efi_simple_text_output_protocol {
>   	void *reset;
>   	efi_status_t (EFIAPI *output_string)(
> diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
> index f508b79ab8..c25d6b16f2 100644
> --- a/lib/efi_loader/efi_console.c
> +++ b/lib/efi_loader/efi_console.c
> @@ -316,14 +316,37 @@ static efi_status_t EFIAPI efi_cout_set_mode(
>   	return EFI_EXIT(EFI_SUCCESS);
>   }
>   
> +static const struct {
> +	unsigned fg;
> +	unsigned bg;
> +} color[] = {
> +	{ 30, 40 },     /* 0: black */
> +	{ 34, 44 },     /* 1: blue */
> +	{ 32, 42 },     /* 2: green */
> +	{ 36, 46 },     /* 3: cyan */
> +	{ 31, 41 },     /* 4: red */
> +	{ 35, 45 },     /* 5: magenta */
> +	{ 33, 43 },     /* 6: brown, map to yellow as edk2 does*/
> +	{ 37, 47 },     /* 7: light grey, map to white */
> +};
> +
> +/* See EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetAttribute(). */
>   static efi_status_t EFIAPI efi_cout_set_attribute(
>   			struct efi_simple_text_output_protocol *this,
>   			unsigned long attribute)
>   {
> +	unsigned int bold = EFI_ATTR_BOLD(attribute);
> +	unsigned int fg = EFI_ATTR_FG(attribute);
> +	unsigned int bg = EFI_ATTR_BG(attribute);
> +
>   	EFI_ENTRY("%p, %lx", this, attribute);
>   
> -	/* Just ignore attributes (colors) for now */
> -	return EFI_EXIT(EFI_UNSUPPORTED);
> +	if (attribute)
> +		printf(ESC"[%u;%u;%um", bold, color[fg].fg, color[bg].bg);
> +	else

Maybe Alex can just add a comment here when merging:

/* EFI console expects attribute = 0 to result in default colors. */

> +		printf(ESC"[0;37;40m");
> +
> +	return EFI_EXIT(EFI_SUCCESS);
>   }
>   
>   static efi_status_t EFIAPI efi_cout_clear_screen(
> 

Works fine.

See appended screenshot.

Tested-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Screenshot_20171011_013002.png
Type: image/png
Size: 15190 bytes
Desc: not available
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20171011/11de4d77/attachment.png>

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 01/11] efi_loader: Initial EFI_DEVICE_PATH_UTILITIES_PROTOCOL
  2017-10-10 12:22 ` [U-Boot] [PATCH 01/11] efi_loader: Initial EFI_DEVICE_PATH_UTILITIES_PROTOCOL Rob Clark
@ 2017-10-11  0:03   ` Heinrich Schuchardt
  2017-10-11 14:07   ` Alexander Graf
  1 sibling, 0 replies; 75+ messages in thread
From: Heinrich Schuchardt @ 2017-10-11  0:03 UTC (permalink / raw)
  To: u-boot



On 10/10/2017 02:22 PM, Rob Clark wrote:
> From: Leif Lindholm <leif.lindholm@linaro.org>
> 
> Not complete, but enough for Shell.efi and SCT.efi.  We'll implement the
> rest as needed or once we have SCT running properly so there is a way to
> validate the interface against the conformance test suite.
> 
> Initial skeleton written by Leif, and then implementation by myself.
> 
> Cc: Leif Lindholm <leif.lindholm@linaro.org>
> Signed-off-by: Rob Clark <robdclark@gmail.com>
> ---
>   include/efi_api.h                          | 34 +++++++++++-
>   include/efi_loader.h                       |  2 +
>   lib/efi_loader/Makefile                    |  1 +
>   lib/efi_loader/efi_boottime.c              |  4 ++
>   lib/efi_loader/efi_device_path_utilities.c | 88 ++++++++++++++++++++++++++++++
>   5 files changed, 127 insertions(+), 2 deletions(-)
>   create mode 100644 lib/efi_loader/efi_device_path_utilities.c
> 
> diff --git a/include/efi_api.h b/include/efi_api.h
> index a9a6494afe..ffdba7fe1a 100644
> --- a/include/efi_api.h
> +++ b/include/efi_api.h
> @@ -28,8 +28,9 @@ enum efi_timer_delay {
>   	EFI_TIMER_RELATIVE = 2
>   };
>   
> -#define UINTN size_t
> -typedef long INTN;
> +#define UINTN size_t   /* TODO this should be removed in a future patch */
> +typedef size_t efi_uintn_t;
> +typedef ssize_t efi_intn_t;
>   typedef uint16_t *efi_string_t;
>   
>   #define EVT_TIMER				0x80000000
> @@ -506,6 +507,35 @@ struct efi_device_path_to_text_protocol
>   			bool allow_shortcuts);
>   };
>   
> +#define EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID \
> +	EFI_GUID(0x0379be4e, 0xd706, 0x437d, \
> +		 0xb0, 0x37, 0xed, 0xb8, 0x2f, 0xb7, 0x72, 0xa4)
> +
> +struct efi_device_path_utilities_protocol {
> +	efi_uintn_t (EFIAPI *get_device_path_size)(
> +		const struct efi_device_path *device_path);
> +	struct efi_device_path *(EFIAPI *duplicate_device_path)(
> +		const struct efi_device_path *device_path);
> +	struct efi_device_path *(EFIAPI *append_device_path)(
> +		const struct efi_device_path *src1,
> +		const struct efi_device_path *src2);
> +	struct efi_device_path *(EFIAPI *append_device_node)(
> +		const struct efi_device_path *device_path,
> +		const struct efi_device_path *device_node);
> +	struct efi_device_path *(EFIAPI *append_device_path_instance)(
> +		const struct efi_device_path *device_path,
> +		const struct efi_device_path *device_path_instance);
> +	struct efi_device_path *(EFIAPI *get_next_device_path_instance)(
> +		struct efi_device_path **device_path_instance,
> +		efi_uintn_t *device_path_instance_size);
> +	bool (EFIAPI *is_device_path_multi_instance)(
> +		const struct efi_device_path *device_path);
> +	struct efi_device_path *(EFIAPI *create_device_node)(
> +		uint8_t node_type,
> +		uint8_t node_sub_type,
> +		uint16_t node_length);
> +};
> +
>   #define EFI_GOP_GUID \
>   	EFI_GUID(0x9042a9de, 0x23dc, 0x4a38, \
>   		 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a)
> diff --git a/include/efi_loader.h b/include/efi_loader.h
> index e1179b7dcd..5d37c1d75f 100644
> --- a/include/efi_loader.h
> +++ b/include/efi_loader.h
> @@ -79,6 +79,7 @@ extern const struct efi_simple_text_output_protocol efi_con_out;
>   extern struct efi_simple_input_interface efi_con_in;
>   extern const struct efi_console_control_protocol efi_console_control;
>   extern const struct efi_device_path_to_text_protocol efi_device_path_to_text;
> +extern const struct efi_device_path_utilities_protocol efi_device_path_utilities;

WARNING: line over 80 characters
#95: FILE: include/efi_loader.h:82:

Please, always run scripts/checkpatch.pl before submitting.

>   
>   uint16_t *efi_dp_str(struct efi_device_path *dp);
>   
> @@ -89,6 +90,7 @@ extern const efi_guid_t efi_guid_loaded_image;
>   extern const efi_guid_t efi_guid_device_path_to_text_protocol;
>   extern const efi_guid_t efi_simple_file_system_protocol_guid;
>   extern const efi_guid_t efi_file_info_guid;
> +extern const efi_guid_t efi_guid_device_path_utilities_protocol;
>   
>   extern unsigned int __efi_runtime_start, __efi_runtime_stop;
>   extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;
> diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
> index ddb978f650..b6927b3b84 100644
> --- a/lib/efi_loader/Makefile
> +++ b/lib/efi_loader/Makefile
> @@ -17,6 +17,7 @@ endif
>   obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o
>   obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o
>   obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o
> +obj-y += efi_device_path_utilities.o
>   obj-y += efi_file.o efi_variable.o efi_bootmgr.o
>   obj-$(CONFIG_LCD) += efi_gop.o
>   obj-$(CONFIG_DM_VIDEO) += efi_gop.o
> diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
> index 976d5822f7..92c778fcca 100644
> --- a/lib/efi_loader/efi_boottime.c
> +++ b/lib/efi_loader/efi_boottime.c
> @@ -1153,6 +1153,10 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob

Applying: efi_loader: Initial EFI_DEVICE_PATH_UTILITIES_PROTOCOL
error: patch failed: lib/efi_loader/efi_boottime.c:1153

Please, rebase.

>   	obj->protocols[3].protocol_interface =
>   		(void *)&efi_device_path_to_text;
>   
> +	obj->protocols[4].guid = &efi_guid_device_path_utilities_protocol;
> +	obj->protocols[4].protocol_interface =
> +		(void *)&efi_device_path_utilities;
> +
>   	info->file_path = file_path;
>   	info->device_handle = efi_dp_find_obj(device_path, NULL);
>   
> diff --git a/lib/efi_loader/efi_device_path_utilities.c b/lib/efi_loader/efi_device_path_utilities.c
> new file mode 100644
> index 0000000000..9d90f14ee4
> --- /dev/null
> +++ b/lib/efi_loader/efi_device_path_utilities.c
> @@ -0,0 +1,88 @@
> +/*
> + *  EFI device path interface
> + *
> + *  Copyright (c) 2017 Leif Lindholm
> + *
> + *  SPDX-License-Identifier:     GPL-2.0+
> + */
> +
> +#include <common.h>
> +#include <efi_loader.h>
> +
> +const efi_guid_t efi_guid_device_path_utilities_protocol =
> +		EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID;
> +
> +static efi_uintn_t EFIAPI get_device_path_size(
> +	const struct efi_device_path *device_path)
> +{
> +	efi_uintn_t sz = 0;

WARNING: Missing a blank line after declarations
#158: FILE: lib/efi_loader/efi_device_path_utilities.c:19:

Regards

Heinrich

> +	EFI_ENTRY("%p", device_path);
> +	/* size includes the END node: */
> +	if (device_path)
> +		sz = efi_dp_size(device_path) + sizeof(struct efi_device_path);
> +	return EFI_EXIT(sz);
> +}
> +
> +static struct efi_device_path * EFIAPI duplicate_device_path(
> +	const struct efi_device_path *device_path)
> +{
> +	EFI_ENTRY("%p", device_path);
> +	return EFI_EXIT(efi_dp_dup(device_path));
> +}
> +
> +static struct efi_device_path * EFIAPI append_device_path(
> +	const struct efi_device_path *src1,
> +	const struct efi_device_path *src2)
> +{
> +	EFI_ENTRY("%p, %p", src1, src2);
> +	return EFI_EXIT(efi_dp_append(src1, src2));
> +}
> +
> +static struct efi_device_path * EFIAPI append_device_node(
> +	const struct efi_device_path *device_path,
> +	const struct efi_device_path *device_node)
> +{
> +	EFI_ENTRY("%p, %p", device_path, device_node);
> +	return EFI_EXIT(efi_dp_append_node(device_path, device_node));
> +}
> +
> +static struct efi_device_path * EFIAPI append_device_path_instance(
> +	const struct efi_device_path *device_path,
> +	const struct efi_device_path *device_path_instance)
> +{
> +	EFI_ENTRY("%p, %p", device_path, device_path_instance);
> +	return EFI_EXIT(NULL);
> +}
> +
> +static struct efi_device_path * EFIAPI get_next_device_path_instance(
> +	struct efi_device_path **device_path_instance,
> +	efi_uintn_t *device_path_instance_size)
> +{
> +	EFI_ENTRY("%p, %p", device_path_instance, device_path_instance_size);
> +	return EFI_EXIT(NULL);
> +}
> +
> +static bool EFIAPI is_device_path_multi_instance(
> +	const struct efi_device_path *device_path)
> +{
> +	EFI_ENTRY("%p", device_path);
> +	return EFI_EXIT(false);
> +}
> +
> +static struct efi_device_path * EFIAPI create_device_node(
> +	uint8_t node_type, uint8_t node_sub_type, uint16_t node_length)
> +{
> +	EFI_ENTRY("%u, %u, %u", node_type, node_sub_type, node_length);
> +	return EFI_EXIT(NULL);
> +}
> +
> +const struct efi_device_path_utilities_protocol efi_device_path_utilities = {
> +	.get_device_path_size = get_device_path_size,
> +	.duplicate_device_path = duplicate_device_path,
> +	.append_device_path = append_device_path,
> +	.append_device_node = append_device_node,
> +	.append_device_path_instance = append_device_path_instance,
> +	.get_next_device_path_instance = get_next_device_path_instance,
> +	.is_device_path_multi_instance = is_device_path_multi_instance,
> +	.create_device_node = create_device_node,
> +};
> 

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 00/11] efi_loader: patches for Shell.efi
  2017-10-10 12:22 [U-Boot] [PATCH 00/11] efi_loader: patches for Shell.efi Rob Clark
                   ` (10 preceding siblings ...)
  2017-10-10 12:23 ` [U-Boot] [PATCH 11/11] efi_loader: exclude openrd devices Rob Clark
@ 2017-10-11  0:24 ` Heinrich Schuchardt
  11 siblings, 0 replies; 75+ messages in thread
From: Heinrich Schuchardt @ 2017-10-11  0:24 UTC (permalink / raw)
  To: u-boot



On 10/10/2017 02:22 PM, Rob Clark wrote:
> Re-send of the patch series to get Shell.efi working, and almost get
> SCT.efi (the UEFI test suite) working.
> 
> Since last time, I've updated to Heinrich's latest SetWatchdogTimer
> patch (as of yesterday evening), and adressed review comments on the
> three new sets of protocols added.  Part of that, to avoid moving
> changes from my later patch that added implementation on top of Leif's
> initial stubs was done by simply squashing the patches together.
> 
> 
> Heinrich Schuchardt (1):
>    efi_loader: implement SetWatchdogTimer
> 
> Leif Lindholm (3):
>    efi_loader: Initial EFI_DEVICE_PATH_UTILITIES_PROTOCOL
>    efi_loader: Initial HII protocols
>    efi_loader: Initial EFI_UNICODE_COLLATION_PROTOCOL
> 
> Rob Clark (7):
>    efi_loader: SIMPLE_TEXT_INPUT_EX plus wire up objects properly
>    efi_loader: console support for color attributes
>    efi_loader: Decouple EFI input/output from stdin/stdout
>    efi_loader: fix events
>    efi_loader: Fix disk dp's for pre-DM/legacy devices
>    efi_loader: Add mem-mapped for fallback
>    efi_loader: exclude openrd devices
> 
>   cmd/bootefi.c                              |  24 ++
>   include/efi_api.h                          | 438 ++++++++++++++++++++++++-
>   include/efi_loader.h                       |  29 +-
>   lib/efi_loader/Kconfig                     |   2 +-
>   lib/efi_loader/Makefile                    |   3 +-
>   lib/efi_loader/efi_boottime.c              | 256 ++++++++-------
>   lib/efi_loader/efi_console.c               | 398 +++++++++++++++++++---
>   lib/efi_loader/efi_device_path.c           |  24 ++
>   lib/efi_loader/efi_device_path_to_text.c   |   9 +
>   lib/efi_loader/efi_device_path_utilities.c |  88 +++++
>   lib/efi_loader/efi_disk.c                  |  11 +
>   lib/efi_loader/efi_hii.c                   | 507 +++++++++++++++++++++++++++++
>   lib/efi_loader/efi_unicode.c               | 170 ++++++++++
>   lib/efi_loader/efi_watchdog.c              |  86 +++++
>   14 files changed, 1861 insertions(+), 184 deletions(-)
>   create mode 100644 lib/efi_loader/efi_device_path_utilities.c
>   create mode 100644 lib/efi_loader/efi_hii.c
>   create mode 100644 lib/efi_loader/efi_unicode.c
>   create mode 100644 lib/efi_loader/efi_watchdog.c
> 


Overall the patch series looks in good shape.

One comment I thought could be helpful in
[PATCH 05/11] efi_loader: console support for color attributes

Some minor checkpatch.pl warnings.

One git am problem (may be a missing space) I had.

I hope we can get this merged now.

Thanks to Rob for driving this.

Regards

Heinrich

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 11/11] efi_loader: exclude openrd devices
  2017-10-10 22:50     ` Rob Clark
@ 2017-10-11  7:07       ` Stefan Roese
  2017-10-11  7:22         ` Alexander Graf
  0 siblings, 1 reply; 75+ messages in thread
From: Stefan Roese @ 2017-10-11  7:07 UTC (permalink / raw)
  To: u-boot

(Adding Albert as maintainer again)

On 11.10.2017 00:50, Rob Clark wrote:
> On Tue, Oct 10, 2017 at 6:28 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>> On 10/10/2017 02:23 PM, Rob Clark wrote:
>>>
>>> These devices have small image size limits, so exclude EFI_LOADER to
>>> help avoid exceeding limits.
>>>
>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>> ---
>>>    lib/efi_loader/Kconfig | 2 +-
>>>    1 file changed, 1 insertion(+), 1 deletion(-)
>>>
>>> diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
>>> index d2b6327119..6e22940da5 100644
>>> --- a/lib/efi_loader/Kconfig
>>> +++ b/lib/efi_loader/Kconfig
>>> @@ -1,6 +1,6 @@
>>>    config EFI_LOADER
>>>          bool "Support running EFI Applications in U-Boot"
>>> -       depends on (ARM || X86) && OF_LIBFDT
>>> +       depends on (ARM || X86) && OF_LIBFDT && !TARGET_OPENRD
>>>          default y
>>>          help
>>>            Select this option if you want to run EFI applications (like
>>> grub2)
>>>
>>
>> I understand that with the progress we make on EFI implementation and other
>> parts of U-Boot the U-Boot image size is growing too big for direct loading
>> by the primary boot loader.
>>
>> The OPENRD boards have abundant memory, e.g. openrd_ultimate_defconfig
>> refers to a board with 512 MB RAM.
>>
>> So I think completely disabling EFI is not the solution.
>> Instead building an SPL should be enabled for this architecture when the
>> image is becoming too big for direct load.
>>
>> I am copying in the KIRKWOOD maintainers go get their view.
>>
> 
> I'm defn open to alternatives..  I don't know too much about what the
> limit was on these boards, other than we were close to it before, and
> the additional uefi proto's add <4k to the image size, which was
> enough to push it over the limit.  Since this was effecting only a few
> boards, I went with this.. if it is only a temporary fix that can be
> removed soon, or if someone can do something better with a separate
> SPL build in the near term, that would be great.

I personally have not used any Kirkwood based platforms in the last few
years (and don't have access to one). And I don't see activities here
from mother developers either. As adding SPL support is not trivial,
frankly I don't see that this will be done anytime soon if at all.

Perhaps the image size can be reduced by removing other features or
interfaces from the OPENRD platform instead (CMD_MII, JFFS2, ...)?

Thanks,
Stefan

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 11/11] efi_loader: exclude openrd devices
  2017-10-11  7:07       ` Stefan Roese
@ 2017-10-11  7:22         ` Alexander Graf
  0 siblings, 0 replies; 75+ messages in thread
From: Alexander Graf @ 2017-10-11  7:22 UTC (permalink / raw)
  To: u-boot



On 11.10.17 09:07, Stefan Roese wrote:
> (Adding Albert as maintainer again)
> 
> On 11.10.2017 00:50, Rob Clark wrote:
>> On Tue, Oct 10, 2017 at 6:28 PM, Heinrich Schuchardt
>> <xypron.glpk@gmx.de> wrote:
>>> On 10/10/2017 02:23 PM, Rob Clark wrote:
>>>>
>>>> These devices have small image size limits, so exclude EFI_LOADER to
>>>> help avoid exceeding limits.
>>>>
>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>>> ---
>>>>    lib/efi_loader/Kconfig | 2 +-
>>>>    1 file changed, 1 insertion(+), 1 deletion(-)
>>>>
>>>> diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
>>>> index d2b6327119..6e22940da5 100644
>>>> --- a/lib/efi_loader/Kconfig
>>>> +++ b/lib/efi_loader/Kconfig
>>>> @@ -1,6 +1,6 @@
>>>>    config EFI_LOADER
>>>>          bool "Support running EFI Applications in U-Boot"
>>>> -       depends on (ARM || X86) && OF_LIBFDT
>>>> +       depends on (ARM || X86) && OF_LIBFDT && !TARGET_OPENRD
>>>>          default y
>>>>          help
>>>>            Select this option if you want to run EFI applications (like
>>>> grub2)
>>>>
>>>
>>> I understand that with the progress we make on EFI implementation and
>>> other
>>> parts of U-Boot the U-Boot image size is growing too big for direct
>>> loading
>>> by the primary boot loader.
>>>
>>> The OPENRD boards have abundant memory, e.g. openrd_ultimate_defconfig
>>> refers to a board with 512 MB RAM.
>>>
>>> So I think completely disabling EFI is not the solution.
>>> Instead building an SPL should be enabled for this architecture when the
>>> image is becoming too big for direct load.
>>>
>>> I am copying in the KIRKWOOD maintainers go get their view.
>>>
>>
>> I'm defn open to alternatives..  I don't know too much about what the
>> limit was on these boards, other than we were close to it before, and
>> the additional uefi proto's add <4k to the image size, which was
>> enough to push it over the limit.  Since this was effecting only a few
>> boards, I went with this.. if it is only a temporary fix that can be
>> removed soon, or if someone can do something better with a separate
>> SPL build in the near term, that would be great.
> 
> I personally have not used any Kirkwood based platforms in the last few
> years (and don't have access to one). And I don't see activities here
> from mother developers either. As adding SPL support is not trivial,
> frankly I don't see that this will be done anytime soon if at all.
> 
> Perhaps the image size can be reduced by removing other features or
> interfaces from the OPENRD platform instead (CMD_MII, JFFS2, ...)?

If it's too much work to make EFI_LOADER work on these platforms, I
guess it's ok to disable it just for them. Given how dated they are,
chances are pretty slim that enabling EFI_LOADER by default will give us
a U-Boot copy on the device that supports it straight from the factory ;).

However, I would ideally prefer to see that happen in the respective
defconfigs, not in Kconfig.


Alex

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 01/11] efi_loader: Initial EFI_DEVICE_PATH_UTILITIES_PROTOCOL
  2017-10-10 12:22 ` [U-Boot] [PATCH 01/11] efi_loader: Initial EFI_DEVICE_PATH_UTILITIES_PROTOCOL Rob Clark
  2017-10-11  0:03   ` Heinrich Schuchardt
@ 2017-10-11 14:07   ` Alexander Graf
  2017-10-11 20:32     ` Rob Clark
  1 sibling, 1 reply; 75+ messages in thread
From: Alexander Graf @ 2017-10-11 14:07 UTC (permalink / raw)
  To: u-boot



On 10.10.17 14:22, Rob Clark wrote:
> From: Leif Lindholm <leif.lindholm@linaro.org>
> 
> Not complete, but enough for Shell.efi and SCT.efi.  We'll implement the
> rest as needed or once we have SCT running properly so there is a way to
> validate the interface against the conformance test suite.
> 
> Initial skeleton written by Leif, and then implementation by myself.
> 
> Cc: Leif Lindholm <leif.lindholm@linaro.org>
> Signed-off-by: Rob Clark <robdclark@gmail.com>
> ---
>  include/efi_api.h                          | 34 +++++++++++-
>  include/efi_loader.h                       |  2 +
>  lib/efi_loader/Makefile                    |  1 +
>  lib/efi_loader/efi_boottime.c              |  4 ++
>  lib/efi_loader/efi_device_path_utilities.c | 88 ++++++++++++++++++++++++++++++
>  5 files changed, 127 insertions(+), 2 deletions(-)
>  create mode 100644 lib/efi_loader/efi_device_path_utilities.c
> 
> diff --git a/include/efi_api.h b/include/efi_api.h
> index a9a6494afe..ffdba7fe1a 100644
> --- a/include/efi_api.h
> +++ b/include/efi_api.h
> @@ -28,8 +28,9 @@ enum efi_timer_delay {
>  	EFI_TIMER_RELATIVE = 2
>  };
>  
> -#define UINTN size_t
> -typedef long INTN;
> +#define UINTN size_t   /* TODO this should be removed in a future patch */

$ git grep UINTN | wc -l
13

Just send a preceding patch that introduces efi_uintn_t and replaces all
occurences of UINTN with it.

The uintn bits shouldn't be part of the
EFI_DEVICE_PATH_UTILITIES_PROTOCOL patch anyways :).

> +typedef size_t efi_uintn_t;
> +typedef ssize_t efi_intn_t;
>  typedef uint16_t *efi_string_t;


Alex

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 02/11] efi_loader: Initial HII protocols
  2017-10-10 12:22 ` [U-Boot] [PATCH 02/11] efi_loader: Initial HII protocols Rob Clark
@ 2017-10-11 14:30   ` Alexander Graf
  2017-10-11 22:02     ` Rob Clark
  2018-09-22 10:34   ` Heinrich Schuchardt
  1 sibling, 1 reply; 75+ messages in thread
From: Alexander Graf @ 2017-10-11 14:30 UTC (permalink / raw)
  To: u-boot



On 10.10.17 14:22, Rob Clark wrote:
> From: Leif Lindholm <leif.lindholm@linaro.org>
> 
> Enough implementation of the following protocols to run Shell.efi and
> SCT.efi:
> 
>   EfiHiiConfigRoutingProtocolGuid
>   EfiHiiDatabaseProtocol
>   EfiHiiStringProtocol
> 
> We'll fill in the rest once SCT is running properly so we can validate
> the implementation against the conformance test suite.
> 
> Initial skeleton written by Leif, and then implementation by myself.
> 
> Cc: Leif Lindholm <leif.lindholm@linaro.org>
> Signed-off-by: Rob Clark <robdclark@gmail.com>
> ---
>  include/efi_api.h             | 261 ++++++++++++++++++++++
>  include/efi_loader.h          |   6 +
>  lib/efi_loader/Makefile       |   2 +-
>  lib/efi_loader/efi_boottime.c |   9 +
>  lib/efi_loader/efi_hii.c      | 507 ++++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 784 insertions(+), 1 deletion(-)
>  create mode 100644 lib/efi_loader/efi_hii.c
> 
> diff --git a/include/efi_api.h b/include/efi_api.h
> index ffdba7fe1a..164147dc87 100644
> --- a/include/efi_api.h
> +++ b/include/efi_api.h
> @@ -16,6 +16,7 @@
>  #define _EFI_API_H
>  
>  #include <efi.h>
> +#include <charset.h>
>  
>  #ifdef CONFIG_EFI_LOADER
>  #include <asm/setjmp.h>
> @@ -536,6 +537,266 @@ struct efi_device_path_utilities_protocol {
>  		uint16_t node_length);
>  };
>  
> +#define EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID \
> +	EFI_GUID(0x587e72d7, 0xcc50, 0x4f79, \
> +		 0x82, 0x09, 0xca, 0x29, 0x1f, 0xc1, 0xa1, 0x0f)
> +
> +typedef uint16_t efi_string_id_t;
> +
> +struct efi_hii_config_routing_protocol {
> +	efi_status_t(EFIAPI *extract_config)(
> +		const struct efi_hii_config_routing_protocol *this,
> +		const efi_string_t request,
> +		efi_string_t *progress,
> +		efi_string_t *results);
> +	efi_status_t(EFIAPI *export_config)(
> +		const struct efi_hii_config_routing_protocol *this,
> +		efi_string_t *results);
> +	efi_status_t(EFIAPI *route_config)(
> +		const struct efi_hii_config_routing_protocol *this,
> +		const efi_string_t configuration,
> +		efi_string_t *progress);
> +	efi_status_t(EFIAPI *block_to_config)(
> +		const struct efi_hii_config_routing_protocol *this,
> +		const efi_string_t config_request,
> +		const uint8_t *block,
> +		const efi_uintn_t block_size,
> +		efi_string_t *config,
> +		efi_string_t *progress);
> +	efi_status_t(EFIAPI *config_to_block)(
> +		const struct efi_hii_config_routing_protocol *this,
> +		const efi_string_t config_resp,
> +		const uint8_t *block,
> +		const efi_uintn_t *block_size,
> +		efi_string_t *progress);
> +	efi_status_t(EFIAPI *get_alt_config)(
> +		const struct efi_hii_config_routing_protocol *this,
> +		const efi_string_t config_resp,
> +		const efi_guid_t *guid,
> +		const efi_string_t name,
> +		const struct efi_device_path *device_path,
> +		const efi_string_t alt_cfg_id,
> +		efi_string_t *alt_cfg_resp);
> +};
> +
> +#define EFI_HII_DATABASE_PROTOCOL_GUID	     \
> +	EFI_GUID(0xef9fc172, 0xa1b2, 0x4693, \
> +		 0xb3, 0x27, 0x6d, 0x32, 0xfc, 0x41, 0x60, 0x42)
> +
> +typedef enum {
> +	EFI_KEY_LCTRL, EFI_KEY_A0, EFI_KEY_LALT, EFI_KEY_SPACE_BAR,
> +	EFI_KEY_A2, EFI_KEY_A3, EFI_KEY_A4, EFI_KEY_RCTRL, EFI_KEY_LEFT_ARROW,
> +	EFI_KEY_DOWN_ARROW, EFI_KEY_RIGHT_ARROW, EFI_KEY_ZERO,
> +	EFI_KEY_PERIOD, EFI_KEY_ENTER, EFI_KEY_LSHIFT, EFI_KEY_B0,
> +	EFI_KEY_B1, EFI_KEY_B2, EFI_KEY_B3, EFI_KEY_B4, EFI_KEY_B5, EFI_KEY_B6,
> +	EFI_KEY_B7, EFI_KEY_B8, EFI_KEY_B9, EFI_KEY_B10, EFI_KEY_RSHIFT,
> +	EFI_KEY_UP_ARROW, EFI_KEY_ONE, EFI_KEY_TWO, EFI_KEY_THREE,
> +	EFI_KEY_CAPS_LOCK, EFI_KEY_C1, EFI_KEY_C2, EFI_KEY_C3, EFI_KEY_C4,
> +	EFI_KEY_C5, EFI_KEY_C6, EFI_KEY_C7, EFI_KEY_C8, EFI_KEY_C9,
> +	EFI_KEY_C10, EFI_KEY_C11, EFI_KEY_C12, EFI_KEY_FOUR, EFI_KEY_FIVE,
> +	EFI_KEY_SIX, EFI_KEY_PLUS, EFI_KEY_TAB, EFI_KEY_D1, EFI_KEY_D2,
> +	EFI_KEY_D3, EFI_KEY_D4, EFI_KEY_D5, EFI_KEY_D6, EFI_KEY_D7, EFI_KEY_D8,
> +	EFI_KEY_D9, EFI_KEY_D10, EFI_KEY_D11, EFI_KEY_D12, EFI_KEY_D13,
> +	EFI_KEY_DEL, EFI_KEY_END, EFI_KEY_PG_DN, EFI_KEY_SEVEN, EFI_KEY_EIGHT,
> +	EFI_KEY_NINE, EFI_KEY_E0, EFI_KEY_E1, EFI_KEY_E2, EFI_KEY_E3,
> +	EFI_KEY_E4, EFI_KEY_E5, EFI_KEY_E6, EFI_KEY_E7, EFI_KEY_E8, EFI_KEY_E9,
> +	EFI_KEY_E10, EFI_KEY_E11, EFI_KEY_E12, EFI_KEY_BACK_SPACE,
> +	EFI_KEY_INS, EFI_KEY_HOME, EFI_KEY_PG_UP, EFI_KEY_NLCK, EFI_KEY_SLASH,
> +	EFI_KEY_ASTERISK, EFI_KEY_MINUS, EFI_KEY_ESC, EFI_KEY_F1, EFI_KEY_F2,
> +	EFI_KEY_F3, EFI_KEY_F4, EFI_KEY_F5, EFI_KEY_F6, EFI_KEY_F7, EFI_KEY_F8,
> +	EFI_KEY_F9, EFI_KEY_F10, EFI_KEY_F11, EFI_KEY_F12, EFI_KEY_PRINT,
> +	EFI_KEY_SLCK, EFI_KEY_PAUSE,
> +} efi_key;
> +
> +struct efi_key_descriptor {
> +	efi_key key;
> +	uint16_t unicode;
> +	uint16_t shifted_unicode;
> +	uint16_t alt_gr_unicode;
> +	uint16_t shifted_alt_gr_unicode;
> +	uint16_t modifier;
> +	uint16_t affected_attribute;
> +};
> +
> +struct efi_hii_keyboard_layout {
> +	uint16_t layout_length;
> +	efi_guid_t guid;
> +	uint32_t layout_descriptor_string_offset;
> +	uint8_t descriptor_count;
> +	struct efi_key_descriptor descriptors[];
> +};
> +
> +struct efi_hii_package_list_header {
> +	efi_guid_t package_list_guid;
> +	uint32_t package_length;
> +} __packed;
> +
> +struct efi_hii_package_header {
> +	uint32_t length : 24;
> +	uint32_t type : 8;
> +} __packed;

Bitfields are terribly evil - they're probably one of the worst defined
things in C. A different compiler may even give you different ordering
here. I've certainly seen bitfields explode in weird ways on
cross-endian conversions.

Do you think you could just make that a uint32_t altogether and work
with MASK/SHIFT defines instead?


> +
> +#define EFI_HII_PACKAGE_TYPE_ALL          0x00
> +#define EFI_HII_PACKAGE_TYPE_GUID         0x01
> +#define EFI_HII_PACKAGE_FORMS             0x02
> +#define EFI_HII_PACKAGE_STRINGS           0x04
> +#define EFI_HII_PACKAGE_FONTS             0x05
> +#define EFI_HII_PACKAGE_IMAGES            0x06
> +#define EFI_HII_PACKAGE_SIMPLE_FONTS      0x07
> +#define EFI_HII_PACKAGE_DEVICE_PATH       0x08
> +#define EFI_HII_PACKAGE_KEYBOARD_LAYOUT   0x09
> +#define EFI_HII_PACKAGE_ANIMATIONS        0x0A
> +#define EFI_HII_PACKAGE_END               0xDF
> +#define EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN 0xE0
> +#define EFI_HII_PACKAGE_TYPE_SYSTEM_END   0xFF
> +
> +struct efi_hii_strings_package {
> +	struct efi_hii_package_header header;
> +	uint32_t header_size;
> +	uint32_t string_info_offset;
> +	uint16_t language_window[16];
> +	efi_string_id_t language_name;
> +	uint8_t  language[];
> +} __packed;
> +
> +struct efi_hii_string_block {
> +	uint8_t block_type;
> +	/*uint8_t block_body[];*/
> +} __packed;
> +
> +#define EFI_HII_SIBT_END               0x00 // The end of the string information.
> +#define EFI_HII_SIBT_STRING_SCSU       0x10 // Single string using default font information.
> +#define EFI_HII_SIBT_STRING_SCSU_FONT  0x11 // Single string with font information.
> +#define EFI_HII_SIBT_STRINGS_SCSU      0x12 // Multiple strings using default font information.
> +#define EFI_HII_SIBT_STRINGS_SCSU_FONT 0x13 // Multiple strings with font information.
> +#define EFI_HII_SIBT_STRING_UCS2       0x14 // Single UCS-2 string using default font information.
> +#define EFI_HII_SIBT_STRING_UCS2_FONT  0x15 // Single UCS-2 string with font information
> +#define EFI_HII_SIBT_STRINGS_UCS2      0x16 // Multiple UCS-2 strings using default font information.
> +#define EFI_HII_SIBT_STRINGS_UCS2_FONT 0x17 // Multiple UCS-2 strings with font information.
> +#define EFI_HII_SIBT_DUPLICATE         0x20 // Create a duplicate of an existing string.
> +#define EFI_HII_SIBT_SKIP2             0x21 // Skip a certain number of string identifiers.
> +#define EFI_HII_SIBT_SKIP1             0x22 // Skip a certain number of string identifiers.
> +#define EFI_HII_SIBT_EXT1              0x30 // For future expansion (one byte length field)
> +#define EFI_HII_SIBT_EXT2              0x31 // For future expansion (two byte length field)
> +#define EFI_HII_SIBT_EXT4              0x32 // For future expansion (four byte length field)
> +#define EFI_HII_SIBT_FONT              0x40 // Font information.
> +
> +struct efi_hii_sibt_string_ucs2_block {
> +	struct efi_hii_string_block header;
> +	uint16_t string_text[];
> +} __packed;
> +
> +static inline struct efi_hii_string_block *efi_hii_sibt_string_ucs2_block_next(
> +	struct efi_hii_sibt_string_ucs2_block *blk)
> +{
> +	return ((void *)blk) + sizeof(*blk) +
> +		(utf16_strlen(blk->string_text) + 1) * 2;

Since you're dealing with actual utf16, is this correct? One character
may as well span 4 bytes, right?

I think we need a different function that actually tells us the bytes
occupied by a utf16 string.

> +}
> +
> +typedef void *efi_hii_handle_t;
> +
> +struct efi_hii_database_protocol {
> +	efi_status_t(EFIAPI *new_package_list)(
> +		const struct efi_hii_database_protocol *this,
> +		const struct efi_hii_package_list_header *package_list,
> +		const efi_handle_t driver_handle,
> +		efi_hii_handle_t *handle);
> +	efi_status_t(EFIAPI *remove_package_list)(
> +		const struct efi_hii_database_protocol *this,
> +		efi_hii_handle_t handle);
> +	efi_status_t(EFIAPI *update_package_list)(
> +		const struct efi_hii_database_protocol *this,
> +		efi_hii_handle_t handle,
> +		const struct efi_hii_package_list_header *package_list);
> +	efi_status_t(EFIAPI *list_package_lists)(
> +		const struct efi_hii_database_protocol *this,
> +		uint8_t package_type,
> +		const efi_guid_t *package_guid,
> +		efi_uintn_t *handle_buffer_length,
> +		efi_hii_handle_t *handle);
> +	efi_status_t(EFIAPI *export_package_lists)(
> +		const struct efi_hii_database_protocol *this,
> +		efi_hii_handle_t handle,
> +		efi_uintn_t *buffer_size,
> +		struct efi_hii_package_list_header *buffer);
> +	efi_status_t(EFIAPI *register_package_notify)(
> +		const struct efi_hii_database_protocol *this,
> +		uint8_t package_type,
> +		const efi_guid_t *package_guid,
> +		const void *package_notify_fn,
> +		efi_uintn_t notify_type,
> +		efi_handle_t *notify_handle);
> +	efi_status_t(EFIAPI *unregister_package_notify)(
> +		const struct efi_hii_database_protocol *this,
> +		efi_handle_t notification_handle
> +		);
> +	efi_status_t(EFIAPI *find_keyboard_layouts)(
> +		const struct efi_hii_database_protocol *this,
> +		uint16_t *key_guid_buffer_length,
> +		efi_guid_t *key_guid_buffer);
> +	efi_status_t(EFIAPI *get_keyboard_layout)(
> +		const struct efi_hii_database_protocol *this,
> +		efi_guid_t *key_guid,
> +		uint16_t *keyboard_layout_length,
> +		struct efi_hii_keyboard_layout *keyboard_layout);
> +	efi_status_t(EFIAPI *set_keyboard_layout)(
> +		const struct efi_hii_database_protocol *this,
> +		efi_guid_t *key_guid);
> +	efi_status_t(EFIAPI *get_package_list_handle)(
> +		const struct efi_hii_database_protocol *this,
> +		efi_hii_handle_t package_list_handle,
> +		efi_handle_t *driver_handle);
> +};
> +
> +#define EFI_HII_STRING_PROTOCOL_GUID \
> +	EFI_GUID(0x0fd96974, 0x23aa, 0x4cdc, \
> +		 0xb9, 0xcb, 0x98, 0xd1, 0x77, 0x50, 0x32, 0x2a)
> +
> +typedef uint32_t efi_hii_font_style_t;
> +
> +struct efi_font_info {
> +	efi_hii_font_style_t font_style;
> +	uint16_t font_size;
> +	uint16_t font_name[1];
> +};
> +
> +struct efi_hii_string_protocol {
> +	efi_status_t(EFIAPI *new_string)(
> +		const struct efi_hii_string_protocol *this,
> +		efi_hii_handle_t package_list,
> +		efi_string_id_t *string_id,
> +		const uint8_t *language,
> +		const uint16_t *language_name,
> +		const efi_string_t string,
> +		const struct efi_font_info *string_font_info);
> +	efi_status_t(EFIAPI *get_string)(
> +		const struct efi_hii_string_protocol *this,
> +		const uint8_t *language,
> +		efi_hii_handle_t package_list,
> +		efi_string_id_t string_id,
> +		efi_string_t string,
> +		efi_uintn_t *string_size,
> +		struct efi_font_info **string_font_info);
> +	efi_status_t(EFIAPI *set_string)(
> +		const struct efi_hii_string_protocol *this,
> +		efi_hii_handle_t package_list,
> +		efi_string_id_t string_id,
> +		const uint8_t *language,
> +		const efi_string_t string,
> +		const struct efi_font_info *string_font_info);
> +	efi_status_t(EFIAPI *get_languages)(
> +		const struct efi_hii_string_protocol *this,
> +		efi_hii_handle_t package_list,
> +		uint8_t *languages,
> +		efi_uintn_t *languages_size);
> +	efi_status_t(EFIAPI *get_secondary_languages)(
> +		const struct efi_hii_string_protocol *this,
> +		efi_hii_handle_t package_list,
> +		const uint8_t *primary_language,
> +		uint8_t *secondary_languages,
> +		efi_uintn_t *secondary_languages_size);
> +};
> +
>  #define EFI_GOP_GUID \
>  	EFI_GUID(0x9042a9de, 0x23dc, 0x4a38, \
>  		 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a)
> diff --git a/include/efi_loader.h b/include/efi_loader.h
> index 5d37c1d75f..591bf07e7a 100644
> --- a/include/efi_loader.h
> +++ b/include/efi_loader.h
> @@ -80,6 +80,9 @@ extern struct efi_simple_input_interface efi_con_in;
>  extern const struct efi_console_control_protocol efi_console_control;
>  extern const struct efi_device_path_to_text_protocol efi_device_path_to_text;
>  extern const struct efi_device_path_utilities_protocol efi_device_path_utilities;
> +extern const struct efi_hii_config_routing_protocol efi_hii_config_routing;
> +extern const struct efi_hii_database_protocol efi_hii_database;
> +extern const struct efi_hii_string_protocol efi_hii_string;
>  
>  uint16_t *efi_dp_str(struct efi_device_path *dp);
>  
> @@ -91,6 +94,9 @@ extern const efi_guid_t efi_guid_device_path_to_text_protocol;
>  extern const efi_guid_t efi_simple_file_system_protocol_guid;
>  extern const efi_guid_t efi_file_info_guid;
>  extern const efi_guid_t efi_guid_device_path_utilities_protocol;
> +extern const efi_guid_t efi_guid_hii_config_routing_protocol;
> +extern const efi_guid_t efi_guid_hii_database_protocol;
> +extern const efi_guid_t efi_guid_hii_string_protocol;
>  
>  extern unsigned int __efi_runtime_start, __efi_runtime_stop;
>  extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;
> diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
> index b6927b3b84..725e0cba85 100644
> --- a/lib/efi_loader/Makefile
> +++ b/lib/efi_loader/Makefile
> @@ -17,7 +17,7 @@ endif
>  obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o
>  obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o
>  obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o
> -obj-y += efi_device_path_utilities.o
> +obj-y += efi_device_path_utilities.o efi_hii.o
>  obj-y += efi_file.o efi_variable.o efi_bootmgr.o
>  obj-$(CONFIG_LCD) += efi_gop.o
>  obj-$(CONFIG_DM_VIDEO) += efi_gop.o
> diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
> index 92c778fcca..c179afc25a 100644
> --- a/lib/efi_loader/efi_boottime.c
> +++ b/lib/efi_loader/efi_boottime.c
> @@ -1157,6 +1157,15 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob
>  	obj->protocols[4].protocol_interface =
>  		(void *)&efi_device_path_utilities;
>  
> +	obj->protocols[5].guid = &efi_guid_hii_string_protocol;
> +	obj->protocols[5].protocol_interface = (void *)&efi_hii_string;
> +
> +	obj->protocols[6].guid = &efi_guid_hii_database_protocol;
> +	obj->protocols[6].protocol_interface = (void *)&efi_hii_database;
> +
> +	obj->protocols[7].guid = &efi_guid_hii_config_routing_protocol;
> +	obj->protocols[7].protocol_interface = (void *)&efi_hii_config_routing;
> +
>  	info->file_path = file_path;
>  	info->device_handle = efi_dp_find_obj(device_path, NULL);
>  
> diff --git a/lib/efi_loader/efi_hii.c b/lib/efi_loader/efi_hii.c
> new file mode 100644
> index 0000000000..25c8e88a60
> --- /dev/null
> +++ b/lib/efi_loader/efi_hii.c
> @@ -0,0 +1,507 @@
> +/*
> + *  EFI Human Interface Infrastructure ... interface
> + *
> + *  Copyright (c) 2017 Leif Lindholm
> + *
> + *  SPDX-License-Identifier:     GPL-2.0+
> + */
> +
> +#include <common.h>
> +#include <malloc.h>
> +#include <efi_loader.h>
> +
> +const efi_guid_t efi_guid_hii_config_routing_protocol =
> +	EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID;
> +const efi_guid_t efi_guid_hii_database_protocol = EFI_HII_DATABASE_PROTOCOL_GUID;
> +const efi_guid_t efi_guid_hii_string_protocol = EFI_HII_STRING_PROTOCOL_GUID;
> +
> +struct hii_package {
> +	// TODO should there be an associated efi_object?
> +	struct list_head string_tables;     /* list of string_table */
> +	/* we could also track fonts, images, etc */
> +};
> +
> +struct string_table {
> +	struct list_head link;
> +	efi_string_id_t language_name;
> +	char *language;
> +	uint32_t nstrings;
> +	/* NOTE: string id starts at 1 so value is stbl->strings[id-1] */
> +	struct {
> +		efi_string_t string;
> +		/* we could also track font info, etc */
> +	} strings[];
> +};
> +
> +static void free_strings_table(struct string_table *stbl)
> +{
> +	int i;
> +
> +	for (i = 0; i < stbl->nstrings; i++)
> +		free(stbl->strings[i].string);
> +	free(stbl->language);
> +	free(stbl);
> +}
> +
> +static struct hii_package *new_package(void)
> +{
> +	struct hii_package *hii = malloc(sizeof(*hii));
> +	INIT_LIST_HEAD(&hii->string_tables);
> +	return hii;
> +}
> +
> +static void free_package(struct hii_package *hii)
> +{
> +
> +	while (!list_empty(&hii->string_tables)) {
> +		struct string_table *stbl;
> +
> +		stbl = list_first_entry(&hii->string_tables,
> +					struct string_table, link);
> +		list_del(&stbl->link);
> +		free_strings_table(stbl);
> +	}
> +
> +	free(hii);
> +}
> +
> +static efi_status_t add_strings_package(struct hii_package *hii,
> +	struct efi_hii_strings_package *strings_package)
> +{
> +	struct efi_hii_string_block *block;
> +	void *end = ((void *)strings_package) + strings_package->header.length;
> +	uint32_t nstrings = 0;
> +	unsigned id = 0;
> +
> +	debug("header_size: %08x\n", strings_package->header_size);
> +	debug("string_info_offset: %08x\n", strings_package->string_info_offset);
> +	debug("language_name: %u\n", strings_package->language_name);
> +	debug("language: %s\n", strings_package->language);
> +
> +	/* count # of string entries: */
> +	block = ((void *)strings_package) + strings_package->string_info_offset;
> +	while ((void *)block < end) {
> +		switch (block->block_type) {
> +		case EFI_HII_SIBT_STRING_UCS2: {
> +			struct efi_hii_sibt_string_ucs2_block *ucs2 =
> +				(void *)block;
> +			nstrings++;
> +			block = efi_hii_sibt_string_ucs2_block_next(ucs2);
> +			break;
> +		}
> +		case EFI_HII_SIBT_END:
> +			block = end;
> +			break;
> +		default:
> +			debug("unknown HII string block type: %02x\n",
> +			      block->block_type);
> +			return EFI_INVALID_PARAMETER;
> +		}
> +	}
> +
> +	struct string_table *stbl = malloc(sizeof(*stbl) +
> +			(nstrings * sizeof(stbl->strings[0])));
> +	stbl->language_name = strings_package->language_name;
> +	stbl->language = strdup((char *)strings_package->language);

Where does the strings_package come from? And why is the language in it
in UTF8?

> +	stbl->nstrings = nstrings;
> +
> +	list_add(&stbl->link, &hii->string_tables);
> +
> +	/* and now parse string entries and populate string_table */
> +	block = ((void *)strings_package) + strings_package->string_info_offset;
> +
> +	while ((void *)block < end) {
> +		switch (block->block_type) {
> +		case EFI_HII_SIBT_STRING_UCS2: {
> +			struct efi_hii_sibt_string_ucs2_block *ucs2 =
> +				(void *)block;
> +			id++;
> +			debug("%4u: \"%ls\"\n", id, ucs2->string_text);
> +			stbl->strings[id-1].string =
> +				utf16_strdup(ucs2->string_text);
> +			block = efi_hii_sibt_string_ucs2_block_next(ucs2);
> +			break;
> +		}
> +		case EFI_HII_SIBT_END:
> +			return EFI_SUCCESS;
> +		default:
> +			debug("unknown HII string block type: %02x\n",
> +			      block->block_type);
> +			return EFI_INVALID_PARAMETER;
> +		}
> +	}
> +
> +	return EFI_SUCCESS;
> +}
> +
> +/*
> + * EFI_HII_CONFIG_ROUTING_PROTOCOL
> + */
> +
> +static efi_status_t EFIAPI extract_config(
> +	const struct efi_hii_config_routing_protocol *this,
> +	const efi_string_t request,
> +	efi_string_t *progress,
> +	efi_string_t *results)
> +{
> +	EFI_ENTRY("%p, \"%ls\", %p, %p", this, request, progress, results);
> +	return EFI_EXIT(EFI_OUT_OF_RESOURCES);
> +}
> +
> +static efi_status_t EFIAPI export_config(
> +	const struct efi_hii_config_routing_protocol *this,
> +	efi_string_t *results)
> +{
> +	EFI_ENTRY("%p, %p", this, results);
> +	return EFI_EXIT(EFI_OUT_OF_RESOURCES);
> +}
> +
> +static efi_status_t EFIAPI route_config(
> +	const struct efi_hii_config_routing_protocol *this,
> +	const efi_string_t configuration,
> +	efi_string_t *progress)
> +{
> +	EFI_ENTRY("%p, \"%ls\", %p", this, configuration, progress);
> +	return EFI_EXIT(EFI_OUT_OF_RESOURCES);
> +}
> +
> +static efi_status_t EFIAPI block_to_config(
> +	const struct efi_hii_config_routing_protocol *this,
> +	const efi_string_t config_request,
> +	const uint8_t *block,
> +	const efi_uintn_t block_size,
> +	efi_string_t *config,
> +	efi_string_t *progress)
> +{
> +	EFI_ENTRY("%p, \"%ls\", %p, %zu, %p, %p", this, config_request, block,
> +		  block_size, config, progress);
> +	return EFI_EXIT(EFI_OUT_OF_RESOURCES);
> +}
> +
> +static efi_status_t EFIAPI config_to_block(
> +	const struct efi_hii_config_routing_protocol *this,
> +	const efi_string_t config_resp,
> +	const uint8_t *block,
> +	const efi_uintn_t *block_size,
> +	efi_string_t *progress)
> +{
> +	EFI_ENTRY("%p, \"%ls\", %p, %p, %p", this, config_resp, block,
> +		  block_size, progress);
> +	return EFI_EXIT(EFI_OUT_OF_RESOURCES);
> +}
> +
> +static efi_status_t EFIAPI get_alt_config(
> +	const struct efi_hii_config_routing_protocol *this,
> +	const efi_string_t config_resp,
> +	const efi_guid_t *guid,
> +	const efi_string_t name,
> +	const struct efi_device_path *device_path,
> +	const efi_string_t alt_cfg_id,
> +	efi_string_t *alt_cfg_resp)
> +{
> +	EFI_ENTRY("%p, \"%ls\", %pUl, \"%ls\", %p, \"%ls\", %p", this,
> +		  config_resp, guid, name, device_path, alt_cfg_id,
> +		  alt_cfg_resp);
> +	return EFI_EXIT(EFI_OUT_OF_RESOURCES);
> +}
> +
> +
> +/*
> + * EFI_HII_DATABASE_PROTOCOL
> + */
> +
> +static efi_status_t EFIAPI new_package_list(
> +	const struct efi_hii_database_protocol *this,
> +	const struct efi_hii_package_list_header *package_list,
> +	const efi_handle_t driver_handle,
> +	efi_hii_handle_t *handle)
> +{
> +	efi_status_t ret = EFI_SUCCESS;
> +
> +	EFI_ENTRY("%p, %p, %p, %p", this, package_list, driver_handle, handle);
> +
> +	if (!package_list || !driver_handle)
> +		return EFI_EXIT(EFI_INVALID_PARAMETER);
> +
> +	struct hii_package *hii = new_package();
> +	struct efi_hii_package_header *package;
> +	void *end = ((void *)package_list) + package_list->package_length;
> +
> +	debug("package_list: %pUl (%u)\n", &package_list->package_list_guid,
> +	      package_list->package_length);
> +
> +	package = ((void *)package_list) + sizeof(*package_list);
> +	while ((void *)package < end) {
> +		debug("package=%p, package type=%x, length=%u\n", package,
> +		      package->type, package->length);
> +		switch (package->type) {
> +		case EFI_HII_PACKAGE_STRINGS:
> +			ret = add_strings_package(hii,
> +				(struct efi_hii_strings_package *)package);
> +			break;
> +		default:
> +			break;
> +		}
> +
> +		if (ret != EFI_SUCCESS)
> +			goto error;
> +
> +		package = ((void *)package) + package->length;
> +	}
> +
> +	// TODO in theory there is some notifications that should be sent..
> +
> +	*handle = hii;
> +
> +	return EFI_EXIT(EFI_SUCCESS);
> +
> +error:
> +	free_package(hii);
> +	return EFI_EXIT(ret);
> +}
> +
> +static efi_status_t EFIAPI remove_package_list(
> +	const struct efi_hii_database_protocol *this,
> +	efi_hii_handle_t handle)
> +{
> +	struct hii_package *hii = handle;
> +	EFI_ENTRY("%p, %p", this, handle);
> +	free_package(hii);
> +	return EFI_EXIT(EFI_SUCCESS);
> +}
> +
> +static efi_status_t EFIAPI update_package_list(
> +	const struct efi_hii_database_protocol *this,
> +	efi_hii_handle_t handle,
> +	const struct efi_hii_package_list_header *package_list)
> +{
> +	EFI_ENTRY("%p, %p, %p", this, handle, package_list);
> +	return EFI_EXIT(EFI_NOT_FOUND);
> +}
> +
> +static efi_status_t EFIAPI list_package_lists(
> +	const struct efi_hii_database_protocol *this,
> +	uint8_t package_type,
> +	const efi_guid_t *package_guid,
> +	efi_uintn_t *handle_buffer_length,
> +	efi_hii_handle_t *handle)
> +{
> +	EFI_ENTRY("%p, %u, %pUl, %p, %p", this, package_type, package_guid,
> +		  handle_buffer_length, handle);
> +	return EFI_EXIT(EFI_NOT_FOUND);
> +}
> +
> +static efi_status_t EFIAPI export_package_lists(
> +	const struct efi_hii_database_protocol *this,
> +	efi_hii_handle_t handle,
> +	efi_uintn_t *buffer_size,
> +	struct efi_hii_package_list_header *buffer)
> +{
> +	EFI_ENTRY("%p, %p, %p, %p", this, handle, buffer_size, buffer);
> +	return EFI_EXIT(EFI_NOT_FOUND);
> +}
> +
> +static efi_status_t EFIAPI register_package_notify(
> +	const struct efi_hii_database_protocol *this,
> +	uint8_t package_type,
> +	const efi_guid_t *package_guid,
> +	const void *package_notify_fn,
> +	efi_uintn_t notify_type,
> +	efi_handle_t *notify_handle)
> +{
> +	EFI_ENTRY("%p, %u, %pUl, %p, %zu, %p", this, package_type,
> +		  package_guid, package_notify_fn, notify_type,
> +		  notify_handle);
> +	return EFI_EXIT(EFI_OUT_OF_RESOURCES);
> +}
> +
> +static efi_status_t EFIAPI unregister_package_notify(
> +	const struct efi_hii_database_protocol *this,
> +	efi_handle_t notification_handle)
> +{
> +	EFI_ENTRY("%p, %p", this, notification_handle);
> +	return EFI_EXIT(EFI_NOT_FOUND);
> +}
> +
> +static efi_status_t EFIAPI find_keyboard_layouts(
> +	const struct efi_hii_database_protocol *this,
> +	uint16_t *key_guid_buffer_length,
> +	efi_guid_t *key_guid_buffer)
> +{
> +	EFI_ENTRY("%p, %p, %p", this, key_guid_buffer_length, key_guid_buffer);
> +	return EFI_EXIT(EFI_NOT_FOUND); /* Invalid */
> +}
> +
> +static efi_status_t EFIAPI get_keyboard_layout(
> +	const struct efi_hii_database_protocol *this,
> +	efi_guid_t *key_guid,
> +	uint16_t *keyboard_layout_length,
> +	struct efi_hii_keyboard_layout *keyboard_layout)
> +{
> +	EFI_ENTRY("%p, %pUl, %p, %p", this, key_guid, keyboard_layout_length,
> +		  keyboard_layout);
> +	return EFI_EXIT(EFI_NOT_FOUND);
> +}
> +
> +static efi_status_t EFIAPI set_keyboard_layout(
> +	const struct efi_hii_database_protocol *this,
> +	efi_guid_t *key_guid)
> +{
> +	EFI_ENTRY("%p, %pUl", this, key_guid);
> +	return EFI_EXIT(EFI_NOT_FOUND);
> +}
> +
> +static efi_status_t EFIAPI get_package_list_handle(
> +	const struct efi_hii_database_protocol *this,
> +	efi_hii_handle_t package_list_handle,
> +	efi_handle_t *driver_handle)
> +{
> +	EFI_ENTRY("%p, %p, %p", this, package_list_handle, driver_handle);
> +	return EFI_EXIT(EFI_INVALID_PARAMETER);
> +}
> +
> +
> +/*
> + * EFI_HII_STRING_PROTOCOL
> + */
> +
> +static efi_status_t EFIAPI new_string(
> +	const struct efi_hii_string_protocol *this,
> +	efi_hii_handle_t package_list,
> +	efi_string_id_t *string_id,
> +	const uint8_t *language,
> +	const uint16_t *language_name,
> +	const efi_string_t string,
> +	const struct efi_font_info *string_font_info)
> +{
> +	EFI_ENTRY("%p, %p, %p, \"%s\", %p, \"%ls\", %p", this, package_list,
> +		  string_id, language, language_name, string,
> +		  string_font_info);
> +	return EFI_EXIT(EFI_NOT_FOUND);
> +}
> +
> +static efi_status_t EFIAPI get_string(
> +	const struct efi_hii_string_protocol *this,
> +	const uint8_t *language,
> +	efi_hii_handle_t package_list,
> +	efi_string_id_t string_id,
> +	efi_string_t string,
> +	efi_uintn_t *string_size,
> +	struct efi_font_info **string_font_info)
> +{
> +	struct hii_package *hii = package_list;
> +	struct string_table *stbl;
> +
> +	EFI_ENTRY("%p, \"%s\", %p, %u, %p, %p, %p", this, language,
> +		  package_list, string_id, string, string_size,
> +		  string_font_info);
> +
> +	list_for_each_entry(stbl, &hii->string_tables, link) {
> +		if (!strcmp((char *)language, (char *)stbl->language)) {
> +			unsigned idx = string_id - 1;
> +			if (idx > stbl->nstrings)
> +				return EFI_EXIT(EFI_NOT_FOUND);
> +			efi_string_t str = stbl->strings[idx].string;
> +			size_t len = utf16_strlen(str) + 1;

I assume that's wrong for sizing too?

Also please try not to define variables mid-scope :). Just define them
above the if() and fill them after ...

Then also for the sake of readability add a blank line after the
variable definitions and before the return.

I think you'd also do yourself a favor if you reduced the indenting a
bit. Just abort the list_for_each when you found and entry and then
process it in the top level scope.

static struct string_table *find_stbl_by_lang(const char *language)
{
    list_for_each(...) {
        if (matches) {
            return stbl;
        }
    }

    return NULL;
}

stbl = find_stbl_by_lang(lang);
if (!stbl)
    return EFI_EXIT(EFI_NOT_FOUND)

work_with_stbl;

return EFI_EXIT(EFI_SUCCESS);


Alex

> +			if (*string_size < len * 2) {
> +				*string_size = len * 2;
> +				return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
> +			}
> +			memcpy(string, str, len * 2);
> +			*string_size = len * 2;
> +			return EFI_EXIT(EFI_SUCCESS);
> +		}
> +	}
> +
> +	return EFI_EXIT(EFI_NOT_FOUND);
> +}
> +
> +static efi_status_t EFIAPI set_string(
> +	const struct efi_hii_string_protocol *this,
> +	efi_hii_handle_t package_list,
> +	efi_string_id_t string_id,
> +	const uint8_t *language,
> +	const efi_string_t string,
> +	const struct efi_font_info *string_font_info)
> +{
> +	EFI_ENTRY("%p, %p, %u, \"%s\", \"%ls\", %p", this, package_list,
> +		  string_id, language, string, string_font_info);
> +	return EFI_EXIT(EFI_NOT_FOUND);
> +}
> +
> +static efi_status_t EFIAPI get_languages(
> +	const struct efi_hii_string_protocol *this,
> +	efi_hii_handle_t package_list,
> +	uint8_t *languages,
> +	efi_uintn_t *languages_size)
> +{
> +	struct hii_package *hii = package_list;
> +	struct string_table *stbl;
> +	size_t len = 0;
> +
> +	EFI_ENTRY("%p, %p, %p, %p", this, package_list, languages,
> +		  languages_size);
> +
> +	/* figure out required size: */
> +	list_for_each_entry(stbl, &hii->string_tables, link) {
> +		len += strlen((char *)stbl->language) + 1;
> +	}
> +
> +	if (*languages_size < len) {
> +		*languages_size = len;
> +		return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
> +	}
> +
> +	char *p = (char *)languages;
> +	list_for_each_entry(stbl, &hii->string_tables, link) {
> +		if (p != (char *)languages)
> +			p += sprintf(p, ";");
> +		p += sprintf(p, "%s", stbl->language);
> +	}
> +
> +	debug("languages: %s\n", languages);
> +
> +	return EFI_EXIT(EFI_SUCCESS);
> +}
> +
> +static efi_status_t EFIAPI get_secondary_languages(
> +	const struct efi_hii_string_protocol *this,
> +	efi_hii_handle_t package_list,
> +	const uint8_t *primary_language,
> +	uint8_t *secondary_languages,
> +	efi_uintn_t *secondary_languages_size)
> +{
> +	EFI_ENTRY("%p, %p, \"%s\", %p, %p", this, package_list,
> +		  primary_language, secondary_languages,
> +		  secondary_languages_size);
> +	return EFI_EXIT(EFI_NOT_FOUND);
> +}
> +
> +const struct efi_hii_config_routing_protocol efi_hii_config_routing = {
> +	.extract_config = extract_config,
> +	.export_config = export_config,
> +	.route_config = route_config,
> +	.block_to_config = block_to_config,
> +	.config_to_block = config_to_block,
> +	.get_alt_config = get_alt_config
> +};
> +const struct efi_hii_database_protocol efi_hii_database = {
> +	.new_package_list = new_package_list,
> +	.remove_package_list = remove_package_list,
> +	.update_package_list = update_package_list,
> +	.list_package_lists = list_package_lists,
> +	.export_package_lists = export_package_lists,
> +	.register_package_notify = register_package_notify,
> +	.unregister_package_notify = unregister_package_notify,
> +	.find_keyboard_layouts = find_keyboard_layouts,
> +	.get_keyboard_layout = get_keyboard_layout,
> +	.set_keyboard_layout = set_keyboard_layout,
> +	.get_package_list_handle = get_package_list_handle
> +};
> +const struct efi_hii_string_protocol efi_hii_string = {
> +	.new_string = new_string,
> +	.get_string = get_string,
> +	.set_string = set_string,
> +	.get_languages = get_languages,
> +	.get_secondary_languages = get_secondary_languages
> +};
> 

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 03/11] efi_loader: Initial EFI_UNICODE_COLLATION_PROTOCOL
  2017-10-10 12:22 ` [U-Boot] [PATCH 03/11] efi_loader: Initial EFI_UNICODE_COLLATION_PROTOCOL Rob Clark
@ 2017-10-11 14:36   ` Alexander Graf
  2017-10-11 20:30     ` Rob Clark
  0 siblings, 1 reply; 75+ messages in thread
From: Alexander Graf @ 2017-10-11 14:36 UTC (permalink / raw)
  To: u-boot



On 10.10.17 14:22, Rob Clark wrote:
> From: Leif Lindholm <leif.lindholm@linaro.org>
> 
> Not complete, but enough for Shell.efi and SCT.efi.
> 
> Initial skeleton written by Leif, and then implementation by myself.
> 
> Cc: Leif Lindholm <leif.lindholm@linaro.org>
> Signed-off-by: Rob Clark <robdclark@gmail.com>
> ---
>  include/efi_api.h             |  41 ++++++++++
>  include/efi_loader.h          |   3 +
>  lib/efi_loader/Makefile       |   2 +-
>  lib/efi_loader/efi_boottime.c |   6 ++
>  lib/efi_loader/efi_unicode.c  | 170 ++++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 221 insertions(+), 1 deletion(-)
>  create mode 100644 lib/efi_loader/efi_unicode.c
> 
> diff --git a/include/efi_api.h b/include/efi_api.h
> index 164147dc87..38dd1240c1 100644
> --- a/include/efi_api.h
> +++ b/include/efi_api.h
> @@ -797,6 +797,47 @@ struct efi_hii_string_protocol {
>  		efi_uintn_t *secondary_languages_size);
>  };
>  
> +/*
> + * Both UNICODE_COLLATION protocols seem to be the same thing, but
> + * advertised with two different GUID's because, why not?
> + */
> +
> +#define EFI_UNICODE_COLLATION_PROTOCOL_GUID \
> +	EFI_GUID(0x1d85cd7f, 0xf43d, 0x11d2, \
> +		 0x9a, 0x0c, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
> +
> +#define EFI_UNICODE_COLLATION_PROTOCOL2_GUID \
> +	EFI_GUID(0xa4c751fc, 0x23ae, 0x4c3e, \
> +		 0x92, 0xe9, 0x49, 0x64, 0xcf, 0x63, 0xf3, 0x49)
> +
> +struct efi_unicode_collation_protocol {
> +	efi_intn_t (EFIAPI *stri_coll)(
> +		struct efi_unicode_collation_protocol *this,
> +		efi_string_t s1,
> +		efi_string_t s2);
> +	bool (EFIAPI *metai_match)(
> +		struct efi_unicode_collation_protocol *this,
> +		efi_string_t string,
> +		efi_string_t pattern);
> +	void (EFIAPI *str_lwr)(
> +		struct efi_unicode_collation_protocol *this,
> +		efi_string_t string);
> +	void (EFIAPI *str_upr)(
> +		struct efi_unicode_collation_protocol *this,
> +		efi_string_t string);
> +	void (EFIAPI *fat_to_str)(
> +		struct efi_unicode_collation_protocol *this,
> +		efi_uintn_t fat_size,
> +		uint8_t *fat,
> +		efi_string_t string);
> +	bool (EFIAPI *str_to_fat)(
> +		struct efi_unicode_collation_protocol *this,
> +		efi_string_t string,
> +		efi_uintn_t fat_size,
> +		uint8_t *fat);
> +	uint8_t *supported_languages;
> +};
> +
>  #define EFI_GOP_GUID \
>  	EFI_GUID(0x9042a9de, 0x23dc, 0x4a38, \
>  		 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a)
> diff --git a/include/efi_loader.h b/include/efi_loader.h
> index 591bf07e7a..af6812b2b4 100644
> --- a/include/efi_loader.h
> +++ b/include/efi_loader.h
> @@ -83,6 +83,7 @@ extern const struct efi_device_path_utilities_protocol efi_device_path_utilities
>  extern const struct efi_hii_config_routing_protocol efi_hii_config_routing;
>  extern const struct efi_hii_database_protocol efi_hii_database;
>  extern const struct efi_hii_string_protocol efi_hii_string;
> +extern const struct efi_unicode_collation_protocol efi_unicode_collation;
>  
>  uint16_t *efi_dp_str(struct efi_device_path *dp);
>  
> @@ -97,6 +98,8 @@ extern const efi_guid_t efi_guid_device_path_utilities_protocol;
>  extern const efi_guid_t efi_guid_hii_config_routing_protocol;
>  extern const efi_guid_t efi_guid_hii_database_protocol;
>  extern const efi_guid_t efi_guid_hii_string_protocol;
> +extern const efi_guid_t efi_guid_unicode_collation_protocol;
> +extern const efi_guid_t efi_guid_unicode_collation_protocol2;
>  
>  extern unsigned int __efi_runtime_start, __efi_runtime_stop;
>  extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;
> diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
> index 725e0cba85..7ea96a4f1c 100644
> --- a/lib/efi_loader/Makefile
> +++ b/lib/efi_loader/Makefile
> @@ -17,7 +17,7 @@ endif
>  obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o
>  obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o
>  obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o
> -obj-y += efi_device_path_utilities.o efi_hii.o
> +obj-y += efi_device_path_utilities.o efi_hii.o efi_unicode.o
>  obj-y += efi_file.o efi_variable.o efi_bootmgr.o
>  obj-$(CONFIG_LCD) += efi_gop.o
>  obj-$(CONFIG_DM_VIDEO) += efi_gop.o
> diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
> index c179afc25a..b568f3f162 100644
> --- a/lib/efi_loader/efi_boottime.c
> +++ b/lib/efi_loader/efi_boottime.c
> @@ -1166,6 +1166,12 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob
>  	obj->protocols[7].guid = &efi_guid_hii_config_routing_protocol;
>  	obj->protocols[7].protocol_interface = (void *)&efi_hii_config_routing;
>  
> +	obj->protocols[8].guid = &efi_guid_unicode_collation_protocol;
> +	obj->protocols[8].protocol_interface = (void *)&efi_unicode_collation;
> +
> +	obj->protocols[9].guid = &efi_guid_unicode_collation_protocol2;
> +	obj->protocols[9].protocol_interface = (void *)&efi_unicode_collation;
> +
>  	info->file_path = file_path;
>  	info->device_handle = efi_dp_find_obj(device_path, NULL);
>  
> diff --git a/lib/efi_loader/efi_unicode.c b/lib/efi_loader/efi_unicode.c
> new file mode 100644
> index 0000000000..2c6302df25
> --- /dev/null
> +++ b/lib/efi_loader/efi_unicode.c
> @@ -0,0 +1,170 @@
> +/*
> +*  EFI Unicode interface
> + *
> + *  Copyright (c) 2017 Leif Lindholm
> + *
> + *  SPDX-License-Identifier:     GPL-2.0+
> + */
> +
> +#include <common.h>
> +#include <charset.h>
> +#include <linux/ctype.h>
> +#include <efi_loader.h>
> +
> +const efi_guid_t efi_guid_unicode_collation_protocol =
> +	EFI_UNICODE_COLLATION_PROTOCOL_GUID;
> +
> +const efi_guid_t efi_guid_unicode_collation_protocol2 =
> +	EFI_UNICODE_COLLATION_PROTOCOL2_GUID;
> +
> +static int matchn(efi_string_t s1, unsigned n1, efi_string_t s2, unsigned n2)
> +{
> +	char u1[MAX_UTF8_PER_UTF16 * n1 + 1];
> +	char u2[MAX_UTF8_PER_UTF16 * n2 + 1];
> +
> +	*utf16_to_utf8((u8 *)u1, s1, n1) = '\0';
> +	*utf16_to_utf8((u8 *)u2, s2, n2) = '\0';
> +
> +	return strcasecmp(u1, u2);
> +}
> +
> +static efi_intn_t EFIAPI stri_coll(struct efi_unicode_collation_protocol *this,
> +				   efi_string_t s1,
> +				   efi_string_t s2)
> +{
> +	EFI_ENTRY("%p, \"%ls\", \"%ls\"", this, s1, s2);
> +
> +	unsigned n1 = utf16_strlen(s1);
> +	unsigned n2 = utf16_strlen(s2);
> +
> +	return EFI_EXIT(matchn(s1, n1, s2, n2));
> +}
> +
> +static bool match(efi_string_t string, efi_string_t pattern)
> +{
> +	while (true) {
> +		uint16_t p = *pattern++;
> +		bool matches = false;
> +
> +		if (p == '\0' || *string == '\0') {
> +			/*
> +			 * End of pattern or string, succeed if
> +			 * end of both:
> +			 */
> +			return *string == p;
> +		}
> +
> +		switch (p) {
> +		case '*':
> +			/* Match zero or more chars: */
> +			while (*string != '\0') {
> +				if (match(string, pattern))
> +					return true;
> +				string++;
> +			}
> +			return match(string, pattern);
> +		case '?':
> +			/* Match any one char: */
> +			string++;
> +			break;
> +		case '[':
> +			/* Match char set, either [abc] or [a-c]: */
> +
> +			if (pattern[0] == '\0' || pattern[0] == ']') {
> +				/* invalid pattern */
> +				return false;
> +			}
> +
> +			if (pattern[1] == '-') {
> +				uint16_t lo, hi, c;
> +
> +				/* range: [a-c] */
> +				lo = pattern[0];
> +				hi = pattern[2];
> +
> +				if (hi == '\0' || hi == ']' || pattern[3] != ']') {
> +					/* invalid pattern */
> +					return false;
> +				}
> +
> +				c  = tolower(*string);
> +				lo = tolower(lo);
> +				hi = tolower(hi);
> +
> +				if (lo <= c && c <= hi)
> +					matches = true;
> +
> +				pattern += 4;
> +			} else {
> +				/* set: [abc] */
> +				while ((p = *pattern++) && p != ']')
> +					if (matchn(string, 1, &p, 1))
> +						matches = true;
> +			}
> +
> +			if (!matches)
> +				return false;
> +
> +			string++;
> +			break;
> +		default:
> +			if (matchn(string, 1, &p, 1))
> +				return false;
> +			string++;
> +			break;
> +		}
> +	}
> +}
> +
> +static bool EFIAPI metai_match(struct efi_unicode_collation_protocol *this,
> +			       efi_string_t string,
> +			       efi_string_t pattern)
> +{
> +	EFI_ENTRY("%p, \"%ls\", \"%ls\"", this, string, pattern);
> +	return EFI_EXIT(match(string, pattern));

EFI_EXIT wants a success/failure parameter, not true/false (which can be
randomly defined). Please either have match() return EFI return codes or
convert it in here :).

> +}
> +
> +static void EFIAPI str_lwr(struct efi_unicode_collation_protocol *this,
> +			   efi_string_t string)
> +{
> +	EFI_ENTRY("%p, \"%ls\"", this, string);
> +	EFI_EXIT(EFI_SUCCESS);

This is not implemented, right? Better indicate that in the EFI_EXIT()
hint so that someone tracing a log of calls will catch it later.

> +	return;

Not needed, no?

> +}
> +
> +static void EFIAPI str_upr(struct efi_unicode_collation_protocol *this,
> +			   efi_string_t string)
> +{
> +	EFI_ENTRY("%p, \"%ls\"", this, string);
> +	EFI_EXIT(EFI_SUCCESS);

Same here

> +	return;
> +}
> +
> +static void EFIAPI fat_to_str(struct efi_unicode_collation_protocol *this,
> +			      efi_uintn_t fat_size,
> +			      uint8_t *fat,
> +			      efi_string_t string)
> +{
> +	EFI_ENTRY("%p, %zu, \"%s\", %p", this, fat_size, fat, string);
> +	EFI_EXIT(EFI_SUCCESS);

Same here

> +	return;
> +}
> +
> +static bool EFIAPI str_to_fat(struct efi_unicode_collation_protocol *this,
> +			      efi_string_t string,
> +			      efi_uintn_t fat_size,
> +			      uint8_t *fat)
> +{
> +	EFI_ENTRY("%p, \"%ls\", %zu, %p", this, string, fat_size, fat);
> +	return EFI_EXIT(false);

Again, please don't pass true/false to EFI_EXIT().


Alex

> +}
> +
> +const struct efi_unicode_collation_protocol efi_unicode_collation = {
> +	.stri_coll = stri_coll,
> +	.metai_match = metai_match,
> +	.str_lwr = str_lwr,
> +	.str_upr = str_upr,
> +	.fat_to_str = fat_to_str,
> +	.str_to_fat = str_to_fat,
> +	.supported_languages = (uint8_t *)"eng",
> +};
> 

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 04/11] efi_loader: SIMPLE_TEXT_INPUT_EX plus wire up objects properly
  2017-10-10 12:23 ` [U-Boot] [PATCH 04/11] efi_loader: SIMPLE_TEXT_INPUT_EX plus wire up objects properly Rob Clark
@ 2017-10-11 14:39   ` Alexander Graf
  2018-09-04 14:07   ` [U-Boot] [U-Boot, " Alexander Graf
  1 sibling, 0 replies; 75+ messages in thread
From: Alexander Graf @ 2017-10-11 14:39 UTC (permalink / raw)
  To: u-boot



On 10.10.17 14:23, Rob Clark wrote:
> We need the _EX version for SCT.. and we need to wire up the
> corresponding objects in the systab properly, as well as dealing
> with the console_in object advertising multiple protocols.
> 
> Signed-off-by: Rob Clark <robdclark@gmail.com>

Reviewed-by: Alexander Graf <agraf@suse.de>

Alex

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 05/11] efi_loader: console support for color attributes
  2017-10-10 12:23 ` [U-Boot] [PATCH 05/11] efi_loader: console support for color attributes Rob Clark
  2017-10-10 23:41   ` Heinrich Schuchardt
@ 2017-10-11 14:41   ` Alexander Graf
  2017-10-12 15:24   ` [U-Boot] [U-Boot, " Alexander Graf
  2 siblings, 0 replies; 75+ messages in thread
From: Alexander Graf @ 2017-10-11 14:41 UTC (permalink / raw)
  To: u-boot



On 10.10.17 14:23, Rob Clark wrote:
> Shell.efi uses this, and supporting color attributes makes things look
> nicer.  Map the EFI fg/bg color attributes to ANSI escape sequences.
> Not all colors have a perfect match, but spec just says "Devices
> supporting a different number of text colors are required to emulate the
> above colors to the best of the device’s capabilities".
> 
> Signed-off-by: Rob Clark <robdclark@gmail.com>

Reviewed-by: Alexander Graf <agraf@suse.de>

Alex

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 06/11] efi_loader: Decouple EFI input/output from stdin/stdout
  2017-10-10 12:23 ` [U-Boot] [PATCH 06/11] efi_loader: Decouple EFI input/output from stdin/stdout Rob Clark
@ 2017-10-11 14:45   ` Alexander Graf
  2017-10-11 22:07     ` Rob Clark
  0 siblings, 1 reply; 75+ messages in thread
From: Alexander Graf @ 2017-10-11 14:45 UTC (permalink / raw)
  To: u-boot



On 10.10.17 14:23, Rob Clark wrote:
> In some cases, it is quite useful to have (for example) EFI on screen
> but u-boot on serial port.
> 
> This adds two new optional environment variables, "efiin" and "efiout",
> which can be used to set EFI console input/output independently of
> u-boot's input/output.  If unset, EFI console will default to stdin/
> stdout as before.
> 
> Signed-off-by: Rob Clark <robdclark@gmail.com>

With this patch, we lose the ability to have the efi in/out go to both
graphical and serial console, right? This is critical functionality to
have, since we don't necessarily know which output/input a user ends up
using.


Alex

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 07/11] efi_loader: fix events
  2017-10-10 12:23 ` [U-Boot] [PATCH 07/11] efi_loader: fix events Rob Clark
  2017-10-10 22:40   ` Heinrich Schuchardt
@ 2017-10-11 14:49   ` Alexander Graf
  2017-10-11 22:09     ` Rob Clark
  2017-10-13  5:24   ` Heinrich Schuchardt
  2 siblings, 1 reply; 75+ messages in thread
From: Alexander Graf @ 2017-10-11 14:49 UTC (permalink / raw)
  To: u-boot



On 10.10.17 14:23, Rob Clark wrote:
> An event can be created with type==0, Shell.efi does this for an event
> that is set when Ctrl-C is typed.  So our current approach of having a
> fixed set of timer slots, and determining which slots are unused by
> type==0 doesn't work so well.  But we don't have any particularly good
> reason to have a fixed table of events, so just dynamically allocate
> them and keep a list.
> 
> Also fixes an incorrect implementation of CheckEvent() which was (a)
> incorrectly returning an error if type==0, and (b) didn't handle the
> case of an unsignaled event with a notify callback.
> 
> With these fixes (plus implementation of SIMPLE_TEXT_INPUT_EX protocol),
> Ctrl-C works in Shell.efi.
> 
> Signed-off-by: Rob Clark <robdclark@gmail.com>
> ---
>  include/efi_loader.h          |   1 +
>  lib/efi_loader/efi_boottime.c | 217 +++++++++++++++++++++---------------------
>  2 files changed, 111 insertions(+), 107 deletions(-)
> 
> diff --git a/include/efi_loader.h b/include/efi_loader.h
> index e6e55d2cb4..2232caca44 100644
> --- a/include/efi_loader.h
> +++ b/include/efi_loader.h
> @@ -154,6 +154,7 @@ struct efi_event {
>  	enum efi_timer_delay trigger_type;
>  	bool is_queued;
>  	bool is_signaled;
> +	struct list_head link;
>  };
>  
>  
> diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
> index 39dcc72648..19fafe546c 100644
> --- a/lib/efi_loader/efi_boottime.c
> +++ b/lib/efi_loader/efi_boottime.c
> @@ -350,11 +350,26 @@ static efi_status_t efi_create_handle(void **handle)
>  	return r;
>  }
>  
> +static LIST_HEAD(efi_events);
> +
>  /*
> - * Our event capabilities are very limited. Only a small limited
> - * number of events is allowed to coexist.
> + * Check if a pointer is a valid event.
> + *
> + * It might be nice at some point to extend this to a more general
> + * mechanism to check if pointers passed from the EFI world are
> + * valid objects of a particular type.
>   */
> -static struct efi_event efi_events[16];
> +static bool efi_is_event(const void *obj)
> +{
> +	struct efi_event *evt;
> +
> +	list_for_each_entry(evt, &efi_events, link) {
> +		if (evt == obj)
> +			return true;
> +	}
> +
> +	return false;
> +}
>  
>  /*
>   * Create an event.
> @@ -377,7 +392,7 @@ efi_status_t efi_create_event(uint32_t type, UINTN notify_tpl,
>  					void *context),
>  			      void *notify_context, struct efi_event **event)
>  {
> -	int i;
> +	struct efi_event *evt;
>  
>  	if (event == NULL)
>  		return EFI_INVALID_PARAMETER;
> @@ -389,21 +404,24 @@ efi_status_t efi_create_event(uint32_t type, UINTN notify_tpl,
>  	    notify_function == NULL)
>  		return EFI_INVALID_PARAMETER;
>  
> -	for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
> -		if (efi_events[i].type)
> -			continue;
> -		efi_events[i].type = type;
> -		efi_events[i].notify_tpl = notify_tpl;
> -		efi_events[i].notify_function = notify_function;
> -		efi_events[i].notify_context = notify_context;
> -		/* Disable timers on bootup */
> -		efi_events[i].trigger_next = -1ULL;
> -		efi_events[i].is_queued = false;
> -		efi_events[i].is_signaled = false;
> -		*event = &efi_events[i];
> -		return EFI_SUCCESS;
> -	}
> -	return EFI_OUT_OF_RESOURCES;
> +	evt = calloc(1, sizeof(*evt));
> +	if (!evt)
> +		return EFI_OUT_OF_RESOURCES;
> +
> +	evt->type = type;
> +	evt->notify_tpl = notify_tpl;
> +	evt->notify_function = notify_function;
> +	evt->notify_context = notify_context;
> +	/* Disable timers on bootup */
> +	evt->trigger_next = -1ULL;
> +	evt->is_queued = false;
> +	evt->is_signaled = false;
> +
> +	list_add_tail(&evt->link, &efi_events);
> +
> +	*event = evt;
> +
> +	return EFI_SUCCESS;
>  }
>  
>  /*
> @@ -443,30 +461,31 @@ static efi_status_t EFIAPI efi_create_event_ext(
>   */
>  void efi_timer_check(void)
>  {
> -	int i;
> +	struct efi_event *evt;
>  	u64 now = timer_get_us();
>  
> -	for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
> -		if (!efi_events[i].type)
> -			continue;
> -		if (efi_events[i].is_queued)
> -			efi_signal_event(&efi_events[i]);
> -		if (!(efi_events[i].type & EVT_TIMER) ||
> -		    now < efi_events[i].trigger_next)
> +	/*
> +	 * TODO perhaps optimize a bit and track the time of next
> +	 * timer to expire?
> +	 */
> +	list_for_each_entry(evt, &efi_events, link) {
> +		if (evt->is_queued)
> +			efi_signal_event(evt);
> +		if (!(evt->type & EVT_TIMER) ||
> +		    now < evt->trigger_next)
>  			continue;
> -		switch (efi_events[i].trigger_type) {
> +		switch (evt->trigger_type) {
>  		case EFI_TIMER_RELATIVE:
> -			efi_events[i].trigger_type = EFI_TIMER_STOP;
> +			evt->trigger_type = EFI_TIMER_STOP;
>  			break;
>  		case EFI_TIMER_PERIODIC:
> -			efi_events[i].trigger_next +=
> -				efi_events[i].trigger_time;
> +			evt->trigger_next += evt->trigger_time;
>  			break;
>  		default:
>  			continue;
>  		}
> -		efi_events[i].is_signaled = true;
> -		efi_signal_event(&efi_events[i]);
> +		evt->is_signaled = true;
> +		efi_signal_event(evt);
>  	}
>  	WATCHDOG_RESET();
>  }
> @@ -485,7 +504,8 @@ void efi_timer_check(void)
>  efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type,
>  			   uint64_t trigger_time)
>  {
> -	int i;
> +	if (!efi_is_event(event))
> +		return EFI_INVALID_PARAMETER;
>  
>  	/*
>  	 * The parameter defines a multiple of 100ns.
> @@ -493,30 +513,25 @@ efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type,
>  	 */
>  	do_div(trigger_time, 10);
>  
> -	for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
> -		if (event != &efi_events[i])
> -			continue;
> +	if (!(event->type & EVT_TIMER))
> +		return EFI_INVALID_PARAMETER;
>  
> -		if (!(event->type & EVT_TIMER))
> -			break;
> -		switch (type) {
> -		case EFI_TIMER_STOP:
> -			event->trigger_next = -1ULL;
> -			break;
> -		case EFI_TIMER_PERIODIC:
> -		case EFI_TIMER_RELATIVE:
> -			event->trigger_next =
> -				timer_get_us() + trigger_time;
> -			break;
> -		default:
> -			return EFI_INVALID_PARAMETER;
> -		}
> -		event->trigger_type = type;
> -		event->trigger_time = trigger_time;
> -		event->is_signaled = false;
> -		return EFI_SUCCESS;
> +	switch (type) {
> +	case EFI_TIMER_STOP:
> +		event->trigger_next = -1ULL;
> +		break;
> +	case EFI_TIMER_PERIODIC:
> +	case EFI_TIMER_RELATIVE:
> +		event->trigger_next = timer_get_us() + trigger_time;
> +		break;
> +	default:
> +		return EFI_INVALID_PARAMETER;
>  	}
> -	return EFI_INVALID_PARAMETER;
> +	event->trigger_type = type;
> +	event->trigger_time = trigger_time;
> +	event->is_signaled = false;
> +
> +	return EFI_SUCCESS;
>  }
>  
>  /*
> @@ -555,7 +570,7 @@ static efi_status_t EFIAPI efi_wait_for_event(unsigned long num_events,
>  					      struct efi_event **event,
>  					      size_t *index)
>  {
> -	int i, j;
> +	int i;
>  
>  	EFI_ENTRY("%ld, %p, %p", num_events, event, index);
>  
> @@ -566,12 +581,8 @@ static efi_status_t EFIAPI efi_wait_for_event(unsigned long num_events,
>  	if (efi_tpl != TPL_APPLICATION)
>  		return EFI_EXIT(EFI_UNSUPPORTED);
>  	for (i = 0; i < num_events; ++i) {
> -		for (j = 0; j < ARRAY_SIZE(efi_events); ++j) {
> -			if (event[i] == &efi_events[j])
> -				goto known_event;
> -		}
> -		return EFI_EXIT(EFI_INVALID_PARAMETER);
> -known_event:
> +		if (!efi_is_event(event[i]))
> +			return EFI_EXIT(EFI_INVALID_PARAMETER);
>  		if (!event[i]->type || event[i]->type & EVT_NOTIFY_SIGNAL)
>  			return EFI_EXIT(EFI_INVALID_PARAMETER);
>  		if (!event[i]->is_signaled)
> @@ -614,19 +625,12 @@ out:
>   */
>  static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event)
>  {
> -	int i;
> -
>  	EFI_ENTRY("%p", event);
> -	for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
> -		if (event != &efi_events[i])
> -			continue;
> -		if (event->is_signaled)
> -			break;
> -		event->is_signaled = true;
> -		if (event->type & EVT_NOTIFY_SIGNAL)
> -			efi_signal_event(event);
> -		break;
> -	}
> +	if (!efi_is_event(event))
> +		return EFI_EXIT(EFI_INVALID_PARAMETER);
> +	event->is_signaled = true;
> +	if (event->type & EVT_NOTIFY_SIGNAL)
> +		efi_signal_event(event);
>  	return EFI_EXIT(EFI_SUCCESS);
>  }
>  
> @@ -642,19 +646,10 @@ static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event)
>   */
>  static efi_status_t EFIAPI efi_close_event(struct efi_event *event)
>  {
> -	int i;
> -
>  	EFI_ENTRY("%p", event);
> -	for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
> -		if (event == &efi_events[i]) {
> -			event->type = 0;
> -			event->trigger_next = -1ULL;
> -			event->is_queued = false;
> -			event->is_signaled = false;
> -			return EFI_EXIT(EFI_SUCCESS);
> -		}
> -	}
> -	return EFI_EXIT(EFI_INVALID_PARAMETER);
> +	list_del(&event->link);
> +	free(event);
> +	return EFI_EXIT(EFI_SUCCESS);
>  }
>  
>  /*
> @@ -664,29 +659,37 @@ static efi_status_t EFIAPI efi_close_event(struct efi_event *event)
>   * See the Unified Extensible Firmware Interface (UEFI) specification
>   * for details.
>   *
> - * If an event is not signaled yet the notification function is queued.
> + * - If Event is in the signaled state, it is cleared and EFI_SUCCESS
> + *   is returned.
> + *
> + * - If Event is not in the signaled state and has no notification
> + *   function, EFI_NOT_READY is returned.
> + *
> + * - If Event is not in the signaled state but does have a notification
> + *   function, the notification function is queued at the event’s
> + *   notification task priority level. If the execution of the
> + *   notification function causes Event to be signaled, then the signaled
> + *   state is cleared and EFI_SUCCESS is returned; if the Event is not
> + *   signaled, then EFI_NOT_READY is returned.
>   *
>   * @event	event to check
>   * @return	status code
>   */
> -static efi_status_t EFIAPI efi_check_event(struct efi_event *event)
> +/*
> + */

I assume this is one comment block too much?

> +static efi_status_t EFIAPI efi_check_event(struct efi_event *evt)
>  {


Alex

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 08/11] efi_loader: implement SetWatchdogTimer
  2017-10-10 12:23 ` [U-Boot] [PATCH 08/11] efi_loader: implement SetWatchdogTimer Rob Clark
@ 2017-10-11 14:55   ` Alexander Graf
  0 siblings, 0 replies; 75+ messages in thread
From: Alexander Graf @ 2017-10-11 14:55 UTC (permalink / raw)
  To: u-boot



On 10.10.17 14:23, Rob Clark wrote:
> From: Heinrich Schuchardt <xypron.glpk@gmx.de>
> 
> The watchdog is initialized with a 5 minute timeout period.
> It can be reset by SetWatchdogTimer.
> It is stopped by ExitBoottimeServices.
> 
> Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>

This is missing an SoB line from Rob.

Reviewed-by: Alexander Graf <agraf@suse.de>


Alex

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 09/11] efi_loader: Fix disk dp's for pre-DM/legacy devices
  2017-10-10 12:23 ` [U-Boot] [PATCH 09/11] efi_loader: Fix disk dp's for pre-DM/legacy devices Rob Clark
@ 2017-10-11 14:56   ` Alexander Graf
  0 siblings, 0 replies; 75+ messages in thread
From: Alexander Graf @ 2017-10-11 14:56 UTC (permalink / raw)
  To: u-boot



On 10.10.17 14:23, Rob Clark wrote:
> This fixes an issue with OpenBSD's bootloader, and I think should also
> fix a similar issue with grub2 on legacy devices.  In the legacy case
> we were creating disk objects for the partitions, but not also the
> parent device.
> 
> Reported-by: Jonathan Gray <jsg@jsg.id.au>
> Signed-off-by: Rob Clark <robdclark@gmail.com>

This patch is already in efi-next?


Alex

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 10/11] efi_loader: Add mem-mapped for fallback
  2017-10-10 12:23 ` [U-Boot] [PATCH 10/11] efi_loader: Add mem-mapped for fallback Rob Clark
  2017-10-10 22:31   ` Heinrich Schuchardt
@ 2017-10-11 14:59   ` Alexander Graf
  2017-10-11 22:14     ` Rob Clark
  2017-10-12 15:24   ` [U-Boot] [U-Boot, " Alexander Graf
  2 siblings, 1 reply; 75+ messages in thread
From: Alexander Graf @ 2017-10-11 14:59 UTC (permalink / raw)
  To: u-boot



On 10.10.17 14:23, Rob Clark wrote:
> When we don't have a real device/image path, such as 'bootefi hello',
> construct a mem-mapped device-path.
> 
> This fixes 'bootefi hello' after devicepath refactoring.
> 
> Fixes: 95c5553ea2 ("efi_loader: refactor boot device and loaded_image handling")
> Signed-off-by: Rob Clark <robdclark@gmail.com>
> ---
>  cmd/bootefi.c                            | 23 +++++++++++++++++++++++
>  include/efi_api.h                        |  8 ++++++++
>  include/efi_loader.h                     |  3 +++
>  lib/efi_loader/efi_device_path.c         | 24 ++++++++++++++++++++++++
>  lib/efi_loader/efi_device_path_to_text.c |  9 +++++++++
>  5 files changed, 67 insertions(+)
> 
> diff --git a/cmd/bootefi.c b/cmd/bootefi.c
> index 24958ada46..18176a1266 100644
> --- a/cmd/bootefi.c
> +++ b/cmd/bootefi.c
> @@ -128,6 +128,7 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt,
>  {
>  	struct efi_loaded_image loaded_image_info = {};
>  	struct efi_object loaded_image_info_obj = {};
> +	struct efi_device_path *memdp = NULL;
>  	ulong ret;
>  
>  	ulong (*entry)(void *image_handle, struct efi_system_table *st)
> @@ -136,6 +137,20 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt,
>  	const efi_guid_t fdt_guid = EFI_FDT_GUID;
>  	bootm_headers_t img = { 0 };
>  
> +	/*
> +	 * Special case for efi payload not loaded from disk, such as
> +	 * 'bootefi hello' or for example payload loaded directly into
> +	 * memory via jtag/etc:
> +	 */
> +	if (!device_path && !image_path) {
> +		printf("WARNING: using memory device/image path, this may confuse some payloads!\n");
> +		/* actual addresses filled in after efi_load_pe() */
> +		memdp = efi_dp_from_mem(0, 0, 0);
> +		device_path = image_path = memdp;
> +	} else {
> +		assert(device_path && image_path);
> +	}
> +
>  	/* Initialize and populate EFI object list */
>  	if (!efi_obj_list_initalized)
>  		efi_init_obj_list();
> @@ -182,6 +197,14 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt,
>  		goto exit;
>  	}
>  
> +	if (memdp) {
> +		struct efi_device_path_memory *mdp = (void *)memdp;
> +		mdp->memory_type = loaded_image_info.image_code_type;
> +		mdp->start_address = (uintptr_t)loaded_image_info.image_base;
> +		mdp->end_address = mdp->start_address +
> +				loaded_image_info.image_size;
> +	}
> +

memdp gets leaked after bootefi is done. Putting it on the stack would
at least remove that problem ;). We currently expect to only return from
bootefi when a payload was successfully quit.


Alex

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 03/11] efi_loader: Initial EFI_UNICODE_COLLATION_PROTOCOL
  2017-10-11 14:36   ` Alexander Graf
@ 2017-10-11 20:30     ` Rob Clark
  2017-10-11 20:47       ` Alexander Graf
  0 siblings, 1 reply; 75+ messages in thread
From: Rob Clark @ 2017-10-11 20:30 UTC (permalink / raw)
  To: u-boot

On Wed, Oct 11, 2017 at 10:36 AM, Alexander Graf <agraf@suse.de> wrote:
>
>
> On 10.10.17 14:22, Rob Clark wrote:
>> From: Leif Lindholm <leif.lindholm@linaro.org>
>>
>> Not complete, but enough for Shell.efi and SCT.efi.
>>
>> Initial skeleton written by Leif, and then implementation by myself.
>>
>> Cc: Leif Lindholm <leif.lindholm@linaro.org>
>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>> ---
>>  include/efi_api.h             |  41 ++++++++++
>>  include/efi_loader.h          |   3 +
>>  lib/efi_loader/Makefile       |   2 +-
>>  lib/efi_loader/efi_boottime.c |   6 ++
>>  lib/efi_loader/efi_unicode.c  | 170 ++++++++++++++++++++++++++++++++++++++++++
>>  5 files changed, 221 insertions(+), 1 deletion(-)
>>  create mode 100644 lib/efi_loader/efi_unicode.c
>>
>> diff --git a/include/efi_api.h b/include/efi_api.h
>> index 164147dc87..38dd1240c1 100644
>> --- a/include/efi_api.h
>> +++ b/include/efi_api.h
>> @@ -797,6 +797,47 @@ struct efi_hii_string_protocol {
>>               efi_uintn_t *secondary_languages_size);
>>  };
>>
>> +/*
>> + * Both UNICODE_COLLATION protocols seem to be the same thing, but
>> + * advertised with two different GUID's because, why not?
>> + */
>> +
>> +#define EFI_UNICODE_COLLATION_PROTOCOL_GUID \
>> +     EFI_GUID(0x1d85cd7f, 0xf43d, 0x11d2, \
>> +              0x9a, 0x0c, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
>> +
>> +#define EFI_UNICODE_COLLATION_PROTOCOL2_GUID \
>> +     EFI_GUID(0xa4c751fc, 0x23ae, 0x4c3e, \
>> +              0x92, 0xe9, 0x49, 0x64, 0xcf, 0x63, 0xf3, 0x49)
>> +
>> +struct efi_unicode_collation_protocol {
>> +     efi_intn_t (EFIAPI *stri_coll)(
>> +             struct efi_unicode_collation_protocol *this,
>> +             efi_string_t s1,
>> +             efi_string_t s2);
>> +     bool (EFIAPI *metai_match)(
>> +             struct efi_unicode_collation_protocol *this,
>> +             efi_string_t string,
>> +             efi_string_t pattern);
>> +     void (EFIAPI *str_lwr)(
>> +             struct efi_unicode_collation_protocol *this,
>> +             efi_string_t string);
>> +     void (EFIAPI *str_upr)(
>> +             struct efi_unicode_collation_protocol *this,
>> +             efi_string_t string);
>> +     void (EFIAPI *fat_to_str)(
>> +             struct efi_unicode_collation_protocol *this,
>> +             efi_uintn_t fat_size,
>> +             uint8_t *fat,
>> +             efi_string_t string);
>> +     bool (EFIAPI *str_to_fat)(
>> +             struct efi_unicode_collation_protocol *this,
>> +             efi_string_t string,
>> +             efi_uintn_t fat_size,
>> +             uint8_t *fat);
>> +     uint8_t *supported_languages;
>> +};
>> +
>>  #define EFI_GOP_GUID \
>>       EFI_GUID(0x9042a9de, 0x23dc, 0x4a38, \
>>                0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a)
>> diff --git a/include/efi_loader.h b/include/efi_loader.h
>> index 591bf07e7a..af6812b2b4 100644
>> --- a/include/efi_loader.h
>> +++ b/include/efi_loader.h
>> @@ -83,6 +83,7 @@ extern const struct efi_device_path_utilities_protocol efi_device_path_utilities
>>  extern const struct efi_hii_config_routing_protocol efi_hii_config_routing;
>>  extern const struct efi_hii_database_protocol efi_hii_database;
>>  extern const struct efi_hii_string_protocol efi_hii_string;
>> +extern const struct efi_unicode_collation_protocol efi_unicode_collation;
>>
>>  uint16_t *efi_dp_str(struct efi_device_path *dp);
>>
>> @@ -97,6 +98,8 @@ extern const efi_guid_t efi_guid_device_path_utilities_protocol;
>>  extern const efi_guid_t efi_guid_hii_config_routing_protocol;
>>  extern const efi_guid_t efi_guid_hii_database_protocol;
>>  extern const efi_guid_t efi_guid_hii_string_protocol;
>> +extern const efi_guid_t efi_guid_unicode_collation_protocol;
>> +extern const efi_guid_t efi_guid_unicode_collation_protocol2;
>>
>>  extern unsigned int __efi_runtime_start, __efi_runtime_stop;
>>  extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;
>> diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
>> index 725e0cba85..7ea96a4f1c 100644
>> --- a/lib/efi_loader/Makefile
>> +++ b/lib/efi_loader/Makefile
>> @@ -17,7 +17,7 @@ endif
>>  obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o
>>  obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o
>>  obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o
>> -obj-y += efi_device_path_utilities.o efi_hii.o
>> +obj-y += efi_device_path_utilities.o efi_hii.o efi_unicode.o
>>  obj-y += efi_file.o efi_variable.o efi_bootmgr.o
>>  obj-$(CONFIG_LCD) += efi_gop.o
>>  obj-$(CONFIG_DM_VIDEO) += efi_gop.o
>> diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
>> index c179afc25a..b568f3f162 100644
>> --- a/lib/efi_loader/efi_boottime.c
>> +++ b/lib/efi_loader/efi_boottime.c
>> @@ -1166,6 +1166,12 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob
>>       obj->protocols[7].guid = &efi_guid_hii_config_routing_protocol;
>>       obj->protocols[7].protocol_interface = (void *)&efi_hii_config_routing;
>>
>> +     obj->protocols[8].guid = &efi_guid_unicode_collation_protocol;
>> +     obj->protocols[8].protocol_interface = (void *)&efi_unicode_collation;
>> +
>> +     obj->protocols[9].guid = &efi_guid_unicode_collation_protocol2;
>> +     obj->protocols[9].protocol_interface = (void *)&efi_unicode_collation;
>> +
>>       info->file_path = file_path;
>>       info->device_handle = efi_dp_find_obj(device_path, NULL);
>>
>> diff --git a/lib/efi_loader/efi_unicode.c b/lib/efi_loader/efi_unicode.c
>> new file mode 100644
>> index 0000000000..2c6302df25
>> --- /dev/null
>> +++ b/lib/efi_loader/efi_unicode.c
>> @@ -0,0 +1,170 @@
>> +/*
>> +*  EFI Unicode interface
>> + *
>> + *  Copyright (c) 2017 Leif Lindholm
>> + *
>> + *  SPDX-License-Identifier:     GPL-2.0+
>> + */
>> +
>> +#include <common.h>
>> +#include <charset.h>
>> +#include <linux/ctype.h>
>> +#include <efi_loader.h>
>> +
>> +const efi_guid_t efi_guid_unicode_collation_protocol =
>> +     EFI_UNICODE_COLLATION_PROTOCOL_GUID;
>> +
>> +const efi_guid_t efi_guid_unicode_collation_protocol2 =
>> +     EFI_UNICODE_COLLATION_PROTOCOL2_GUID;
>> +
>> +static int matchn(efi_string_t s1, unsigned n1, efi_string_t s2, unsigned n2)
>> +{
>> +     char u1[MAX_UTF8_PER_UTF16 * n1 + 1];
>> +     char u2[MAX_UTF8_PER_UTF16 * n2 + 1];
>> +
>> +     *utf16_to_utf8((u8 *)u1, s1, n1) = '\0';
>> +     *utf16_to_utf8((u8 *)u2, s2, n2) = '\0';
>> +
>> +     return strcasecmp(u1, u2);
>> +}
>> +
>> +static efi_intn_t EFIAPI stri_coll(struct efi_unicode_collation_protocol *this,
>> +                                efi_string_t s1,
>> +                                efi_string_t s2)
>> +{
>> +     EFI_ENTRY("%p, \"%ls\", \"%ls\"", this, s1, s2);
>> +
>> +     unsigned n1 = utf16_strlen(s1);
>> +     unsigned n2 = utf16_strlen(s2);
>> +
>> +     return EFI_EXIT(matchn(s1, n1, s2, n2));
>> +}
>> +
>> +static bool match(efi_string_t string, efi_string_t pattern)
>> +{
>> +     while (true) {
>> +             uint16_t p = *pattern++;
>> +             bool matches = false;
>> +
>> +             if (p == '\0' || *string == '\0') {
>> +                     /*
>> +                      * End of pattern or string, succeed if
>> +                      * end of both:
>> +                      */
>> +                     return *string == p;
>> +             }
>> +
>> +             switch (p) {
>> +             case '*':
>> +                     /* Match zero or more chars: */
>> +                     while (*string != '\0') {
>> +                             if (match(string, pattern))
>> +                                     return true;
>> +                             string++;
>> +                     }
>> +                     return match(string, pattern);
>> +             case '?':
>> +                     /* Match any one char: */
>> +                     string++;
>> +                     break;
>> +             case '[':
>> +                     /* Match char set, either [abc] or [a-c]: */
>> +
>> +                     if (pattern[0] == '\0' || pattern[0] == ']') {
>> +                             /* invalid pattern */
>> +                             return false;
>> +                     }
>> +
>> +                     if (pattern[1] == '-') {
>> +                             uint16_t lo, hi, c;
>> +
>> +                             /* range: [a-c] */
>> +                             lo = pattern[0];
>> +                             hi = pattern[2];
>> +
>> +                             if (hi == '\0' || hi == ']' || pattern[3] != ']') {
>> +                                     /* invalid pattern */
>> +                                     return false;
>> +                             }
>> +
>> +                             c  = tolower(*string);
>> +                             lo = tolower(lo);
>> +                             hi = tolower(hi);
>> +
>> +                             if (lo <= c && c <= hi)
>> +                                     matches = true;
>> +
>> +                             pattern += 4;
>> +                     } else {
>> +                             /* set: [abc] */
>> +                             while ((p = *pattern++) && p != ']')
>> +                                     if (matchn(string, 1, &p, 1))
>> +                                             matches = true;
>> +                     }
>> +
>> +                     if (!matches)
>> +                             return false;
>> +
>> +                     string++;
>> +                     break;
>> +             default:
>> +                     if (matchn(string, 1, &p, 1))
>> +                             return false;
>> +                     string++;
>> +                     break;
>> +             }
>> +     }
>> +}
>> +
>> +static bool EFIAPI metai_match(struct efi_unicode_collation_protocol *this,
>> +                            efi_string_t string,
>> +                            efi_string_t pattern)
>> +{
>> +     EFI_ENTRY("%p, \"%ls\", \"%ls\"", this, string, pattern);
>> +     return EFI_EXIT(match(string, pattern));
>
> EFI_EXIT wants a success/failure parameter, not true/false (which can be
> randomly defined). Please either have match() return EFI return codes or
> convert it in here :).

That isn't strictly true, it does use typeof(ret).. and while it masks
the resulting debug msg with ~EFI_ERROR_MASK, in practice it isn't a
problem with boolean return.  Just a bit funny.

And there already other EFI entry points that return something other
than efi_status_t..  trying to force them all into efi_status_t mold
makes them somewhat more awkward.

BR,
-R

>> +}
>> +
>> +static void EFIAPI str_lwr(struct efi_unicode_collation_protocol *this,
>> +                        efi_string_t string)
>> +{
>> +     EFI_ENTRY("%p, \"%ls\"", this, string);
>> +     EFI_EXIT(EFI_SUCCESS);
>
> This is not implemented, right? Better indicate that in the EFI_EXIT()
> hint so that someone tracing a log of calls will catch it later.
>
>> +     return;
>
> Not needed, no?
>
>> +}
>> +
>> +static void EFIAPI str_upr(struct efi_unicode_collation_protocol *this,
>> +                        efi_string_t string)
>> +{
>> +     EFI_ENTRY("%p, \"%ls\"", this, string);
>> +     EFI_EXIT(EFI_SUCCESS);
>
> Same here
>
>> +     return;
>> +}
>> +
>> +static void EFIAPI fat_to_str(struct efi_unicode_collation_protocol *this,
>> +                           efi_uintn_t fat_size,
>> +                           uint8_t *fat,
>> +                           efi_string_t string)
>> +{
>> +     EFI_ENTRY("%p, %zu, \"%s\", %p", this, fat_size, fat, string);
>> +     EFI_EXIT(EFI_SUCCESS);
>
> Same here
>
>> +     return;
>> +}
>> +
>> +static bool EFIAPI str_to_fat(struct efi_unicode_collation_protocol *this,
>> +                           efi_string_t string,
>> +                           efi_uintn_t fat_size,
>> +                           uint8_t *fat)
>> +{
>> +     EFI_ENTRY("%p, \"%ls\", %zu, %p", this, string, fat_size, fat);
>> +     return EFI_EXIT(false);
>
> Again, please don't pass true/false to EFI_EXIT().
>
>
> Alex
>
>> +}
>> +
>> +const struct efi_unicode_collation_protocol efi_unicode_collation = {
>> +     .stri_coll = stri_coll,
>> +     .metai_match = metai_match,
>> +     .str_lwr = str_lwr,
>> +     .str_upr = str_upr,
>> +     .fat_to_str = fat_to_str,
>> +     .str_to_fat = str_to_fat,
>> +     .supported_languages = (uint8_t *)"eng",
>> +};
>>

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 01/11] efi_loader: Initial EFI_DEVICE_PATH_UTILITIES_PROTOCOL
  2017-10-11 14:07   ` Alexander Graf
@ 2017-10-11 20:32     ` Rob Clark
  2017-10-12  6:51       ` Heinrich Schuchardt
  0 siblings, 1 reply; 75+ messages in thread
From: Rob Clark @ 2017-10-11 20:32 UTC (permalink / raw)
  To: u-boot

On Wed, Oct 11, 2017 at 10:07 AM, Alexander Graf <agraf@suse.de> wrote:
>
>
> On 10.10.17 14:22, Rob Clark wrote:
>> From: Leif Lindholm <leif.lindholm@linaro.org>
>>
>> Not complete, but enough for Shell.efi and SCT.efi.  We'll implement the
>> rest as needed or once we have SCT running properly so there is a way to
>> validate the interface against the conformance test suite.
>>
>> Initial skeleton written by Leif, and then implementation by myself.
>>
>> Cc: Leif Lindholm <leif.lindholm@linaro.org>
>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>> ---
>>  include/efi_api.h                          | 34 +++++++++++-
>>  include/efi_loader.h                       |  2 +
>>  lib/efi_loader/Makefile                    |  1 +
>>  lib/efi_loader/efi_boottime.c              |  4 ++
>>  lib/efi_loader/efi_device_path_utilities.c | 88 ++++++++++++++++++++++++++++++
>>  5 files changed, 127 insertions(+), 2 deletions(-)
>>  create mode 100644 lib/efi_loader/efi_device_path_utilities.c
>>
>> diff --git a/include/efi_api.h b/include/efi_api.h
>> index a9a6494afe..ffdba7fe1a 100644
>> --- a/include/efi_api.h
>> +++ b/include/efi_api.h
>> @@ -28,8 +28,9 @@ enum efi_timer_delay {
>>       EFI_TIMER_RELATIVE = 2
>>  };
>>
>> -#define UINTN size_t
>> -typedef long INTN;
>> +#define UINTN size_t   /* TODO this should be removed in a future patch */
>
> $ git grep UINTN | wc -l
> 13
>
> Just send a preceding patch that introduces efi_uintn_t and replaces all
> occurences of UINTN with it.
>
> The uintn bits shouldn't be part of the
> EFI_DEVICE_PATH_UTILITIES_PROTOCOL patch anyways :).
>

Heinrich mentioned he was doing that, so I didn't want to step on
feet.  I figured this was the easiest approach regardless of the order
of merging patches (should be simple enough to drop the duplicate
efi_uintn_t)

BR,
-R

>> +typedef size_t efi_uintn_t;
>> +typedef ssize_t efi_intn_t;
>>  typedef uint16_t *efi_string_t;
>
>
> Alex

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 03/11] efi_loader: Initial EFI_UNICODE_COLLATION_PROTOCOL
  2017-10-11 20:30     ` Rob Clark
@ 2017-10-11 20:47       ` Alexander Graf
  2017-10-12 11:54         ` Alexander Graf
  0 siblings, 1 reply; 75+ messages in thread
From: Alexander Graf @ 2017-10-11 20:47 UTC (permalink / raw)
  To: u-boot



On 11.10.17 22:30, Rob Clark wrote:
> On Wed, Oct 11, 2017 at 10:36 AM, Alexander Graf <agraf@suse.de> wrote:
>>
>>
>> On 10.10.17 14:22, Rob Clark wrote:
>>> From: Leif Lindholm <leif.lindholm@linaro.org>
>>>
>>> Not complete, but enough for Shell.efi and SCT.efi.
>>>
>>> Initial skeleton written by Leif, and then implementation by myself.
>>>
>>> Cc: Leif Lindholm <leif.lindholm@linaro.org>
>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>> ---
>>>  include/efi_api.h             |  41 ++++++++++
>>>  include/efi_loader.h          |   3 +
>>>  lib/efi_loader/Makefile       |   2 +-
>>>  lib/efi_loader/efi_boottime.c |   6 ++
>>>  lib/efi_loader/efi_unicode.c  | 170 ++++++++++++++++++++++++++++++++++++++++++
>>>  5 files changed, 221 insertions(+), 1 deletion(-)
>>>  create mode 100644 lib/efi_loader/efi_unicode.c
>>>
>>> diff --git a/include/efi_api.h b/include/efi_api.h
>>> index 164147dc87..38dd1240c1 100644
>>> --- a/include/efi_api.h
>>> +++ b/include/efi_api.h
>>> @@ -797,6 +797,47 @@ struct efi_hii_string_protocol {
>>>               efi_uintn_t *secondary_languages_size);
>>>  };
>>>
>>> +/*
>>> + * Both UNICODE_COLLATION protocols seem to be the same thing, but
>>> + * advertised with two different GUID's because, why not?
>>> + */
>>> +
>>> +#define EFI_UNICODE_COLLATION_PROTOCOL_GUID \
>>> +     EFI_GUID(0x1d85cd7f, 0xf43d, 0x11d2, \
>>> +              0x9a, 0x0c, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
>>> +
>>> +#define EFI_UNICODE_COLLATION_PROTOCOL2_GUID \
>>> +     EFI_GUID(0xa4c751fc, 0x23ae, 0x4c3e, \
>>> +              0x92, 0xe9, 0x49, 0x64, 0xcf, 0x63, 0xf3, 0x49)
>>> +
>>> +struct efi_unicode_collation_protocol {
>>> +     efi_intn_t (EFIAPI *stri_coll)(
>>> +             struct efi_unicode_collation_protocol *this,
>>> +             efi_string_t s1,
>>> +             efi_string_t s2);
>>> +     bool (EFIAPI *metai_match)(
>>> +             struct efi_unicode_collation_protocol *this,
>>> +             efi_string_t string,
>>> +             efi_string_t pattern);
>>> +     void (EFIAPI *str_lwr)(
>>> +             struct efi_unicode_collation_protocol *this,
>>> +             efi_string_t string);
>>> +     void (EFIAPI *str_upr)(
>>> +             struct efi_unicode_collation_protocol *this,
>>> +             efi_string_t string);
>>> +     void (EFIAPI *fat_to_str)(
>>> +             struct efi_unicode_collation_protocol *this,
>>> +             efi_uintn_t fat_size,
>>> +             uint8_t *fat,
>>> +             efi_string_t string);
>>> +     bool (EFIAPI *str_to_fat)(
>>> +             struct efi_unicode_collation_protocol *this,
>>> +             efi_string_t string,
>>> +             efi_uintn_t fat_size,
>>> +             uint8_t *fat);
>>> +     uint8_t *supported_languages;
>>> +};
>>> +
>>>  #define EFI_GOP_GUID \
>>>       EFI_GUID(0x9042a9de, 0x23dc, 0x4a38, \
>>>                0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a)
>>> diff --git a/include/efi_loader.h b/include/efi_loader.h
>>> index 591bf07e7a..af6812b2b4 100644
>>> --- a/include/efi_loader.h
>>> +++ b/include/efi_loader.h
>>> @@ -83,6 +83,7 @@ extern const struct efi_device_path_utilities_protocol efi_device_path_utilities
>>>  extern const struct efi_hii_config_routing_protocol efi_hii_config_routing;
>>>  extern const struct efi_hii_database_protocol efi_hii_database;
>>>  extern const struct efi_hii_string_protocol efi_hii_string;
>>> +extern const struct efi_unicode_collation_protocol efi_unicode_collation;
>>>
>>>  uint16_t *efi_dp_str(struct efi_device_path *dp);
>>>
>>> @@ -97,6 +98,8 @@ extern const efi_guid_t efi_guid_device_path_utilities_protocol;
>>>  extern const efi_guid_t efi_guid_hii_config_routing_protocol;
>>>  extern const efi_guid_t efi_guid_hii_database_protocol;
>>>  extern const efi_guid_t efi_guid_hii_string_protocol;
>>> +extern const efi_guid_t efi_guid_unicode_collation_protocol;
>>> +extern const efi_guid_t efi_guid_unicode_collation_protocol2;
>>>
>>>  extern unsigned int __efi_runtime_start, __efi_runtime_stop;
>>>  extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;
>>> diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
>>> index 725e0cba85..7ea96a4f1c 100644
>>> --- a/lib/efi_loader/Makefile
>>> +++ b/lib/efi_loader/Makefile
>>> @@ -17,7 +17,7 @@ endif
>>>  obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o
>>>  obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o
>>>  obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o
>>> -obj-y += efi_device_path_utilities.o efi_hii.o
>>> +obj-y += efi_device_path_utilities.o efi_hii.o efi_unicode.o
>>>  obj-y += efi_file.o efi_variable.o efi_bootmgr.o
>>>  obj-$(CONFIG_LCD) += efi_gop.o
>>>  obj-$(CONFIG_DM_VIDEO) += efi_gop.o
>>> diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
>>> index c179afc25a..b568f3f162 100644
>>> --- a/lib/efi_loader/efi_boottime.c
>>> +++ b/lib/efi_loader/efi_boottime.c
>>> @@ -1166,6 +1166,12 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob
>>>       obj->protocols[7].guid = &efi_guid_hii_config_routing_protocol;
>>>       obj->protocols[7].protocol_interface = (void *)&efi_hii_config_routing;
>>>
>>> +     obj->protocols[8].guid = &efi_guid_unicode_collation_protocol;
>>> +     obj->protocols[8].protocol_interface = (void *)&efi_unicode_collation;
>>> +
>>> +     obj->protocols[9].guid = &efi_guid_unicode_collation_protocol2;
>>> +     obj->protocols[9].protocol_interface = (void *)&efi_unicode_collation;
>>> +
>>>       info->file_path = file_path;
>>>       info->device_handle = efi_dp_find_obj(device_path, NULL);
>>>
>>> diff --git a/lib/efi_loader/efi_unicode.c b/lib/efi_loader/efi_unicode.c
>>> new file mode 100644
>>> index 0000000000..2c6302df25
>>> --- /dev/null
>>> +++ b/lib/efi_loader/efi_unicode.c
>>> @@ -0,0 +1,170 @@
>>> +/*
>>> +*  EFI Unicode interface
>>> + *
>>> + *  Copyright (c) 2017 Leif Lindholm
>>> + *
>>> + *  SPDX-License-Identifier:     GPL-2.0+
>>> + */
>>> +
>>> +#include <common.h>
>>> +#include <charset.h>
>>> +#include <linux/ctype.h>
>>> +#include <efi_loader.h>
>>> +
>>> +const efi_guid_t efi_guid_unicode_collation_protocol =
>>> +     EFI_UNICODE_COLLATION_PROTOCOL_GUID;
>>> +
>>> +const efi_guid_t efi_guid_unicode_collation_protocol2 =
>>> +     EFI_UNICODE_COLLATION_PROTOCOL2_GUID;
>>> +
>>> +static int matchn(efi_string_t s1, unsigned n1, efi_string_t s2, unsigned n2)
>>> +{
>>> +     char u1[MAX_UTF8_PER_UTF16 * n1 + 1];
>>> +     char u2[MAX_UTF8_PER_UTF16 * n2 + 1];
>>> +
>>> +     *utf16_to_utf8((u8 *)u1, s1, n1) = '\0';
>>> +     *utf16_to_utf8((u8 *)u2, s2, n2) = '\0';
>>> +
>>> +     return strcasecmp(u1, u2);
>>> +}
>>> +
>>> +static efi_intn_t EFIAPI stri_coll(struct efi_unicode_collation_protocol *this,
>>> +                                efi_string_t s1,
>>> +                                efi_string_t s2)
>>> +{
>>> +     EFI_ENTRY("%p, \"%ls\", \"%ls\"", this, s1, s2);
>>> +
>>> +     unsigned n1 = utf16_strlen(s1);
>>> +     unsigned n2 = utf16_strlen(s2);
>>> +
>>> +     return EFI_EXIT(matchn(s1, n1, s2, n2));
>>> +}
>>> +
>>> +static bool match(efi_string_t string, efi_string_t pattern)
>>> +{
>>> +     while (true) {
>>> +             uint16_t p = *pattern++;
>>> +             bool matches = false;
>>> +
>>> +             if (p == '\0' || *string == '\0') {
>>> +                     /*
>>> +                      * End of pattern or string, succeed if
>>> +                      * end of both:
>>> +                      */
>>> +                     return *string == p;
>>> +             }
>>> +
>>> +             switch (p) {
>>> +             case '*':
>>> +                     /* Match zero or more chars: */
>>> +                     while (*string != '\0') {
>>> +                             if (match(string, pattern))
>>> +                                     return true;
>>> +                             string++;
>>> +                     }
>>> +                     return match(string, pattern);
>>> +             case '?':
>>> +                     /* Match any one char: */
>>> +                     string++;
>>> +                     break;
>>> +             case '[':
>>> +                     /* Match char set, either [abc] or [a-c]: */
>>> +
>>> +                     if (pattern[0] == '\0' || pattern[0] == ']') {
>>> +                             /* invalid pattern */
>>> +                             return false;
>>> +                     }
>>> +
>>> +                     if (pattern[1] == '-') {
>>> +                             uint16_t lo, hi, c;
>>> +
>>> +                             /* range: [a-c] */
>>> +                             lo = pattern[0];
>>> +                             hi = pattern[2];
>>> +
>>> +                             if (hi == '\0' || hi == ']' || pattern[3] != ']') {
>>> +                                     /* invalid pattern */
>>> +                                     return false;
>>> +                             }
>>> +
>>> +                             c  = tolower(*string);
>>> +                             lo = tolower(lo);
>>> +                             hi = tolower(hi);
>>> +
>>> +                             if (lo <= c && c <= hi)
>>> +                                     matches = true;
>>> +
>>> +                             pattern += 4;
>>> +                     } else {
>>> +                             /* set: [abc] */
>>> +                             while ((p = *pattern++) && p != ']')
>>> +                                     if (matchn(string, 1, &p, 1))
>>> +                                             matches = true;
>>> +                     }
>>> +
>>> +                     if (!matches)
>>> +                             return false;
>>> +
>>> +                     string++;
>>> +                     break;
>>> +             default:
>>> +                     if (matchn(string, 1, &p, 1))
>>> +                             return false;
>>> +                     string++;
>>> +                     break;
>>> +             }
>>> +     }
>>> +}
>>> +
>>> +static bool EFIAPI metai_match(struct efi_unicode_collation_protocol *this,
>>> +                            efi_string_t string,
>>> +                            efi_string_t pattern)
>>> +{
>>> +     EFI_ENTRY("%p, \"%ls\", \"%ls\"", this, string, pattern);
>>> +     return EFI_EXIT(match(string, pattern));
>>
>> EFI_EXIT wants a success/failure parameter, not true/false (which can be
>> randomly defined). Please either have match() return EFI return codes or
>> convert it in here :).
> 
> That isn't strictly true, it does use typeof(ret).. and while it masks
> the resulting debug msg with ~EFI_ERROR_MASK, in practice it isn't a
> problem with boolean return.  Just a bit funny.
> 
> And there already other EFI entry points that return something other
> than efi_status_t..  trying to force them all into efi_status_t mold
> makes them somewhat more awkward.

Well, anything that casts well into an integer is reasonably valid for
EFI_EXIT(). But with bool things aren't always as clear as they should
be. I'm for example not 100% sure if the return value of a bool function
can never be different from 0 or 1.

So please just use something more obvious and keep bool values as inputs
for conditional branches :). Even something like EFI_EXIT(foo ? EFI_TRUE
: EFI_FALSE); would work for me. Or you just make the return type of
those functions an enum efi_bool.

The resulting code should basically be the same if the compiler is
smart, but at least I'm 100% sure when reading it that it does "the
right thing".


Alex

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 02/11] efi_loader: Initial HII protocols
  2017-10-11 14:30   ` Alexander Graf
@ 2017-10-11 22:02     ` Rob Clark
  2017-10-12  7:13       ` Alexander Graf
  0 siblings, 1 reply; 75+ messages in thread
From: Rob Clark @ 2017-10-11 22:02 UTC (permalink / raw)
  To: u-boot

On Wed, Oct 11, 2017 at 10:30 AM, Alexander Graf <agraf@suse.de> wrote:
>
>
> On 10.10.17 14:22, Rob Clark wrote:
>> From: Leif Lindholm <leif.lindholm@linaro.org>
>>
>> Enough implementation of the following protocols to run Shell.efi and
>> SCT.efi:
>>
>>   EfiHiiConfigRoutingProtocolGuid
>>   EfiHiiDatabaseProtocol
>>   EfiHiiStringProtocol
>>
>> We'll fill in the rest once SCT is running properly so we can validate
>> the implementation against the conformance test suite.
>>
>> Initial skeleton written by Leif, and then implementation by myself.
>>
>> Cc: Leif Lindholm <leif.lindholm@linaro.org>
>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>> ---
>>  include/efi_api.h             | 261 ++++++++++++++++++++++
>>  include/efi_loader.h          |   6 +
>>  lib/efi_loader/Makefile       |   2 +-
>>  lib/efi_loader/efi_boottime.c |   9 +
>>  lib/efi_loader/efi_hii.c      | 507 ++++++++++++++++++++++++++++++++++++++++++
>>  5 files changed, 784 insertions(+), 1 deletion(-)
>>  create mode 100644 lib/efi_loader/efi_hii.c
>>
>> diff --git a/include/efi_api.h b/include/efi_api.h
>> index ffdba7fe1a..164147dc87 100644
>> --- a/include/efi_api.h
>> +++ b/include/efi_api.h
>> @@ -16,6 +16,7 @@
>>  #define _EFI_API_H
>>
>>  #include <efi.h>
>> +#include <charset.h>
>>
>>  #ifdef CONFIG_EFI_LOADER
>>  #include <asm/setjmp.h>
>> @@ -536,6 +537,266 @@ struct efi_device_path_utilities_protocol {
>>               uint16_t node_length);
>>  };
>>
>> +#define EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID \
>> +     EFI_GUID(0x587e72d7, 0xcc50, 0x4f79, \
>> +              0x82, 0x09, 0xca, 0x29, 0x1f, 0xc1, 0xa1, 0x0f)
>> +
>> +typedef uint16_t efi_string_id_t;
>> +
>> +struct efi_hii_config_routing_protocol {
>> +     efi_status_t(EFIAPI *extract_config)(
>> +             const struct efi_hii_config_routing_protocol *this,
>> +             const efi_string_t request,
>> +             efi_string_t *progress,
>> +             efi_string_t *results);
>> +     efi_status_t(EFIAPI *export_config)(
>> +             const struct efi_hii_config_routing_protocol *this,
>> +             efi_string_t *results);
>> +     efi_status_t(EFIAPI *route_config)(
>> +             const struct efi_hii_config_routing_protocol *this,
>> +             const efi_string_t configuration,
>> +             efi_string_t *progress);
>> +     efi_status_t(EFIAPI *block_to_config)(
>> +             const struct efi_hii_config_routing_protocol *this,
>> +             const efi_string_t config_request,
>> +             const uint8_t *block,
>> +             const efi_uintn_t block_size,
>> +             efi_string_t *config,
>> +             efi_string_t *progress);
>> +     efi_status_t(EFIAPI *config_to_block)(
>> +             const struct efi_hii_config_routing_protocol *this,
>> +             const efi_string_t config_resp,
>> +             const uint8_t *block,
>> +             const efi_uintn_t *block_size,
>> +             efi_string_t *progress);
>> +     efi_status_t(EFIAPI *get_alt_config)(
>> +             const struct efi_hii_config_routing_protocol *this,
>> +             const efi_string_t config_resp,
>> +             const efi_guid_t *guid,
>> +             const efi_string_t name,
>> +             const struct efi_device_path *device_path,
>> +             const efi_string_t alt_cfg_id,
>> +             efi_string_t *alt_cfg_resp);
>> +};
>> +
>> +#define EFI_HII_DATABASE_PROTOCOL_GUID            \
>> +     EFI_GUID(0xef9fc172, 0xa1b2, 0x4693, \
>> +              0xb3, 0x27, 0x6d, 0x32, 0xfc, 0x41, 0x60, 0x42)
>> +
>> +typedef enum {
>> +     EFI_KEY_LCTRL, EFI_KEY_A0, EFI_KEY_LALT, EFI_KEY_SPACE_BAR,
>> +     EFI_KEY_A2, EFI_KEY_A3, EFI_KEY_A4, EFI_KEY_RCTRL, EFI_KEY_LEFT_ARROW,
>> +     EFI_KEY_DOWN_ARROW, EFI_KEY_RIGHT_ARROW, EFI_KEY_ZERO,
>> +     EFI_KEY_PERIOD, EFI_KEY_ENTER, EFI_KEY_LSHIFT, EFI_KEY_B0,
>> +     EFI_KEY_B1, EFI_KEY_B2, EFI_KEY_B3, EFI_KEY_B4, EFI_KEY_B5, EFI_KEY_B6,
>> +     EFI_KEY_B7, EFI_KEY_B8, EFI_KEY_B9, EFI_KEY_B10, EFI_KEY_RSHIFT,
>> +     EFI_KEY_UP_ARROW, EFI_KEY_ONE, EFI_KEY_TWO, EFI_KEY_THREE,
>> +     EFI_KEY_CAPS_LOCK, EFI_KEY_C1, EFI_KEY_C2, EFI_KEY_C3, EFI_KEY_C4,
>> +     EFI_KEY_C5, EFI_KEY_C6, EFI_KEY_C7, EFI_KEY_C8, EFI_KEY_C9,
>> +     EFI_KEY_C10, EFI_KEY_C11, EFI_KEY_C12, EFI_KEY_FOUR, EFI_KEY_FIVE,
>> +     EFI_KEY_SIX, EFI_KEY_PLUS, EFI_KEY_TAB, EFI_KEY_D1, EFI_KEY_D2,
>> +     EFI_KEY_D3, EFI_KEY_D4, EFI_KEY_D5, EFI_KEY_D6, EFI_KEY_D7, EFI_KEY_D8,
>> +     EFI_KEY_D9, EFI_KEY_D10, EFI_KEY_D11, EFI_KEY_D12, EFI_KEY_D13,
>> +     EFI_KEY_DEL, EFI_KEY_END, EFI_KEY_PG_DN, EFI_KEY_SEVEN, EFI_KEY_EIGHT,
>> +     EFI_KEY_NINE, EFI_KEY_E0, EFI_KEY_E1, EFI_KEY_E2, EFI_KEY_E3,
>> +     EFI_KEY_E4, EFI_KEY_E5, EFI_KEY_E6, EFI_KEY_E7, EFI_KEY_E8, EFI_KEY_E9,
>> +     EFI_KEY_E10, EFI_KEY_E11, EFI_KEY_E12, EFI_KEY_BACK_SPACE,
>> +     EFI_KEY_INS, EFI_KEY_HOME, EFI_KEY_PG_UP, EFI_KEY_NLCK, EFI_KEY_SLASH,
>> +     EFI_KEY_ASTERISK, EFI_KEY_MINUS, EFI_KEY_ESC, EFI_KEY_F1, EFI_KEY_F2,
>> +     EFI_KEY_F3, EFI_KEY_F4, EFI_KEY_F5, EFI_KEY_F6, EFI_KEY_F7, EFI_KEY_F8,
>> +     EFI_KEY_F9, EFI_KEY_F10, EFI_KEY_F11, EFI_KEY_F12, EFI_KEY_PRINT,
>> +     EFI_KEY_SLCK, EFI_KEY_PAUSE,
>> +} efi_key;
>> +
>> +struct efi_key_descriptor {
>> +     efi_key key;
>> +     uint16_t unicode;
>> +     uint16_t shifted_unicode;
>> +     uint16_t alt_gr_unicode;
>> +     uint16_t shifted_alt_gr_unicode;
>> +     uint16_t modifier;
>> +     uint16_t affected_attribute;
>> +};
>> +
>> +struct efi_hii_keyboard_layout {
>> +     uint16_t layout_length;
>> +     efi_guid_t guid;
>> +     uint32_t layout_descriptor_string_offset;
>> +     uint8_t descriptor_count;
>> +     struct efi_key_descriptor descriptors[];
>> +};
>> +
>> +struct efi_hii_package_list_header {
>> +     efi_guid_t package_list_guid;
>> +     uint32_t package_length;
>> +} __packed;
>> +
>> +struct efi_hii_package_header {
>> +     uint32_t length : 24;
>> +     uint32_t type : 8;
>> +} __packed;
>
> Bitfields are terribly evil - they're probably one of the worst defined
> things in C. A different compiler may even give you different ordering
> here. I've certainly seen bitfields explode in weird ways on
> cross-endian conversions.

edk2 defines it in the same way.  And this is UEFI we are talking
about here, big endian is strictly out of scope.


> Do you think you could just make that a uint32_t altogether and work
> with MASK/SHIFT defines instead?
>
>
>> +
>> +#define EFI_HII_PACKAGE_TYPE_ALL          0x00
>> +#define EFI_HII_PACKAGE_TYPE_GUID         0x01
>> +#define EFI_HII_PACKAGE_FORMS             0x02
>> +#define EFI_HII_PACKAGE_STRINGS           0x04
>> +#define EFI_HII_PACKAGE_FONTS             0x05
>> +#define EFI_HII_PACKAGE_IMAGES            0x06
>> +#define EFI_HII_PACKAGE_SIMPLE_FONTS      0x07
>> +#define EFI_HII_PACKAGE_DEVICE_PATH       0x08
>> +#define EFI_HII_PACKAGE_KEYBOARD_LAYOUT   0x09
>> +#define EFI_HII_PACKAGE_ANIMATIONS        0x0A
>> +#define EFI_HII_PACKAGE_END               0xDF
>> +#define EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN 0xE0
>> +#define EFI_HII_PACKAGE_TYPE_SYSTEM_END   0xFF
>> +
>> +struct efi_hii_strings_package {
>> +     struct efi_hii_package_header header;
>> +     uint32_t header_size;
>> +     uint32_t string_info_offset;
>> +     uint16_t language_window[16];
>> +     efi_string_id_t language_name;
>> +     uint8_t  language[];
>> +} __packed;
>> +
>> +struct efi_hii_string_block {
>> +     uint8_t block_type;
>> +     /*uint8_t block_body[];*/
>> +} __packed;
>> +
>> +#define EFI_HII_SIBT_END               0x00 // The end of the string information.
>> +#define EFI_HII_SIBT_STRING_SCSU       0x10 // Single string using default font information.
>> +#define EFI_HII_SIBT_STRING_SCSU_FONT  0x11 // Single string with font information.
>> +#define EFI_HII_SIBT_STRINGS_SCSU      0x12 // Multiple strings using default font information.
>> +#define EFI_HII_SIBT_STRINGS_SCSU_FONT 0x13 // Multiple strings with font information.
>> +#define EFI_HII_SIBT_STRING_UCS2       0x14 // Single UCS-2 string using default font information.
>> +#define EFI_HII_SIBT_STRING_UCS2_FONT  0x15 // Single UCS-2 string with font information
>> +#define EFI_HII_SIBT_STRINGS_UCS2      0x16 // Multiple UCS-2 strings using default font information.
>> +#define EFI_HII_SIBT_STRINGS_UCS2_FONT 0x17 // Multiple UCS-2 strings with font information.
>> +#define EFI_HII_SIBT_DUPLICATE         0x20 // Create a duplicate of an existing string.
>> +#define EFI_HII_SIBT_SKIP2             0x21 // Skip a certain number of string identifiers.
>> +#define EFI_HII_SIBT_SKIP1             0x22 // Skip a certain number of string identifiers.
>> +#define EFI_HII_SIBT_EXT1              0x30 // For future expansion (one byte length field)
>> +#define EFI_HII_SIBT_EXT2              0x31 // For future expansion (two byte length field)
>> +#define EFI_HII_SIBT_EXT4              0x32 // For future expansion (four byte length field)
>> +#define EFI_HII_SIBT_FONT              0x40 // Font information.
>> +
>> +struct efi_hii_sibt_string_ucs2_block {
>> +     struct efi_hii_string_block header;
>> +     uint16_t string_text[];
>> +} __packed;
>> +
>> +static inline struct efi_hii_string_block *efi_hii_sibt_string_ucs2_block_next(
>> +     struct efi_hii_sibt_string_ucs2_block *blk)
>> +{
>> +     return ((void *)blk) + sizeof(*blk) +
>> +             (utf16_strlen(blk->string_text) + 1) * 2;
>
> Since you're dealing with actual utf16, is this correct? One character
> may as well span 4 bytes, right?
>
> I think we need a different function that actually tells us the bytes
> occupied by a utf16 string.

as mentioned on IRC (just repeating here for those who weren't
following #u-boot), utf16_strlen() is actually telling us the number
of 16b "bytes" in a utf16 string, not the number of "characters".
Similar to strlen() with a utf8 string.

>> +}
>> +
>> +typedef void *efi_hii_handle_t;
>> +
>> +struct efi_hii_database_protocol {
>> +     efi_status_t(EFIAPI *new_package_list)(
>> +             const struct efi_hii_database_protocol *this,
>> +             const struct efi_hii_package_list_header *package_list,
>> +             const efi_handle_t driver_handle,
>> +             efi_hii_handle_t *handle);
>> +     efi_status_t(EFIAPI *remove_package_list)(
>> +             const struct efi_hii_database_protocol *this,
>> +             efi_hii_handle_t handle);
>> +     efi_status_t(EFIAPI *update_package_list)(
>> +             const struct efi_hii_database_protocol *this,
>> +             efi_hii_handle_t handle,
>> +             const struct efi_hii_package_list_header *package_list);
>> +     efi_status_t(EFIAPI *list_package_lists)(
>> +             const struct efi_hii_database_protocol *this,
>> +             uint8_t package_type,
>> +             const efi_guid_t *package_guid,
>> +             efi_uintn_t *handle_buffer_length,
>> +             efi_hii_handle_t *handle);
>> +     efi_status_t(EFIAPI *export_package_lists)(
>> +             const struct efi_hii_database_protocol *this,
>> +             efi_hii_handle_t handle,
>> +             efi_uintn_t *buffer_size,
>> +             struct efi_hii_package_list_header *buffer);
>> +     efi_status_t(EFIAPI *register_package_notify)(
>> +             const struct efi_hii_database_protocol *this,
>> +             uint8_t package_type,
>> +             const efi_guid_t *package_guid,
>> +             const void *package_notify_fn,
>> +             efi_uintn_t notify_type,
>> +             efi_handle_t *notify_handle);
>> +     efi_status_t(EFIAPI *unregister_package_notify)(
>> +             const struct efi_hii_database_protocol *this,
>> +             efi_handle_t notification_handle
>> +             );
>> +     efi_status_t(EFIAPI *find_keyboard_layouts)(
>> +             const struct efi_hii_database_protocol *this,
>> +             uint16_t *key_guid_buffer_length,
>> +             efi_guid_t *key_guid_buffer);
>> +     efi_status_t(EFIAPI *get_keyboard_layout)(
>> +             const struct efi_hii_database_protocol *this,
>> +             efi_guid_t *key_guid,
>> +             uint16_t *keyboard_layout_length,
>> +             struct efi_hii_keyboard_layout *keyboard_layout);
>> +     efi_status_t(EFIAPI *set_keyboard_layout)(
>> +             const struct efi_hii_database_protocol *this,
>> +             efi_guid_t *key_guid);
>> +     efi_status_t(EFIAPI *get_package_list_handle)(
>> +             const struct efi_hii_database_protocol *this,
>> +             efi_hii_handle_t package_list_handle,
>> +             efi_handle_t *driver_handle);
>> +};
>> +
>> +#define EFI_HII_STRING_PROTOCOL_GUID \
>> +     EFI_GUID(0x0fd96974, 0x23aa, 0x4cdc, \
>> +              0xb9, 0xcb, 0x98, 0xd1, 0x77, 0x50, 0x32, 0x2a)
>> +
>> +typedef uint32_t efi_hii_font_style_t;
>> +
>> +struct efi_font_info {
>> +     efi_hii_font_style_t font_style;
>> +     uint16_t font_size;
>> +     uint16_t font_name[1];
>> +};
>> +
>> +struct efi_hii_string_protocol {
>> +     efi_status_t(EFIAPI *new_string)(
>> +             const struct efi_hii_string_protocol *this,
>> +             efi_hii_handle_t package_list,
>> +             efi_string_id_t *string_id,
>> +             const uint8_t *language,
>> +             const uint16_t *language_name,
>> +             const efi_string_t string,
>> +             const struct efi_font_info *string_font_info);
>> +     efi_status_t(EFIAPI *get_string)(
>> +             const struct efi_hii_string_protocol *this,
>> +             const uint8_t *language,
>> +             efi_hii_handle_t package_list,
>> +             efi_string_id_t string_id,
>> +             efi_string_t string,
>> +             efi_uintn_t *string_size,
>> +             struct efi_font_info **string_font_info);
>> +     efi_status_t(EFIAPI *set_string)(
>> +             const struct efi_hii_string_protocol *this,
>> +             efi_hii_handle_t package_list,
>> +             efi_string_id_t string_id,
>> +             const uint8_t *language,
>> +             const efi_string_t string,
>> +             const struct efi_font_info *string_font_info);
>> +     efi_status_t(EFIAPI *get_languages)(
>> +             const struct efi_hii_string_protocol *this,
>> +             efi_hii_handle_t package_list,
>> +             uint8_t *languages,
>> +             efi_uintn_t *languages_size);
>> +     efi_status_t(EFIAPI *get_secondary_languages)(
>> +             const struct efi_hii_string_protocol *this,
>> +             efi_hii_handle_t package_list,
>> +             const uint8_t *primary_language,
>> +             uint8_t *secondary_languages,
>> +             efi_uintn_t *secondary_languages_size);
>> +};
>> +
>>  #define EFI_GOP_GUID \
>>       EFI_GUID(0x9042a9de, 0x23dc, 0x4a38, \
>>                0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a)
>> diff --git a/include/efi_loader.h b/include/efi_loader.h
>> index 5d37c1d75f..591bf07e7a 100644
>> --- a/include/efi_loader.h
>> +++ b/include/efi_loader.h
>> @@ -80,6 +80,9 @@ extern struct efi_simple_input_interface efi_con_in;
>>  extern const struct efi_console_control_protocol efi_console_control;
>>  extern const struct efi_device_path_to_text_protocol efi_device_path_to_text;
>>  extern const struct efi_device_path_utilities_protocol efi_device_path_utilities;
>> +extern const struct efi_hii_config_routing_protocol efi_hii_config_routing;
>> +extern const struct efi_hii_database_protocol efi_hii_database;
>> +extern const struct efi_hii_string_protocol efi_hii_string;
>>
>>  uint16_t *efi_dp_str(struct efi_device_path *dp);
>>
>> @@ -91,6 +94,9 @@ extern const efi_guid_t efi_guid_device_path_to_text_protocol;
>>  extern const efi_guid_t efi_simple_file_system_protocol_guid;
>>  extern const efi_guid_t efi_file_info_guid;
>>  extern const efi_guid_t efi_guid_device_path_utilities_protocol;
>> +extern const efi_guid_t efi_guid_hii_config_routing_protocol;
>> +extern const efi_guid_t efi_guid_hii_database_protocol;
>> +extern const efi_guid_t efi_guid_hii_string_protocol;
>>
>>  extern unsigned int __efi_runtime_start, __efi_runtime_stop;
>>  extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;
>> diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
>> index b6927b3b84..725e0cba85 100644
>> --- a/lib/efi_loader/Makefile
>> +++ b/lib/efi_loader/Makefile
>> @@ -17,7 +17,7 @@ endif
>>  obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o
>>  obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o
>>  obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o
>> -obj-y += efi_device_path_utilities.o
>> +obj-y += efi_device_path_utilities.o efi_hii.o
>>  obj-y += efi_file.o efi_variable.o efi_bootmgr.o
>>  obj-$(CONFIG_LCD) += efi_gop.o
>>  obj-$(CONFIG_DM_VIDEO) += efi_gop.o
>> diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
>> index 92c778fcca..c179afc25a 100644
>> --- a/lib/efi_loader/efi_boottime.c
>> +++ b/lib/efi_loader/efi_boottime.c
>> @@ -1157,6 +1157,15 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob
>>       obj->protocols[4].protocol_interface =
>>               (void *)&efi_device_path_utilities;
>>
>> +     obj->protocols[5].guid = &efi_guid_hii_string_protocol;
>> +     obj->protocols[5].protocol_interface = (void *)&efi_hii_string;
>> +
>> +     obj->protocols[6].guid = &efi_guid_hii_database_protocol;
>> +     obj->protocols[6].protocol_interface = (void *)&efi_hii_database;
>> +
>> +     obj->protocols[7].guid = &efi_guid_hii_config_routing_protocol;
>> +     obj->protocols[7].protocol_interface = (void *)&efi_hii_config_routing;
>> +
>>       info->file_path = file_path;
>>       info->device_handle = efi_dp_find_obj(device_path, NULL);
>>
>> diff --git a/lib/efi_loader/efi_hii.c b/lib/efi_loader/efi_hii.c
>> new file mode 100644
>> index 0000000000..25c8e88a60
>> --- /dev/null
>> +++ b/lib/efi_loader/efi_hii.c
>> @@ -0,0 +1,507 @@
>> +/*
>> + *  EFI Human Interface Infrastructure ... interface
>> + *
>> + *  Copyright (c) 2017 Leif Lindholm
>> + *
>> + *  SPDX-License-Identifier:     GPL-2.0+
>> + */
>> +
>> +#include <common.h>
>> +#include <malloc.h>
>> +#include <efi_loader.h>
>> +
>> +const efi_guid_t efi_guid_hii_config_routing_protocol =
>> +     EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID;
>> +const efi_guid_t efi_guid_hii_database_protocol = EFI_HII_DATABASE_PROTOCOL_GUID;
>> +const efi_guid_t efi_guid_hii_string_protocol = EFI_HII_STRING_PROTOCOL_GUID;
>> +
>> +struct hii_package {
>> +     // TODO should there be an associated efi_object?
>> +     struct list_head string_tables;     /* list of string_table */
>> +     /* we could also track fonts, images, etc */
>> +};
>> +
>> +struct string_table {
>> +     struct list_head link;
>> +     efi_string_id_t language_name;
>> +     char *language;
>> +     uint32_t nstrings;
>> +     /* NOTE: string id starts at 1 so value is stbl->strings[id-1] */
>> +     struct {
>> +             efi_string_t string;
>> +             /* we could also track font info, etc */
>> +     } strings[];
>> +};
>> +
>> +static void free_strings_table(struct string_table *stbl)
>> +{
>> +     int i;
>> +
>> +     for (i = 0; i < stbl->nstrings; i++)
>> +             free(stbl->strings[i].string);
>> +     free(stbl->language);
>> +     free(stbl);
>> +}
>> +
>> +static struct hii_package *new_package(void)
>> +{
>> +     struct hii_package *hii = malloc(sizeof(*hii));
>> +     INIT_LIST_HEAD(&hii->string_tables);
>> +     return hii;
>> +}
>> +
>> +static void free_package(struct hii_package *hii)
>> +{
>> +
>> +     while (!list_empty(&hii->string_tables)) {
>> +             struct string_table *stbl;
>> +
>> +             stbl = list_first_entry(&hii->string_tables,
>> +                                     struct string_table, link);
>> +             list_del(&stbl->link);
>> +             free_strings_table(stbl);
>> +     }
>> +
>> +     free(hii);
>> +}
>> +
>> +static efi_status_t add_strings_package(struct hii_package *hii,
>> +     struct efi_hii_strings_package *strings_package)
>> +{
>> +     struct efi_hii_string_block *block;
>> +     void *end = ((void *)strings_package) + strings_package->header.length;
>> +     uint32_t nstrings = 0;
>> +     unsigned id = 0;
>> +
>> +     debug("header_size: %08x\n", strings_package->header_size);
>> +     debug("string_info_offset: %08x\n", strings_package->string_info_offset);
>> +     debug("language_name: %u\n", strings_package->language_name);
>> +     debug("language: %s\n", strings_package->language);
>> +
>> +     /* count # of string entries: */
>> +     block = ((void *)strings_package) + strings_package->string_info_offset;
>> +     while ((void *)block < end) {
>> +             switch (block->block_type) {
>> +             case EFI_HII_SIBT_STRING_UCS2: {
>> +                     struct efi_hii_sibt_string_ucs2_block *ucs2 =
>> +                             (void *)block;
>> +                     nstrings++;
>> +                     block = efi_hii_sibt_string_ucs2_block_next(ucs2);
>> +                     break;
>> +             }
>> +             case EFI_HII_SIBT_END:
>> +                     block = end;
>> +                     break;
>> +             default:
>> +                     debug("unknown HII string block type: %02x\n",
>> +                           block->block_type);
>> +                     return EFI_INVALID_PARAMETER;
>> +             }
>> +     }
>> +
>> +     struct string_table *stbl = malloc(sizeof(*stbl) +
>> +                     (nstrings * sizeof(stbl->strings[0])));
>> +     stbl->language_name = strings_package->language_name;
>> +     stbl->language = strdup((char *)strings_package->language);
>
> Where does the strings_package come from? And why is the language in it
> in UTF8?

The strings_package is a part of the "package list" blob passed in
from (in this case) Shell.efi.  The package list can actually contain
a lot more (fonts/glyphs/images/forms), but not really sure how much
of that we'll actually support.  (HII seems to be able to do enough
for rendering a full blown GUI.. kinda overkill, IMHO.. but Shell.efi
wants it for silly reasons.)

This is actually utf8.. it is a "RFC 4646 language code identifier".
See appendix M.


>
>> +     stbl->nstrings = nstrings;
>> +
>> +     list_add(&stbl->link, &hii->string_tables);
>> +
>> +     /* and now parse string entries and populate string_table */
>> +     block = ((void *)strings_package) + strings_package->string_info_offset;
>> +
>> +     while ((void *)block < end) {
>> +             switch (block->block_type) {
>> +             case EFI_HII_SIBT_STRING_UCS2: {
>> +                     struct efi_hii_sibt_string_ucs2_block *ucs2 =
>> +                             (void *)block;
>> +                     id++;
>> +                     debug("%4u: \"%ls\"\n", id, ucs2->string_text);
>> +                     stbl->strings[id-1].string =
>> +                             utf16_strdup(ucs2->string_text);
>> +                     block = efi_hii_sibt_string_ucs2_block_next(ucs2);
>> +                     break;
>> +             }
>> +             case EFI_HII_SIBT_END:
>> +                     return EFI_SUCCESS;
>> +             default:
>> +                     debug("unknown HII string block type: %02x\n",
>> +                           block->block_type);
>> +                     return EFI_INVALID_PARAMETER;
>> +             }
>> +     }
>> +
>> +     return EFI_SUCCESS;
>> +}
>> +
>> +/*
>> + * EFI_HII_CONFIG_ROUTING_PROTOCOL
>> + */
>> +
>> +static efi_status_t EFIAPI extract_config(
>> +     const struct efi_hii_config_routing_protocol *this,
>> +     const efi_string_t request,
>> +     efi_string_t *progress,
>> +     efi_string_t *results)
>> +{
>> +     EFI_ENTRY("%p, \"%ls\", %p, %p", this, request, progress, results);
>> +     return EFI_EXIT(EFI_OUT_OF_RESOURCES);
>> +}
>> +
>> +static efi_status_t EFIAPI export_config(
>> +     const struct efi_hii_config_routing_protocol *this,
>> +     efi_string_t *results)
>> +{
>> +     EFI_ENTRY("%p, %p", this, results);
>> +     return EFI_EXIT(EFI_OUT_OF_RESOURCES);
>> +}
>> +
>> +static efi_status_t EFIAPI route_config(
>> +     const struct efi_hii_config_routing_protocol *this,
>> +     const efi_string_t configuration,
>> +     efi_string_t *progress)
>> +{
>> +     EFI_ENTRY("%p, \"%ls\", %p", this, configuration, progress);
>> +     return EFI_EXIT(EFI_OUT_OF_RESOURCES);
>> +}
>> +
>> +static efi_status_t EFIAPI block_to_config(
>> +     const struct efi_hii_config_routing_protocol *this,
>> +     const efi_string_t config_request,
>> +     const uint8_t *block,
>> +     const efi_uintn_t block_size,
>> +     efi_string_t *config,
>> +     efi_string_t *progress)
>> +{
>> +     EFI_ENTRY("%p, \"%ls\", %p, %zu, %p, %p", this, config_request, block,
>> +               block_size, config, progress);
>> +     return EFI_EXIT(EFI_OUT_OF_RESOURCES);
>> +}
>> +
>> +static efi_status_t EFIAPI config_to_block(
>> +     const struct efi_hii_config_routing_protocol *this,
>> +     const efi_string_t config_resp,
>> +     const uint8_t *block,
>> +     const efi_uintn_t *block_size,
>> +     efi_string_t *progress)
>> +{
>> +     EFI_ENTRY("%p, \"%ls\", %p, %p, %p", this, config_resp, block,
>> +               block_size, progress);
>> +     return EFI_EXIT(EFI_OUT_OF_RESOURCES);
>> +}
>> +
>> +static efi_status_t EFIAPI get_alt_config(
>> +     const struct efi_hii_config_routing_protocol *this,
>> +     const efi_string_t config_resp,
>> +     const efi_guid_t *guid,
>> +     const efi_string_t name,
>> +     const struct efi_device_path *device_path,
>> +     const efi_string_t alt_cfg_id,
>> +     efi_string_t *alt_cfg_resp)
>> +{
>> +     EFI_ENTRY("%p, \"%ls\", %pUl, \"%ls\", %p, \"%ls\", %p", this,
>> +               config_resp, guid, name, device_path, alt_cfg_id,
>> +               alt_cfg_resp);
>> +     return EFI_EXIT(EFI_OUT_OF_RESOURCES);
>> +}
>> +
>> +
>> +/*
>> + * EFI_HII_DATABASE_PROTOCOL
>> + */
>> +
>> +static efi_status_t EFIAPI new_package_list(
>> +     const struct efi_hii_database_protocol *this,
>> +     const struct efi_hii_package_list_header *package_list,
>> +     const efi_handle_t driver_handle,
>> +     efi_hii_handle_t *handle)
>> +{
>> +     efi_status_t ret = EFI_SUCCESS;
>> +
>> +     EFI_ENTRY("%p, %p, %p, %p", this, package_list, driver_handle, handle);
>> +
>> +     if (!package_list || !driver_handle)
>> +             return EFI_EXIT(EFI_INVALID_PARAMETER);
>> +
>> +     struct hii_package *hii = new_package();
>> +     struct efi_hii_package_header *package;
>> +     void *end = ((void *)package_list) + package_list->package_length;
>> +
>> +     debug("package_list: %pUl (%u)\n", &package_list->package_list_guid,
>> +           package_list->package_length);
>> +
>> +     package = ((void *)package_list) + sizeof(*package_list);
>> +     while ((void *)package < end) {
>> +             debug("package=%p, package type=%x, length=%u\n", package,
>> +                   package->type, package->length);
>> +             switch (package->type) {
>> +             case EFI_HII_PACKAGE_STRINGS:
>> +                     ret = add_strings_package(hii,
>> +                             (struct efi_hii_strings_package *)package);
>> +                     break;
>> +             default:
>> +                     break;
>> +             }
>> +
>> +             if (ret != EFI_SUCCESS)
>> +                     goto error;
>> +
>> +             package = ((void *)package) + package->length;
>> +     }
>> +
>> +     // TODO in theory there is some notifications that should be sent..
>> +
>> +     *handle = hii;
>> +
>> +     return EFI_EXIT(EFI_SUCCESS);
>> +
>> +error:
>> +     free_package(hii);
>> +     return EFI_EXIT(ret);
>> +}
>> +
>> +static efi_status_t EFIAPI remove_package_list(
>> +     const struct efi_hii_database_protocol *this,
>> +     efi_hii_handle_t handle)
>> +{
>> +     struct hii_package *hii = handle;
>> +     EFI_ENTRY("%p, %p", this, handle);
>> +     free_package(hii);
>> +     return EFI_EXIT(EFI_SUCCESS);
>> +}
>> +
>> +static efi_status_t EFIAPI update_package_list(
>> +     const struct efi_hii_database_protocol *this,
>> +     efi_hii_handle_t handle,
>> +     const struct efi_hii_package_list_header *package_list)
>> +{
>> +     EFI_ENTRY("%p, %p, %p", this, handle, package_list);
>> +     return EFI_EXIT(EFI_NOT_FOUND);
>> +}
>> +
>> +static efi_status_t EFIAPI list_package_lists(
>> +     const struct efi_hii_database_protocol *this,
>> +     uint8_t package_type,
>> +     const efi_guid_t *package_guid,
>> +     efi_uintn_t *handle_buffer_length,
>> +     efi_hii_handle_t *handle)
>> +{
>> +     EFI_ENTRY("%p, %u, %pUl, %p, %p", this, package_type, package_guid,
>> +               handle_buffer_length, handle);
>> +     return EFI_EXIT(EFI_NOT_FOUND);
>> +}
>> +
>> +static efi_status_t EFIAPI export_package_lists(
>> +     const struct efi_hii_database_protocol *this,
>> +     efi_hii_handle_t handle,
>> +     efi_uintn_t *buffer_size,
>> +     struct efi_hii_package_list_header *buffer)
>> +{
>> +     EFI_ENTRY("%p, %p, %p, %p", this, handle, buffer_size, buffer);
>> +     return EFI_EXIT(EFI_NOT_FOUND);
>> +}
>> +
>> +static efi_status_t EFIAPI register_package_notify(
>> +     const struct efi_hii_database_protocol *this,
>> +     uint8_t package_type,
>> +     const efi_guid_t *package_guid,
>> +     const void *package_notify_fn,
>> +     efi_uintn_t notify_type,
>> +     efi_handle_t *notify_handle)
>> +{
>> +     EFI_ENTRY("%p, %u, %pUl, %p, %zu, %p", this, package_type,
>> +               package_guid, package_notify_fn, notify_type,
>> +               notify_handle);
>> +     return EFI_EXIT(EFI_OUT_OF_RESOURCES);
>> +}
>> +
>> +static efi_status_t EFIAPI unregister_package_notify(
>> +     const struct efi_hii_database_protocol *this,
>> +     efi_handle_t notification_handle)
>> +{
>> +     EFI_ENTRY("%p, %p", this, notification_handle);
>> +     return EFI_EXIT(EFI_NOT_FOUND);
>> +}
>> +
>> +static efi_status_t EFIAPI find_keyboard_layouts(
>> +     const struct efi_hii_database_protocol *this,
>> +     uint16_t *key_guid_buffer_length,
>> +     efi_guid_t *key_guid_buffer)
>> +{
>> +     EFI_ENTRY("%p, %p, %p", this, key_guid_buffer_length, key_guid_buffer);
>> +     return EFI_EXIT(EFI_NOT_FOUND); /* Invalid */
>> +}
>> +
>> +static efi_status_t EFIAPI get_keyboard_layout(
>> +     const struct efi_hii_database_protocol *this,
>> +     efi_guid_t *key_guid,
>> +     uint16_t *keyboard_layout_length,
>> +     struct efi_hii_keyboard_layout *keyboard_layout)
>> +{
>> +     EFI_ENTRY("%p, %pUl, %p, %p", this, key_guid, keyboard_layout_length,
>> +               keyboard_layout);
>> +     return EFI_EXIT(EFI_NOT_FOUND);
>> +}
>> +
>> +static efi_status_t EFIAPI set_keyboard_layout(
>> +     const struct efi_hii_database_protocol *this,
>> +     efi_guid_t *key_guid)
>> +{
>> +     EFI_ENTRY("%p, %pUl", this, key_guid);
>> +     return EFI_EXIT(EFI_NOT_FOUND);
>> +}
>> +
>> +static efi_status_t EFIAPI get_package_list_handle(
>> +     const struct efi_hii_database_protocol *this,
>> +     efi_hii_handle_t package_list_handle,
>> +     efi_handle_t *driver_handle)
>> +{
>> +     EFI_ENTRY("%p, %p, %p", this, package_list_handle, driver_handle);
>> +     return EFI_EXIT(EFI_INVALID_PARAMETER);
>> +}
>> +
>> +
>> +/*
>> + * EFI_HII_STRING_PROTOCOL
>> + */
>> +
>> +static efi_status_t EFIAPI new_string(
>> +     const struct efi_hii_string_protocol *this,
>> +     efi_hii_handle_t package_list,
>> +     efi_string_id_t *string_id,
>> +     const uint8_t *language,
>> +     const uint16_t *language_name,
>> +     const efi_string_t string,
>> +     const struct efi_font_info *string_font_info)
>> +{
>> +     EFI_ENTRY("%p, %p, %p, \"%s\", %p, \"%ls\", %p", this, package_list,
>> +               string_id, language, language_name, string,
>> +               string_font_info);
>> +     return EFI_EXIT(EFI_NOT_FOUND);
>> +}
>> +
>> +static efi_status_t EFIAPI get_string(
>> +     const struct efi_hii_string_protocol *this,
>> +     const uint8_t *language,
>> +     efi_hii_handle_t package_list,
>> +     efi_string_id_t string_id,
>> +     efi_string_t string,
>> +     efi_uintn_t *string_size,
>> +     struct efi_font_info **string_font_info)
>> +{
>> +     struct hii_package *hii = package_list;
>> +     struct string_table *stbl;
>> +
>> +     EFI_ENTRY("%p, \"%s\", %p, %u, %p, %p, %p", this, language,
>> +               package_list, string_id, string, string_size,
>> +               string_font_info);
>> +
>> +     list_for_each_entry(stbl, &hii->string_tables, link) {
>> +             if (!strcmp((char *)language, (char *)stbl->language)) {
>> +                     unsigned idx = string_id - 1;
>> +                     if (idx > stbl->nstrings)
>> +                             return EFI_EXIT(EFI_NOT_FOUND);
>> +                     efi_string_t str = stbl->strings[idx].string;
>> +                     size_t len = utf16_strlen(str) + 1;
>
> I assume that's wrong for sizing too?

nope :-)

> Also please try not to define variables mid-scope :). Just define them
> above the if() and fill them after ...

Hmm, I'd have the inverse comment if someone else wrote it and defined
all the variables at the top ;-)

> Then also for the sake of readability add a blank line after the
> variable definitions and before the return.
>
> I think you'd also do yourself a favor if you reduced the indenting a
> bit. Just abort the list_for_each when you found and entry and then
> process it in the top level scope.
>
> static struct string_table *find_stbl_by_lang(const char *language)
> {
>     list_for_each(...) {
>         if (matches) {
>             return stbl;
>         }
>     }
>
>     return NULL;
> }
>
> stbl = find_stbl_by_lang(lang);
> if (!stbl)
>     return EFI_EXIT(EFI_NOT_FOUND)

yeah, perhaps

BR,
-R

> work_with_stbl;
>
> return EFI_EXIT(EFI_SUCCESS);
>
>
> Alex
>
>> +                     if (*string_size < len * 2) {
>> +                             *string_size = len * 2;
>> +                             return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
>> +                     }
>> +                     memcpy(string, str, len * 2);
>> +                     *string_size = len * 2;
>> +                     return EFI_EXIT(EFI_SUCCESS);
>> +             }
>> +     }
>> +
>> +     return EFI_EXIT(EFI_NOT_FOUND);
>> +}
>> +
>> +static efi_status_t EFIAPI set_string(
>> +     const struct efi_hii_string_protocol *this,
>> +     efi_hii_handle_t package_list,
>> +     efi_string_id_t string_id,
>> +     const uint8_t *language,
>> +     const efi_string_t string,
>> +     const struct efi_font_info *string_font_info)
>> +{
>> +     EFI_ENTRY("%p, %p, %u, \"%s\", \"%ls\", %p", this, package_list,
>> +               string_id, language, string, string_font_info);
>> +     return EFI_EXIT(EFI_NOT_FOUND);
>> +}
>> +
>> +static efi_status_t EFIAPI get_languages(
>> +     const struct efi_hii_string_protocol *this,
>> +     efi_hii_handle_t package_list,
>> +     uint8_t *languages,
>> +     efi_uintn_t *languages_size)
>> +{
>> +     struct hii_package *hii = package_list;
>> +     struct string_table *stbl;
>> +     size_t len = 0;
>> +
>> +     EFI_ENTRY("%p, %p, %p, %p", this, package_list, languages,
>> +               languages_size);
>> +
>> +     /* figure out required size: */
>> +     list_for_each_entry(stbl, &hii->string_tables, link) {
>> +             len += strlen((char *)stbl->language) + 1;
>> +     }
>> +
>> +     if (*languages_size < len) {
>> +             *languages_size = len;
>> +             return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
>> +     }
>> +
>> +     char *p = (char *)languages;
>> +     list_for_each_entry(stbl, &hii->string_tables, link) {
>> +             if (p != (char *)languages)
>> +                     p += sprintf(p, ";");
>> +             p += sprintf(p, "%s", stbl->language);
>> +     }
>> +
>> +     debug("languages: %s\n", languages);
>> +
>> +     return EFI_EXIT(EFI_SUCCESS);
>> +}
>> +
>> +static efi_status_t EFIAPI get_secondary_languages(
>> +     const struct efi_hii_string_protocol *this,
>> +     efi_hii_handle_t package_list,
>> +     const uint8_t *primary_language,
>> +     uint8_t *secondary_languages,
>> +     efi_uintn_t *secondary_languages_size)
>> +{
>> +     EFI_ENTRY("%p, %p, \"%s\", %p, %p", this, package_list,
>> +               primary_language, secondary_languages,
>> +               secondary_languages_size);
>> +     return EFI_EXIT(EFI_NOT_FOUND);
>> +}
>> +
>> +const struct efi_hii_config_routing_protocol efi_hii_config_routing = {
>> +     .extract_config = extract_config,
>> +     .export_config = export_config,
>> +     .route_config = route_config,
>> +     .block_to_config = block_to_config,
>> +     .config_to_block = config_to_block,
>> +     .get_alt_config = get_alt_config
>> +};
>> +const struct efi_hii_database_protocol efi_hii_database = {
>> +     .new_package_list = new_package_list,
>> +     .remove_package_list = remove_package_list,
>> +     .update_package_list = update_package_list,
>> +     .list_package_lists = list_package_lists,
>> +     .export_package_lists = export_package_lists,
>> +     .register_package_notify = register_package_notify,
>> +     .unregister_package_notify = unregister_package_notify,
>> +     .find_keyboard_layouts = find_keyboard_layouts,
>> +     .get_keyboard_layout = get_keyboard_layout,
>> +     .set_keyboard_layout = set_keyboard_layout,
>> +     .get_package_list_handle = get_package_list_handle
>> +};
>> +const struct efi_hii_string_protocol efi_hii_string = {
>> +     .new_string = new_string,
>> +     .get_string = get_string,
>> +     .set_string = set_string,
>> +     .get_languages = get_languages,
>> +     .get_secondary_languages = get_secondary_languages
>> +};
>>

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 06/11] efi_loader: Decouple EFI input/output from stdin/stdout
  2017-10-11 14:45   ` Alexander Graf
@ 2017-10-11 22:07     ` Rob Clark
  2017-10-12  7:15       ` Alexander Graf
  0 siblings, 1 reply; 75+ messages in thread
From: Rob Clark @ 2017-10-11 22:07 UTC (permalink / raw)
  To: u-boot

On Wed, Oct 11, 2017 at 10:45 AM, Alexander Graf <agraf@suse.de> wrote:
>
>
> On 10.10.17 14:23, Rob Clark wrote:
>> In some cases, it is quite useful to have (for example) EFI on screen
>> but u-boot on serial port.
>>
>> This adds two new optional environment variables, "efiin" and "efiout",
>> which can be used to set EFI console input/output independently of
>> u-boot's input/output.  If unset, EFI console will default to stdin/
>> stdout as before.
>>
>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>
> With this patch, we lose the ability to have the efi in/out go to both
> graphical and serial console, right? This is critical functionality to
> have, since we don't necessarily know which output/input a user ends up
> using.

I'll think about how to support iomux.. but some things like console
size are just not going to work properly there.  And as long as we fix
the stdout shenanigans (ie. what I was seeing w/ qemu-x86) you can
simply not set efiout var and have things working as before, so you
don't loose any existing functionality (although, like I said, if the
two different consoles have different sizes things aren't going to
work properly for anything other than simple cases).

In most cases, the display driver should be able to detect whether a
display is connected.. this is what I've done on dragonboard410c, so
if no display plugged in, 'efiout=vidconsole' fails and you fall back
to serial, else you get efi on screen like you would on a "real"
computer.  For boards that have a display driver that isn't able to do
the basic check of whether a cable is plugged in, just don't set
"efiout" (or fix the display driver) ;-)

BR,
-R


>
> Alex

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 07/11] efi_loader: fix events
  2017-10-11 14:49   ` Alexander Graf
@ 2017-10-11 22:09     ` Rob Clark
  0 siblings, 0 replies; 75+ messages in thread
From: Rob Clark @ 2017-10-11 22:09 UTC (permalink / raw)
  To: u-boot

On Wed, Oct 11, 2017 at 10:49 AM, Alexander Graf <agraf@suse.de> wrote:
>
>
> On 10.10.17 14:23, Rob Clark wrote:
>> An event can be created with type==0, Shell.efi does this for an event
>> that is set when Ctrl-C is typed.  So our current approach of having a
>> fixed set of timer slots, and determining which slots are unused by
>> type==0 doesn't work so well.  But we don't have any particularly good
>> reason to have a fixed table of events, so just dynamically allocate
>> them and keep a list.
>>
>> Also fixes an incorrect implementation of CheckEvent() which was (a)
>> incorrectly returning an error if type==0, and (b) didn't handle the
>> case of an unsignaled event with a notify callback.
>>
>> With these fixes (plus implementation of SIMPLE_TEXT_INPUT_EX protocol),
>> Ctrl-C works in Shell.efi.
>>
>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>> ---
>>  include/efi_loader.h          |   1 +
>>  lib/efi_loader/efi_boottime.c | 217 +++++++++++++++++++++---------------------
>>  2 files changed, 111 insertions(+), 107 deletions(-)
>>
>> diff --git a/include/efi_loader.h b/include/efi_loader.h
>> index e6e55d2cb4..2232caca44 100644
>> --- a/include/efi_loader.h
>> +++ b/include/efi_loader.h
>> @@ -154,6 +154,7 @@ struct efi_event {
>>       enum efi_timer_delay trigger_type;
>>       bool is_queued;
>>       bool is_signaled;
>> +     struct list_head link;
>>  };
>>
>>
>> diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
>> index 39dcc72648..19fafe546c 100644
>> --- a/lib/efi_loader/efi_boottime.c
>> +++ b/lib/efi_loader/efi_boottime.c
>> @@ -350,11 +350,26 @@ static efi_status_t efi_create_handle(void **handle)
>>       return r;
>>  }
>>
>> +static LIST_HEAD(efi_events);
>> +
>>  /*
>> - * Our event capabilities are very limited. Only a small limited
>> - * number of events is allowed to coexist.
>> + * Check if a pointer is a valid event.
>> + *
>> + * It might be nice at some point to extend this to a more general
>> + * mechanism to check if pointers passed from the EFI world are
>> + * valid objects of a particular type.
>>   */
>> -static struct efi_event efi_events[16];
>> +static bool efi_is_event(const void *obj)
>> +{
>> +     struct efi_event *evt;
>> +
>> +     list_for_each_entry(evt, &efi_events, link) {
>> +             if (evt == obj)
>> +                     return true;
>> +     }
>> +
>> +     return false;
>> +}
>>
>>  /*
>>   * Create an event.
>> @@ -377,7 +392,7 @@ efi_status_t efi_create_event(uint32_t type, UINTN notify_tpl,
>>                                       void *context),
>>                             void *notify_context, struct efi_event **event)
>>  {
>> -     int i;
>> +     struct efi_event *evt;
>>
>>       if (event == NULL)
>>               return EFI_INVALID_PARAMETER;
>> @@ -389,21 +404,24 @@ efi_status_t efi_create_event(uint32_t type, UINTN notify_tpl,
>>           notify_function == NULL)
>>               return EFI_INVALID_PARAMETER;
>>
>> -     for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
>> -             if (efi_events[i].type)
>> -                     continue;
>> -             efi_events[i].type = type;
>> -             efi_events[i].notify_tpl = notify_tpl;
>> -             efi_events[i].notify_function = notify_function;
>> -             efi_events[i].notify_context = notify_context;
>> -             /* Disable timers on bootup */
>> -             efi_events[i].trigger_next = -1ULL;
>> -             efi_events[i].is_queued = false;
>> -             efi_events[i].is_signaled = false;
>> -             *event = &efi_events[i];
>> -             return EFI_SUCCESS;
>> -     }
>> -     return EFI_OUT_OF_RESOURCES;
>> +     evt = calloc(1, sizeof(*evt));
>> +     if (!evt)
>> +             return EFI_OUT_OF_RESOURCES;
>> +
>> +     evt->type = type;
>> +     evt->notify_tpl = notify_tpl;
>> +     evt->notify_function = notify_function;
>> +     evt->notify_context = notify_context;
>> +     /* Disable timers on bootup */
>> +     evt->trigger_next = -1ULL;
>> +     evt->is_queued = false;
>> +     evt->is_signaled = false;
>> +
>> +     list_add_tail(&evt->link, &efi_events);
>> +
>> +     *event = evt;
>> +
>> +     return EFI_SUCCESS;
>>  }
>>
>>  /*
>> @@ -443,30 +461,31 @@ static efi_status_t EFIAPI efi_create_event_ext(
>>   */
>>  void efi_timer_check(void)
>>  {
>> -     int i;
>> +     struct efi_event *evt;
>>       u64 now = timer_get_us();
>>
>> -     for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
>> -             if (!efi_events[i].type)
>> -                     continue;
>> -             if (efi_events[i].is_queued)
>> -                     efi_signal_event(&efi_events[i]);
>> -             if (!(efi_events[i].type & EVT_TIMER) ||
>> -                 now < efi_events[i].trigger_next)
>> +     /*
>> +      * TODO perhaps optimize a bit and track the time of next
>> +      * timer to expire?
>> +      */
>> +     list_for_each_entry(evt, &efi_events, link) {
>> +             if (evt->is_queued)
>> +                     efi_signal_event(evt);
>> +             if (!(evt->type & EVT_TIMER) ||
>> +                 now < evt->trigger_next)
>>                       continue;
>> -             switch (efi_events[i].trigger_type) {
>> +             switch (evt->trigger_type) {
>>               case EFI_TIMER_RELATIVE:
>> -                     efi_events[i].trigger_type = EFI_TIMER_STOP;
>> +                     evt->trigger_type = EFI_TIMER_STOP;
>>                       break;
>>               case EFI_TIMER_PERIODIC:
>> -                     efi_events[i].trigger_next +=
>> -                             efi_events[i].trigger_time;
>> +                     evt->trigger_next += evt->trigger_time;
>>                       break;
>>               default:
>>                       continue;
>>               }
>> -             efi_events[i].is_signaled = true;
>> -             efi_signal_event(&efi_events[i]);
>> +             evt->is_signaled = true;
>> +             efi_signal_event(evt);
>>       }
>>       WATCHDOG_RESET();
>>  }
>> @@ -485,7 +504,8 @@ void efi_timer_check(void)
>>  efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type,
>>                          uint64_t trigger_time)
>>  {
>> -     int i;
>> +     if (!efi_is_event(event))
>> +             return EFI_INVALID_PARAMETER;
>>
>>       /*
>>        * The parameter defines a multiple of 100ns.
>> @@ -493,30 +513,25 @@ efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type,
>>        */
>>       do_div(trigger_time, 10);
>>
>> -     for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
>> -             if (event != &efi_events[i])
>> -                     continue;
>> +     if (!(event->type & EVT_TIMER))
>> +             return EFI_INVALID_PARAMETER;
>>
>> -             if (!(event->type & EVT_TIMER))
>> -                     break;
>> -             switch (type) {
>> -             case EFI_TIMER_STOP:
>> -                     event->trigger_next = -1ULL;
>> -                     break;
>> -             case EFI_TIMER_PERIODIC:
>> -             case EFI_TIMER_RELATIVE:
>> -                     event->trigger_next =
>> -                             timer_get_us() + trigger_time;
>> -                     break;
>> -             default:
>> -                     return EFI_INVALID_PARAMETER;
>> -             }
>> -             event->trigger_type = type;
>> -             event->trigger_time = trigger_time;
>> -             event->is_signaled = false;
>> -             return EFI_SUCCESS;
>> +     switch (type) {
>> +     case EFI_TIMER_STOP:
>> +             event->trigger_next = -1ULL;
>> +             break;
>> +     case EFI_TIMER_PERIODIC:
>> +     case EFI_TIMER_RELATIVE:
>> +             event->trigger_next = timer_get_us() + trigger_time;
>> +             break;
>> +     default:
>> +             return EFI_INVALID_PARAMETER;
>>       }
>> -     return EFI_INVALID_PARAMETER;
>> +     event->trigger_type = type;
>> +     event->trigger_time = trigger_time;
>> +     event->is_signaled = false;
>> +
>> +     return EFI_SUCCESS;
>>  }
>>
>>  /*
>> @@ -555,7 +570,7 @@ static efi_status_t EFIAPI efi_wait_for_event(unsigned long num_events,
>>                                             struct efi_event **event,
>>                                             size_t *index)
>>  {
>> -     int i, j;
>> +     int i;
>>
>>       EFI_ENTRY("%ld, %p, %p", num_events, event, index);
>>
>> @@ -566,12 +581,8 @@ static efi_status_t EFIAPI efi_wait_for_event(unsigned long num_events,
>>       if (efi_tpl != TPL_APPLICATION)
>>               return EFI_EXIT(EFI_UNSUPPORTED);
>>       for (i = 0; i < num_events; ++i) {
>> -             for (j = 0; j < ARRAY_SIZE(efi_events); ++j) {
>> -                     if (event[i] == &efi_events[j])
>> -                             goto known_event;
>> -             }
>> -             return EFI_EXIT(EFI_INVALID_PARAMETER);
>> -known_event:
>> +             if (!efi_is_event(event[i]))
>> +                     return EFI_EXIT(EFI_INVALID_PARAMETER);
>>               if (!event[i]->type || event[i]->type & EVT_NOTIFY_SIGNAL)
>>                       return EFI_EXIT(EFI_INVALID_PARAMETER);
>>               if (!event[i]->is_signaled)
>> @@ -614,19 +625,12 @@ out:
>>   */
>>  static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event)
>>  {
>> -     int i;
>> -
>>       EFI_ENTRY("%p", event);
>> -     for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
>> -             if (event != &efi_events[i])
>> -                     continue;
>> -             if (event->is_signaled)
>> -                     break;
>> -             event->is_signaled = true;
>> -             if (event->type & EVT_NOTIFY_SIGNAL)
>> -                     efi_signal_event(event);
>> -             break;
>> -     }
>> +     if (!efi_is_event(event))
>> +             return EFI_EXIT(EFI_INVALID_PARAMETER);
>> +     event->is_signaled = true;
>> +     if (event->type & EVT_NOTIFY_SIGNAL)
>> +             efi_signal_event(event);
>>       return EFI_EXIT(EFI_SUCCESS);
>>  }
>>
>> @@ -642,19 +646,10 @@ static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event)
>>   */
>>  static efi_status_t EFIAPI efi_close_event(struct efi_event *event)
>>  {
>> -     int i;
>> -
>>       EFI_ENTRY("%p", event);
>> -     for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
>> -             if (event == &efi_events[i]) {
>> -                     event->type = 0;
>> -                     event->trigger_next = -1ULL;
>> -                     event->is_queued = false;
>> -                     event->is_signaled = false;
>> -                     return EFI_EXIT(EFI_SUCCESS);
>> -             }
>> -     }
>> -     return EFI_EXIT(EFI_INVALID_PARAMETER);
>> +     list_del(&event->link);
>> +     free(event);
>> +     return EFI_EXIT(EFI_SUCCESS);
>>  }
>>
>>  /*
>> @@ -664,29 +659,37 @@ static efi_status_t EFIAPI efi_close_event(struct efi_event *event)
>>   * See the Unified Extensible Firmware Interface (UEFI) specification
>>   * for details.
>>   *
>> - * If an event is not signaled yet the notification function is queued.
>> + * - If Event is in the signaled state, it is cleared and EFI_SUCCESS
>> + *   is returned.
>> + *
>> + * - If Event is not in the signaled state and has no notification
>> + *   function, EFI_NOT_READY is returned.
>> + *
>> + * - If Event is not in the signaled state but does have a notification
>> + *   function, the notification function is queued at the event’s
>> + *   notification task priority level. If the execution of the
>> + *   notification function causes Event to be signaled, then the signaled
>> + *   state is cleared and EFI_SUCCESS is returned; if the Event is not
>> + *   signaled, then EFI_NOT_READY is returned.
>>   *
>>   * @event    event to check
>>   * @return   status code
>>   */
>> -static efi_status_t EFIAPI efi_check_event(struct efi_event *event)
>> +/*
>> + */
>
> I assume this is one comment block too much?

ugg, looks like I screwed that up when rebase/mergetool'ing.. can you
drop that when applying or do you want me to resend?

BR,
-R

>> +static efi_status_t EFIAPI efi_check_event(struct efi_event *evt)
>>  {
>
>
> Alex
>
>

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 10/11] efi_loader: Add mem-mapped for fallback
  2017-10-11 14:59   ` Alexander Graf
@ 2017-10-11 22:14     ` Rob Clark
  0 siblings, 0 replies; 75+ messages in thread
From: Rob Clark @ 2017-10-11 22:14 UTC (permalink / raw)
  To: u-boot

On Wed, Oct 11, 2017 at 10:59 AM, Alexander Graf <agraf@suse.de> wrote:
>
>
> On 10.10.17 14:23, Rob Clark wrote:
>> When we don't have a real device/image path, such as 'bootefi hello',
>> construct a mem-mapped device-path.
>>
>> This fixes 'bootefi hello' after devicepath refactoring.
>>
>> Fixes: 95c5553ea2 ("efi_loader: refactor boot device and loaded_image handling")
>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>> ---
>>  cmd/bootefi.c                            | 23 +++++++++++++++++++++++
>>  include/efi_api.h                        |  8 ++++++++
>>  include/efi_loader.h                     |  3 +++
>>  lib/efi_loader/efi_device_path.c         | 24 ++++++++++++++++++++++++
>>  lib/efi_loader/efi_device_path_to_text.c |  9 +++++++++
>>  5 files changed, 67 insertions(+)
>>
>> diff --git a/cmd/bootefi.c b/cmd/bootefi.c
>> index 24958ada46..18176a1266 100644
>> --- a/cmd/bootefi.c
>> +++ b/cmd/bootefi.c
>> @@ -128,6 +128,7 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt,
>>  {
>>       struct efi_loaded_image loaded_image_info = {};
>>       struct efi_object loaded_image_info_obj = {};
>> +     struct efi_device_path *memdp = NULL;
>>       ulong ret;
>>
>>       ulong (*entry)(void *image_handle, struct efi_system_table *st)
>> @@ -136,6 +137,20 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt,
>>       const efi_guid_t fdt_guid = EFI_FDT_GUID;
>>       bootm_headers_t img = { 0 };
>>
>> +     /*
>> +      * Special case for efi payload not loaded from disk, such as
>> +      * 'bootefi hello' or for example payload loaded directly into
>> +      * memory via jtag/etc:
>> +      */
>> +     if (!device_path && !image_path) {
>> +             printf("WARNING: using memory device/image path, this may confuse some payloads!\n");
>> +             /* actual addresses filled in after efi_load_pe() */
>> +             memdp = efi_dp_from_mem(0, 0, 0);
>> +             device_path = image_path = memdp;
>> +     } else {
>> +             assert(device_path && image_path);
>> +     }
>> +
>>       /* Initialize and populate EFI object list */
>>       if (!efi_obj_list_initalized)
>>               efi_init_obj_list();
>> @@ -182,6 +197,14 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt,
>>               goto exit;
>>       }
>>
>> +     if (memdp) {
>> +             struct efi_device_path_memory *mdp = (void *)memdp;
>> +             mdp->memory_type = loaded_image_info.image_code_type;
>> +             mdp->start_address = (uintptr_t)loaded_image_info.image_base;
>> +             mdp->end_address = mdp->start_address +
>> +                             loaded_image_info.image_size;
>> +     }
>> +
>
> memdp gets leaked after bootefi is done. Putting it on the stack would
> at least remove that problem ;). We currently expect to only return from
> bootefi when a payload was successfully quit.
>

dp's that aren't allocated from pool are a bad idea, in some cases
they get free'd by the payload.  (Well not really in this particular
case but it feels like a bad idea to mix/match how we allocate dp's..
also, it needs an /End node.)  I guess it isn't such a critical leak,
but the right solution would be to efi_free_pool() it..

BR,
-R

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 01/11] efi_loader: Initial EFI_DEVICE_PATH_UTILITIES_PROTOCOL
  2017-10-11 20:32     ` Rob Clark
@ 2017-10-12  6:51       ` Heinrich Schuchardt
  0 siblings, 0 replies; 75+ messages in thread
From: Heinrich Schuchardt @ 2017-10-12  6:51 UTC (permalink / raw)
  To: u-boot



On 10/11/2017 10:32 PM, Rob Clark wrote:
> On Wed, Oct 11, 2017 at 10:07 AM, Alexander Graf <agraf@suse.de> wrote:
>>
>>
>> On 10.10.17 14:22, Rob Clark wrote:
>>> From: Leif Lindholm <leif.lindholm@linaro.org>
>>>
>>> Not complete, but enough for Shell.efi and SCT.efi.  We'll implement the
>>> rest as needed or once we have SCT running properly so there is a way to
>>> validate the interface against the conformance test suite.
>>>
>>> Initial skeleton written by Leif, and then implementation by myself.
>>>
>>> Cc: Leif Lindholm <leif.lindholm@linaro.org>
>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>> ---
>>>   include/efi_api.h                          | 34 +++++++++++-
>>>   include/efi_loader.h                       |  2 +
>>>   lib/efi_loader/Makefile                    |  1 +
>>>   lib/efi_loader/efi_boottime.c              |  4 ++
>>>   lib/efi_loader/efi_device_path_utilities.c | 88 ++++++++++++++++++++++++++++++
>>>   5 files changed, 127 insertions(+), 2 deletions(-)
>>>   create mode 100644 lib/efi_loader/efi_device_path_utilities.c
>>>
>>> diff --git a/include/efi_api.h b/include/efi_api.h
>>> index a9a6494afe..ffdba7fe1a 100644
>>> --- a/include/efi_api.h
>>> +++ b/include/efi_api.h
>>> @@ -28,8 +28,9 @@ enum efi_timer_delay {
>>>        EFI_TIMER_RELATIVE = 2
>>>   };
>>>
>>> -#define UINTN size_t
>>> -typedef long INTN;
>>> +#define UINTN size_t   /* TODO this should be removed in a future patch */
>>
>> $ git grep UINTN | wc -l
>> 13
>>
>> Just send a preceding patch that introduces efi_uintn_t and replaces all
>> occurences of UINTN with it.
>>
>> The uintn bits shouldn't be part of the
>> EFI_DEVICE_PATH_UTILITIES_PROTOCOL patch anyways :).
>>
> 
> Heinrich mentioned he was doing that, so I didn't want to step on
> feet.  I figured this was the easiest approach regardless of the order
> of merging patches (should be simple enough to drop the duplicate
> efi_uintn_t)

I do not mind if you put the change in one of your patches. Just do what 
is needed to get your patch series merged.

Best regards

Heinrich

> 
> BR,
> -R
> 
>>> +typedef size_t efi_uintn_t;
>>> +typedef ssize_t efi_intn_t;
>>>   typedef uint16_t *efi_string_t;
>>
>>
>> Alex
> 

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 02/11] efi_loader: Initial HII protocols
  2017-10-11 22:02     ` Rob Clark
@ 2017-10-12  7:13       ` Alexander Graf
  2017-10-12  9:55         ` Rob Clark
  0 siblings, 1 reply; 75+ messages in thread
From: Alexander Graf @ 2017-10-12  7:13 UTC (permalink / raw)
  To: u-boot



On 12.10.17 00:02, Rob Clark wrote:
> On Wed, Oct 11, 2017 at 10:30 AM, Alexander Graf <agraf@suse.de> wrote:
>>
>>
>> On 10.10.17 14:22, Rob Clark wrote:
>>> From: Leif Lindholm <leif.lindholm@linaro.org>
>>>
>>> Enough implementation of the following protocols to run Shell.efi and
>>> SCT.efi:
>>>
>>>   EfiHiiConfigRoutingProtocolGuid
>>>   EfiHiiDatabaseProtocol
>>>   EfiHiiStringProtocol
>>>
>>> We'll fill in the rest once SCT is running properly so we can validate
>>> the implementation against the conformance test suite.
>>>
>>> Initial skeleton written by Leif, and then implementation by myself.
>>>
>>> Cc: Leif Lindholm <leif.lindholm@linaro.org>
>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>> ---
>>>  include/efi_api.h             | 261 ++++++++++++++++++++++
>>>  include/efi_loader.h          |   6 +
>>>  lib/efi_loader/Makefile       |   2 +-
>>>  lib/efi_loader/efi_boottime.c |   9 +
>>>  lib/efi_loader/efi_hii.c      | 507 ++++++++++++++++++++++++++++++++++++++++++
>>>  5 files changed, 784 insertions(+), 1 deletion(-)
>>>  create mode 100644 lib/efi_loader/efi_hii.c
>>>
>>> diff --git a/include/efi_api.h b/include/efi_api.h
>>> index ffdba7fe1a..164147dc87 100644
>>> --- a/include/efi_api.h
>>> +++ b/include/efi_api.h
>>> @@ -16,6 +16,7 @@
>>>  #define _EFI_API_H
>>>
>>>  #include <efi.h>
>>> +#include <charset.h>
>>>
>>>  #ifdef CONFIG_EFI_LOADER
>>>  #include <asm/setjmp.h>
>>> @@ -536,6 +537,266 @@ struct efi_device_path_utilities_protocol {
>>>               uint16_t node_length);
>>>  };
>>>
>>> +#define EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID \
>>> +     EFI_GUID(0x587e72d7, 0xcc50, 0x4f79, \
>>> +              0x82, 0x09, 0xca, 0x29, 0x1f, 0xc1, 0xa1, 0x0f)
>>> +
>>> +typedef uint16_t efi_string_id_t;
>>> +
>>> +struct efi_hii_config_routing_protocol {
>>> +     efi_status_t(EFIAPI *extract_config)(
>>> +             const struct efi_hii_config_routing_protocol *this,
>>> +             const efi_string_t request,
>>> +             efi_string_t *progress,
>>> +             efi_string_t *results);
>>> +     efi_status_t(EFIAPI *export_config)(
>>> +             const struct efi_hii_config_routing_protocol *this,
>>> +             efi_string_t *results);
>>> +     efi_status_t(EFIAPI *route_config)(
>>> +             const struct efi_hii_config_routing_protocol *this,
>>> +             const efi_string_t configuration,
>>> +             efi_string_t *progress);
>>> +     efi_status_t(EFIAPI *block_to_config)(
>>> +             const struct efi_hii_config_routing_protocol *this,
>>> +             const efi_string_t config_request,
>>> +             const uint8_t *block,
>>> +             const efi_uintn_t block_size,
>>> +             efi_string_t *config,
>>> +             efi_string_t *progress);
>>> +     efi_status_t(EFIAPI *config_to_block)(
>>> +             const struct efi_hii_config_routing_protocol *this,
>>> +             const efi_string_t config_resp,
>>> +             const uint8_t *block,
>>> +             const efi_uintn_t *block_size,
>>> +             efi_string_t *progress);
>>> +     efi_status_t(EFIAPI *get_alt_config)(
>>> +             const struct efi_hii_config_routing_protocol *this,
>>> +             const efi_string_t config_resp,
>>> +             const efi_guid_t *guid,
>>> +             const efi_string_t name,
>>> +             const struct efi_device_path *device_path,
>>> +             const efi_string_t alt_cfg_id,
>>> +             efi_string_t *alt_cfg_resp);
>>> +};
>>> +
>>> +#define EFI_HII_DATABASE_PROTOCOL_GUID            \
>>> +     EFI_GUID(0xef9fc172, 0xa1b2, 0x4693, \
>>> +              0xb3, 0x27, 0x6d, 0x32, 0xfc, 0x41, 0x60, 0x42)
>>> +
>>> +typedef enum {
>>> +     EFI_KEY_LCTRL, EFI_KEY_A0, EFI_KEY_LALT, EFI_KEY_SPACE_BAR,
>>> +     EFI_KEY_A2, EFI_KEY_A3, EFI_KEY_A4, EFI_KEY_RCTRL, EFI_KEY_LEFT_ARROW,
>>> +     EFI_KEY_DOWN_ARROW, EFI_KEY_RIGHT_ARROW, EFI_KEY_ZERO,
>>> +     EFI_KEY_PERIOD, EFI_KEY_ENTER, EFI_KEY_LSHIFT, EFI_KEY_B0,
>>> +     EFI_KEY_B1, EFI_KEY_B2, EFI_KEY_B3, EFI_KEY_B4, EFI_KEY_B5, EFI_KEY_B6,
>>> +     EFI_KEY_B7, EFI_KEY_B8, EFI_KEY_B9, EFI_KEY_B10, EFI_KEY_RSHIFT,
>>> +     EFI_KEY_UP_ARROW, EFI_KEY_ONE, EFI_KEY_TWO, EFI_KEY_THREE,
>>> +     EFI_KEY_CAPS_LOCK, EFI_KEY_C1, EFI_KEY_C2, EFI_KEY_C3, EFI_KEY_C4,
>>> +     EFI_KEY_C5, EFI_KEY_C6, EFI_KEY_C7, EFI_KEY_C8, EFI_KEY_C9,
>>> +     EFI_KEY_C10, EFI_KEY_C11, EFI_KEY_C12, EFI_KEY_FOUR, EFI_KEY_FIVE,
>>> +     EFI_KEY_SIX, EFI_KEY_PLUS, EFI_KEY_TAB, EFI_KEY_D1, EFI_KEY_D2,
>>> +     EFI_KEY_D3, EFI_KEY_D4, EFI_KEY_D5, EFI_KEY_D6, EFI_KEY_D7, EFI_KEY_D8,
>>> +     EFI_KEY_D9, EFI_KEY_D10, EFI_KEY_D11, EFI_KEY_D12, EFI_KEY_D13,
>>> +     EFI_KEY_DEL, EFI_KEY_END, EFI_KEY_PG_DN, EFI_KEY_SEVEN, EFI_KEY_EIGHT,
>>> +     EFI_KEY_NINE, EFI_KEY_E0, EFI_KEY_E1, EFI_KEY_E2, EFI_KEY_E3,
>>> +     EFI_KEY_E4, EFI_KEY_E5, EFI_KEY_E6, EFI_KEY_E7, EFI_KEY_E8, EFI_KEY_E9,
>>> +     EFI_KEY_E10, EFI_KEY_E11, EFI_KEY_E12, EFI_KEY_BACK_SPACE,
>>> +     EFI_KEY_INS, EFI_KEY_HOME, EFI_KEY_PG_UP, EFI_KEY_NLCK, EFI_KEY_SLASH,
>>> +     EFI_KEY_ASTERISK, EFI_KEY_MINUS, EFI_KEY_ESC, EFI_KEY_F1, EFI_KEY_F2,
>>> +     EFI_KEY_F3, EFI_KEY_F4, EFI_KEY_F5, EFI_KEY_F6, EFI_KEY_F7, EFI_KEY_F8,
>>> +     EFI_KEY_F9, EFI_KEY_F10, EFI_KEY_F11, EFI_KEY_F12, EFI_KEY_PRINT,
>>> +     EFI_KEY_SLCK, EFI_KEY_PAUSE,
>>> +} efi_key;
>>> +
>>> +struct efi_key_descriptor {
>>> +     efi_key key;
>>> +     uint16_t unicode;
>>> +     uint16_t shifted_unicode;
>>> +     uint16_t alt_gr_unicode;
>>> +     uint16_t shifted_alt_gr_unicode;
>>> +     uint16_t modifier;
>>> +     uint16_t affected_attribute;
>>> +};
>>> +
>>> +struct efi_hii_keyboard_layout {
>>> +     uint16_t layout_length;
>>> +     efi_guid_t guid;
>>> +     uint32_t layout_descriptor_string_offset;
>>> +     uint8_t descriptor_count;
>>> +     struct efi_key_descriptor descriptors[];
>>> +};
>>> +
>>> +struct efi_hii_package_list_header {
>>> +     efi_guid_t package_list_guid;
>>> +     uint32_t package_length;
>>> +} __packed;
>>> +
>>> +struct efi_hii_package_header {
>>> +     uint32_t length : 24;
>>> +     uint32_t type : 8;
>>> +} __packed;
>>
>> Bitfields are terribly evil - they're probably one of the worst defined
>> things in C. A different compiler may even give you different ordering
>> here. I've certainly seen bitfields explode in weird ways on
>> cross-endian conversions.
> 
> edk2 defines it in the same way.  And this is UEFI we are talking
> about here, big endian is strictly out of scope.

I don't see why big endian is strictly out of scope. I don't want to
ignore it light heartedly. All we'd need to do is byte swap every
input/output there is today.

So please change it to not use bitmasks. I don't think we should copy
bad design decisions from edk2.

> 
> 
>> Do you think you could just make that a uint32_t altogether and work
>> with MASK/SHIFT defines instead?
>>
>>
>>> +
>>> +#define EFI_HII_PACKAGE_TYPE_ALL          0x00
>>> +#define EFI_HII_PACKAGE_TYPE_GUID         0x01
>>> +#define EFI_HII_PACKAGE_FORMS             0x02
>>> +#define EFI_HII_PACKAGE_STRINGS           0x04
>>> +#define EFI_HII_PACKAGE_FONTS             0x05
>>> +#define EFI_HII_PACKAGE_IMAGES            0x06
>>> +#define EFI_HII_PACKAGE_SIMPLE_FONTS      0x07
>>> +#define EFI_HII_PACKAGE_DEVICE_PATH       0x08
>>> +#define EFI_HII_PACKAGE_KEYBOARD_LAYOUT   0x09
>>> +#define EFI_HII_PACKAGE_ANIMATIONS        0x0A
>>> +#define EFI_HII_PACKAGE_END               0xDF
>>> +#define EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN 0xE0
>>> +#define EFI_HII_PACKAGE_TYPE_SYSTEM_END   0xFF
>>> +
>>> +struct efi_hii_strings_package {
>>> +     struct efi_hii_package_header header;
>>> +     uint32_t header_size;
>>> +     uint32_t string_info_offset;
>>> +     uint16_t language_window[16];
>>> +     efi_string_id_t language_name;
>>> +     uint8_t  language[];
>>> +} __packed;
>>> +
>>> +struct efi_hii_string_block {
>>> +     uint8_t block_type;
>>> +     /*uint8_t block_body[];*/
>>> +} __packed;
>>> +
>>> +#define EFI_HII_SIBT_END               0x00 // The end of the string information.
>>> +#define EFI_HII_SIBT_STRING_SCSU       0x10 // Single string using default font information.
>>> +#define EFI_HII_SIBT_STRING_SCSU_FONT  0x11 // Single string with font information.
>>> +#define EFI_HII_SIBT_STRINGS_SCSU      0x12 // Multiple strings using default font information.
>>> +#define EFI_HII_SIBT_STRINGS_SCSU_FONT 0x13 // Multiple strings with font information.
>>> +#define EFI_HII_SIBT_STRING_UCS2       0x14 // Single UCS-2 string using default font information.
>>> +#define EFI_HII_SIBT_STRING_UCS2_FONT  0x15 // Single UCS-2 string with font information
>>> +#define EFI_HII_SIBT_STRINGS_UCS2      0x16 // Multiple UCS-2 strings using default font information.
>>> +#define EFI_HII_SIBT_STRINGS_UCS2_FONT 0x17 // Multiple UCS-2 strings with font information.
>>> +#define EFI_HII_SIBT_DUPLICATE         0x20 // Create a duplicate of an existing string.
>>> +#define EFI_HII_SIBT_SKIP2             0x21 // Skip a certain number of string identifiers.
>>> +#define EFI_HII_SIBT_SKIP1             0x22 // Skip a certain number of string identifiers.
>>> +#define EFI_HII_SIBT_EXT1              0x30 // For future expansion (one byte length field)
>>> +#define EFI_HII_SIBT_EXT2              0x31 // For future expansion (two byte length field)
>>> +#define EFI_HII_SIBT_EXT4              0x32 // For future expansion (four byte length field)
>>> +#define EFI_HII_SIBT_FONT              0x40 // Font information.
>>> +
>>> +struct efi_hii_sibt_string_ucs2_block {
>>> +     struct efi_hii_string_block header;
>>> +     uint16_t string_text[];
>>> +} __packed;
>>> +
>>> +static inline struct efi_hii_string_block *efi_hii_sibt_string_ucs2_block_next(
>>> +     struct efi_hii_sibt_string_ucs2_block *blk)
>>> +{
>>> +     return ((void *)blk) + sizeof(*blk) +
>>> +             (utf16_strlen(blk->string_text) + 1) * 2;
>>
>> Since you're dealing with actual utf16, is this correct? One character
>> may as well span 4 bytes, right?
>>
>> I think we need a different function that actually tells us the bytes
>> occupied by a utf16 string.
> 
> as mentioned on IRC (just repeating here for those who weren't
> following #u-boot), utf16_strlen() is actually telling us the number
> of 16b "bytes" in a utf16 string, not the number of "characters".
> Similar to strlen() with a utf8 string.
> 
>>> +}
>>> +
>>> +typedef void *efi_hii_handle_t;
>>> +
>>> +struct efi_hii_database_protocol {
>>> +     efi_status_t(EFIAPI *new_package_list)(
>>> +             const struct efi_hii_database_protocol *this,
>>> +             const struct efi_hii_package_list_header *package_list,
>>> +             const efi_handle_t driver_handle,
>>> +             efi_hii_handle_t *handle);
>>> +     efi_status_t(EFIAPI *remove_package_list)(
>>> +             const struct efi_hii_database_protocol *this,
>>> +             efi_hii_handle_t handle);
>>> +     efi_status_t(EFIAPI *update_package_list)(
>>> +             const struct efi_hii_database_protocol *this,
>>> +             efi_hii_handle_t handle,
>>> +             const struct efi_hii_package_list_header *package_list);
>>> +     efi_status_t(EFIAPI *list_package_lists)(
>>> +             const struct efi_hii_database_protocol *this,
>>> +             uint8_t package_type,
>>> +             const efi_guid_t *package_guid,
>>> +             efi_uintn_t *handle_buffer_length,
>>> +             efi_hii_handle_t *handle);
>>> +     efi_status_t(EFIAPI *export_package_lists)(
>>> +             const struct efi_hii_database_protocol *this,
>>> +             efi_hii_handle_t handle,
>>> +             efi_uintn_t *buffer_size,
>>> +             struct efi_hii_package_list_header *buffer);
>>> +     efi_status_t(EFIAPI *register_package_notify)(
>>> +             const struct efi_hii_database_protocol *this,
>>> +             uint8_t package_type,
>>> +             const efi_guid_t *package_guid,
>>> +             const void *package_notify_fn,
>>> +             efi_uintn_t notify_type,
>>> +             efi_handle_t *notify_handle);
>>> +     efi_status_t(EFIAPI *unregister_package_notify)(
>>> +             const struct efi_hii_database_protocol *this,
>>> +             efi_handle_t notification_handle
>>> +             );
>>> +     efi_status_t(EFIAPI *find_keyboard_layouts)(
>>> +             const struct efi_hii_database_protocol *this,
>>> +             uint16_t *key_guid_buffer_length,
>>> +             efi_guid_t *key_guid_buffer);
>>> +     efi_status_t(EFIAPI *get_keyboard_layout)(
>>> +             const struct efi_hii_database_protocol *this,
>>> +             efi_guid_t *key_guid,
>>> +             uint16_t *keyboard_layout_length,
>>> +             struct efi_hii_keyboard_layout *keyboard_layout);
>>> +     efi_status_t(EFIAPI *set_keyboard_layout)(
>>> +             const struct efi_hii_database_protocol *this,
>>> +             efi_guid_t *key_guid);
>>> +     efi_status_t(EFIAPI *get_package_list_handle)(
>>> +             const struct efi_hii_database_protocol *this,
>>> +             efi_hii_handle_t package_list_handle,
>>> +             efi_handle_t *driver_handle);
>>> +};
>>> +
>>> +#define EFI_HII_STRING_PROTOCOL_GUID \
>>> +     EFI_GUID(0x0fd96974, 0x23aa, 0x4cdc, \
>>> +              0xb9, 0xcb, 0x98, 0xd1, 0x77, 0x50, 0x32, 0x2a)
>>> +
>>> +typedef uint32_t efi_hii_font_style_t;
>>> +
>>> +struct efi_font_info {
>>> +     efi_hii_font_style_t font_style;
>>> +     uint16_t font_size;
>>> +     uint16_t font_name[1];
>>> +};
>>> +
>>> +struct efi_hii_string_protocol {
>>> +     efi_status_t(EFIAPI *new_string)(
>>> +             const struct efi_hii_string_protocol *this,
>>> +             efi_hii_handle_t package_list,
>>> +             efi_string_id_t *string_id,
>>> +             const uint8_t *language,
>>> +             const uint16_t *language_name,
>>> +             const efi_string_t string,
>>> +             const struct efi_font_info *string_font_info);
>>> +     efi_status_t(EFIAPI *get_string)(
>>> +             const struct efi_hii_string_protocol *this,
>>> +             const uint8_t *language,
>>> +             efi_hii_handle_t package_list,
>>> +             efi_string_id_t string_id,
>>> +             efi_string_t string,
>>> +             efi_uintn_t *string_size,
>>> +             struct efi_font_info **string_font_info);
>>> +     efi_status_t(EFIAPI *set_string)(
>>> +             const struct efi_hii_string_protocol *this,
>>> +             efi_hii_handle_t package_list,
>>> +             efi_string_id_t string_id,
>>> +             const uint8_t *language,
>>> +             const efi_string_t string,
>>> +             const struct efi_font_info *string_font_info);
>>> +     efi_status_t(EFIAPI *get_languages)(
>>> +             const struct efi_hii_string_protocol *this,
>>> +             efi_hii_handle_t package_list,
>>> +             uint8_t *languages,
>>> +             efi_uintn_t *languages_size);
>>> +     efi_status_t(EFIAPI *get_secondary_languages)(
>>> +             const struct efi_hii_string_protocol *this,
>>> +             efi_hii_handle_t package_list,
>>> +             const uint8_t *primary_language,
>>> +             uint8_t *secondary_languages,
>>> +             efi_uintn_t *secondary_languages_size);
>>> +};
>>> +
>>>  #define EFI_GOP_GUID \
>>>       EFI_GUID(0x9042a9de, 0x23dc, 0x4a38, \
>>>                0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a)
>>> diff --git a/include/efi_loader.h b/include/efi_loader.h
>>> index 5d37c1d75f..591bf07e7a 100644
>>> --- a/include/efi_loader.h
>>> +++ b/include/efi_loader.h
>>> @@ -80,6 +80,9 @@ extern struct efi_simple_input_interface efi_con_in;
>>>  extern const struct efi_console_control_protocol efi_console_control;
>>>  extern const struct efi_device_path_to_text_protocol efi_device_path_to_text;
>>>  extern const struct efi_device_path_utilities_protocol efi_device_path_utilities;
>>> +extern const struct efi_hii_config_routing_protocol efi_hii_config_routing;
>>> +extern const struct efi_hii_database_protocol efi_hii_database;
>>> +extern const struct efi_hii_string_protocol efi_hii_string;
>>>
>>>  uint16_t *efi_dp_str(struct efi_device_path *dp);
>>>
>>> @@ -91,6 +94,9 @@ extern const efi_guid_t efi_guid_device_path_to_text_protocol;
>>>  extern const efi_guid_t efi_simple_file_system_protocol_guid;
>>>  extern const efi_guid_t efi_file_info_guid;
>>>  extern const efi_guid_t efi_guid_device_path_utilities_protocol;
>>> +extern const efi_guid_t efi_guid_hii_config_routing_protocol;
>>> +extern const efi_guid_t efi_guid_hii_database_protocol;
>>> +extern const efi_guid_t efi_guid_hii_string_protocol;
>>>
>>>  extern unsigned int __efi_runtime_start, __efi_runtime_stop;
>>>  extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;
>>> diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
>>> index b6927b3b84..725e0cba85 100644
>>> --- a/lib/efi_loader/Makefile
>>> +++ b/lib/efi_loader/Makefile
>>> @@ -17,7 +17,7 @@ endif
>>>  obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o
>>>  obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o
>>>  obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o
>>> -obj-y += efi_device_path_utilities.o
>>> +obj-y += efi_device_path_utilities.o efi_hii.o
>>>  obj-y += efi_file.o efi_variable.o efi_bootmgr.o
>>>  obj-$(CONFIG_LCD) += efi_gop.o
>>>  obj-$(CONFIG_DM_VIDEO) += efi_gop.o
>>> diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
>>> index 92c778fcca..c179afc25a 100644
>>> --- a/lib/efi_loader/efi_boottime.c
>>> +++ b/lib/efi_loader/efi_boottime.c
>>> @@ -1157,6 +1157,15 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob
>>>       obj->protocols[4].protocol_interface =
>>>               (void *)&efi_device_path_utilities;
>>>
>>> +     obj->protocols[5].guid = &efi_guid_hii_string_protocol;
>>> +     obj->protocols[5].protocol_interface = (void *)&efi_hii_string;
>>> +
>>> +     obj->protocols[6].guid = &efi_guid_hii_database_protocol;
>>> +     obj->protocols[6].protocol_interface = (void *)&efi_hii_database;
>>> +
>>> +     obj->protocols[7].guid = &efi_guid_hii_config_routing_protocol;
>>> +     obj->protocols[7].protocol_interface = (void *)&efi_hii_config_routing;
>>> +
>>>       info->file_path = file_path;
>>>       info->device_handle = efi_dp_find_obj(device_path, NULL);
>>>
>>> diff --git a/lib/efi_loader/efi_hii.c b/lib/efi_loader/efi_hii.c
>>> new file mode 100644
>>> index 0000000000..25c8e88a60
>>> --- /dev/null
>>> +++ b/lib/efi_loader/efi_hii.c
>>> @@ -0,0 +1,507 @@
>>> +/*
>>> + *  EFI Human Interface Infrastructure ... interface
>>> + *
>>> + *  Copyright (c) 2017 Leif Lindholm
>>> + *
>>> + *  SPDX-License-Identifier:     GPL-2.0+
>>> + */
>>> +
>>> +#include <common.h>
>>> +#include <malloc.h>
>>> +#include <efi_loader.h>
>>> +
>>> +const efi_guid_t efi_guid_hii_config_routing_protocol =
>>> +     EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID;
>>> +const efi_guid_t efi_guid_hii_database_protocol = EFI_HII_DATABASE_PROTOCOL_GUID;
>>> +const efi_guid_t efi_guid_hii_string_protocol = EFI_HII_STRING_PROTOCOL_GUID;
>>> +
>>> +struct hii_package {
>>> +     // TODO should there be an associated efi_object?
>>> +     struct list_head string_tables;     /* list of string_table */
>>> +     /* we could also track fonts, images, etc */
>>> +};
>>> +
>>> +struct string_table {
>>> +     struct list_head link;
>>> +     efi_string_id_t language_name;
>>> +     char *language;
>>> +     uint32_t nstrings;
>>> +     /* NOTE: string id starts at 1 so value is stbl->strings[id-1] */
>>> +     struct {
>>> +             efi_string_t string;
>>> +             /* we could also track font info, etc */
>>> +     } strings[];
>>> +};
>>> +
>>> +static void free_strings_table(struct string_table *stbl)
>>> +{
>>> +     int i;
>>> +
>>> +     for (i = 0; i < stbl->nstrings; i++)
>>> +             free(stbl->strings[i].string);
>>> +     free(stbl->language);
>>> +     free(stbl);
>>> +}
>>> +
>>> +static struct hii_package *new_package(void)
>>> +{
>>> +     struct hii_package *hii = malloc(sizeof(*hii));
>>> +     INIT_LIST_HEAD(&hii->string_tables);
>>> +     return hii;
>>> +}
>>> +
>>> +static void free_package(struct hii_package *hii)
>>> +{
>>> +
>>> +     while (!list_empty(&hii->string_tables)) {
>>> +             struct string_table *stbl;
>>> +
>>> +             stbl = list_first_entry(&hii->string_tables,
>>> +                                     struct string_table, link);
>>> +             list_del(&stbl->link);
>>> +             free_strings_table(stbl);
>>> +     }
>>> +
>>> +     free(hii);
>>> +}
>>> +
>>> +static efi_status_t add_strings_package(struct hii_package *hii,
>>> +     struct efi_hii_strings_package *strings_package)
>>> +{
>>> +     struct efi_hii_string_block *block;
>>> +     void *end = ((void *)strings_package) + strings_package->header.length;
>>> +     uint32_t nstrings = 0;
>>> +     unsigned id = 0;
>>> +
>>> +     debug("header_size: %08x\n", strings_package->header_size);
>>> +     debug("string_info_offset: %08x\n", strings_package->string_info_offset);
>>> +     debug("language_name: %u\n", strings_package->language_name);
>>> +     debug("language: %s\n", strings_package->language);
>>> +
>>> +     /* count # of string entries: */
>>> +     block = ((void *)strings_package) + strings_package->string_info_offset;
>>> +     while ((void *)block < end) {
>>> +             switch (block->block_type) {
>>> +             case EFI_HII_SIBT_STRING_UCS2: {
>>> +                     struct efi_hii_sibt_string_ucs2_block *ucs2 =
>>> +                             (void *)block;
>>> +                     nstrings++;
>>> +                     block = efi_hii_sibt_string_ucs2_block_next(ucs2);
>>> +                     break;
>>> +             }
>>> +             case EFI_HII_SIBT_END:
>>> +                     block = end;
>>> +                     break;
>>> +             default:
>>> +                     debug("unknown HII string block type: %02x\n",
>>> +                           block->block_type);
>>> +                     return EFI_INVALID_PARAMETER;
>>> +             }
>>> +     }
>>> +
>>> +     struct string_table *stbl = malloc(sizeof(*stbl) +
>>> +                     (nstrings * sizeof(stbl->strings[0])));
>>> +     stbl->language_name = strings_package->language_name;
>>> +     stbl->language = strdup((char *)strings_package->language);
>>
>> Where does the strings_package come from? And why is the language in it
>> in UTF8?
> 
> The strings_package is a part of the "package list" blob passed in
> from (in this case) Shell.efi.  The package list can actually contain
> a lot more (fonts/glyphs/images/forms), but not really sure how much
> of that we'll actually support.  (HII seems to be able to do enough
> for rendering a full blown GUI.. kinda overkill, IMHO.. but Shell.efi
> wants it for silly reasons.)
> 
> This is actually utf8.. it is a "RFC 4646 language code identifier".
> See appendix M.
> 
> 
>>
>>> +     stbl->nstrings = nstrings;
>>> +
>>> +     list_add(&stbl->link, &hii->string_tables);
>>> +
>>> +     /* and now parse string entries and populate string_table */
>>> +     block = ((void *)strings_package) + strings_package->string_info_offset;
>>> +
>>> +     while ((void *)block < end) {
>>> +             switch (block->block_type) {
>>> +             case EFI_HII_SIBT_STRING_UCS2: {
>>> +                     struct efi_hii_sibt_string_ucs2_block *ucs2 =
>>> +                             (void *)block;
>>> +                     id++;
>>> +                     debug("%4u: \"%ls\"\n", id, ucs2->string_text);
>>> +                     stbl->strings[id-1].string =
>>> +                             utf16_strdup(ucs2->string_text);
>>> +                     block = efi_hii_sibt_string_ucs2_block_next(ucs2);
>>> +                     break;
>>> +             }
>>> +             case EFI_HII_SIBT_END:
>>> +                     return EFI_SUCCESS;
>>> +             default:
>>> +                     debug("unknown HII string block type: %02x\n",
>>> +                           block->block_type);
>>> +                     return EFI_INVALID_PARAMETER;
>>> +             }
>>> +     }
>>> +
>>> +     return EFI_SUCCESS;
>>> +}
>>> +
>>> +/*
>>> + * EFI_HII_CONFIG_ROUTING_PROTOCOL
>>> + */
>>> +
>>> +static efi_status_t EFIAPI extract_config(
>>> +     const struct efi_hii_config_routing_protocol *this,
>>> +     const efi_string_t request,
>>> +     efi_string_t *progress,
>>> +     efi_string_t *results)
>>> +{
>>> +     EFI_ENTRY("%p, \"%ls\", %p, %p", this, request, progress, results);
>>> +     return EFI_EXIT(EFI_OUT_OF_RESOURCES);
>>> +}
>>> +
>>> +static efi_status_t EFIAPI export_config(
>>> +     const struct efi_hii_config_routing_protocol *this,
>>> +     efi_string_t *results)
>>> +{
>>> +     EFI_ENTRY("%p, %p", this, results);
>>> +     return EFI_EXIT(EFI_OUT_OF_RESOURCES);
>>> +}
>>> +
>>> +static efi_status_t EFIAPI route_config(
>>> +     const struct efi_hii_config_routing_protocol *this,
>>> +     const efi_string_t configuration,
>>> +     efi_string_t *progress)
>>> +{
>>> +     EFI_ENTRY("%p, \"%ls\", %p", this, configuration, progress);
>>> +     return EFI_EXIT(EFI_OUT_OF_RESOURCES);
>>> +}
>>> +
>>> +static efi_status_t EFIAPI block_to_config(
>>> +     const struct efi_hii_config_routing_protocol *this,
>>> +     const efi_string_t config_request,
>>> +     const uint8_t *block,
>>> +     const efi_uintn_t block_size,
>>> +     efi_string_t *config,
>>> +     efi_string_t *progress)
>>> +{
>>> +     EFI_ENTRY("%p, \"%ls\", %p, %zu, %p, %p", this, config_request, block,
>>> +               block_size, config, progress);
>>> +     return EFI_EXIT(EFI_OUT_OF_RESOURCES);
>>> +}
>>> +
>>> +static efi_status_t EFIAPI config_to_block(
>>> +     const struct efi_hii_config_routing_protocol *this,
>>> +     const efi_string_t config_resp,
>>> +     const uint8_t *block,
>>> +     const efi_uintn_t *block_size,
>>> +     efi_string_t *progress)
>>> +{
>>> +     EFI_ENTRY("%p, \"%ls\", %p, %p, %p", this, config_resp, block,
>>> +               block_size, progress);
>>> +     return EFI_EXIT(EFI_OUT_OF_RESOURCES);
>>> +}
>>> +
>>> +static efi_status_t EFIAPI get_alt_config(
>>> +     const struct efi_hii_config_routing_protocol *this,
>>> +     const efi_string_t config_resp,
>>> +     const efi_guid_t *guid,
>>> +     const efi_string_t name,
>>> +     const struct efi_device_path *device_path,
>>> +     const efi_string_t alt_cfg_id,
>>> +     efi_string_t *alt_cfg_resp)
>>> +{
>>> +     EFI_ENTRY("%p, \"%ls\", %pUl, \"%ls\", %p, \"%ls\", %p", this,
>>> +               config_resp, guid, name, device_path, alt_cfg_id,
>>> +               alt_cfg_resp);
>>> +     return EFI_EXIT(EFI_OUT_OF_RESOURCES);
>>> +}
>>> +
>>> +
>>> +/*
>>> + * EFI_HII_DATABASE_PROTOCOL
>>> + */
>>> +
>>> +static efi_status_t EFIAPI new_package_list(
>>> +     const struct efi_hii_database_protocol *this,
>>> +     const struct efi_hii_package_list_header *package_list,
>>> +     const efi_handle_t driver_handle,
>>> +     efi_hii_handle_t *handle)
>>> +{
>>> +     efi_status_t ret = EFI_SUCCESS;
>>> +
>>> +     EFI_ENTRY("%p, %p, %p, %p", this, package_list, driver_handle, handle);
>>> +
>>> +     if (!package_list || !driver_handle)
>>> +             return EFI_EXIT(EFI_INVALID_PARAMETER);
>>> +
>>> +     struct hii_package *hii = new_package();
>>> +     struct efi_hii_package_header *package;
>>> +     void *end = ((void *)package_list) + package_list->package_length;
>>> +
>>> +     debug("package_list: %pUl (%u)\n", &package_list->package_list_guid,
>>> +           package_list->package_length);
>>> +
>>> +     package = ((void *)package_list) + sizeof(*package_list);
>>> +     while ((void *)package < end) {
>>> +             debug("package=%p, package type=%x, length=%u\n", package,
>>> +                   package->type, package->length);
>>> +             switch (package->type) {
>>> +             case EFI_HII_PACKAGE_STRINGS:
>>> +                     ret = add_strings_package(hii,
>>> +                             (struct efi_hii_strings_package *)package);
>>> +                     break;
>>> +             default:
>>> +                     break;
>>> +             }
>>> +
>>> +             if (ret != EFI_SUCCESS)
>>> +                     goto error;
>>> +
>>> +             package = ((void *)package) + package->length;
>>> +     }
>>> +
>>> +     // TODO in theory there is some notifications that should be sent..
>>> +
>>> +     *handle = hii;
>>> +
>>> +     return EFI_EXIT(EFI_SUCCESS);
>>> +
>>> +error:
>>> +     free_package(hii);
>>> +     return EFI_EXIT(ret);
>>> +}
>>> +
>>> +static efi_status_t EFIAPI remove_package_list(
>>> +     const struct efi_hii_database_protocol *this,
>>> +     efi_hii_handle_t handle)
>>> +{
>>> +     struct hii_package *hii = handle;
>>> +     EFI_ENTRY("%p, %p", this, handle);
>>> +     free_package(hii);
>>> +     return EFI_EXIT(EFI_SUCCESS);
>>> +}
>>> +
>>> +static efi_status_t EFIAPI update_package_list(
>>> +     const struct efi_hii_database_protocol *this,
>>> +     efi_hii_handle_t handle,
>>> +     const struct efi_hii_package_list_header *package_list)
>>> +{
>>> +     EFI_ENTRY("%p, %p, %p", this, handle, package_list);
>>> +     return EFI_EXIT(EFI_NOT_FOUND);
>>> +}
>>> +
>>> +static efi_status_t EFIAPI list_package_lists(
>>> +     const struct efi_hii_database_protocol *this,
>>> +     uint8_t package_type,
>>> +     const efi_guid_t *package_guid,
>>> +     efi_uintn_t *handle_buffer_length,
>>> +     efi_hii_handle_t *handle)
>>> +{
>>> +     EFI_ENTRY("%p, %u, %pUl, %p, %p", this, package_type, package_guid,
>>> +               handle_buffer_length, handle);
>>> +     return EFI_EXIT(EFI_NOT_FOUND);
>>> +}
>>> +
>>> +static efi_status_t EFIAPI export_package_lists(
>>> +     const struct efi_hii_database_protocol *this,
>>> +     efi_hii_handle_t handle,
>>> +     efi_uintn_t *buffer_size,
>>> +     struct efi_hii_package_list_header *buffer)
>>> +{
>>> +     EFI_ENTRY("%p, %p, %p, %p", this, handle, buffer_size, buffer);
>>> +     return EFI_EXIT(EFI_NOT_FOUND);
>>> +}
>>> +
>>> +static efi_status_t EFIAPI register_package_notify(
>>> +     const struct efi_hii_database_protocol *this,
>>> +     uint8_t package_type,
>>> +     const efi_guid_t *package_guid,
>>> +     const void *package_notify_fn,
>>> +     efi_uintn_t notify_type,
>>> +     efi_handle_t *notify_handle)
>>> +{
>>> +     EFI_ENTRY("%p, %u, %pUl, %p, %zu, %p", this, package_type,
>>> +               package_guid, package_notify_fn, notify_type,
>>> +               notify_handle);
>>> +     return EFI_EXIT(EFI_OUT_OF_RESOURCES);
>>> +}
>>> +
>>> +static efi_status_t EFIAPI unregister_package_notify(
>>> +     const struct efi_hii_database_protocol *this,
>>> +     efi_handle_t notification_handle)
>>> +{
>>> +     EFI_ENTRY("%p, %p", this, notification_handle);
>>> +     return EFI_EXIT(EFI_NOT_FOUND);
>>> +}
>>> +
>>> +static efi_status_t EFIAPI find_keyboard_layouts(
>>> +     const struct efi_hii_database_protocol *this,
>>> +     uint16_t *key_guid_buffer_length,
>>> +     efi_guid_t *key_guid_buffer)
>>> +{
>>> +     EFI_ENTRY("%p, %p, %p", this, key_guid_buffer_length, key_guid_buffer);
>>> +     return EFI_EXIT(EFI_NOT_FOUND); /* Invalid */
>>> +}
>>> +
>>> +static efi_status_t EFIAPI get_keyboard_layout(
>>> +     const struct efi_hii_database_protocol *this,
>>> +     efi_guid_t *key_guid,
>>> +     uint16_t *keyboard_layout_length,
>>> +     struct efi_hii_keyboard_layout *keyboard_layout)
>>> +{
>>> +     EFI_ENTRY("%p, %pUl, %p, %p", this, key_guid, keyboard_layout_length,
>>> +               keyboard_layout);
>>> +     return EFI_EXIT(EFI_NOT_FOUND);
>>> +}
>>> +
>>> +static efi_status_t EFIAPI set_keyboard_layout(
>>> +     const struct efi_hii_database_protocol *this,
>>> +     efi_guid_t *key_guid)
>>> +{
>>> +     EFI_ENTRY("%p, %pUl", this, key_guid);
>>> +     return EFI_EXIT(EFI_NOT_FOUND);
>>> +}
>>> +
>>> +static efi_status_t EFIAPI get_package_list_handle(
>>> +     const struct efi_hii_database_protocol *this,
>>> +     efi_hii_handle_t package_list_handle,
>>> +     efi_handle_t *driver_handle)
>>> +{
>>> +     EFI_ENTRY("%p, %p, %p", this, package_list_handle, driver_handle);
>>> +     return EFI_EXIT(EFI_INVALID_PARAMETER);
>>> +}
>>> +
>>> +
>>> +/*
>>> + * EFI_HII_STRING_PROTOCOL
>>> + */
>>> +
>>> +static efi_status_t EFIAPI new_string(
>>> +     const struct efi_hii_string_protocol *this,
>>> +     efi_hii_handle_t package_list,
>>> +     efi_string_id_t *string_id,
>>> +     const uint8_t *language,
>>> +     const uint16_t *language_name,
>>> +     const efi_string_t string,
>>> +     const struct efi_font_info *string_font_info)
>>> +{
>>> +     EFI_ENTRY("%p, %p, %p, \"%s\", %p, \"%ls\", %p", this, package_list,
>>> +               string_id, language, language_name, string,
>>> +               string_font_info);
>>> +     return EFI_EXIT(EFI_NOT_FOUND);
>>> +}
>>> +
>>> +static efi_status_t EFIAPI get_string(
>>> +     const struct efi_hii_string_protocol *this,
>>> +     const uint8_t *language,
>>> +     efi_hii_handle_t package_list,
>>> +     efi_string_id_t string_id,
>>> +     efi_string_t string,
>>> +     efi_uintn_t *string_size,
>>> +     struct efi_font_info **string_font_info)
>>> +{
>>> +     struct hii_package *hii = package_list;
>>> +     struct string_table *stbl;
>>> +
>>> +     EFI_ENTRY("%p, \"%s\", %p, %u, %p, %p, %p", this, language,
>>> +               package_list, string_id, string, string_size,
>>> +               string_font_info);
>>> +
>>> +     list_for_each_entry(stbl, &hii->string_tables, link) {
>>> +             if (!strcmp((char *)language, (char *)stbl->language)) {
>>> +                     unsigned idx = string_id - 1;
>>> +                     if (idx > stbl->nstrings)
>>> +                             return EFI_EXIT(EFI_NOT_FOUND);
>>> +                     efi_string_t str = stbl->strings[idx].string;
>>> +                     size_t len = utf16_strlen(str) + 1;
>>
>> I assume that's wrong for sizing too?
> 
> nope :-)
> 
>> Also please try not to define variables mid-scope :). Just define them
>> above the if() and fill them after ...
> 
> Hmm, I'd have the inverse comment if someone else wrote it and defined
> all the variables at the top ;-)
> 
>> Then also for the sake of readability add a blank line after the
>> variable definitions and before the return.
>>
>> I think you'd also do yourself a favor if you reduced the indenting a
>> bit. Just abort the list_for_each when you found and entry and then
>> process it in the top level scope.
>>
>> static struct string_table *find_stbl_by_lang(const char *language)
>> {
>>     list_for_each(...) {
>>         if (matches) {
>>             return stbl;
>>         }
>>     }
>>
>>     return NULL;
>> }
>>
>> stbl = find_stbl_by_lang(lang);
>> if (!stbl)
>>     return EFI_EXIT(EFI_NOT_FOUND)
> 
> yeah, perhaps

Please rework it for v2 :)


Alex

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 06/11] efi_loader: Decouple EFI input/output from stdin/stdout
  2017-10-11 22:07     ` Rob Clark
@ 2017-10-12  7:15       ` Alexander Graf
  2017-10-12 12:48         ` Rob Clark
  0 siblings, 1 reply; 75+ messages in thread
From: Alexander Graf @ 2017-10-12  7:15 UTC (permalink / raw)
  To: u-boot



On 12.10.17 00:07, Rob Clark wrote:
> On Wed, Oct 11, 2017 at 10:45 AM, Alexander Graf <agraf@suse.de> wrote:
>>
>>
>> On 10.10.17 14:23, Rob Clark wrote:
>>> In some cases, it is quite useful to have (for example) EFI on screen
>>> but u-boot on serial port.
>>>
>>> This adds two new optional environment variables, "efiin" and "efiout",
>>> which can be used to set EFI console input/output independently of
>>> u-boot's input/output.  If unset, EFI console will default to stdin/
>>> stdout as before.
>>>
>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>
>> With this patch, we lose the ability to have the efi in/out go to both
>> graphical and serial console, right? This is critical functionality to
>> have, since we don't necessarily know which output/input a user ends up
>> using.
> 
> I'll think about how to support iomux.. but some things like console
> size are just not going to work properly there.  And as long as we fix

Yeah, those probably would need to get special cased.

> the stdout shenanigans (ie. what I was seeing w/ qemu-x86) you can
> simply not set efiout var and have things working as before, so you
> don't loose any existing functionality (although, like I said, if the
> two different consoles have different sizes things aren't going to
> work properly for anything other than simple cases).
> 
> In most cases, the display driver should be able to detect whether a
> display is connected.. this is what I've done on dragonboard410c, so
> if no display plugged in, 'efiout=vidconsole' fails and you fall back
> to serial, else you get efi on screen like you would on a "real"
> computer.  For boards that have a display driver that isn't able to do
> the basic check of whether a cable is plugged in, just don't set
> "efiout" (or fix the display driver) ;-)

Are you sure that's what happens on a "real" computer? As far as I
remember from all ARM servers running edk2 based firmware that I've
touched so far, the default is always to display on serial *and*
graphical output at the same time.


Alex

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 02/11] efi_loader: Initial HII protocols
  2017-10-12  7:13       ` Alexander Graf
@ 2017-10-12  9:55         ` Rob Clark
  2017-10-12  9:59           ` Alexander Graf
  0 siblings, 1 reply; 75+ messages in thread
From: Rob Clark @ 2017-10-12  9:55 UTC (permalink / raw)
  To: u-boot

On Thu, Oct 12, 2017 at 3:13 AM, Alexander Graf <agraf@suse.de> wrote:
>
>
> On 12.10.17 00:02, Rob Clark wrote:
>> On Wed, Oct 11, 2017 at 10:30 AM, Alexander Graf <agraf@suse.de> wrote:
>>>
>>>
>>> On 10.10.17 14:22, Rob Clark wrote:
>>>> From: Leif Lindholm <leif.lindholm@linaro.org>
>>>>
>>>> Enough implementation of the following protocols to run Shell.efi and
>>>> SCT.efi:
>>>>
>>>>   EfiHiiConfigRoutingProtocolGuid
>>>>   EfiHiiDatabaseProtocol
>>>>   EfiHiiStringProtocol
>>>>
>>>> We'll fill in the rest once SCT is running properly so we can validate
>>>> the implementation against the conformance test suite.
>>>>
>>>> Initial skeleton written by Leif, and then implementation by myself.
>>>>
>>>> Cc: Leif Lindholm <leif.lindholm@linaro.org>
>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>>> ---
>>>>  include/efi_api.h             | 261 ++++++++++++++++++++++
>>>>  include/efi_loader.h          |   6 +
>>>>  lib/efi_loader/Makefile       |   2 +-
>>>>  lib/efi_loader/efi_boottime.c |   9 +
>>>>  lib/efi_loader/efi_hii.c      | 507 ++++++++++++++++++++++++++++++++++++++++++
>>>>  5 files changed, 784 insertions(+), 1 deletion(-)
>>>>  create mode 100644 lib/efi_loader/efi_hii.c
>>>>
>>>> diff --git a/include/efi_api.h b/include/efi_api.h
>>>> index ffdba7fe1a..164147dc87 100644
>>>> --- a/include/efi_api.h
>>>> +++ b/include/efi_api.h
>>>> @@ -16,6 +16,7 @@
>>>>  #define _EFI_API_H
>>>>
>>>>  #include <efi.h>
>>>> +#include <charset.h>
>>>>
>>>>  #ifdef CONFIG_EFI_LOADER
>>>>  #include <asm/setjmp.h>
>>>> @@ -536,6 +537,266 @@ struct efi_device_path_utilities_protocol {
>>>>               uint16_t node_length);
>>>>  };
>>>>
>>>> +#define EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID \
>>>> +     EFI_GUID(0x587e72d7, 0xcc50, 0x4f79, \
>>>> +              0x82, 0x09, 0xca, 0x29, 0x1f, 0xc1, 0xa1, 0x0f)
>>>> +
>>>> +typedef uint16_t efi_string_id_t;
>>>> +
>>>> +struct efi_hii_config_routing_protocol {
>>>> +     efi_status_t(EFIAPI *extract_config)(
>>>> +             const struct efi_hii_config_routing_protocol *this,
>>>> +             const efi_string_t request,
>>>> +             efi_string_t *progress,
>>>> +             efi_string_t *results);
>>>> +     efi_status_t(EFIAPI *export_config)(
>>>> +             const struct efi_hii_config_routing_protocol *this,
>>>> +             efi_string_t *results);
>>>> +     efi_status_t(EFIAPI *route_config)(
>>>> +             const struct efi_hii_config_routing_protocol *this,
>>>> +             const efi_string_t configuration,
>>>> +             efi_string_t *progress);
>>>> +     efi_status_t(EFIAPI *block_to_config)(
>>>> +             const struct efi_hii_config_routing_protocol *this,
>>>> +             const efi_string_t config_request,
>>>> +             const uint8_t *block,
>>>> +             const efi_uintn_t block_size,
>>>> +             efi_string_t *config,
>>>> +             efi_string_t *progress);
>>>> +     efi_status_t(EFIAPI *config_to_block)(
>>>> +             const struct efi_hii_config_routing_protocol *this,
>>>> +             const efi_string_t config_resp,
>>>> +             const uint8_t *block,
>>>> +             const efi_uintn_t *block_size,
>>>> +             efi_string_t *progress);
>>>> +     efi_status_t(EFIAPI *get_alt_config)(
>>>> +             const struct efi_hii_config_routing_protocol *this,
>>>> +             const efi_string_t config_resp,
>>>> +             const efi_guid_t *guid,
>>>> +             const efi_string_t name,
>>>> +             const struct efi_device_path *device_path,
>>>> +             const efi_string_t alt_cfg_id,
>>>> +             efi_string_t *alt_cfg_resp);
>>>> +};
>>>> +
>>>> +#define EFI_HII_DATABASE_PROTOCOL_GUID            \
>>>> +     EFI_GUID(0xef9fc172, 0xa1b2, 0x4693, \
>>>> +              0xb3, 0x27, 0x6d, 0x32, 0xfc, 0x41, 0x60, 0x42)
>>>> +
>>>> +typedef enum {
>>>> +     EFI_KEY_LCTRL, EFI_KEY_A0, EFI_KEY_LALT, EFI_KEY_SPACE_BAR,
>>>> +     EFI_KEY_A2, EFI_KEY_A3, EFI_KEY_A4, EFI_KEY_RCTRL, EFI_KEY_LEFT_ARROW,
>>>> +     EFI_KEY_DOWN_ARROW, EFI_KEY_RIGHT_ARROW, EFI_KEY_ZERO,
>>>> +     EFI_KEY_PERIOD, EFI_KEY_ENTER, EFI_KEY_LSHIFT, EFI_KEY_B0,
>>>> +     EFI_KEY_B1, EFI_KEY_B2, EFI_KEY_B3, EFI_KEY_B4, EFI_KEY_B5, EFI_KEY_B6,
>>>> +     EFI_KEY_B7, EFI_KEY_B8, EFI_KEY_B9, EFI_KEY_B10, EFI_KEY_RSHIFT,
>>>> +     EFI_KEY_UP_ARROW, EFI_KEY_ONE, EFI_KEY_TWO, EFI_KEY_THREE,
>>>> +     EFI_KEY_CAPS_LOCK, EFI_KEY_C1, EFI_KEY_C2, EFI_KEY_C3, EFI_KEY_C4,
>>>> +     EFI_KEY_C5, EFI_KEY_C6, EFI_KEY_C7, EFI_KEY_C8, EFI_KEY_C9,
>>>> +     EFI_KEY_C10, EFI_KEY_C11, EFI_KEY_C12, EFI_KEY_FOUR, EFI_KEY_FIVE,
>>>> +     EFI_KEY_SIX, EFI_KEY_PLUS, EFI_KEY_TAB, EFI_KEY_D1, EFI_KEY_D2,
>>>> +     EFI_KEY_D3, EFI_KEY_D4, EFI_KEY_D5, EFI_KEY_D6, EFI_KEY_D7, EFI_KEY_D8,
>>>> +     EFI_KEY_D9, EFI_KEY_D10, EFI_KEY_D11, EFI_KEY_D12, EFI_KEY_D13,
>>>> +     EFI_KEY_DEL, EFI_KEY_END, EFI_KEY_PG_DN, EFI_KEY_SEVEN, EFI_KEY_EIGHT,
>>>> +     EFI_KEY_NINE, EFI_KEY_E0, EFI_KEY_E1, EFI_KEY_E2, EFI_KEY_E3,
>>>> +     EFI_KEY_E4, EFI_KEY_E5, EFI_KEY_E6, EFI_KEY_E7, EFI_KEY_E8, EFI_KEY_E9,
>>>> +     EFI_KEY_E10, EFI_KEY_E11, EFI_KEY_E12, EFI_KEY_BACK_SPACE,
>>>> +     EFI_KEY_INS, EFI_KEY_HOME, EFI_KEY_PG_UP, EFI_KEY_NLCK, EFI_KEY_SLASH,
>>>> +     EFI_KEY_ASTERISK, EFI_KEY_MINUS, EFI_KEY_ESC, EFI_KEY_F1, EFI_KEY_F2,
>>>> +     EFI_KEY_F3, EFI_KEY_F4, EFI_KEY_F5, EFI_KEY_F6, EFI_KEY_F7, EFI_KEY_F8,
>>>> +     EFI_KEY_F9, EFI_KEY_F10, EFI_KEY_F11, EFI_KEY_F12, EFI_KEY_PRINT,
>>>> +     EFI_KEY_SLCK, EFI_KEY_PAUSE,
>>>> +} efi_key;
>>>> +
>>>> +struct efi_key_descriptor {
>>>> +     efi_key key;
>>>> +     uint16_t unicode;
>>>> +     uint16_t shifted_unicode;
>>>> +     uint16_t alt_gr_unicode;
>>>> +     uint16_t shifted_alt_gr_unicode;
>>>> +     uint16_t modifier;
>>>> +     uint16_t affected_attribute;
>>>> +};
>>>> +
>>>> +struct efi_hii_keyboard_layout {
>>>> +     uint16_t layout_length;
>>>> +     efi_guid_t guid;
>>>> +     uint32_t layout_descriptor_string_offset;
>>>> +     uint8_t descriptor_count;
>>>> +     struct efi_key_descriptor descriptors[];
>>>> +};
>>>> +
>>>> +struct efi_hii_package_list_header {
>>>> +     efi_guid_t package_list_guid;
>>>> +     uint32_t package_length;
>>>> +} __packed;
>>>> +
>>>> +struct efi_hii_package_header {
>>>> +     uint32_t length : 24;
>>>> +     uint32_t type : 8;
>>>> +} __packed;
>>>
>>> Bitfields are terribly evil - they're probably one of the worst defined
>>> things in C. A different compiler may even give you different ordering
>>> here. I've certainly seen bitfields explode in weird ways on
>>> cross-endian conversions.
>>
>> edk2 defines it in the same way.  And this is UEFI we are talking
>> about here, big endian is strictly out of scope.
>
> I don't see why big endian is strictly out of scope. I don't want to
> ignore it light heartedly. All we'd need to do is byte swap every
> input/output there is today.

See section 1.9.1:

"
Supported processors are “little endian” machines. This distinction
means that the low-
order byte of a multibyte data item in memory is at the lowest
address, while the high-
order byte is at the highest address. Some supported 64-bit processors may be
configured for both “little endian” and “big endian” operation. All
implementations
designed to conform to this specification use “little endian” operation.
"

even power9 got sane and is finally is switching to LE ;-)

BR,
-R

> So please change it to not use bitmasks. I don't think we should copy
> bad design decisions from edk2.
>
>>
>>
>>> Do you think you could just make that a uint32_t altogether and work
>>> with MASK/SHIFT defines instead?
>>>
>>>
>>>> +
>>>> +#define EFI_HII_PACKAGE_TYPE_ALL          0x00
>>>> +#define EFI_HII_PACKAGE_TYPE_GUID         0x01
>>>> +#define EFI_HII_PACKAGE_FORMS             0x02
>>>> +#define EFI_HII_PACKAGE_STRINGS           0x04
>>>> +#define EFI_HII_PACKAGE_FONTS             0x05
>>>> +#define EFI_HII_PACKAGE_IMAGES            0x06
>>>> +#define EFI_HII_PACKAGE_SIMPLE_FONTS      0x07
>>>> +#define EFI_HII_PACKAGE_DEVICE_PATH       0x08
>>>> +#define EFI_HII_PACKAGE_KEYBOARD_LAYOUT   0x09
>>>> +#define EFI_HII_PACKAGE_ANIMATIONS        0x0A
>>>> +#define EFI_HII_PACKAGE_END               0xDF
>>>> +#define EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN 0xE0
>>>> +#define EFI_HII_PACKAGE_TYPE_SYSTEM_END   0xFF
>>>> +
>>>> +struct efi_hii_strings_package {
>>>> +     struct efi_hii_package_header header;
>>>> +     uint32_t header_size;
>>>> +     uint32_t string_info_offset;
>>>> +     uint16_t language_window[16];
>>>> +     efi_string_id_t language_name;
>>>> +     uint8_t  language[];
>>>> +} __packed;
>>>> +
>>>> +struct efi_hii_string_block {
>>>> +     uint8_t block_type;
>>>> +     /*uint8_t block_body[];*/
>>>> +} __packed;
>>>> +
>>>> +#define EFI_HII_SIBT_END               0x00 // The end of the string information.
>>>> +#define EFI_HII_SIBT_STRING_SCSU       0x10 // Single string using default font information.
>>>> +#define EFI_HII_SIBT_STRING_SCSU_FONT  0x11 // Single string with font information.
>>>> +#define EFI_HII_SIBT_STRINGS_SCSU      0x12 // Multiple strings using default font information.
>>>> +#define EFI_HII_SIBT_STRINGS_SCSU_FONT 0x13 // Multiple strings with font information.
>>>> +#define EFI_HII_SIBT_STRING_UCS2       0x14 // Single UCS-2 string using default font information.
>>>> +#define EFI_HII_SIBT_STRING_UCS2_FONT  0x15 // Single UCS-2 string with font information
>>>> +#define EFI_HII_SIBT_STRINGS_UCS2      0x16 // Multiple UCS-2 strings using default font information.
>>>> +#define EFI_HII_SIBT_STRINGS_UCS2_FONT 0x17 // Multiple UCS-2 strings with font information.
>>>> +#define EFI_HII_SIBT_DUPLICATE         0x20 // Create a duplicate of an existing string.
>>>> +#define EFI_HII_SIBT_SKIP2             0x21 // Skip a certain number of string identifiers.
>>>> +#define EFI_HII_SIBT_SKIP1             0x22 // Skip a certain number of string identifiers.
>>>> +#define EFI_HII_SIBT_EXT1              0x30 // For future expansion (one byte length field)
>>>> +#define EFI_HII_SIBT_EXT2              0x31 // For future expansion (two byte length field)
>>>> +#define EFI_HII_SIBT_EXT4              0x32 // For future expansion (four byte length field)
>>>> +#define EFI_HII_SIBT_FONT              0x40 // Font information.
>>>> +
>>>> +struct efi_hii_sibt_string_ucs2_block {
>>>> +     struct efi_hii_string_block header;
>>>> +     uint16_t string_text[];
>>>> +} __packed;
>>>> +
>>>> +static inline struct efi_hii_string_block *efi_hii_sibt_string_ucs2_block_next(
>>>> +     struct efi_hii_sibt_string_ucs2_block *blk)
>>>> +{
>>>> +     return ((void *)blk) + sizeof(*blk) +
>>>> +             (utf16_strlen(blk->string_text) + 1) * 2;
>>>
>>> Since you're dealing with actual utf16, is this correct? One character
>>> may as well span 4 bytes, right?
>>>
>>> I think we need a different function that actually tells us the bytes
>>> occupied by a utf16 string.
>>
>> as mentioned on IRC (just repeating here for those who weren't
>> following #u-boot), utf16_strlen() is actually telling us the number
>> of 16b "bytes" in a utf16 string, not the number of "characters".
>> Similar to strlen() with a utf8 string.
>>
>>>> +}
>>>> +
>>>> +typedef void *efi_hii_handle_t;
>>>> +
>>>> +struct efi_hii_database_protocol {
>>>> +     efi_status_t(EFIAPI *new_package_list)(
>>>> +             const struct efi_hii_database_protocol *this,
>>>> +             const struct efi_hii_package_list_header *package_list,
>>>> +             const efi_handle_t driver_handle,
>>>> +             efi_hii_handle_t *handle);
>>>> +     efi_status_t(EFIAPI *remove_package_list)(
>>>> +             const struct efi_hii_database_protocol *this,
>>>> +             efi_hii_handle_t handle);
>>>> +     efi_status_t(EFIAPI *update_package_list)(
>>>> +             const struct efi_hii_database_protocol *this,
>>>> +             efi_hii_handle_t handle,
>>>> +             const struct efi_hii_package_list_header *package_list);
>>>> +     efi_status_t(EFIAPI *list_package_lists)(
>>>> +             const struct efi_hii_database_protocol *this,
>>>> +             uint8_t package_type,
>>>> +             const efi_guid_t *package_guid,
>>>> +             efi_uintn_t *handle_buffer_length,
>>>> +             efi_hii_handle_t *handle);
>>>> +     efi_status_t(EFIAPI *export_package_lists)(
>>>> +             const struct efi_hii_database_protocol *this,
>>>> +             efi_hii_handle_t handle,
>>>> +             efi_uintn_t *buffer_size,
>>>> +             struct efi_hii_package_list_header *buffer);
>>>> +     efi_status_t(EFIAPI *register_package_notify)(
>>>> +             const struct efi_hii_database_protocol *this,
>>>> +             uint8_t package_type,
>>>> +             const efi_guid_t *package_guid,
>>>> +             const void *package_notify_fn,
>>>> +             efi_uintn_t notify_type,
>>>> +             efi_handle_t *notify_handle);
>>>> +     efi_status_t(EFIAPI *unregister_package_notify)(
>>>> +             const struct efi_hii_database_protocol *this,
>>>> +             efi_handle_t notification_handle
>>>> +             );
>>>> +     efi_status_t(EFIAPI *find_keyboard_layouts)(
>>>> +             const struct efi_hii_database_protocol *this,
>>>> +             uint16_t *key_guid_buffer_length,
>>>> +             efi_guid_t *key_guid_buffer);
>>>> +     efi_status_t(EFIAPI *get_keyboard_layout)(
>>>> +             const struct efi_hii_database_protocol *this,
>>>> +             efi_guid_t *key_guid,
>>>> +             uint16_t *keyboard_layout_length,
>>>> +             struct efi_hii_keyboard_layout *keyboard_layout);
>>>> +     efi_status_t(EFIAPI *set_keyboard_layout)(
>>>> +             const struct efi_hii_database_protocol *this,
>>>> +             efi_guid_t *key_guid);
>>>> +     efi_status_t(EFIAPI *get_package_list_handle)(
>>>> +             const struct efi_hii_database_protocol *this,
>>>> +             efi_hii_handle_t package_list_handle,
>>>> +             efi_handle_t *driver_handle);
>>>> +};
>>>> +
>>>> +#define EFI_HII_STRING_PROTOCOL_GUID \
>>>> +     EFI_GUID(0x0fd96974, 0x23aa, 0x4cdc, \
>>>> +              0xb9, 0xcb, 0x98, 0xd1, 0x77, 0x50, 0x32, 0x2a)
>>>> +
>>>> +typedef uint32_t efi_hii_font_style_t;
>>>> +
>>>> +struct efi_font_info {
>>>> +     efi_hii_font_style_t font_style;
>>>> +     uint16_t font_size;
>>>> +     uint16_t font_name[1];
>>>> +};
>>>> +
>>>> +struct efi_hii_string_protocol {
>>>> +     efi_status_t(EFIAPI *new_string)(
>>>> +             const struct efi_hii_string_protocol *this,
>>>> +             efi_hii_handle_t package_list,
>>>> +             efi_string_id_t *string_id,
>>>> +             const uint8_t *language,
>>>> +             const uint16_t *language_name,
>>>> +             const efi_string_t string,
>>>> +             const struct efi_font_info *string_font_info);
>>>> +     efi_status_t(EFIAPI *get_string)(
>>>> +             const struct efi_hii_string_protocol *this,
>>>> +             const uint8_t *language,
>>>> +             efi_hii_handle_t package_list,
>>>> +             efi_string_id_t string_id,
>>>> +             efi_string_t string,
>>>> +             efi_uintn_t *string_size,
>>>> +             struct efi_font_info **string_font_info);
>>>> +     efi_status_t(EFIAPI *set_string)(
>>>> +             const struct efi_hii_string_protocol *this,
>>>> +             efi_hii_handle_t package_list,
>>>> +             efi_string_id_t string_id,
>>>> +             const uint8_t *language,
>>>> +             const efi_string_t string,
>>>> +             const struct efi_font_info *string_font_info);
>>>> +     efi_status_t(EFIAPI *get_languages)(
>>>> +             const struct efi_hii_string_protocol *this,
>>>> +             efi_hii_handle_t package_list,
>>>> +             uint8_t *languages,
>>>> +             efi_uintn_t *languages_size);
>>>> +     efi_status_t(EFIAPI *get_secondary_languages)(
>>>> +             const struct efi_hii_string_protocol *this,
>>>> +             efi_hii_handle_t package_list,
>>>> +             const uint8_t *primary_language,
>>>> +             uint8_t *secondary_languages,
>>>> +             efi_uintn_t *secondary_languages_size);
>>>> +};
>>>> +
>>>>  #define EFI_GOP_GUID \
>>>>       EFI_GUID(0x9042a9de, 0x23dc, 0x4a38, \
>>>>                0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a)
>>>> diff --git a/include/efi_loader.h b/include/efi_loader.h
>>>> index 5d37c1d75f..591bf07e7a 100644
>>>> --- a/include/efi_loader.h
>>>> +++ b/include/efi_loader.h
>>>> @@ -80,6 +80,9 @@ extern struct efi_simple_input_interface efi_con_in;
>>>>  extern const struct efi_console_control_protocol efi_console_control;
>>>>  extern const struct efi_device_path_to_text_protocol efi_device_path_to_text;
>>>>  extern const struct efi_device_path_utilities_protocol efi_device_path_utilities;
>>>> +extern const struct efi_hii_config_routing_protocol efi_hii_config_routing;
>>>> +extern const struct efi_hii_database_protocol efi_hii_database;
>>>> +extern const struct efi_hii_string_protocol efi_hii_string;
>>>>
>>>>  uint16_t *efi_dp_str(struct efi_device_path *dp);
>>>>
>>>> @@ -91,6 +94,9 @@ extern const efi_guid_t efi_guid_device_path_to_text_protocol;
>>>>  extern const efi_guid_t efi_simple_file_system_protocol_guid;
>>>>  extern const efi_guid_t efi_file_info_guid;
>>>>  extern const efi_guid_t efi_guid_device_path_utilities_protocol;
>>>> +extern const efi_guid_t efi_guid_hii_config_routing_protocol;
>>>> +extern const efi_guid_t efi_guid_hii_database_protocol;
>>>> +extern const efi_guid_t efi_guid_hii_string_protocol;
>>>>
>>>>  extern unsigned int __efi_runtime_start, __efi_runtime_stop;
>>>>  extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;
>>>> diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
>>>> index b6927b3b84..725e0cba85 100644
>>>> --- a/lib/efi_loader/Makefile
>>>> +++ b/lib/efi_loader/Makefile
>>>> @@ -17,7 +17,7 @@ endif
>>>>  obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o
>>>>  obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o
>>>>  obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o
>>>> -obj-y += efi_device_path_utilities.o
>>>> +obj-y += efi_device_path_utilities.o efi_hii.o
>>>>  obj-y += efi_file.o efi_variable.o efi_bootmgr.o
>>>>  obj-$(CONFIG_LCD) += efi_gop.o
>>>>  obj-$(CONFIG_DM_VIDEO) += efi_gop.o
>>>> diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
>>>> index 92c778fcca..c179afc25a 100644
>>>> --- a/lib/efi_loader/efi_boottime.c
>>>> +++ b/lib/efi_loader/efi_boottime.c
>>>> @@ -1157,6 +1157,15 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob
>>>>       obj->protocols[4].protocol_interface =
>>>>               (void *)&efi_device_path_utilities;
>>>>
>>>> +     obj->protocols[5].guid = &efi_guid_hii_string_protocol;
>>>> +     obj->protocols[5].protocol_interface = (void *)&efi_hii_string;
>>>> +
>>>> +     obj->protocols[6].guid = &efi_guid_hii_database_protocol;
>>>> +     obj->protocols[6].protocol_interface = (void *)&efi_hii_database;
>>>> +
>>>> +     obj->protocols[7].guid = &efi_guid_hii_config_routing_protocol;
>>>> +     obj->protocols[7].protocol_interface = (void *)&efi_hii_config_routing;
>>>> +
>>>>       info->file_path = file_path;
>>>>       info->device_handle = efi_dp_find_obj(device_path, NULL);
>>>>
>>>> diff --git a/lib/efi_loader/efi_hii.c b/lib/efi_loader/efi_hii.c
>>>> new file mode 100644
>>>> index 0000000000..25c8e88a60
>>>> --- /dev/null
>>>> +++ b/lib/efi_loader/efi_hii.c
>>>> @@ -0,0 +1,507 @@
>>>> +/*
>>>> + *  EFI Human Interface Infrastructure ... interface
>>>> + *
>>>> + *  Copyright (c) 2017 Leif Lindholm
>>>> + *
>>>> + *  SPDX-License-Identifier:     GPL-2.0+
>>>> + */
>>>> +
>>>> +#include <common.h>
>>>> +#include <malloc.h>
>>>> +#include <efi_loader.h>
>>>> +
>>>> +const efi_guid_t efi_guid_hii_config_routing_protocol =
>>>> +     EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID;
>>>> +const efi_guid_t efi_guid_hii_database_protocol = EFI_HII_DATABASE_PROTOCOL_GUID;
>>>> +const efi_guid_t efi_guid_hii_string_protocol = EFI_HII_STRING_PROTOCOL_GUID;
>>>> +
>>>> +struct hii_package {
>>>> +     // TODO should there be an associated efi_object?
>>>> +     struct list_head string_tables;     /* list of string_table */
>>>> +     /* we could also track fonts, images, etc */
>>>> +};
>>>> +
>>>> +struct string_table {
>>>> +     struct list_head link;
>>>> +     efi_string_id_t language_name;
>>>> +     char *language;
>>>> +     uint32_t nstrings;
>>>> +     /* NOTE: string id starts at 1 so value is stbl->strings[id-1] */
>>>> +     struct {
>>>> +             efi_string_t string;
>>>> +             /* we could also track font info, etc */
>>>> +     } strings[];
>>>> +};
>>>> +
>>>> +static void free_strings_table(struct string_table *stbl)
>>>> +{
>>>> +     int i;
>>>> +
>>>> +     for (i = 0; i < stbl->nstrings; i++)
>>>> +             free(stbl->strings[i].string);
>>>> +     free(stbl->language);
>>>> +     free(stbl);
>>>> +}
>>>> +
>>>> +static struct hii_package *new_package(void)
>>>> +{
>>>> +     struct hii_package *hii = malloc(sizeof(*hii));
>>>> +     INIT_LIST_HEAD(&hii->string_tables);
>>>> +     return hii;
>>>> +}
>>>> +
>>>> +static void free_package(struct hii_package *hii)
>>>> +{
>>>> +
>>>> +     while (!list_empty(&hii->string_tables)) {
>>>> +             struct string_table *stbl;
>>>> +
>>>> +             stbl = list_first_entry(&hii->string_tables,
>>>> +                                     struct string_table, link);
>>>> +             list_del(&stbl->link);
>>>> +             free_strings_table(stbl);
>>>> +     }
>>>> +
>>>> +     free(hii);
>>>> +}
>>>> +
>>>> +static efi_status_t add_strings_package(struct hii_package *hii,
>>>> +     struct efi_hii_strings_package *strings_package)
>>>> +{
>>>> +     struct efi_hii_string_block *block;
>>>> +     void *end = ((void *)strings_package) + strings_package->header.length;
>>>> +     uint32_t nstrings = 0;
>>>> +     unsigned id = 0;
>>>> +
>>>> +     debug("header_size: %08x\n", strings_package->header_size);
>>>> +     debug("string_info_offset: %08x\n", strings_package->string_info_offset);
>>>> +     debug("language_name: %u\n", strings_package->language_name);
>>>> +     debug("language: %s\n", strings_package->language);
>>>> +
>>>> +     /* count # of string entries: */
>>>> +     block = ((void *)strings_package) + strings_package->string_info_offset;
>>>> +     while ((void *)block < end) {
>>>> +             switch (block->block_type) {
>>>> +             case EFI_HII_SIBT_STRING_UCS2: {
>>>> +                     struct efi_hii_sibt_string_ucs2_block *ucs2 =
>>>> +                             (void *)block;
>>>> +                     nstrings++;
>>>> +                     block = efi_hii_sibt_string_ucs2_block_next(ucs2);
>>>> +                     break;
>>>> +             }
>>>> +             case EFI_HII_SIBT_END:
>>>> +                     block = end;
>>>> +                     break;
>>>> +             default:
>>>> +                     debug("unknown HII string block type: %02x\n",
>>>> +                           block->block_type);
>>>> +                     return EFI_INVALID_PARAMETER;
>>>> +             }
>>>> +     }
>>>> +
>>>> +     struct string_table *stbl = malloc(sizeof(*stbl) +
>>>> +                     (nstrings * sizeof(stbl->strings[0])));
>>>> +     stbl->language_name = strings_package->language_name;
>>>> +     stbl->language = strdup((char *)strings_package->language);
>>>
>>> Where does the strings_package come from? And why is the language in it
>>> in UTF8?
>>
>> The strings_package is a part of the "package list" blob passed in
>> from (in this case) Shell.efi.  The package list can actually contain
>> a lot more (fonts/glyphs/images/forms), but not really sure how much
>> of that we'll actually support.  (HII seems to be able to do enough
>> for rendering a full blown GUI.. kinda overkill, IMHO.. but Shell.efi
>> wants it for silly reasons.)
>>
>> This is actually utf8.. it is a "RFC 4646 language code identifier".
>> See appendix M.
>>
>>
>>>
>>>> +     stbl->nstrings = nstrings;
>>>> +
>>>> +     list_add(&stbl->link, &hii->string_tables);
>>>> +
>>>> +     /* and now parse string entries and populate string_table */
>>>> +     block = ((void *)strings_package) + strings_package->string_info_offset;
>>>> +
>>>> +     while ((void *)block < end) {
>>>> +             switch (block->block_type) {
>>>> +             case EFI_HII_SIBT_STRING_UCS2: {
>>>> +                     struct efi_hii_sibt_string_ucs2_block *ucs2 =
>>>> +                             (void *)block;
>>>> +                     id++;
>>>> +                     debug("%4u: \"%ls\"\n", id, ucs2->string_text);
>>>> +                     stbl->strings[id-1].string =
>>>> +                             utf16_strdup(ucs2->string_text);
>>>> +                     block = efi_hii_sibt_string_ucs2_block_next(ucs2);
>>>> +                     break;
>>>> +             }
>>>> +             case EFI_HII_SIBT_END:
>>>> +                     return EFI_SUCCESS;
>>>> +             default:
>>>> +                     debug("unknown HII string block type: %02x\n",
>>>> +                           block->block_type);
>>>> +                     return EFI_INVALID_PARAMETER;
>>>> +             }
>>>> +     }
>>>> +
>>>> +     return EFI_SUCCESS;
>>>> +}
>>>> +
>>>> +/*
>>>> + * EFI_HII_CONFIG_ROUTING_PROTOCOL
>>>> + */
>>>> +
>>>> +static efi_status_t EFIAPI extract_config(
>>>> +     const struct efi_hii_config_routing_protocol *this,
>>>> +     const efi_string_t request,
>>>> +     efi_string_t *progress,
>>>> +     efi_string_t *results)
>>>> +{
>>>> +     EFI_ENTRY("%p, \"%ls\", %p, %p", this, request, progress, results);
>>>> +     return EFI_EXIT(EFI_OUT_OF_RESOURCES);
>>>> +}
>>>> +
>>>> +static efi_status_t EFIAPI export_config(
>>>> +     const struct efi_hii_config_routing_protocol *this,
>>>> +     efi_string_t *results)
>>>> +{
>>>> +     EFI_ENTRY("%p, %p", this, results);
>>>> +     return EFI_EXIT(EFI_OUT_OF_RESOURCES);
>>>> +}
>>>> +
>>>> +static efi_status_t EFIAPI route_config(
>>>> +     const struct efi_hii_config_routing_protocol *this,
>>>> +     const efi_string_t configuration,
>>>> +     efi_string_t *progress)
>>>> +{
>>>> +     EFI_ENTRY("%p, \"%ls\", %p", this, configuration, progress);
>>>> +     return EFI_EXIT(EFI_OUT_OF_RESOURCES);
>>>> +}
>>>> +
>>>> +static efi_status_t EFIAPI block_to_config(
>>>> +     const struct efi_hii_config_routing_protocol *this,
>>>> +     const efi_string_t config_request,
>>>> +     const uint8_t *block,
>>>> +     const efi_uintn_t block_size,
>>>> +     efi_string_t *config,
>>>> +     efi_string_t *progress)
>>>> +{
>>>> +     EFI_ENTRY("%p, \"%ls\", %p, %zu, %p, %p", this, config_request, block,
>>>> +               block_size, config, progress);
>>>> +     return EFI_EXIT(EFI_OUT_OF_RESOURCES);
>>>> +}
>>>> +
>>>> +static efi_status_t EFIAPI config_to_block(
>>>> +     const struct efi_hii_config_routing_protocol *this,
>>>> +     const efi_string_t config_resp,
>>>> +     const uint8_t *block,
>>>> +     const efi_uintn_t *block_size,
>>>> +     efi_string_t *progress)
>>>> +{
>>>> +     EFI_ENTRY("%p, \"%ls\", %p, %p, %p", this, config_resp, block,
>>>> +               block_size, progress);
>>>> +     return EFI_EXIT(EFI_OUT_OF_RESOURCES);
>>>> +}
>>>> +
>>>> +static efi_status_t EFIAPI get_alt_config(
>>>> +     const struct efi_hii_config_routing_protocol *this,
>>>> +     const efi_string_t config_resp,
>>>> +     const efi_guid_t *guid,
>>>> +     const efi_string_t name,
>>>> +     const struct efi_device_path *device_path,
>>>> +     const efi_string_t alt_cfg_id,
>>>> +     efi_string_t *alt_cfg_resp)
>>>> +{
>>>> +     EFI_ENTRY("%p, \"%ls\", %pUl, \"%ls\", %p, \"%ls\", %p", this,
>>>> +               config_resp, guid, name, device_path, alt_cfg_id,
>>>> +               alt_cfg_resp);
>>>> +     return EFI_EXIT(EFI_OUT_OF_RESOURCES);
>>>> +}
>>>> +
>>>> +
>>>> +/*
>>>> + * EFI_HII_DATABASE_PROTOCOL
>>>> + */
>>>> +
>>>> +static efi_status_t EFIAPI new_package_list(
>>>> +     const struct efi_hii_database_protocol *this,
>>>> +     const struct efi_hii_package_list_header *package_list,
>>>> +     const efi_handle_t driver_handle,
>>>> +     efi_hii_handle_t *handle)
>>>> +{
>>>> +     efi_status_t ret = EFI_SUCCESS;
>>>> +
>>>> +     EFI_ENTRY("%p, %p, %p, %p", this, package_list, driver_handle, handle);
>>>> +
>>>> +     if (!package_list || !driver_handle)
>>>> +             return EFI_EXIT(EFI_INVALID_PARAMETER);
>>>> +
>>>> +     struct hii_package *hii = new_package();
>>>> +     struct efi_hii_package_header *package;
>>>> +     void *end = ((void *)package_list) + package_list->package_length;
>>>> +
>>>> +     debug("package_list: %pUl (%u)\n", &package_list->package_list_guid,
>>>> +           package_list->package_length);
>>>> +
>>>> +     package = ((void *)package_list) + sizeof(*package_list);
>>>> +     while ((void *)package < end) {
>>>> +             debug("package=%p, package type=%x, length=%u\n", package,
>>>> +                   package->type, package->length);
>>>> +             switch (package->type) {
>>>> +             case EFI_HII_PACKAGE_STRINGS:
>>>> +                     ret = add_strings_package(hii,
>>>> +                             (struct efi_hii_strings_package *)package);
>>>> +                     break;
>>>> +             default:
>>>> +                     break;
>>>> +             }
>>>> +
>>>> +             if (ret != EFI_SUCCESS)
>>>> +                     goto error;
>>>> +
>>>> +             package = ((void *)package) + package->length;
>>>> +     }
>>>> +
>>>> +     // TODO in theory there is some notifications that should be sent..
>>>> +
>>>> +     *handle = hii;
>>>> +
>>>> +     return EFI_EXIT(EFI_SUCCESS);
>>>> +
>>>> +error:
>>>> +     free_package(hii);
>>>> +     return EFI_EXIT(ret);
>>>> +}
>>>> +
>>>> +static efi_status_t EFIAPI remove_package_list(
>>>> +     const struct efi_hii_database_protocol *this,
>>>> +     efi_hii_handle_t handle)
>>>> +{
>>>> +     struct hii_package *hii = handle;
>>>> +     EFI_ENTRY("%p, %p", this, handle);
>>>> +     free_package(hii);
>>>> +     return EFI_EXIT(EFI_SUCCESS);
>>>> +}
>>>> +
>>>> +static efi_status_t EFIAPI update_package_list(
>>>> +     const struct efi_hii_database_protocol *this,
>>>> +     efi_hii_handle_t handle,
>>>> +     const struct efi_hii_package_list_header *package_list)
>>>> +{
>>>> +     EFI_ENTRY("%p, %p, %p", this, handle, package_list);
>>>> +     return EFI_EXIT(EFI_NOT_FOUND);
>>>> +}
>>>> +
>>>> +static efi_status_t EFIAPI list_package_lists(
>>>> +     const struct efi_hii_database_protocol *this,
>>>> +     uint8_t package_type,
>>>> +     const efi_guid_t *package_guid,
>>>> +     efi_uintn_t *handle_buffer_length,
>>>> +     efi_hii_handle_t *handle)
>>>> +{
>>>> +     EFI_ENTRY("%p, %u, %pUl, %p, %p", this, package_type, package_guid,
>>>> +               handle_buffer_length, handle);
>>>> +     return EFI_EXIT(EFI_NOT_FOUND);
>>>> +}
>>>> +
>>>> +static efi_status_t EFIAPI export_package_lists(
>>>> +     const struct efi_hii_database_protocol *this,
>>>> +     efi_hii_handle_t handle,
>>>> +     efi_uintn_t *buffer_size,
>>>> +     struct efi_hii_package_list_header *buffer)
>>>> +{
>>>> +     EFI_ENTRY("%p, %p, %p, %p", this, handle, buffer_size, buffer);
>>>> +     return EFI_EXIT(EFI_NOT_FOUND);
>>>> +}
>>>> +
>>>> +static efi_status_t EFIAPI register_package_notify(
>>>> +     const struct efi_hii_database_protocol *this,
>>>> +     uint8_t package_type,
>>>> +     const efi_guid_t *package_guid,
>>>> +     const void *package_notify_fn,
>>>> +     efi_uintn_t notify_type,
>>>> +     efi_handle_t *notify_handle)
>>>> +{
>>>> +     EFI_ENTRY("%p, %u, %pUl, %p, %zu, %p", this, package_type,
>>>> +               package_guid, package_notify_fn, notify_type,
>>>> +               notify_handle);
>>>> +     return EFI_EXIT(EFI_OUT_OF_RESOURCES);
>>>> +}
>>>> +
>>>> +static efi_status_t EFIAPI unregister_package_notify(
>>>> +     const struct efi_hii_database_protocol *this,
>>>> +     efi_handle_t notification_handle)
>>>> +{
>>>> +     EFI_ENTRY("%p, %p", this, notification_handle);
>>>> +     return EFI_EXIT(EFI_NOT_FOUND);
>>>> +}
>>>> +
>>>> +static efi_status_t EFIAPI find_keyboard_layouts(
>>>> +     const struct efi_hii_database_protocol *this,
>>>> +     uint16_t *key_guid_buffer_length,
>>>> +     efi_guid_t *key_guid_buffer)
>>>> +{
>>>> +     EFI_ENTRY("%p, %p, %p", this, key_guid_buffer_length, key_guid_buffer);
>>>> +     return EFI_EXIT(EFI_NOT_FOUND); /* Invalid */
>>>> +}
>>>> +
>>>> +static efi_status_t EFIAPI get_keyboard_layout(
>>>> +     const struct efi_hii_database_protocol *this,
>>>> +     efi_guid_t *key_guid,
>>>> +     uint16_t *keyboard_layout_length,
>>>> +     struct efi_hii_keyboard_layout *keyboard_layout)
>>>> +{
>>>> +     EFI_ENTRY("%p, %pUl, %p, %p", this, key_guid, keyboard_layout_length,
>>>> +               keyboard_layout);
>>>> +     return EFI_EXIT(EFI_NOT_FOUND);
>>>> +}
>>>> +
>>>> +static efi_status_t EFIAPI set_keyboard_layout(
>>>> +     const struct efi_hii_database_protocol *this,
>>>> +     efi_guid_t *key_guid)
>>>> +{
>>>> +     EFI_ENTRY("%p, %pUl", this, key_guid);
>>>> +     return EFI_EXIT(EFI_NOT_FOUND);
>>>> +}
>>>> +
>>>> +static efi_status_t EFIAPI get_package_list_handle(
>>>> +     const struct efi_hii_database_protocol *this,
>>>> +     efi_hii_handle_t package_list_handle,
>>>> +     efi_handle_t *driver_handle)
>>>> +{
>>>> +     EFI_ENTRY("%p, %p, %p", this, package_list_handle, driver_handle);
>>>> +     return EFI_EXIT(EFI_INVALID_PARAMETER);
>>>> +}
>>>> +
>>>> +
>>>> +/*
>>>> + * EFI_HII_STRING_PROTOCOL
>>>> + */
>>>> +
>>>> +static efi_status_t EFIAPI new_string(
>>>> +     const struct efi_hii_string_protocol *this,
>>>> +     efi_hii_handle_t package_list,
>>>> +     efi_string_id_t *string_id,
>>>> +     const uint8_t *language,
>>>> +     const uint16_t *language_name,
>>>> +     const efi_string_t string,
>>>> +     const struct efi_font_info *string_font_info)
>>>> +{
>>>> +     EFI_ENTRY("%p, %p, %p, \"%s\", %p, \"%ls\", %p", this, package_list,
>>>> +               string_id, language, language_name, string,
>>>> +               string_font_info);
>>>> +     return EFI_EXIT(EFI_NOT_FOUND);
>>>> +}
>>>> +
>>>> +static efi_status_t EFIAPI get_string(
>>>> +     const struct efi_hii_string_protocol *this,
>>>> +     const uint8_t *language,
>>>> +     efi_hii_handle_t package_list,
>>>> +     efi_string_id_t string_id,
>>>> +     efi_string_t string,
>>>> +     efi_uintn_t *string_size,
>>>> +     struct efi_font_info **string_font_info)
>>>> +{
>>>> +     struct hii_package *hii = package_list;
>>>> +     struct string_table *stbl;
>>>> +
>>>> +     EFI_ENTRY("%p, \"%s\", %p, %u, %p, %p, %p", this, language,
>>>> +               package_list, string_id, string, string_size,
>>>> +               string_font_info);
>>>> +
>>>> +     list_for_each_entry(stbl, &hii->string_tables, link) {
>>>> +             if (!strcmp((char *)language, (char *)stbl->language)) {
>>>> +                     unsigned idx = string_id - 1;
>>>> +                     if (idx > stbl->nstrings)
>>>> +                             return EFI_EXIT(EFI_NOT_FOUND);
>>>> +                     efi_string_t str = stbl->strings[idx].string;
>>>> +                     size_t len = utf16_strlen(str) + 1;
>>>
>>> I assume that's wrong for sizing too?
>>
>> nope :-)
>>
>>> Also please try not to define variables mid-scope :). Just define them
>>> above the if() and fill them after ...
>>
>> Hmm, I'd have the inverse comment if someone else wrote it and defined
>> all the variables at the top ;-)
>>
>>> Then also for the sake of readability add a blank line after the
>>> variable definitions and before the return.
>>>
>>> I think you'd also do yourself a favor if you reduced the indenting a
>>> bit. Just abort the list_for_each when you found and entry and then
>>> process it in the top level scope.
>>>
>>> static struct string_table *find_stbl_by_lang(const char *language)
>>> {
>>>     list_for_each(...) {
>>>         if (matches) {
>>>             return stbl;
>>>         }
>>>     }
>>>
>>>     return NULL;
>>> }
>>>
>>> stbl = find_stbl_by_lang(lang);
>>> if (!stbl)
>>>     return EFI_EXIT(EFI_NOT_FOUND)
>>
>> yeah, perhaps
>
> Please rework it for v2 :)
>
>
> Alex

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 02/11] efi_loader: Initial HII protocols
  2017-10-12  9:55         ` Rob Clark
@ 2017-10-12  9:59           ` Alexander Graf
  0 siblings, 0 replies; 75+ messages in thread
From: Alexander Graf @ 2017-10-12  9:59 UTC (permalink / raw)
  To: u-boot

On 10/12/2017 11:55 AM, Rob Clark wrote:
> On Thu, Oct 12, 2017 at 3:13 AM, Alexander Graf <agraf@suse.de> wrote:
>>
>> On 12.10.17 00:02, Rob Clark wrote:
>>> On Wed, Oct 11, 2017 at 10:30 AM, Alexander Graf <agraf@suse.de> wrote:
>>>>
>>>> On 10.10.17 14:22, Rob Clark wrote:
>>>>> From: Leif Lindholm <leif.lindholm@linaro.org>
>>>>>
>>>>> Enough implementation of the following protocols to run Shell.efi and
>>>>> SCT.efi:
>>>>>
>>>>>    EfiHiiConfigRoutingProtocolGuid
>>>>>    EfiHiiDatabaseProtocol
>>>>>    EfiHiiStringProtocol
>>>>>
>>>>> We'll fill in the rest once SCT is running properly so we can validate
>>>>> the implementation against the conformance test suite.
>>>>>
>>>>> Initial skeleton written by Leif, and then implementation by myself.
>>>>>
>>>>> Cc: Leif Lindholm <leif.lindholm@linaro.org>
>>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>>>> ---
>>>>>   include/efi_api.h             | 261 ++++++++++++++++++++++
>>>>>   include/efi_loader.h          |   6 +
>>>>>   lib/efi_loader/Makefile       |   2 +-
>>>>>   lib/efi_loader/efi_boottime.c |   9 +
>>>>>   lib/efi_loader/efi_hii.c      | 507 ++++++++++++++++++++++++++++++++++++++++++
>>>>>   5 files changed, 784 insertions(+), 1 deletion(-)
>>>>>   create mode 100644 lib/efi_loader/efi_hii.c
>>>>>
>>>>> diff --git a/include/efi_api.h b/include/efi_api.h
>>>>> index ffdba7fe1a..164147dc87 100644
>>>>> --- a/include/efi_api.h
>>>>> +++ b/include/efi_api.h
>>>>> @@ -16,6 +16,7 @@
>>>>>   #define _EFI_API_H
>>>>>
>>>>>   #include <efi.h>
>>>>> +#include <charset.h>
>>>>>
>>>>>   #ifdef CONFIG_EFI_LOADER
>>>>>   #include <asm/setjmp.h>
>>>>> @@ -536,6 +537,266 @@ struct efi_device_path_utilities_protocol {
>>>>>                uint16_t node_length);
>>>>>   };
>>>>>
>>>>> +#define EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID \
>>>>> +     EFI_GUID(0x587e72d7, 0xcc50, 0x4f79, \
>>>>> +              0x82, 0x09, 0xca, 0x29, 0x1f, 0xc1, 0xa1, 0x0f)
>>>>> +
>>>>> +typedef uint16_t efi_string_id_t;
>>>>> +
>>>>> +struct efi_hii_config_routing_protocol {
>>>>> +     efi_status_t(EFIAPI *extract_config)(
>>>>> +             const struct efi_hii_config_routing_protocol *this,
>>>>> +             const efi_string_t request,
>>>>> +             efi_string_t *progress,
>>>>> +             efi_string_t *results);
>>>>> +     efi_status_t(EFIAPI *export_config)(
>>>>> +             const struct efi_hii_config_routing_protocol *this,
>>>>> +             efi_string_t *results);
>>>>> +     efi_status_t(EFIAPI *route_config)(
>>>>> +             const struct efi_hii_config_routing_protocol *this,
>>>>> +             const efi_string_t configuration,
>>>>> +             efi_string_t *progress);
>>>>> +     efi_status_t(EFIAPI *block_to_config)(
>>>>> +             const struct efi_hii_config_routing_protocol *this,
>>>>> +             const efi_string_t config_request,
>>>>> +             const uint8_t *block,
>>>>> +             const efi_uintn_t block_size,
>>>>> +             efi_string_t *config,
>>>>> +             efi_string_t *progress);
>>>>> +     efi_status_t(EFIAPI *config_to_block)(
>>>>> +             const struct efi_hii_config_routing_protocol *this,
>>>>> +             const efi_string_t config_resp,
>>>>> +             const uint8_t *block,
>>>>> +             const efi_uintn_t *block_size,
>>>>> +             efi_string_t *progress);
>>>>> +     efi_status_t(EFIAPI *get_alt_config)(
>>>>> +             const struct efi_hii_config_routing_protocol *this,
>>>>> +             const efi_string_t config_resp,
>>>>> +             const efi_guid_t *guid,
>>>>> +             const efi_string_t name,
>>>>> +             const struct efi_device_path *device_path,
>>>>> +             const efi_string_t alt_cfg_id,
>>>>> +             efi_string_t *alt_cfg_resp);
>>>>> +};
>>>>> +
>>>>> +#define EFI_HII_DATABASE_PROTOCOL_GUID            \
>>>>> +     EFI_GUID(0xef9fc172, 0xa1b2, 0x4693, \
>>>>> +              0xb3, 0x27, 0x6d, 0x32, 0xfc, 0x41, 0x60, 0x42)
>>>>> +
>>>>> +typedef enum {
>>>>> +     EFI_KEY_LCTRL, EFI_KEY_A0, EFI_KEY_LALT, EFI_KEY_SPACE_BAR,
>>>>> +     EFI_KEY_A2, EFI_KEY_A3, EFI_KEY_A4, EFI_KEY_RCTRL, EFI_KEY_LEFT_ARROW,
>>>>> +     EFI_KEY_DOWN_ARROW, EFI_KEY_RIGHT_ARROW, EFI_KEY_ZERO,
>>>>> +     EFI_KEY_PERIOD, EFI_KEY_ENTER, EFI_KEY_LSHIFT, EFI_KEY_B0,
>>>>> +     EFI_KEY_B1, EFI_KEY_B2, EFI_KEY_B3, EFI_KEY_B4, EFI_KEY_B5, EFI_KEY_B6,
>>>>> +     EFI_KEY_B7, EFI_KEY_B8, EFI_KEY_B9, EFI_KEY_B10, EFI_KEY_RSHIFT,
>>>>> +     EFI_KEY_UP_ARROW, EFI_KEY_ONE, EFI_KEY_TWO, EFI_KEY_THREE,
>>>>> +     EFI_KEY_CAPS_LOCK, EFI_KEY_C1, EFI_KEY_C2, EFI_KEY_C3, EFI_KEY_C4,
>>>>> +     EFI_KEY_C5, EFI_KEY_C6, EFI_KEY_C7, EFI_KEY_C8, EFI_KEY_C9,
>>>>> +     EFI_KEY_C10, EFI_KEY_C11, EFI_KEY_C12, EFI_KEY_FOUR, EFI_KEY_FIVE,
>>>>> +     EFI_KEY_SIX, EFI_KEY_PLUS, EFI_KEY_TAB, EFI_KEY_D1, EFI_KEY_D2,
>>>>> +     EFI_KEY_D3, EFI_KEY_D4, EFI_KEY_D5, EFI_KEY_D6, EFI_KEY_D7, EFI_KEY_D8,
>>>>> +     EFI_KEY_D9, EFI_KEY_D10, EFI_KEY_D11, EFI_KEY_D12, EFI_KEY_D13,
>>>>> +     EFI_KEY_DEL, EFI_KEY_END, EFI_KEY_PG_DN, EFI_KEY_SEVEN, EFI_KEY_EIGHT,
>>>>> +     EFI_KEY_NINE, EFI_KEY_E0, EFI_KEY_E1, EFI_KEY_E2, EFI_KEY_E3,
>>>>> +     EFI_KEY_E4, EFI_KEY_E5, EFI_KEY_E6, EFI_KEY_E7, EFI_KEY_E8, EFI_KEY_E9,
>>>>> +     EFI_KEY_E10, EFI_KEY_E11, EFI_KEY_E12, EFI_KEY_BACK_SPACE,
>>>>> +     EFI_KEY_INS, EFI_KEY_HOME, EFI_KEY_PG_UP, EFI_KEY_NLCK, EFI_KEY_SLASH,
>>>>> +     EFI_KEY_ASTERISK, EFI_KEY_MINUS, EFI_KEY_ESC, EFI_KEY_F1, EFI_KEY_F2,
>>>>> +     EFI_KEY_F3, EFI_KEY_F4, EFI_KEY_F5, EFI_KEY_F6, EFI_KEY_F7, EFI_KEY_F8,
>>>>> +     EFI_KEY_F9, EFI_KEY_F10, EFI_KEY_F11, EFI_KEY_F12, EFI_KEY_PRINT,
>>>>> +     EFI_KEY_SLCK, EFI_KEY_PAUSE,
>>>>> +} efi_key;
>>>>> +
>>>>> +struct efi_key_descriptor {
>>>>> +     efi_key key;
>>>>> +     uint16_t unicode;
>>>>> +     uint16_t shifted_unicode;
>>>>> +     uint16_t alt_gr_unicode;
>>>>> +     uint16_t shifted_alt_gr_unicode;
>>>>> +     uint16_t modifier;
>>>>> +     uint16_t affected_attribute;
>>>>> +};
>>>>> +
>>>>> +struct efi_hii_keyboard_layout {
>>>>> +     uint16_t layout_length;
>>>>> +     efi_guid_t guid;
>>>>> +     uint32_t layout_descriptor_string_offset;
>>>>> +     uint8_t descriptor_count;
>>>>> +     struct efi_key_descriptor descriptors[];
>>>>> +};
>>>>> +
>>>>> +struct efi_hii_package_list_header {
>>>>> +     efi_guid_t package_list_guid;
>>>>> +     uint32_t package_length;
>>>>> +} __packed;
>>>>> +
>>>>> +struct efi_hii_package_header {
>>>>> +     uint32_t length : 24;
>>>>> +     uint32_t type : 8;
>>>>> +} __packed;
>>>> Bitfields are terribly evil - they're probably one of the worst defined
>>>> things in C. A different compiler may even give you different ordering
>>>> here. I've certainly seen bitfields explode in weird ways on
>>>> cross-endian conversions.
>>> edk2 defines it in the same way.  And this is UEFI we are talking
>>> about here, big endian is strictly out of scope.
>> I don't see why big endian is strictly out of scope. I don't want to
>> ignore it light heartedly. All we'd need to do is byte swap every
>> input/output there is today.
> See section 1.9.1:
>
> "
> Supported processors are “little endian” machines. This distinction
> means that the low-
> order byte of a multibyte data item in memory is at the lowest
> address, while the high-
> order byte is at the highest address. Some supported 64-bit processors may be
> configured for both “little endian” and “big endian” operation. All
> implementations
> designed to conform to this specification use “little endian” operation.
> "
>
> even power9 got sane and is finally is switching to LE ;-)

You know as well as me that specs are changeable :). I think UEFI will 
always stay LE, but that doesn't mean that it always has to also be 
executed in an LE environment. We've done funny stunts with grub before 
where we ran LE grub on a BE OpenFirmware implementation.

Really, I just always cringe when I see bitfields.


Alex

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 03/11] efi_loader: Initial EFI_UNICODE_COLLATION_PROTOCOL
  2017-10-11 20:47       ` Alexander Graf
@ 2017-10-12 11:54         ` Alexander Graf
  0 siblings, 0 replies; 75+ messages in thread
From: Alexander Graf @ 2017-10-12 11:54 UTC (permalink / raw)
  To: u-boot

On 10/11/2017 10:47 PM, Alexander Graf wrote:
>
> On 11.10.17 22:30, Rob Clark wrote:
>> On Wed, Oct 11, 2017 at 10:36 AM, Alexander Graf <agraf@suse.de> wrote:
>>>
>>> On 10.10.17 14:22, Rob Clark wrote:
>>>> From: Leif Lindholm <leif.lindholm@linaro.org>
>>>>
>>>> Not complete, but enough for Shell.efi and SCT.efi.
>>>>
>>>> Initial skeleton written by Leif, and then implementation by myself.
>>>>
>>>> Cc: Leif Lindholm <leif.lindholm@linaro.org>
>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>>> ---
>>>>   include/efi_api.h             |  41 ++++++++++
>>>>   include/efi_loader.h          |   3 +
>>>>   lib/efi_loader/Makefile       |   2 +-
>>>>   lib/efi_loader/efi_boottime.c |   6 ++
>>>>   lib/efi_loader/efi_unicode.c  | 170 ++++++++++++++++++++++++++++++++++++++++++
>>>>   5 files changed, 221 insertions(+), 1 deletion(-)
>>>>   create mode 100644 lib/efi_loader/efi_unicode.c
>>>>
>>>> diff --git a/include/efi_api.h b/include/efi_api.h
>>>> index 164147dc87..38dd1240c1 100644
>>>> --- a/include/efi_api.h
>>>> +++ b/include/efi_api.h
>>>> @@ -797,6 +797,47 @@ struct efi_hii_string_protocol {
>>>>                efi_uintn_t *secondary_languages_size);
>>>>   };
>>>>
>>>> +/*
>>>> + * Both UNICODE_COLLATION protocols seem to be the same thing, but
>>>> + * advertised with two different GUID's because, why not?
>>>> + */
>>>> +
>>>> +#define EFI_UNICODE_COLLATION_PROTOCOL_GUID \
>>>> +     EFI_GUID(0x1d85cd7f, 0xf43d, 0x11d2, \
>>>> +              0x9a, 0x0c, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
>>>> +
>>>> +#define EFI_UNICODE_COLLATION_PROTOCOL2_GUID \
>>>> +     EFI_GUID(0xa4c751fc, 0x23ae, 0x4c3e, \
>>>> +              0x92, 0xe9, 0x49, 0x64, 0xcf, 0x63, 0xf3, 0x49)
>>>> +
>>>> +struct efi_unicode_collation_protocol {
>>>> +     efi_intn_t (EFIAPI *stri_coll)(
>>>> +             struct efi_unicode_collation_protocol *this,
>>>> +             efi_string_t s1,
>>>> +             efi_string_t s2);
>>>> +     bool (EFIAPI *metai_match)(
>>>> +             struct efi_unicode_collation_protocol *this,
>>>> +             efi_string_t string,
>>>> +             efi_string_t pattern);
>>>> +     void (EFIAPI *str_lwr)(
>>>> +             struct efi_unicode_collation_protocol *this,
>>>> +             efi_string_t string);
>>>> +     void (EFIAPI *str_upr)(
>>>> +             struct efi_unicode_collation_protocol *this,
>>>> +             efi_string_t string);
>>>> +     void (EFIAPI *fat_to_str)(
>>>> +             struct efi_unicode_collation_protocol *this,
>>>> +             efi_uintn_t fat_size,
>>>> +             uint8_t *fat,
>>>> +             efi_string_t string);
>>>> +     bool (EFIAPI *str_to_fat)(
>>>> +             struct efi_unicode_collation_protocol *this,
>>>> +             efi_string_t string,
>>>> +             efi_uintn_t fat_size,
>>>> +             uint8_t *fat);
>>>> +     uint8_t *supported_languages;
>>>> +};
>>>> +
>>>>   #define EFI_GOP_GUID \
>>>>        EFI_GUID(0x9042a9de, 0x23dc, 0x4a38, \
>>>>                 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a)
>>>> diff --git a/include/efi_loader.h b/include/efi_loader.h
>>>> index 591bf07e7a..af6812b2b4 100644
>>>> --- a/include/efi_loader.h
>>>> +++ b/include/efi_loader.h
>>>> @@ -83,6 +83,7 @@ extern const struct efi_device_path_utilities_protocol efi_device_path_utilities
>>>>   extern const struct efi_hii_config_routing_protocol efi_hii_config_routing;
>>>>   extern const struct efi_hii_database_protocol efi_hii_database;
>>>>   extern const struct efi_hii_string_protocol efi_hii_string;
>>>> +extern const struct efi_unicode_collation_protocol efi_unicode_collation;
>>>>
>>>>   uint16_t *efi_dp_str(struct efi_device_path *dp);
>>>>
>>>> @@ -97,6 +98,8 @@ extern const efi_guid_t efi_guid_device_path_utilities_protocol;
>>>>   extern const efi_guid_t efi_guid_hii_config_routing_protocol;
>>>>   extern const efi_guid_t efi_guid_hii_database_protocol;
>>>>   extern const efi_guid_t efi_guid_hii_string_protocol;
>>>> +extern const efi_guid_t efi_guid_unicode_collation_protocol;
>>>> +extern const efi_guid_t efi_guid_unicode_collation_protocol2;
>>>>
>>>>   extern unsigned int __efi_runtime_start, __efi_runtime_stop;
>>>>   extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;
>>>> diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
>>>> index 725e0cba85..7ea96a4f1c 100644
>>>> --- a/lib/efi_loader/Makefile
>>>> +++ b/lib/efi_loader/Makefile
>>>> @@ -17,7 +17,7 @@ endif
>>>>   obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o
>>>>   obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o
>>>>   obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o
>>>> -obj-y += efi_device_path_utilities.o efi_hii.o
>>>> +obj-y += efi_device_path_utilities.o efi_hii.o efi_unicode.o
>>>>   obj-y += efi_file.o efi_variable.o efi_bootmgr.o
>>>>   obj-$(CONFIG_LCD) += efi_gop.o
>>>>   obj-$(CONFIG_DM_VIDEO) += efi_gop.o
>>>> diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
>>>> index c179afc25a..b568f3f162 100644
>>>> --- a/lib/efi_loader/efi_boottime.c
>>>> +++ b/lib/efi_loader/efi_boottime.c
>>>> @@ -1166,6 +1166,12 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob
>>>>        obj->protocols[7].guid = &efi_guid_hii_config_routing_protocol;
>>>>        obj->protocols[7].protocol_interface = (void *)&efi_hii_config_routing;
>>>>
>>>> +     obj->protocols[8].guid = &efi_guid_unicode_collation_protocol;
>>>> +     obj->protocols[8].protocol_interface = (void *)&efi_unicode_collation;
>>>> +
>>>> +     obj->protocols[9].guid = &efi_guid_unicode_collation_protocol2;
>>>> +     obj->protocols[9].protocol_interface = (void *)&efi_unicode_collation;
>>>> +
>>>>        info->file_path = file_path;
>>>>        info->device_handle = efi_dp_find_obj(device_path, NULL);
>>>>
>>>> diff --git a/lib/efi_loader/efi_unicode.c b/lib/efi_loader/efi_unicode.c
>>>> new file mode 100644
>>>> index 0000000000..2c6302df25
>>>> --- /dev/null
>>>> +++ b/lib/efi_loader/efi_unicode.c
>>>> @@ -0,0 +1,170 @@
>>>> +/*
>>>> +*  EFI Unicode interface
>>>> + *
>>>> + *  Copyright (c) 2017 Leif Lindholm
>>>> + *
>>>> + *  SPDX-License-Identifier:     GPL-2.0+
>>>> + */
>>>> +
>>>> +#include <common.h>
>>>> +#include <charset.h>
>>>> +#include <linux/ctype.h>
>>>> +#include <efi_loader.h>
>>>> +
>>>> +const efi_guid_t efi_guid_unicode_collation_protocol =
>>>> +     EFI_UNICODE_COLLATION_PROTOCOL_GUID;
>>>> +
>>>> +const efi_guid_t efi_guid_unicode_collation_protocol2 =
>>>> +     EFI_UNICODE_COLLATION_PROTOCOL2_GUID;
>>>> +
>>>> +static int matchn(efi_string_t s1, unsigned n1, efi_string_t s2, unsigned n2)
>>>> +{
>>>> +     char u1[MAX_UTF8_PER_UTF16 * n1 + 1];
>>>> +     char u2[MAX_UTF8_PER_UTF16 * n2 + 1];
>>>> +
>>>> +     *utf16_to_utf8((u8 *)u1, s1, n1) = '\0';
>>>> +     *utf16_to_utf8((u8 *)u2, s2, n2) = '\0';
>>>> +
>>>> +     return strcasecmp(u1, u2);
>>>> +}
>>>> +
>>>> +static efi_intn_t EFIAPI stri_coll(struct efi_unicode_collation_protocol *this,
>>>> +                                efi_string_t s1,
>>>> +                                efi_string_t s2)
>>>> +{
>>>> +     EFI_ENTRY("%p, \"%ls\", \"%ls\"", this, s1, s2);
>>>> +
>>>> +     unsigned n1 = utf16_strlen(s1);
>>>> +     unsigned n2 = utf16_strlen(s2);
>>>> +
>>>> +     return EFI_EXIT(matchn(s1, n1, s2, n2));
>>>> +}
>>>> +
>>>> +static bool match(efi_string_t string, efi_string_t pattern)
>>>> +{
>>>> +     while (true) {
>>>> +             uint16_t p = *pattern++;
>>>> +             bool matches = false;
>>>> +
>>>> +             if (p == '\0' || *string == '\0') {
>>>> +                     /*
>>>> +                      * End of pattern or string, succeed if
>>>> +                      * end of both:
>>>> +                      */
>>>> +                     return *string == p;
>>>> +             }
>>>> +
>>>> +             switch (p) {
>>>> +             case '*':
>>>> +                     /* Match zero or more chars: */
>>>> +                     while (*string != '\0') {
>>>> +                             if (match(string, pattern))
>>>> +                                     return true;
>>>> +                             string++;
>>>> +                     }
>>>> +                     return match(string, pattern);
>>>> +             case '?':
>>>> +                     /* Match any one char: */
>>>> +                     string++;
>>>> +                     break;
>>>> +             case '[':
>>>> +                     /* Match char set, either [abc] or [a-c]: */
>>>> +
>>>> +                     if (pattern[0] == '\0' || pattern[0] == ']') {
>>>> +                             /* invalid pattern */
>>>> +                             return false;
>>>> +                     }
>>>> +
>>>> +                     if (pattern[1] == '-') {
>>>> +                             uint16_t lo, hi, c;
>>>> +
>>>> +                             /* range: [a-c] */
>>>> +                             lo = pattern[0];
>>>> +                             hi = pattern[2];
>>>> +
>>>> +                             if (hi == '\0' || hi == ']' || pattern[3] != ']') {
>>>> +                                     /* invalid pattern */
>>>> +                                     return false;
>>>> +                             }
>>>> +
>>>> +                             c  = tolower(*string);
>>>> +                             lo = tolower(lo);
>>>> +                             hi = tolower(hi);
>>>> +
>>>> +                             if (lo <= c && c <= hi)
>>>> +                                     matches = true;
>>>> +
>>>> +                             pattern += 4;
>>>> +                     } else {
>>>> +                             /* set: [abc] */
>>>> +                             while ((p = *pattern++) && p != ']')
>>>> +                                     if (matchn(string, 1, &p, 1))
>>>> +                                             matches = true;
>>>> +                     }
>>>> +
>>>> +                     if (!matches)
>>>> +                             return false;
>>>> +
>>>> +                     string++;
>>>> +                     break;
>>>> +             default:
>>>> +                     if (matchn(string, 1, &p, 1))
>>>> +                             return false;
>>>> +                     string++;
>>>> +                     break;
>>>> +             }
>>>> +     }
>>>> +}
>>>> +
>>>> +static bool EFIAPI metai_match(struct efi_unicode_collation_protocol *this,
>>>> +                            efi_string_t string,
>>>> +                            efi_string_t pattern)
>>>> +{
>>>> +     EFI_ENTRY("%p, \"%ls\", \"%ls\"", this, string, pattern);
>>>> +     return EFI_EXIT(match(string, pattern));
>>> EFI_EXIT wants a success/failure parameter, not true/false (which can be
>>> randomly defined). Please either have match() return EFI return codes or
>>> convert it in here :).
>> That isn't strictly true, it does use typeof(ret).. and while it masks
>> the resulting debug msg with ~EFI_ERROR_MASK, in practice it isn't a
>> problem with boolean return.  Just a bit funny.
>>
>> And there already other EFI entry points that return something other
>> than efi_status_t..  trying to force them all into efi_status_t mold
>> makes them somewhat more awkward.
> Well, anything that casts well into an integer is reasonably valid for
> EFI_EXIT(). But with bool things aren't always as clear as they should
> be. I'm for example not 100% sure if the return value of a bool function
> can never be different from 0 or 1.

So I just double-checked with one of our compiler guys. Since we compile 
with at least C99, bool is defined as _Bool which is defined as an 
unsigned 1-bit data type that is defined as 0 or 1.

In a nutshell, keeping it as bool is fine I hope.


Alex

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 06/11] efi_loader: Decouple EFI input/output from stdin/stdout
  2017-10-12  7:15       ` Alexander Graf
@ 2017-10-12 12:48         ` Rob Clark
  2017-10-12 13:05           ` Heinrich Schuchardt
                             ` (2 more replies)
  0 siblings, 3 replies; 75+ messages in thread
From: Rob Clark @ 2017-10-12 12:48 UTC (permalink / raw)
  To: u-boot

On Thu, Oct 12, 2017 at 3:15 AM, Alexander Graf <agraf@suse.de> wrote:
>
>
> On 12.10.17 00:07, Rob Clark wrote:
>> On Wed, Oct 11, 2017 at 10:45 AM, Alexander Graf <agraf@suse.de> wrote:
>>>
>>>
>>> On 10.10.17 14:23, Rob Clark wrote:
>>>> In some cases, it is quite useful to have (for example) EFI on screen
>>>> but u-boot on serial port.
>>>>
>>>> This adds two new optional environment variables, "efiin" and "efiout",
>>>> which can be used to set EFI console input/output independently of
>>>> u-boot's input/output.  If unset, EFI console will default to stdin/
>>>> stdout as before.
>>>>
>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>>
>>> With this patch, we lose the ability to have the efi in/out go to both
>>> graphical and serial console, right? This is critical functionality to
>>> have, since we don't necessarily know which output/input a user ends up
>>> using.
>>
>> I'll think about how to support iomux.. but some things like console
>> size are just not going to work properly there.  And as long as we fix
>
> Yeah, those probably would need to get special cased.
>
>> the stdout shenanigans (ie. what I was seeing w/ qemu-x86) you can
>> simply not set efiout var and have things working as before, so you
>> don't loose any existing functionality (although, like I said, if the
>> two different consoles have different sizes things aren't going to
>> work properly for anything other than simple cases).
>>
>> In most cases, the display driver should be able to detect whether a
>> display is connected.. this is what I've done on dragonboard410c, so
>> if no display plugged in, 'efiout=vidconsole' fails and you fall back
>> to serial, else you get efi on screen like you would on a "real"
>> computer.  For boards that have a display driver that isn't able to do
>> the basic check of whether a cable is plugged in, just don't set
>> "efiout" (or fix the display driver) ;-)
>
> Are you sure that's what happens on a "real" computer? As far as I
> remember from all ARM servers running edk2 based firmware that I've
> touched so far, the default is always to display on serial *and*
> graphical output at the same time.

Well, I suppose some of the arm64 server vendors have done a better
job than others on firmware.. you'd hope they would probe EDID, and
report correct console dimensions based on display resolution, etc.

Doing both serial and display works for simple stuff, but it goes
badly once the efi payload starts trying to change the cursor position
and write to specific parts of the screen (which both Shell.efi and
grub try to do).

BR,
-R

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 06/11] efi_loader: Decouple EFI input/output from stdin/stdout
  2017-10-12 12:48         ` Rob Clark
@ 2017-10-12 13:05           ` Heinrich Schuchardt
  2017-10-12 13:40             ` Rob Clark
  2017-10-12 13:11           ` Alexander Graf
  2017-10-12 13:44           ` Mark Kettenis
  2 siblings, 1 reply; 75+ messages in thread
From: Heinrich Schuchardt @ 2017-10-12 13:05 UTC (permalink / raw)
  To: u-boot



On 10/12/2017 02:48 PM, Rob Clark wrote:
> On Thu, Oct 12, 2017 at 3:15 AM, Alexander Graf <agraf@suse.de> wrote:
>>
>>
>> On 12.10.17 00:07, Rob Clark wrote:
>>> On Wed, Oct 11, 2017 at 10:45 AM, Alexander Graf <agraf@suse.de> wrote:
>>>>
>>>>
>>>> On 10.10.17 14:23, Rob Clark wrote:
>>>>> In some cases, it is quite useful to have (for example) EFI on screen
>>>>> but u-boot on serial port.
>>>>>
>>>>> This adds two new optional environment variables, "efiin" and "efiout",
>>>>> which can be used to set EFI console input/output independently of
>>>>> u-boot's input/output.  If unset, EFI console will default to stdin/
>>>>> stdout as before.
>>>>>
>>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>>>
>>>> With this patch, we lose the ability to have the efi in/out go to both
>>>> graphical and serial console, right? This is critical functionality to
>>>> have, since we don't necessarily know which output/input a user ends up
>>>> using.
>>>
>>> I'll think about how to support iomux.. but some things like console
>>> size are just not going to work properly there.  And as long as we fix
>>
>> Yeah, those probably would need to get special cased.
>>
>>> the stdout shenanigans (ie. what I was seeing w/ qemu-x86) you can
>>> simply not set efiout var and have things working as before, so you
>>> don't loose any existing functionality (although, like I said, if the
>>> two different consoles have different sizes things aren't going to
>>> work properly for anything other than simple cases).
>>>
>>> In most cases, the display driver should be able to detect whether a
>>> display is connected.. this is what I've done on dragonboard410c, so
>>> if no display plugged in, 'efiout=vidconsole' fails and you fall back
>>> to serial, else you get efi on screen like you would on a "real"
>>> computer.  For boards that have a display driver that isn't able to do
>>> the basic check of whether a cable is plugged in, just don't set
>>> "efiout" (or fix the display driver) ;-)
>>
>> Are you sure that's what happens on a "real" computer? As far as I
>> remember from all ARM servers running edk2 based firmware that I've
>> touched so far, the default is always to display on serial *and*
>> graphical output at the same time.
> 
> Well, I suppose some of the arm64 server vendors have done a better
> job than others on firmware.. you'd hope they would probe EDID, and
> report correct console dimensions based on display resolution, etc.
> 
> Doing both serial and display works for simple stuff, but it goes
> badly once the efi payload starts trying to change the cursor position
> and write to specific parts of the screen (which both Shell.efi and
> grub try to do).
> 
> BR,
> -R
> 
Hello Rob,

I do not know which program you use for connecting to your serial 
console. I use minicom which is a Debian/Ubuntu package. I had no 
problem using grub, vim, nano or any other console program.

Minicom just provides a VT100 emulation and that is close enough to what 
Linux expects.

So I would not see what should be so special about Shell.efi.

My U-Boot system all have video but I never have a monitor connected.

So being able to use serial even if video is available is a necessity.

Best regards

Heinrich

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 06/11] efi_loader: Decouple EFI input/output from stdin/stdout
  2017-10-12 12:48         ` Rob Clark
  2017-10-12 13:05           ` Heinrich Schuchardt
@ 2017-10-12 13:11           ` Alexander Graf
  2017-10-12 13:42             ` Rob Clark
  2017-10-12 13:44           ` Mark Kettenis
  2 siblings, 1 reply; 75+ messages in thread
From: Alexander Graf @ 2017-10-12 13:11 UTC (permalink / raw)
  To: u-boot

On 10/12/2017 02:48 PM, Rob Clark wrote:
> On Thu, Oct 12, 2017 at 3:15 AM, Alexander Graf <agraf@suse.de> wrote:
>>
>> On 12.10.17 00:07, Rob Clark wrote:
>>> On Wed, Oct 11, 2017 at 10:45 AM, Alexander Graf <agraf@suse.de> wrote:
>>>>
>>>> On 10.10.17 14:23, Rob Clark wrote:
>>>>> In some cases, it is quite useful to have (for example) EFI on screen
>>>>> but u-boot on serial port.
>>>>>
>>>>> This adds two new optional environment variables, "efiin" and "efiout",
>>>>> which can be used to set EFI console input/output independently of
>>>>> u-boot's input/output.  If unset, EFI console will default to stdin/
>>>>> stdout as before.
>>>>>
>>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>>> With this patch, we lose the ability to have the efi in/out go to both
>>>> graphical and serial console, right? This is critical functionality to
>>>> have, since we don't necessarily know which output/input a user ends up
>>>> using.
>>> I'll think about how to support iomux.. but some things like console
>>> size are just not going to work properly there.  And as long as we fix
>> Yeah, those probably would need to get special cased.
>>
>>> the stdout shenanigans (ie. what I was seeing w/ qemu-x86) you can
>>> simply not set efiout var and have things working as before, so you
>>> don't loose any existing functionality (although, like I said, if the
>>> two different consoles have different sizes things aren't going to
>>> work properly for anything other than simple cases).
>>>
>>> In most cases, the display driver should be able to detect whether a
>>> display is connected.. this is what I've done on dragonboard410c, so
>>> if no display plugged in, 'efiout=vidconsole' fails and you fall back
>>> to serial, else you get efi on screen like you would on a "real"
>>> computer.  For boards that have a display driver that isn't able to do
>>> the basic check of whether a cable is plugged in, just don't set
>>> "efiout" (or fix the display driver) ;-)
>> Are you sure that's what happens on a "real" computer? As far as I
>> remember from all ARM servers running edk2 based firmware that I've
>> touched so far, the default is always to display on serial *and*
>> graphical output at the same time.
> Well, I suppose some of the arm64 server vendors have done a better
> job than others on firmware.. you'd hope they would probe EDID, and
> report correct console dimensions based on display resolution, etc.

Not sure that's terribly helpful. Most of these servers have built-in 
BMC chips that just go to a fake video console, so they always get EDID 
information, but that doesn't mean that it's sensible for what the user 
ends up seeing.

I think what happens is that in most cases they just assume you have a 
80x25 console :).

> Doing both serial and display works for simple stuff, but it goes
> badly once the efi payload starts trying to change the cursor position
> and write to specific parts of the screen (which both Shell.efi and
> grub try to do).

Yes, and on basically all arm servers what you see happening is that 
grub gets squeezed into 80x25 for the text output. For graphical output, 
at least SUSE usually just defaults to gfxterm which directly drives GOP.


Alex

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 06/11] efi_loader: Decouple EFI input/output from stdin/stdout
  2017-10-12 13:05           ` Heinrich Schuchardt
@ 2017-10-12 13:40             ` Rob Clark
  2017-10-12 13:50               ` Alexander Graf
  0 siblings, 1 reply; 75+ messages in thread
From: Rob Clark @ 2017-10-12 13:40 UTC (permalink / raw)
  To: u-boot

On Thu, Oct 12, 2017 at 9:05 AM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>
>
> On 10/12/2017 02:48 PM, Rob Clark wrote:
>>
>> On Thu, Oct 12, 2017 at 3:15 AM, Alexander Graf <agraf@suse.de> wrote:
>>>
>>>
>>>
>>> On 12.10.17 00:07, Rob Clark wrote:
>>>>
>>>> On Wed, Oct 11, 2017 at 10:45 AM, Alexander Graf <agraf@suse.de> wrote:
>>>>>
>>>>>
>>>>>
>>>>> On 10.10.17 14:23, Rob Clark wrote:
>>>>>>
>>>>>> In some cases, it is quite useful to have (for example) EFI on screen
>>>>>> but u-boot on serial port.
>>>>>>
>>>>>> This adds two new optional environment variables, "efiin" and
>>>>>> "efiout",
>>>>>> which can be used to set EFI console input/output independently of
>>>>>> u-boot's input/output.  If unset, EFI console will default to stdin/
>>>>>> stdout as before.
>>>>>>
>>>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>>>>
>>>>>
>>>>> With this patch, we lose the ability to have the efi in/out go to both
>>>>> graphical and serial console, right? This is critical functionality to
>>>>> have, since we don't necessarily know which output/input a user ends up
>>>>> using.
>>>>
>>>>
>>>> I'll think about how to support iomux.. but some things like console
>>>> size are just not going to work properly there.  And as long as we fix
>>>
>>>
>>> Yeah, those probably would need to get special cased.
>>>
>>>> the stdout shenanigans (ie. what I was seeing w/ qemu-x86) you can
>>>> simply not set efiout var and have things working as before, so you
>>>> don't loose any existing functionality (although, like I said, if the
>>>> two different consoles have different sizes things aren't going to
>>>> work properly for anything other than simple cases).
>>>>
>>>> In most cases, the display driver should be able to detect whether a
>>>> display is connected.. this is what I've done on dragonboard410c, so
>>>> if no display plugged in, 'efiout=vidconsole' fails and you fall back
>>>> to serial, else you get efi on screen like you would on a "real"
>>>> computer.  For boards that have a display driver that isn't able to do
>>>> the basic check of whether a cable is plugged in, just don't set
>>>> "efiout" (or fix the display driver) ;-)
>>>
>>>
>>> Are you sure that's what happens on a "real" computer? As far as I
>>> remember from all ARM servers running edk2 based firmware that I've
>>> touched so far, the default is always to display on serial *and*
>>> graphical output at the same time.
>>
>>
>> Well, I suppose some of the arm64 server vendors have done a better
>> job than others on firmware.. you'd hope they would probe EDID, and
>> report correct console dimensions based on display resolution, etc.
>>
>> Doing both serial and display works for simple stuff, but it goes
>> badly once the efi payload starts trying to change the cursor position
>> and write to specific parts of the screen (which both Shell.efi and
>> grub try to do).
>>
>> BR,
>> -R
>>
> Hello Rob,
>
> I do not know which program you use for connecting to your serial console. I
> use minicom which is a Debian/Ubuntu package. I had no problem using grub,
> vim, nano or any other console program.
>
> Minicom just provides a VT100 emulation and that is close enough to what
> Linux expects.

fwiw, I generally use kermit so my terminal emulator is whatever
"xterm" type app I'm using.  (Currently a big fan of Tilix).. but that
isn't so much the issue..

> So I would not see what should be so special about Shell.efi.

I'm not explaining the problem well, but you can see basically the
same issue if you resize your terminal emulator to something smaller
than what grub/shell/etc think you are using.

I guess if they just fall back to assuming 80x25 like agraf mentioned,
that would kind of work.  It just means shell or grub will only use
the tiny upper-left corner of your monitor.

> My U-Boot system all have video but I never have a monitor connected.
>
> So being able to use serial even if video is available is a necessity.

If the video driver doesn't detect that it is unconnected, someone
should really fix that, otherwise you'll have problems booting an
image where grub tries to use gfxterm if GOP is present (but we are
really getting off topic here)

Either way, you still have the option of not setting efiout (or
setting it to serial)

But for end users (at least of boards that I care about), if they plug
in a monitor they should get grub on screen.  Not everyone has a
serial cable attached.

BR,
-R

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 06/11] efi_loader: Decouple EFI input/output from stdin/stdout
  2017-10-12 13:11           ` Alexander Graf
@ 2017-10-12 13:42             ` Rob Clark
  0 siblings, 0 replies; 75+ messages in thread
From: Rob Clark @ 2017-10-12 13:42 UTC (permalink / raw)
  To: u-boot

On Thu, Oct 12, 2017 at 9:11 AM, Alexander Graf <agraf@suse.de> wrote:
> On 10/12/2017 02:48 PM, Rob Clark wrote:
>>
>> On Thu, Oct 12, 2017 at 3:15 AM, Alexander Graf <agraf@suse.de> wrote:
>>>
>>>
>>> On 12.10.17 00:07, Rob Clark wrote:
>>>>
>>>> On Wed, Oct 11, 2017 at 10:45 AM, Alexander Graf <agraf@suse.de> wrote:
>>>>>
>>>>>
>>>>> On 10.10.17 14:23, Rob Clark wrote:
>>>>>>
>>>>>> In some cases, it is quite useful to have (for example) EFI on screen
>>>>>> but u-boot on serial port.
>>>>>>
>>>>>> This adds two new optional environment variables, "efiin" and
>>>>>> "efiout",
>>>>>> which can be used to set EFI console input/output independently of
>>>>>> u-boot's input/output.  If unset, EFI console will default to stdin/
>>>>>> stdout as before.
>>>>>>
>>>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>>>>
>>>>> With this patch, we lose the ability to have the efi in/out go to both
>>>>> graphical and serial console, right? This is critical functionality to
>>>>> have, since we don't necessarily know which output/input a user ends up
>>>>> using.
>>>>
>>>> I'll think about how to support iomux.. but some things like console
>>>> size are just not going to work properly there.  And as long as we fix
>>>
>>> Yeah, those probably would need to get special cased.
>>>
>>>> the stdout shenanigans (ie. what I was seeing w/ qemu-x86) you can
>>>> simply not set efiout var and have things working as before, so you
>>>> don't loose any existing functionality (although, like I said, if the
>>>> two different consoles have different sizes things aren't going to
>>>> work properly for anything other than simple cases).
>>>>
>>>> In most cases, the display driver should be able to detect whether a
>>>> display is connected.. this is what I've done on dragonboard410c, so
>>>> if no display plugged in, 'efiout=vidconsole' fails and you fall back
>>>> to serial, else you get efi on screen like you would on a "real"
>>>> computer.  For boards that have a display driver that isn't able to do
>>>> the basic check of whether a cable is plugged in, just don't set
>>>> "efiout" (or fix the display driver) ;-)
>>>
>>> Are you sure that's what happens on a "real" computer? As far as I
>>> remember from all ARM servers running edk2 based firmware that I've
>>> touched so far, the default is always to display on serial *and*
>>> graphical output at the same time.
>>
>> Well, I suppose some of the arm64 server vendors have done a better
>> job than others on firmware.. you'd hope they would probe EDID, and
>> report correct console dimensions based on display resolution, etc.
>
>
> Not sure that's terribly helpful. Most of these servers have built-in BMC
> chips that just go to a fake video console, so they always get EDID
> information, but that doesn't mean that it's sensible for what the user ends
> up seeing.
>
> I think what happens is that in most cases they just assume you have a 80x25
> console :).

oh, right.. BMC's..  well, let's not strive to be as horrible as
enterprise hardware ;-)

BR,
-R

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 06/11] efi_loader: Decouple EFI input/output from stdin/stdout
  2017-10-12 12:48         ` Rob Clark
  2017-10-12 13:05           ` Heinrich Schuchardt
  2017-10-12 13:11           ` Alexander Graf
@ 2017-10-12 13:44           ` Mark Kettenis
  2017-10-12 14:24             ` Rob Clark
  2 siblings, 1 reply; 75+ messages in thread
From: Mark Kettenis @ 2017-10-12 13:44 UTC (permalink / raw)
  To: u-boot

> From: Rob Clark <robdclark@gmail.com>
> Date: Thu, 12 Oct 2017 08:48:39 -0400
> 
> On Thu, Oct 12, 2017 at 3:15 AM, Alexander Graf <agraf@suse.de> wrote:
> >
> >
> > On 12.10.17 00:07, Rob Clark wrote:
> >> On Wed, Oct 11, 2017 at 10:45 AM, Alexander Graf <agraf@suse.de> wrote:
> >>>
> >>>
> >>> On 10.10.17 14:23, Rob Clark wrote:
> >>>> In some cases, it is quite useful to have (for example) EFI on screen
> >>>> but u-boot on serial port.
> >>>>
> >>>> This adds two new optional environment variables, "efiin" and "efiout",
> >>>> which can be used to set EFI console input/output independently of
> >>>> u-boot's input/output.  If unset, EFI console will default to stdin/
> >>>> stdout as before.
> >>>>
> >>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
> >>>
> >>> With this patch, we lose the ability to have the efi in/out go to both
> >>> graphical and serial console, right? This is critical functionality to
> >>> have, since we don't necessarily know which output/input a user ends up
> >>> using.

Seconded.  In many cases I'd want to continue using serial as the
console even if a display is connected.

> >> I'll think about how to support iomux.. but some things like console
> >> size are just not going to work properly there.  And as long as we fix
> >
> > Yeah, those probably would need to get special cased.
> >
> >> the stdout shenanigans (ie. what I was seeing w/ qemu-x86) you can
> >> simply not set efiout var and have things working as before, so you
> >> don't loose any existing functionality (although, like I said, if the
> >> two different consoles have different sizes things aren't going to
> >> work properly for anything other than simple cases).
> >>
> >> In most cases, the display driver should be able to detect whether a
> >> display is connected.. this is what I've done on dragonboard410c, so
> >> if no display plugged in, 'efiout=vidconsole' fails and you fall back
> >> to serial, else you get efi on screen like you would on a "real"
> >> computer.  For boards that have a display driver that isn't able to do
> >> the basic check of whether a cable is plugged in, just don't set
> >> "efiout" (or fix the display driver) ;-)

Display detection will always be somewhat fragile.  The old Sun
workstations used to base the decision on whether a keyboard was
connected.  With no keyboard detected the output would always go to
serial.

> > Are you sure that's what happens on a "real" computer? As far as I
> > remember from all ARM servers running edk2 based firmware that I've
> > touched so far, the default is always to display on serial *and*
> > graphical output at the same time.
> 
> Well, I suppose some of the arm64 server vendors have done a better
> job than others on firmware.. you'd hope they would probe EDID, and
> report correct console dimensions based on display resolution, etc.
> 
> Doing both serial and display works for simple stuff, but it goes
> badly once the efi payload starts trying to change the cursor position
> and write to specific parts of the screen (which both Shell.efi and
> grub try to do).

From my point of view a bootloader should only do "simple stuff".  All
this fancy display stuff makes a serial console much harder to use.

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 06/11] efi_loader: Decouple EFI input/output from stdin/stdout
  2017-10-12 13:40             ` Rob Clark
@ 2017-10-12 13:50               ` Alexander Graf
  2017-10-12 14:28                 ` Rob Clark
  0 siblings, 1 reply; 75+ messages in thread
From: Alexander Graf @ 2017-10-12 13:50 UTC (permalink / raw)
  To: u-boot

On 10/12/2017 03:40 PM, Rob Clark wrote:
> On Thu, Oct 12, 2017 at 9:05 AM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>>
>> On 10/12/2017 02:48 PM, Rob Clark wrote:
>>> On Thu, Oct 12, 2017 at 3:15 AM, Alexander Graf <agraf@suse.de> wrote:
>>>>
>>>>
>>>> On 12.10.17 00:07, Rob Clark wrote:
>>>>> On Wed, Oct 11, 2017 at 10:45 AM, Alexander Graf <agraf@suse.de> wrote:
>>>>>>
>>>>>>
>>>>>> On 10.10.17 14:23, Rob Clark wrote:
>>>>>>> In some cases, it is quite useful to have (for example) EFI on screen
>>>>>>> but u-boot on serial port.
>>>>>>>
>>>>>>> This adds two new optional environment variables, "efiin" and
>>>>>>> "efiout",
>>>>>>> which can be used to set EFI console input/output independently of
>>>>>>> u-boot's input/output.  If unset, EFI console will default to stdin/
>>>>>>> stdout as before.
>>>>>>>
>>>>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>>>>>
>>>>>> With this patch, we lose the ability to have the efi in/out go to both
>>>>>> graphical and serial console, right? This is critical functionality to
>>>>>> have, since we don't necessarily know which output/input a user ends up
>>>>>> using.
>>>>>
>>>>> I'll think about how to support iomux.. but some things like console
>>>>> size are just not going to work properly there.  And as long as we fix
>>>>
>>>> Yeah, those probably would need to get special cased.
>>>>
>>>>> the stdout shenanigans (ie. what I was seeing w/ qemu-x86) you can
>>>>> simply not set efiout var and have things working as before, so you
>>>>> don't loose any existing functionality (although, like I said, if the
>>>>> two different consoles have different sizes things aren't going to
>>>>> work properly for anything other than simple cases).
>>>>>
>>>>> In most cases, the display driver should be able to detect whether a
>>>>> display is connected.. this is what I've done on dragonboard410c, so
>>>>> if no display plugged in, 'efiout=vidconsole' fails and you fall back
>>>>> to serial, else you get efi on screen like you would on a "real"
>>>>> computer.  For boards that have a display driver that isn't able to do
>>>>> the basic check of whether a cable is plugged in, just don't set
>>>>> "efiout" (or fix the display driver) ;-)
>>>>
>>>> Are you sure that's what happens on a "real" computer? As far as I
>>>> remember from all ARM servers running edk2 based firmware that I've
>>>> touched so far, the default is always to display on serial *and*
>>>> graphical output at the same time.
>>>
>>> Well, I suppose some of the arm64 server vendors have done a better
>>> job than others on firmware.. you'd hope they would probe EDID, and
>>> report correct console dimensions based on display resolution, etc.
>>>
>>> Doing both serial and display works for simple stuff, but it goes
>>> badly once the efi payload starts trying to change the cursor position
>>> and write to specific parts of the screen (which both Shell.efi and
>>> grub try to do).
>>>
>>> BR,
>>> -R
>>>
>> Hello Rob,
>>
>> I do not know which program you use for connecting to your serial console. I
>> use minicom which is a Debian/Ubuntu package. I had no problem using grub,
>> vim, nano or any other console program.
>>
>> Minicom just provides a VT100 emulation and that is close enough to what
>> Linux expects.
> fwiw, I generally use kermit so my terminal emulator is whatever
> "xterm" type app I'm using.  (Currently a big fan of Tilix).. but that
> isn't so much the issue..
>
>> So I would not see what should be so special about Shell.efi.
> I'm not explaining the problem well, but you can see basically the
> same issue if you resize your terminal emulator to something smaller
> than what grub/shell/etc think you are using.
>
> I guess if they just fall back to assuming 80x25 like agraf mentioned,
> that would kind of work.  It just means shell or grub will only use
> the tiny upper-left corner of your monitor.
>
>> My U-Boot system all have video but I never have a monitor connected.
>>
>> So being able to use serial even if video is available is a necessity.
> If the video driver doesn't detect that it is unconnected, someone
> should really fix that, otherwise you'll have problems booting an
> image where grub tries to use gfxterm if GOP is present (but we are
> really getting off topic here)
>
> Either way, you still have the option of not setting efiout (or
> setting it to serial)
>
> But for end users (at least of boards that I care about), if they plug
> in a monitor they should get grub on screen.  Not everyone has a
> serial cable attached.

I fully agree there. The same applies the other way around too. Even if 
they have a monitor attached, they should get grub on serial if serial 
is a valid output :). Just attaching a monitor doesn't mean you only use 
that monitor to control the system.

I think for multi-out we really just have to do what edk2 does and limit 
the screen size to 80x25. I guess you'd just create an iomux target 
there that would return the fake size info?


Alex

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 06/11] efi_loader: Decouple EFI input/output from stdin/stdout
  2017-10-12 13:44           ` Mark Kettenis
@ 2017-10-12 14:24             ` Rob Clark
  0 siblings, 0 replies; 75+ messages in thread
From: Rob Clark @ 2017-10-12 14:24 UTC (permalink / raw)
  To: u-boot

On Thu, Oct 12, 2017 at 9:44 AM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>> From: Rob Clark <robdclark@gmail.com>
>> Date: Thu, 12 Oct 2017 08:48:39 -0400
>>
>> On Thu, Oct 12, 2017 at 3:15 AM, Alexander Graf <agraf@suse.de> wrote:
>> >
>> >
>> > On 12.10.17 00:07, Rob Clark wrote:
>> >> On Wed, Oct 11, 2017 at 10:45 AM, Alexander Graf <agraf@suse.de> wrote:
>> >>>
>> >>>
>> >>> On 10.10.17 14:23, Rob Clark wrote:
>> >>>> In some cases, it is quite useful to have (for example) EFI on screen
>> >>>> but u-boot on serial port.
>> >>>>
>> >>>> This adds two new optional environment variables, "efiin" and "efiout",
>> >>>> which can be used to set EFI console input/output independently of
>> >>>> u-boot's input/output.  If unset, EFI console will default to stdin/
>> >>>> stdout as before.
>> >>>>
>> >>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>> >>>
>> >>> With this patch, we lose the ability to have the efi in/out go to both
>> >>> graphical and serial console, right? This is critical functionality to
>> >>> have, since we don't necessarily know which output/input a user ends up
>> >>> using.
>
> Seconded.  In many cases I'd want to continue using serial as the
> console even if a display is connected.

Sure, and this patch isn't preventing that.

>> >> I'll think about how to support iomux.. but some things like console
>> >> size are just not going to work properly there.  And as long as we fix
>> >
>> > Yeah, those probably would need to get special cased.
>> >
>> >> the stdout shenanigans (ie. what I was seeing w/ qemu-x86) you can
>> >> simply not set efiout var and have things working as before, so you
>> >> don't loose any existing functionality (although, like I said, if the
>> >> two different consoles have different sizes things aren't going to
>> >> work properly for anything other than simple cases).
>> >>
>> >> In most cases, the display driver should be able to detect whether a
>> >> display is connected.. this is what I've done on dragonboard410c, so
>> >> if no display plugged in, 'efiout=vidconsole' fails and you fall back
>> >> to serial, else you get efi on screen like you would on a "real"
>> >> computer.  For boards that have a display driver that isn't able to do
>> >> the basic check of whether a cable is plugged in, just don't set
>> >> "efiout" (or fix the display driver) ;-)
>
> Display detection will always be somewhat fragile.  The old Sun
> workstations used to base the decision on whether a keyboard was
> connected.  With no keyboard detected the output would always go to
> serial.

s/always/sometimes/

For analog outputs it can be more tricky.  For any display technology
from this century, it isn't really that hard.

Boards that cannot reliably detect whether a display is connected
probably don't want to set efiout.

>> > Are you sure that's what happens on a "real" computer? As far as I
>> > remember from all ARM servers running edk2 based firmware that I've
>> > touched so far, the default is always to display on serial *and*
>> > graphical output at the same time.
>>
>> Well, I suppose some of the arm64 server vendors have done a better
>> job than others on firmware.. you'd hope they would probe EDID, and
>> report correct console dimensions based on display resolution, etc.
>>
>> Doing both serial and display works for simple stuff, but it goes
>> badly once the efi payload starts trying to change the cursor position
>> and write to specific parts of the screen (which both Shell.efi and
>> grub try to do).
>
> From my point of view a bootloader should only do "simple stuff".  All
> this fancy display stuff makes a serial console much harder to use.

Sure, but people who tinker with u-boot and low level stuff aren't the
only target audience here.

This patch provides a (completely optional) way to provide a sane
default that doesn't require a serial cable, yet still works with one
if you don't have a display connected.. some people expect to be able
to just plug in display + keyboard + power and get to a grub boot
menu, just like you would on an x86/uefi system.

BR,
-R

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 06/11] efi_loader: Decouple EFI input/output from stdin/stdout
  2017-10-12 13:50               ` Alexander Graf
@ 2017-10-12 14:28                 ` Rob Clark
  2017-10-12 14:31                   ` Alexander Graf
                                     ` (2 more replies)
  0 siblings, 3 replies; 75+ messages in thread
From: Rob Clark @ 2017-10-12 14:28 UTC (permalink / raw)
  To: u-boot

On Thu, Oct 12, 2017 at 9:50 AM, Alexander Graf <agraf@suse.de> wrote:
> On 10/12/2017 03:40 PM, Rob Clark wrote:
>>
>> On Thu, Oct 12, 2017 at 9:05 AM, Heinrich Schuchardt <xypron.glpk@gmx.de>
>> wrote:
>>>
>>>
>>> On 10/12/2017 02:48 PM, Rob Clark wrote:
>>>>
>>>> On Thu, Oct 12, 2017 at 3:15 AM, Alexander Graf <agraf@suse.de> wrote:
>>>>>
>>>>>
>>>>>
>>>>> On 12.10.17 00:07, Rob Clark wrote:
>>>>>>
>>>>>> On Wed, Oct 11, 2017 at 10:45 AM, Alexander Graf <agraf@suse.de>
>>>>>> wrote:
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> On 10.10.17 14:23, Rob Clark wrote:
>>>>>>>>
>>>>>>>> In some cases, it is quite useful to have (for example) EFI on
>>>>>>>> screen
>>>>>>>> but u-boot on serial port.
>>>>>>>>
>>>>>>>> This adds two new optional environment variables, "efiin" and
>>>>>>>> "efiout",
>>>>>>>> which can be used to set EFI console input/output independently of
>>>>>>>> u-boot's input/output.  If unset, EFI console will default to stdin/
>>>>>>>> stdout as before.
>>>>>>>>
>>>>>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>>>>>>
>>>>>>>
>>>>>>> With this patch, we lose the ability to have the efi in/out go to
>>>>>>> both
>>>>>>> graphical and serial console, right? This is critical functionality
>>>>>>> to
>>>>>>> have, since we don't necessarily know which output/input a user ends
>>>>>>> up
>>>>>>> using.
>>>>>>
>>>>>>
>>>>>> I'll think about how to support iomux.. but some things like console
>>>>>> size are just not going to work properly there.  And as long as we fix
>>>>>
>>>>>
>>>>> Yeah, those probably would need to get special cased.
>>>>>
>>>>>> the stdout shenanigans (ie. what I was seeing w/ qemu-x86) you can
>>>>>> simply not set efiout var and have things working as before, so you
>>>>>> don't loose any existing functionality (although, like I said, if the
>>>>>> two different consoles have different sizes things aren't going to
>>>>>> work properly for anything other than simple cases).
>>>>>>
>>>>>> In most cases, the display driver should be able to detect whether a
>>>>>> display is connected.. this is what I've done on dragonboard410c, so
>>>>>> if no display plugged in, 'efiout=vidconsole' fails and you fall back
>>>>>> to serial, else you get efi on screen like you would on a "real"
>>>>>> computer.  For boards that have a display driver that isn't able to do
>>>>>> the basic check of whether a cable is plugged in, just don't set
>>>>>> "efiout" (or fix the display driver) ;-)
>>>>>
>>>>>
>>>>> Are you sure that's what happens on a "real" computer? As far as I
>>>>> remember from all ARM servers running edk2 based firmware that I've
>>>>> touched so far, the default is always to display on serial *and*
>>>>> graphical output at the same time.
>>>>
>>>>
>>>> Well, I suppose some of the arm64 server vendors have done a better
>>>> job than others on firmware.. you'd hope they would probe EDID, and
>>>> report correct console dimensions based on display resolution, etc.
>>>>
>>>> Doing both serial and display works for simple stuff, but it goes
>>>> badly once the efi payload starts trying to change the cursor position
>>>> and write to specific parts of the screen (which both Shell.efi and
>>>> grub try to do).
>>>>
>>>> BR,
>>>> -R
>>>>
>>> Hello Rob,
>>>
>>> I do not know which program you use for connecting to your serial
>>> console. I
>>> use minicom which is a Debian/Ubuntu package. I had no problem using
>>> grub,
>>> vim, nano or any other console program.
>>>
>>> Minicom just provides a VT100 emulation and that is close enough to what
>>> Linux expects.
>>
>> fwiw, I generally use kermit so my terminal emulator is whatever
>> "xterm" type app I'm using.  (Currently a big fan of Tilix).. but that
>> isn't so much the issue..
>>
>>> So I would not see what should be so special about Shell.efi.
>>
>> I'm not explaining the problem well, but you can see basically the
>> same issue if you resize your terminal emulator to something smaller
>> than what grub/shell/etc think you are using.
>>
>> I guess if they just fall back to assuming 80x25 like agraf mentioned,
>> that would kind of work.  It just means shell or grub will only use
>> the tiny upper-left corner of your monitor.
>>
>>> My U-Boot system all have video but I never have a monitor connected.
>>>
>>> So being able to use serial even if video is available is a necessity.
>>
>> If the video driver doesn't detect that it is unconnected, someone
>> should really fix that, otherwise you'll have problems booting an
>> image where grub tries to use gfxterm if GOP is present (but we are
>> really getting off topic here)
>>
>> Either way, you still have the option of not setting efiout (or
>> setting it to serial)
>>
>> But for end users (at least of boards that I care about), if they plug
>> in a monitor they should get grub on screen.  Not everyone has a
>> serial cable attached.
>
>
> I fully agree there. The same applies the other way around too. Even if they
> have a monitor attached, they should get grub on serial if serial is a valid
> output :). Just attaching a monitor doesn't mean you only use that monitor
> to control the system.

We could, I suppose, try probing the serial console's size, as an
approximation of hotplug detect for serial.  If we timeout without
getting a response, assume no serial console.

That would also let us pick the minimum of each dimension to report to
the payload, which is less horrible than just having an 80x25 grub
menu on your 4k screen.  And if no serial attached, then we can use
the full screen.

BR,
-R

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 06/11] efi_loader: Decouple EFI input/output from stdin/stdout
  2017-10-12 14:28                 ` Rob Clark
@ 2017-10-12 14:31                   ` Alexander Graf
  2017-10-12 16:00                   ` Mark Kettenis
  2017-10-12 22:38                   ` Heinrich Schuchardt
  2 siblings, 0 replies; 75+ messages in thread
From: Alexander Graf @ 2017-10-12 14:31 UTC (permalink / raw)
  To: u-boot

On 10/12/2017 04:28 PM, Rob Clark wrote:
> On Thu, Oct 12, 2017 at 9:50 AM, Alexander Graf <agraf@suse.de> wrote:
>> On 10/12/2017 03:40 PM, Rob Clark wrote:
>>> On Thu, Oct 12, 2017 at 9:05 AM, Heinrich Schuchardt <xypron.glpk@gmx.de>
>>> wrote:
>>>>
>>>> On 10/12/2017 02:48 PM, Rob Clark wrote:
>>>>> On Thu, Oct 12, 2017 at 3:15 AM, Alexander Graf <agraf@suse.de> wrote:
>>>>>>
>>>>>>
>>>>>> On 12.10.17 00:07, Rob Clark wrote:
>>>>>>> On Wed, Oct 11, 2017 at 10:45 AM, Alexander Graf <agraf@suse.de>
>>>>>>> wrote:
>>>>>>>>
>>>>>>>>
>>>>>>>> On 10.10.17 14:23, Rob Clark wrote:
>>>>>>>>> In some cases, it is quite useful to have (for example) EFI on
>>>>>>>>> screen
>>>>>>>>> but u-boot on serial port.
>>>>>>>>>
>>>>>>>>> This adds two new optional environment variables, "efiin" and
>>>>>>>>> "efiout",
>>>>>>>>> which can be used to set EFI console input/output independently of
>>>>>>>>> u-boot's input/output.  If unset, EFI console will default to stdin/
>>>>>>>>> stdout as before.
>>>>>>>>>
>>>>>>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>>>>>>>
>>>>>>>> With this patch, we lose the ability to have the efi in/out go to
>>>>>>>> both
>>>>>>>> graphical and serial console, right? This is critical functionality
>>>>>>>> to
>>>>>>>> have, since we don't necessarily know which output/input a user ends
>>>>>>>> up
>>>>>>>> using.
>>>>>>>
>>>>>>> I'll think about how to support iomux.. but some things like console
>>>>>>> size are just not going to work properly there.  And as long as we fix
>>>>>>
>>>>>> Yeah, those probably would need to get special cased.
>>>>>>
>>>>>>> the stdout shenanigans (ie. what I was seeing w/ qemu-x86) you can
>>>>>>> simply not set efiout var and have things working as before, so you
>>>>>>> don't loose any existing functionality (although, like I said, if the
>>>>>>> two different consoles have different sizes things aren't going to
>>>>>>> work properly for anything other than simple cases).
>>>>>>>
>>>>>>> In most cases, the display driver should be able to detect whether a
>>>>>>> display is connected.. this is what I've done on dragonboard410c, so
>>>>>>> if no display plugged in, 'efiout=vidconsole' fails and you fall back
>>>>>>> to serial, else you get efi on screen like you would on a "real"
>>>>>>> computer.  For boards that have a display driver that isn't able to do
>>>>>>> the basic check of whether a cable is plugged in, just don't set
>>>>>>> "efiout" (or fix the display driver) ;-)
>>>>>>
>>>>>> Are you sure that's what happens on a "real" computer? As far as I
>>>>>> remember from all ARM servers running edk2 based firmware that I've
>>>>>> touched so far, the default is always to display on serial *and*
>>>>>> graphical output at the same time.
>>>>>
>>>>> Well, I suppose some of the arm64 server vendors have done a better
>>>>> job than others on firmware.. you'd hope they would probe EDID, and
>>>>> report correct console dimensions based on display resolution, etc.
>>>>>
>>>>> Doing both serial and display works for simple stuff, but it goes
>>>>> badly once the efi payload starts trying to change the cursor position
>>>>> and write to specific parts of the screen (which both Shell.efi and
>>>>> grub try to do).
>>>>>
>>>>> BR,
>>>>> -R
>>>>>
>>>> Hello Rob,
>>>>
>>>> I do not know which program you use for connecting to your serial
>>>> console. I
>>>> use minicom which is a Debian/Ubuntu package. I had no problem using
>>>> grub,
>>>> vim, nano or any other console program.
>>>>
>>>> Minicom just provides a VT100 emulation and that is close enough to what
>>>> Linux expects.
>>> fwiw, I generally use kermit so my terminal emulator is whatever
>>> "xterm" type app I'm using.  (Currently a big fan of Tilix).. but that
>>> isn't so much the issue..
>>>
>>>> So I would not see what should be so special about Shell.efi.
>>> I'm not explaining the problem well, but you can see basically the
>>> same issue if you resize your terminal emulator to something smaller
>>> than what grub/shell/etc think you are using.
>>>
>>> I guess if they just fall back to assuming 80x25 like agraf mentioned,
>>> that would kind of work.  It just means shell or grub will only use
>>> the tiny upper-left corner of your monitor.
>>>
>>>> My U-Boot system all have video but I never have a monitor connected.
>>>>
>>>> So being able to use serial even if video is available is a necessity.
>>> If the video driver doesn't detect that it is unconnected, someone
>>> should really fix that, otherwise you'll have problems booting an
>>> image where grub tries to use gfxterm if GOP is present (but we are
>>> really getting off topic here)
>>>
>>> Either way, you still have the option of not setting efiout (or
>>> setting it to serial)
>>>
>>> But for end users (at least of boards that I care about), if they plug
>>> in a monitor they should get grub on screen.  Not everyone has a
>>> serial cable attached.
>>
>> I fully agree there. The same applies the other way around too. Even if they
>> have a monitor attached, they should get grub on serial if serial is a valid
>> output :). Just attaching a monitor doesn't mean you only use that monitor
>> to control the system.
> We could, I suppose, try probing the serial console's size, as an
> approximation of hotplug detect for serial.  If we timeout without
> getting a response, assume no serial console.
>
> That would also let us pick the minimum of each dimension to report to
> the payload, which is less horrible than just having an 80x25 grub
> menu on your 4k screen.  And if no serial attached, then we can use
> the full screen.

Now we're talking - that sounds much nicer indeed :)


Alex

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [U-Boot, 10/11] efi_loader: Add mem-mapped for fallback
  2017-10-10 12:23 ` [U-Boot] [PATCH 10/11] efi_loader: Add mem-mapped for fallback Rob Clark
  2017-10-10 22:31   ` Heinrich Schuchardt
  2017-10-11 14:59   ` Alexander Graf
@ 2017-10-12 15:24   ` Alexander Graf
  2 siblings, 0 replies; 75+ messages in thread
From: Alexander Graf @ 2017-10-12 15:24 UTC (permalink / raw)
  To: u-boot

> When we don't have a real device/image path, such as 'bootefi hello',
> construct a mem-mapped device-path.
> 
> This fixes 'bootefi hello' after devicepath refactoring.
> 
> Fixes: 95c5553ea2 ("efi_loader: refactor boot device and loaded_image handling")
> Signed-off-by: Rob Clark <robdclark@gmail.com>
> Acked-by: Heinrich Schuchardt <xypron.glpk@gmx.de>

Thanks, applied to efi-next

Alex

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [U-Boot, 05/11] efi_loader: console support for color attributes
  2017-10-10 12:23 ` [U-Boot] [PATCH 05/11] efi_loader: console support for color attributes Rob Clark
  2017-10-10 23:41   ` Heinrich Schuchardt
  2017-10-11 14:41   ` Alexander Graf
@ 2017-10-12 15:24   ` Alexander Graf
  2 siblings, 0 replies; 75+ messages in thread
From: Alexander Graf @ 2017-10-12 15:24 UTC (permalink / raw)
  To: u-boot

> Shell.efi uses this, and supporting color attributes makes things look
> nicer.  Map the EFI fg/bg color attributes to ANSI escape sequences.
> Not all colors have a perfect match, but spec just says "Devices
> supporting a different number of text colors are required to emulate the
> above colors to the best of the device’s capabilities".
> 
> Signed-off-by: Rob Clark <robdclark@gmail.com>
> Tested-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
> Reviewed-by: Alexander Graf <agraf@suse.de>

Thanks, applied to efi-next

Alex

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 06/11] efi_loader: Decouple EFI input/output from stdin/stdout
  2017-10-12 14:28                 ` Rob Clark
  2017-10-12 14:31                   ` Alexander Graf
@ 2017-10-12 16:00                   ` Mark Kettenis
  2017-10-12 16:25                     ` Alexander Graf
  2017-10-12 22:38                   ` Heinrich Schuchardt
  2 siblings, 1 reply; 75+ messages in thread
From: Mark Kettenis @ 2017-10-12 16:00 UTC (permalink / raw)
  To: u-boot

> From: Rob Clark <robdclark@gmail.com>
> Date: Thu, 12 Oct 2017 10:28:43 -0400
> 
> On Thu, Oct 12, 2017 at 9:50 AM, Alexander Graf <agraf@suse.de> wrote:
> > On 10/12/2017 03:40 PM, Rob Clark wrote:
> >>
> >> On Thu, Oct 12, 2017 at 9:05 AM, Heinrich Schuchardt <xypron.glpk@gmx.de>
> >> wrote:
> >>>
> >>>
> >>> On 10/12/2017 02:48 PM, Rob Clark wrote:
> >>>>
> >>>> On Thu, Oct 12, 2017 at 3:15 AM, Alexander Graf <agraf@suse.de> wrote:
> >>>>>
> >>>>>
> >>>>>
> >>>>> On 12.10.17 00:07, Rob Clark wrote:
> >>>>>>
> >>>>>> On Wed, Oct 11, 2017 at 10:45 AM, Alexander Graf <agraf@suse.de>
> >>>>>> wrote:
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> On 10.10.17 14:23, Rob Clark wrote:
> >>>>>>>>
> >>>>>>>> In some cases, it is quite useful to have (for example) EFI on
> >>>>>>>> screen
> >>>>>>>> but u-boot on serial port.
> >>>>>>>>
> >>>>>>>> This adds two new optional environment variables, "efiin" and
> >>>>>>>> "efiout",
> >>>>>>>> which can be used to set EFI console input/output independently of
> >>>>>>>> u-boot's input/output.  If unset, EFI console will default to stdin/
> >>>>>>>> stdout as before.
> >>>>>>>>
> >>>>>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
> >>>>>>>
> >>>>>>>
> >>>>>>> With this patch, we lose the ability to have the efi in/out go to
> >>>>>>> both
> >>>>>>> graphical and serial console, right? This is critical functionality
> >>>>>>> to
> >>>>>>> have, since we don't necessarily know which output/input a user ends
> >>>>>>> up
> >>>>>>> using.
> >>>>>>
> >>>>>>
> >>>>>> I'll think about how to support iomux.. but some things like console
> >>>>>> size are just not going to work properly there.  And as long as we fix
> >>>>>
> >>>>>
> >>>>> Yeah, those probably would need to get special cased.
> >>>>>
> >>>>>> the stdout shenanigans (ie. what I was seeing w/ qemu-x86) you can
> >>>>>> simply not set efiout var and have things working as before, so you
> >>>>>> don't loose any existing functionality (although, like I said, if the
> >>>>>> two different consoles have different sizes things aren't going to
> >>>>>> work properly for anything other than simple cases).
> >>>>>>
> >>>>>> In most cases, the display driver should be able to detect whether a
> >>>>>> display is connected.. this is what I've done on dragonboard410c, so
> >>>>>> if no display plugged in, 'efiout=vidconsole' fails and you fall back
> >>>>>> to serial, else you get efi on screen like you would on a "real"
> >>>>>> computer.  For boards that have a display driver that isn't able to do
> >>>>>> the basic check of whether a cable is plugged in, just don't set
> >>>>>> "efiout" (or fix the display driver) ;-)
> >>>>>
> >>>>>
> >>>>> Are you sure that's what happens on a "real" computer? As far as I
> >>>>> remember from all ARM servers running edk2 based firmware that I've
> >>>>> touched so far, the default is always to display on serial *and*
> >>>>> graphical output at the same time.
> >>>>
> >>>>
> >>>> Well, I suppose some of the arm64 server vendors have done a better
> >>>> job than others on firmware.. you'd hope they would probe EDID, and
> >>>> report correct console dimensions based on display resolution, etc.
> >>>>
> >>>> Doing both serial and display works for simple stuff, but it goes
> >>>> badly once the efi payload starts trying to change the cursor position
> >>>> and write to specific parts of the screen (which both Shell.efi and
> >>>> grub try to do).
> >>>>
> >>>> BR,
> >>>> -R
> >>>>
> >>> Hello Rob,
> >>>
> >>> I do not know which program you use for connecting to your serial
> >>> console. I
> >>> use minicom which is a Debian/Ubuntu package. I had no problem using
> >>> grub,
> >>> vim, nano or any other console program.
> >>>
> >>> Minicom just provides a VT100 emulation and that is close enough to what
> >>> Linux expects.
> >>
> >> fwiw, I generally use kermit so my terminal emulator is whatever
> >> "xterm" type app I'm using.  (Currently a big fan of Tilix).. but that
> >> isn't so much the issue..
> >>
> >>> So I would not see what should be so special about Shell.efi.
> >>
> >> I'm not explaining the problem well, but you can see basically the
> >> same issue if you resize your terminal emulator to something smaller
> >> than what grub/shell/etc think you are using.
> >>
> >> I guess if they just fall back to assuming 80x25 like agraf mentioned,
> >> that would kind of work.  It just means shell or grub will only use
> >> the tiny upper-left corner of your monitor.
> >>
> >>> My U-Boot system all have video but I never have a monitor connected.
> >>>
> >>> So being able to use serial even if video is available is a necessity.
> >>
> >> If the video driver doesn't detect that it is unconnected, someone
> >> should really fix that, otherwise you'll have problems booting an
> >> image where grub tries to use gfxterm if GOP is present (but we are
> >> really getting off topic here)
> >>
> >> Either way, you still have the option of not setting efiout (or
> >> setting it to serial)
> >>
> >> But for end users (at least of boards that I care about), if they plug
> >> in a monitor they should get grub on screen.  Not everyone has a
> >> serial cable attached.
> >
> >
> > I fully agree there. The same applies the other way around too. Even if they
> > have a monitor attached, they should get grub on serial if serial is a valid
> > output :). Just attaching a monitor doesn't mean you only use that monitor
> > to control the system.
> 
> We could, I suppose, try probing the serial console's size, as an
> approximation of hotplug detect for serial.  If we timeout without
> getting a response, assume no serial console.

By spitting out random control characters and hope they match the
terminal emulation on the other end?  Sounds like a bad idea to me to
do that by default.

Or would you only do it for EFI payload that uses more than just the
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL?  That might be acceptable.

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 06/11] efi_loader: Decouple EFI input/output from stdin/stdout
  2017-10-12 16:00                   ` Mark Kettenis
@ 2017-10-12 16:25                     ` Alexander Graf
  0 siblings, 0 replies; 75+ messages in thread
From: Alexander Graf @ 2017-10-12 16:25 UTC (permalink / raw)
  To: u-boot



Am 12.10.2017 um 18:00 schrieb Mark Kettenis <mark.kettenis@xs4all.nl>:

>> From: Rob Clark <robdclark@gmail.com>
>> Date: Thu, 12 Oct 2017 10:28:43 -0400
>> 
>>> On Thu, Oct 12, 2017 at 9:50 AM, Alexander Graf <agraf@suse.de> wrote:
>>>> On 10/12/2017 03:40 PM, Rob Clark wrote:
>>>> 
>>>> On Thu, Oct 12, 2017 at 9:05 AM, Heinrich Schuchardt <xypron.glpk@gmx.de>
>>>> wrote:
>>>>> 
>>>>> 
>>>>>> On 10/12/2017 02:48 PM, Rob Clark wrote:
>>>>>> 
>>>>>>> On Thu, Oct 12, 2017 at 3:15 AM, Alexander Graf <agraf@suse.de> wrote:
>>>>>>> 
>>>>>>> 
>>>>>>> 
>>>>>>>> On 12.10.17 00:07, Rob Clark wrote:
>>>>>>>> 
>>>>>>>> On Wed, Oct 11, 2017 at 10:45 AM, Alexander Graf <agraf@suse.de>
>>>>>>>> wrote:
>>>>>>>>> 
>>>>>>>>> 
>>>>>>>>> 
>>>>>>>>>> On 10.10.17 14:23, Rob Clark wrote:
>>>>>>>>>> 
>>>>>>>>>> In some cases, it is quite useful to have (for example) EFI on
>>>>>>>>>> screen
>>>>>>>>>> but u-boot on serial port.
>>>>>>>>>> 
>>>>>>>>>> This adds two new optional environment variables, "efiin" and
>>>>>>>>>> "efiout",
>>>>>>>>>> which can be used to set EFI console input/output independently of
>>>>>>>>>> u-boot's input/output.  If unset, EFI console will default to stdin/
>>>>>>>>>> stdout as before.
>>>>>>>>>> 
>>>>>>>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>>>>>>>> 
>>>>>>>>> 
>>>>>>>>> With this patch, we lose the ability to have the efi in/out go to
>>>>>>>>> both
>>>>>>>>> graphical and serial console, right? This is critical functionality
>>>>>>>>> to
>>>>>>>>> have, since we don't necessarily know which output/input a user ends
>>>>>>>>> up
>>>>>>>>> using.
>>>>>>>> 
>>>>>>>> 
>>>>>>>> I'll think about how to support iomux.. but some things like console
>>>>>>>> size are just not going to work properly there.  And as long as we fix
>>>>>>> 
>>>>>>> 
>>>>>>> Yeah, those probably would need to get special cased.
>>>>>>> 
>>>>>>>> the stdout shenanigans (ie. what I was seeing w/ qemu-x86) you can
>>>>>>>> simply not set efiout var and have things working as before, so you
>>>>>>>> don't loose any existing functionality (although, like I said, if the
>>>>>>>> two different consoles have different sizes things aren't going to
>>>>>>>> work properly for anything other than simple cases).
>>>>>>>> 
>>>>>>>> In most cases, the display driver should be able to detect whether a
>>>>>>>> display is connected.. this is what I've done on dragonboard410c, so
>>>>>>>> if no display plugged in, 'efiout=vidconsole' fails and you fall back
>>>>>>>> to serial, else you get efi on screen like you would on a "real"
>>>>>>>> computer.  For boards that have a display driver that isn't able to do
>>>>>>>> the basic check of whether a cable is plugged in, just don't set
>>>>>>>> "efiout" (or fix the display driver) ;-)
>>>>>>> 
>>>>>>> 
>>>>>>> Are you sure that's what happens on a "real" computer? As far as I
>>>>>>> remember from all ARM servers running edk2 based firmware that I've
>>>>>>> touched so far, the default is always to display on serial *and*
>>>>>>> graphical output at the same time.
>>>>>> 
>>>>>> 
>>>>>> Well, I suppose some of the arm64 server vendors have done a better
>>>>>> job than others on firmware.. you'd hope they would probe EDID, and
>>>>>> report correct console dimensions based on display resolution, etc.
>>>>>> 
>>>>>> Doing both serial and display works for simple stuff, but it goes
>>>>>> badly once the efi payload starts trying to change the cursor position
>>>>>> and write to specific parts of the screen (which both Shell.efi and
>>>>>> grub try to do).
>>>>>> 
>>>>>> BR,
>>>>>> -R
>>>>>> 
>>>>> Hello Rob,
>>>>> 
>>>>> I do not know which program you use for connecting to your serial
>>>>> console. I
>>>>> use minicom which is a Debian/Ubuntu package. I had no problem using
>>>>> grub,
>>>>> vim, nano or any other console program.
>>>>> 
>>>>> Minicom just provides a VT100 emulation and that is close enough to what
>>>>> Linux expects.
>>>> 
>>>> fwiw, I generally use kermit so my terminal emulator is whatever
>>>> "xterm" type app I'm using.  (Currently a big fan of Tilix).. but that
>>>> isn't so much the issue..
>>>> 
>>>>> So I would not see what should be so special about Shell.efi.
>>>> 
>>>> I'm not explaining the problem well, but you can see basically the
>>>> same issue if you resize your terminal emulator to something smaller
>>>> than what grub/shell/etc think you are using.
>>>> 
>>>> I guess if they just fall back to assuming 80x25 like agraf mentioned,
>>>> that would kind of work.  It just means shell or grub will only use
>>>> the tiny upper-left corner of your monitor.
>>>> 
>>>>> My U-Boot system all have video but I never have a monitor connected.
>>>>> 
>>>>> So being able to use serial even if video is available is a necessity.
>>>> 
>>>> If the video driver doesn't detect that it is unconnected, someone
>>>> should really fix that, otherwise you'll have problems booting an
>>>> image where grub tries to use gfxterm if GOP is present (but we are
>>>> really getting off topic here)
>>>> 
>>>> Either way, you still have the option of not setting efiout (or
>>>> setting it to serial)
>>>> 
>>>> But for end users (at least of boards that I care about), if they plug
>>>> in a monitor they should get grub on screen.  Not everyone has a
>>>> serial cable attached.
>>> 
>>> 
>>> I fully agree there. The same applies the other way around too. Even if they
>>> have a monitor attached, they should get grub on serial if serial is a valid
>>> output :). Just attaching a monitor doesn't mean you only use that monitor
>>> to control the system.
>> 
>> We could, I suppose, try probing the serial console's size, as an
>> approximation of hotplug detect for serial.  If we timeout without
>> getting a response, assume no serial console.
> 
> By spitting out random control characters and hope they match the
> terminal emulation on the other end?  Sounds like a bad idea to me to
> do that by default.

We actually do exactly that today already :).

> 
> Or would you only do it for EFI payload that uses more than just the
> EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL?  That might be acceptable.

Simply only to the first call that wants to know the screen size ;)

Alex

> 
> 

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 06/11] efi_loader: Decouple EFI input/output from stdin/stdout
  2017-10-12 22:38                   ` Heinrich Schuchardt
@ 2017-10-12 21:26                     ` Rob Clark
  2017-10-12 23:48                       ` Heinrich Schuchardt
  0 siblings, 1 reply; 75+ messages in thread
From: Rob Clark @ 2017-10-12 21:26 UTC (permalink / raw)
  To: u-boot

On Thu, Oct 12, 2017 at 6:38 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
> On 10/12/2017 04:28 PM, Rob Clark wrote:
>> On Thu, Oct 12, 2017 at 9:50 AM, Alexander Graf <agraf@suse.de> wrote:
>>> On 10/12/2017 03:40 PM, Rob Clark wrote:
>>>>
>>>> On Thu, Oct 12, 2017 at 9:05 AM, Heinrich Schuchardt <xypron.glpk@gmx.de>
>>>> wrote:
>>>>>
>>>>>
>>>>> On 10/12/2017 02:48 PM, Rob Clark wrote:
>>>>>>
>>>>>> On Thu, Oct 12, 2017 at 3:15 AM, Alexander Graf <agraf@suse.de> wrote:
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> On 12.10.17 00:07, Rob Clark wrote:
>>>>>>>>
>>>>>>>> On Wed, Oct 11, 2017 at 10:45 AM, Alexander Graf <agraf@suse.de>
>>>>>>>> wrote:
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On 10.10.17 14:23, Rob Clark wrote:
>>>>>>>>>>
>>>>>>>>>> In some cases, it is quite useful to have (for example) EFI on
>>>>>>>>>> screen
>>>>>>>>>> but u-boot on serial port.
>>>>>>>>>>
>>>>>>>>>> This adds two new optional environment variables, "efiin" and
>>>>>>>>>> "efiout",
>>>>>>>>>> which can be used to set EFI console input/output independently of
>>>>>>>>>> u-boot's input/output.  If unset, EFI console will default to stdin/
>>>>>>>>>> stdout as before.
>>>>>>>>>>
>>>>>>>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> With this patch, we lose the ability to have the efi in/out go to
>>>>>>>>> both
>>>>>>>>> graphical and serial console, right? This is critical functionality
>>>>>>>>> to
>>>>>>>>> have, since we don't necessarily know which output/input a user ends
>>>>>>>>> up
>>>>>>>>> using.
>>>>>>>>
>>>>>>>>
>>>>>>>> I'll think about how to support iomux.. but some things like console
>>>>>>>> size are just not going to work properly there.  And as long as we fix
>>>>>>>
>>>>>>>
>>>>>>> Yeah, those probably would need to get special cased.
>>>>>>>
>>>>>>>> the stdout shenanigans (ie. what I was seeing w/ qemu-x86) you can
>>>>>>>> simply not set efiout var and have things working as before, so you
>>>>>>>> don't loose any existing functionality (although, like I said, if the
>>>>>>>> two different consoles have different sizes things aren't going to
>>>>>>>> work properly for anything other than simple cases).
>>>>>>>>
>>>>>>>> In most cases, the display driver should be able to detect whether a
>>>>>>>> display is connected.. this is what I've done on dragonboard410c, so
>>>>>>>> if no display plugged in, 'efiout=vidconsole' fails and you fall back
>>>>>>>> to serial, else you get efi on screen like you would on a "real"
>>>>>>>> computer.  For boards that have a display driver that isn't able to do
>>>>>>>> the basic check of whether a cable is plugged in, just don't set
>>>>>>>> "efiout" (or fix the display driver) ;-)
>>>>>>>
>>>>>>>
>>>>>>> Are you sure that's what happens on a "real" computer? As far as I
>>>>>>> remember from all ARM servers running edk2 based firmware that I've
>>>>>>> touched so far, the default is always to display on serial *and*
>>>>>>> graphical output at the same time.
>>>>>>
>>>>>>
>>>>>> Well, I suppose some of the arm64 server vendors have done a better
>>>>>> job than others on firmware.. you'd hope they would probe EDID, and
>>>>>> report correct console dimensions based on display resolution, etc.
>>>>>>
>>>>>> Doing both serial and display works for simple stuff, but it goes
>>>>>> badly once the efi payload starts trying to change the cursor position
>>>>>> and write to specific parts of the screen (which both Shell.efi and
>>>>>> grub try to do).
>>>>>>
>>>>>> BR,
>>>>>> -R
>>>>>>
>>>>> Hello Rob,
>>>>>
>>>>> I do not know which program you use for connecting to your serial
>>>>> console. I
>>>>> use minicom which is a Debian/Ubuntu package. I had no problem using
>>>>> grub,
>>>>> vim, nano or any other console program.
>>>>>
>>>>> Minicom just provides a VT100 emulation and that is close enough to what
>>>>> Linux expects.
>>>>
>>>> fwiw, I generally use kermit so my terminal emulator is whatever
>>>> "xterm" type app I'm using.  (Currently a big fan of Tilix).. but that
>>>> isn't so much the issue..
>>>>
>>>>> So I would not see what should be so special about Shell.efi.
>>>>
>>>> I'm not explaining the problem well, but you can see basically the
>>>> same issue if you resize your terminal emulator to something smaller
>>>> than what grub/shell/etc think you are using.
>>>>
>>>> I guess if they just fall back to assuming 80x25 like agraf mentioned,
>>>> that would kind of work.  It just means shell or grub will only use
>>>> the tiny upper-left corner of your monitor.
>>>>
>>>>> My U-Boot system all have video but I never have a monitor connected.
>>>>>
>>>>> So being able to use serial even if video is available is a necessity.
>>>>
>>>> If the video driver doesn't detect that it is unconnected, someone
>>>> should really fix that, otherwise you'll have problems booting an
>>>> image where grub tries to use gfxterm if GOP is present (but we are
>>>> really getting off topic here)
>>>>
>>>> Either way, you still have the option of not setting efiout (or
>>>> setting it to serial)
>>>>
>>>> But for end users (at least of boards that I care about), if they plug
>>>> in a monitor they should get grub on screen.  Not everyone has a
>>>> serial cable attached.
>>>
>>>
>>> I fully agree there. The same applies the other way around too. Even if they
>>> have a monitor attached, they should get grub on serial if serial is a valid
>>> output :). Just attaching a monitor doesn't mean you only use that monitor
>>> to control the system.
>>
>> We could, I suppose, try probing the serial console's size, as an
>> approximation of hotplug detect for serial.  If we timeout without
>> getting a response, assume no serial console.
>
> Your assumption is illegal:
>
> If no terminal emulation is used don't expect any reply unless the user
> (or the control program at the other end of the line) is typing.
> Typically there is not even flow control on the serial connection.
>
> Only if a terminal emulation is active you may be able to determine the
> console size by putting the cursor into the lower right corner. Then
> send ESC[6n. An ANSI terminal will respond by ESC[n;mR, where n is the
> row and m is the column.

I think I'm ok with the requirement of a terminal emulator, at least
for sane default behavior.. things aren't really going to work without
a terminal emulator anyways.  You aren't going to be able to query the
terminal size, and you are going to see a whole lot of jibberish when
grub/shell/etc attempt to set the cursor position and set attributes.

We can make something like efiout=serial just force serial, term
emulator or not.  A sane default behavior doesn't have to be exclusive
to catering to someone's crazy oddball setup.  People with oddball
setups can set an env var.

>
>>
>> That would also let us pick the minimum of each dimension to report to
>> the payload, which is less horrible than just having an 80x25 grub
>> menu on your 4k screen.  And if no serial attached, then we can use
>> the full screen.
>>
>
> A bit off-topic:
> My horror is 4k resolution terminal mode with letters so small that you
> cannot read them without magnifying glasses. For grub 80x25 blown up to
> screen size is fully sufficient. I never had more than 5 lines to choose
> from.

yeah, but scaling up isn't going to be what happens ;-)

and 80x25 is kinda sub-optimal when you need to edit a kernel cmdline

BR,
-R

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 06/11] efi_loader: Decouple EFI input/output from stdin/stdout
  2017-10-12 14:28                 ` Rob Clark
  2017-10-12 14:31                   ` Alexander Graf
  2017-10-12 16:00                   ` Mark Kettenis
@ 2017-10-12 22:38                   ` Heinrich Schuchardt
  2017-10-12 21:26                     ` Rob Clark
  2 siblings, 1 reply; 75+ messages in thread
From: Heinrich Schuchardt @ 2017-10-12 22:38 UTC (permalink / raw)
  To: u-boot

On 10/12/2017 04:28 PM, Rob Clark wrote:
> On Thu, Oct 12, 2017 at 9:50 AM, Alexander Graf <agraf@suse.de> wrote:
>> On 10/12/2017 03:40 PM, Rob Clark wrote:
>>>
>>> On Thu, Oct 12, 2017 at 9:05 AM, Heinrich Schuchardt <xypron.glpk@gmx.de>
>>> wrote:
>>>>
>>>>
>>>> On 10/12/2017 02:48 PM, Rob Clark wrote:
>>>>>
>>>>> On Thu, Oct 12, 2017 at 3:15 AM, Alexander Graf <agraf@suse.de> wrote:
>>>>>>
>>>>>>
>>>>>>
>>>>>> On 12.10.17 00:07, Rob Clark wrote:
>>>>>>>
>>>>>>> On Wed, Oct 11, 2017 at 10:45 AM, Alexander Graf <agraf@suse.de>
>>>>>>> wrote:
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> On 10.10.17 14:23, Rob Clark wrote:
>>>>>>>>>
>>>>>>>>> In some cases, it is quite useful to have (for example) EFI on
>>>>>>>>> screen
>>>>>>>>> but u-boot on serial port.
>>>>>>>>>
>>>>>>>>> This adds two new optional environment variables, "efiin" and
>>>>>>>>> "efiout",
>>>>>>>>> which can be used to set EFI console input/output independently of
>>>>>>>>> u-boot's input/output.  If unset, EFI console will default to stdin/
>>>>>>>>> stdout as before.
>>>>>>>>>
>>>>>>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>>>>>>>
>>>>>>>>
>>>>>>>> With this patch, we lose the ability to have the efi in/out go to
>>>>>>>> both
>>>>>>>> graphical and serial console, right? This is critical functionality
>>>>>>>> to
>>>>>>>> have, since we don't necessarily know which output/input a user ends
>>>>>>>> up
>>>>>>>> using.
>>>>>>>
>>>>>>>
>>>>>>> I'll think about how to support iomux.. but some things like console
>>>>>>> size are just not going to work properly there.  And as long as we fix
>>>>>>
>>>>>>
>>>>>> Yeah, those probably would need to get special cased.
>>>>>>
>>>>>>> the stdout shenanigans (ie. what I was seeing w/ qemu-x86) you can
>>>>>>> simply not set efiout var and have things working as before, so you
>>>>>>> don't loose any existing functionality (although, like I said, if the
>>>>>>> two different consoles have different sizes things aren't going to
>>>>>>> work properly for anything other than simple cases).
>>>>>>>
>>>>>>> In most cases, the display driver should be able to detect whether a
>>>>>>> display is connected.. this is what I've done on dragonboard410c, so
>>>>>>> if no display plugged in, 'efiout=vidconsole' fails and you fall back
>>>>>>> to serial, else you get efi on screen like you would on a "real"
>>>>>>> computer.  For boards that have a display driver that isn't able to do
>>>>>>> the basic check of whether a cable is plugged in, just don't set
>>>>>>> "efiout" (or fix the display driver) ;-)
>>>>>>
>>>>>>
>>>>>> Are you sure that's what happens on a "real" computer? As far as I
>>>>>> remember from all ARM servers running edk2 based firmware that I've
>>>>>> touched so far, the default is always to display on serial *and*
>>>>>> graphical output at the same time.
>>>>>
>>>>>
>>>>> Well, I suppose some of the arm64 server vendors have done a better
>>>>> job than others on firmware.. you'd hope they would probe EDID, and
>>>>> report correct console dimensions based on display resolution, etc.
>>>>>
>>>>> Doing both serial and display works for simple stuff, but it goes
>>>>> badly once the efi payload starts trying to change the cursor position
>>>>> and write to specific parts of the screen (which both Shell.efi and
>>>>> grub try to do).
>>>>>
>>>>> BR,
>>>>> -R
>>>>>
>>>> Hello Rob,
>>>>
>>>> I do not know which program you use for connecting to your serial
>>>> console. I
>>>> use minicom which is a Debian/Ubuntu package. I had no problem using
>>>> grub,
>>>> vim, nano or any other console program.
>>>>
>>>> Minicom just provides a VT100 emulation and that is close enough to what
>>>> Linux expects.
>>>
>>> fwiw, I generally use kermit so my terminal emulator is whatever
>>> "xterm" type app I'm using.  (Currently a big fan of Tilix).. but that
>>> isn't so much the issue..
>>>
>>>> So I would not see what should be so special about Shell.efi.
>>>
>>> I'm not explaining the problem well, but you can see basically the
>>> same issue if you resize your terminal emulator to something smaller
>>> than what grub/shell/etc think you are using.
>>>
>>> I guess if they just fall back to assuming 80x25 like agraf mentioned,
>>> that would kind of work.  It just means shell or grub will only use
>>> the tiny upper-left corner of your monitor.
>>>
>>>> My U-Boot system all have video but I never have a monitor connected.
>>>>
>>>> So being able to use serial even if video is available is a necessity.
>>>
>>> If the video driver doesn't detect that it is unconnected, someone
>>> should really fix that, otherwise you'll have problems booting an
>>> image where grub tries to use gfxterm if GOP is present (but we are
>>> really getting off topic here)
>>>
>>> Either way, you still have the option of not setting efiout (or
>>> setting it to serial)
>>>
>>> But for end users (at least of boards that I care about), if they plug
>>> in a monitor they should get grub on screen.  Not everyone has a
>>> serial cable attached.
>>
>>
>> I fully agree there. The same applies the other way around too. Even if they
>> have a monitor attached, they should get grub on serial if serial is a valid
>> output :). Just attaching a monitor doesn't mean you only use that monitor
>> to control the system.
> 
> We could, I suppose, try probing the serial console's size, as an
> approximation of hotplug detect for serial.  If we timeout without
> getting a response, assume no serial console.

Your assumption is illegal:

If no terminal emulation is used don't expect any reply unless the user
(or the control program at the other end of the line) is typing.
Typically there is not even flow control on the serial connection.

Only if a terminal emulation is active you may be able to determine the
console size by putting the cursor into the lower right corner. Then
send ESC[6n. An ANSI terminal will respond by ESC[n;mR, where n is the
row and m is the column.

> 
> That would also let us pick the minimum of each dimension to report to
> the payload, which is less horrible than just having an 80x25 grub
> menu on your 4k screen.  And if no serial attached, then we can use
> the full screen.
> 

A bit off-topic:
My horror is 4k resolution terminal mode with letters so small that you
cannot read them without magnifying glasses. For grub 80x25 blown up to
screen size is fully sufficient. I never had more than 5 lines to choose
from.

Regards

Heinrich

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 06/11] efi_loader: Decouple EFI input/output from stdin/stdout
  2017-10-12 21:26                     ` Rob Clark
@ 2017-10-12 23:48                       ` Heinrich Schuchardt
  2017-10-13  0:41                         ` Rob Clark
  0 siblings, 1 reply; 75+ messages in thread
From: Heinrich Schuchardt @ 2017-10-12 23:48 UTC (permalink / raw)
  To: u-boot

On 10/12/2017 11:26 PM, Rob Clark wrote:
> On Thu, Oct 12, 2017 at 6:38 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>> On 10/12/2017 04:28 PM, Rob Clark wrote:
>>> On Thu, Oct 12, 2017 at 9:50 AM, Alexander Graf <agraf@suse.de> wrote:
>>>> On 10/12/2017 03:40 PM, Rob Clark wrote:
>>>>>
>>>>> On Thu, Oct 12, 2017 at 9:05 AM, Heinrich Schuchardt <xypron.glpk@gmx.de>
>>>>> wrote:
>>>>>>
>>>>>>
>>>>>> On 10/12/2017 02:48 PM, Rob Clark wrote:
>>>>>>>
>>>>>>> On Thu, Oct 12, 2017 at 3:15 AM, Alexander Graf <agraf@suse.de> wrote:
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> On 12.10.17 00:07, Rob Clark wrote:
>>>>>>>>>
>>>>>>>>> On Wed, Oct 11, 2017 at 10:45 AM, Alexander Graf <agraf@suse.de>
>>>>>>>>> wrote:
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> On 10.10.17 14:23, Rob Clark wrote:
>>>>>>>>>>>
>>>>>>>>>>> In some cases, it is quite useful to have (for example) EFI on
>>>>>>>>>>> screen
>>>>>>>>>>> but u-boot on serial port.
>>>>>>>>>>>
>>>>>>>>>>> This adds two new optional environment variables, "efiin" and
>>>>>>>>>>> "efiout",
>>>>>>>>>>> which can be used to set EFI console input/output independently of
>>>>>>>>>>> u-boot's input/output.  If unset, EFI console will default to stdin/
>>>>>>>>>>> stdout as before.
>>>>>>>>>>>
>>>>>>>>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> With this patch, we lose the ability to have the efi in/out go to
>>>>>>>>>> both
>>>>>>>>>> graphical and serial console, right? This is critical functionality
>>>>>>>>>> to
>>>>>>>>>> have, since we don't necessarily know which output/input a user ends
>>>>>>>>>> up
>>>>>>>>>> using.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> I'll think about how to support iomux.. but some things like console
>>>>>>>>> size are just not going to work properly there.  And as long as we fix
>>>>>>>>
>>>>>>>>
>>>>>>>> Yeah, those probably would need to get special cased.
>>>>>>>>
>>>>>>>>> the stdout shenanigans (ie. what I was seeing w/ qemu-x86) you can
>>>>>>>>> simply not set efiout var and have things working as before, so you
>>>>>>>>> don't loose any existing functionality (although, like I said, if the
>>>>>>>>> two different consoles have different sizes things aren't going to
>>>>>>>>> work properly for anything other than simple cases).
>>>>>>>>>
>>>>>>>>> In most cases, the display driver should be able to detect whether a
>>>>>>>>> display is connected.. this is what I've done on dragonboard410c, so
>>>>>>>>> if no display plugged in, 'efiout=vidconsole' fails and you fall back
>>>>>>>>> to serial, else you get efi on screen like you would on a "real"
>>>>>>>>> computer.  For boards that have a display driver that isn't able to do
>>>>>>>>> the basic check of whether a cable is plugged in, just don't set
>>>>>>>>> "efiout" (or fix the display driver) ;-)
>>>>>>>>
>>>>>>>>
>>>>>>>> Are you sure that's what happens on a "real" computer? As far as I
>>>>>>>> remember from all ARM servers running edk2 based firmware that I've
>>>>>>>> touched so far, the default is always to display on serial *and*
>>>>>>>> graphical output at the same time.
>>>>>>>
>>>>>>>
>>>>>>> Well, I suppose some of the arm64 server vendors have done a better
>>>>>>> job than others on firmware.. you'd hope they would probe EDID, and
>>>>>>> report correct console dimensions based on display resolution, etc.
>>>>>>>
>>>>>>> Doing both serial and display works for simple stuff, but it goes
>>>>>>> badly once the efi payload starts trying to change the cursor position
>>>>>>> and write to specific parts of the screen (which both Shell.efi and
>>>>>>> grub try to do).
>>>>>>>
>>>>>>> BR,
>>>>>>> -R
>>>>>>>
>>>>>> Hello Rob,
>>>>>>
>>>>>> I do not know which program you use for connecting to your serial
>>>>>> console. I
>>>>>> use minicom which is a Debian/Ubuntu package. I had no problem using
>>>>>> grub,
>>>>>> vim, nano or any other console program.
>>>>>>
>>>>>> Minicom just provides a VT100 emulation and that is close enough to what
>>>>>> Linux expects.
>>>>>
>>>>> fwiw, I generally use kermit so my terminal emulator is whatever
>>>>> "xterm" type app I'm using.  (Currently a big fan of Tilix).. but that
>>>>> isn't so much the issue..
>>>>>
>>>>>> So I would not see what should be so special about Shell.efi.
>>>>>
>>>>> I'm not explaining the problem well, but you can see basically the
>>>>> same issue if you resize your terminal emulator to something smaller
>>>>> than what grub/shell/etc think you are using.
>>>>>
>>>>> I guess if they just fall back to assuming 80x25 like agraf mentioned,
>>>>> that would kind of work.  It just means shell or grub will only use
>>>>> the tiny upper-left corner of your monitor.
>>>>>
>>>>>> My U-Boot system all have video but I never have a monitor connected.
>>>>>>
>>>>>> So being able to use serial even if video is available is a necessity.
>>>>>
>>>>> If the video driver doesn't detect that it is unconnected, someone
>>>>> should really fix that, otherwise you'll have problems booting an
>>>>> image where grub tries to use gfxterm if GOP is present (but we are
>>>>> really getting off topic here)
>>>>>
>>>>> Either way, you still have the option of not setting efiout (or
>>>>> setting it to serial)
>>>>>
>>>>> But for end users (at least of boards that I care about), if they plug
>>>>> in a monitor they should get grub on screen.  Not everyone has a
>>>>> serial cable attached.
>>>>
>>>>
>>>> I fully agree there. The same applies the other way around too. Even if they
>>>> have a monitor attached, they should get grub on serial if serial is a valid
>>>> output :). Just attaching a monitor doesn't mean you only use that monitor
>>>> to control the system.
>>>
>>> We could, I suppose, try probing the serial console's size, as an
>>> approximation of hotplug detect for serial.  If we timeout without
>>> getting a response, assume no serial console.
>>
>> Your assumption is illegal:
>>
>> If no terminal emulation is used don't expect any reply unless the user
>> (or the control program at the other end of the line) is typing.
>> Typically there is not even flow control on the serial connection.
>>
>> Only if a terminal emulation is active you may be able to determine the
>> console size by putting the cursor into the lower right corner. Then
>> send ESC[6n. An ANSI terminal will respond by ESC[n;mR, where n is the
>> row and m is the column.
> 
> I think I'm ok with the requirement of a terminal emulator, at least
> for sane default behavior.. things aren't really going to work without
> a terminal emulator anyways.  You aren't going to be able to query the
> terminal size, and you are going to see a whole lot of jibberish when
> grub/shell/etc attempt to set the cursor position and set attributes.
> 
> We can make something like efiout=serial just force serial, term
> emulator or not.  A sane default behavior doesn't have to be exclusive
> to catering to someone's crazy oddball setup.  People with oddball
> setups can set an env var.
> 

I thought you were close to finishing off this patch series.

Is this patch essential?

Or could you simply resubmit the series without this patch and sort the
questions about this patch out later?

Best regards

Heinrich

>>
>>>
>>> That would also let us pick the minimum of each dimension to report to
>>> the payload, which is less horrible than just having an 80x25 grub
>>> menu on your 4k screen.  And if no serial attached, then we can use
>>> the full screen.
>>>
>>
>> A bit off-topic:
>> My horror is 4k resolution terminal mode with letters so small that you
>> cannot read them without magnifying glasses. For grub 80x25 blown up to
>> screen size is fully sufficient. I never had more than 5 lines to choose
>> from.
> 
> yeah, but scaling up isn't going to be what happens ;-)
> 
> and 80x25 is kinda sub-optimal when you need to edit a kernel cmdline
> 
> BR,
> -R
> 

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 06/11] efi_loader: Decouple EFI input/output from stdin/stdout
  2017-10-12 23:48                       ` Heinrich Schuchardt
@ 2017-10-13  0:41                         ` Rob Clark
  0 siblings, 0 replies; 75+ messages in thread
From: Rob Clark @ 2017-10-13  0:41 UTC (permalink / raw)
  To: u-boot

On Thu, Oct 12, 2017 at 7:48 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
> On 10/12/2017 11:26 PM, Rob Clark wrote:
>> On Thu, Oct 12, 2017 at 6:38 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>>> On 10/12/2017 04:28 PM, Rob Clark wrote:
>>>> On Thu, Oct 12, 2017 at 9:50 AM, Alexander Graf <agraf@suse.de> wrote:
>>>>> On 10/12/2017 03:40 PM, Rob Clark wrote:
>>>>>>
>>>>>> On Thu, Oct 12, 2017 at 9:05 AM, Heinrich Schuchardt <xypron.glpk@gmx.de>
>>>>>> wrote:
>>>>>>>
>>>>>>>
>>>>>>> On 10/12/2017 02:48 PM, Rob Clark wrote:
>>>>>>>>
>>>>>>>> On Thu, Oct 12, 2017 at 3:15 AM, Alexander Graf <agraf@suse.de> wrote:
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On 12.10.17 00:07, Rob Clark wrote:
>>>>>>>>>>
>>>>>>>>>> On Wed, Oct 11, 2017 at 10:45 AM, Alexander Graf <agraf@suse.de>
>>>>>>>>>> wrote:
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> On 10.10.17 14:23, Rob Clark wrote:
>>>>>>>>>>>>
>>>>>>>>>>>> In some cases, it is quite useful to have (for example) EFI on
>>>>>>>>>>>> screen
>>>>>>>>>>>> but u-boot on serial port.
>>>>>>>>>>>>
>>>>>>>>>>>> This adds two new optional environment variables, "efiin" and
>>>>>>>>>>>> "efiout",
>>>>>>>>>>>> which can be used to set EFI console input/output independently of
>>>>>>>>>>>> u-boot's input/output.  If unset, EFI console will default to stdin/
>>>>>>>>>>>> stdout as before.
>>>>>>>>>>>>
>>>>>>>>>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> With this patch, we lose the ability to have the efi in/out go to
>>>>>>>>>>> both
>>>>>>>>>>> graphical and serial console, right? This is critical functionality
>>>>>>>>>>> to
>>>>>>>>>>> have, since we don't necessarily know which output/input a user ends
>>>>>>>>>>> up
>>>>>>>>>>> using.
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> I'll think about how to support iomux.. but some things like console
>>>>>>>>>> size are just not going to work properly there.  And as long as we fix
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Yeah, those probably would need to get special cased.
>>>>>>>>>
>>>>>>>>>> the stdout shenanigans (ie. what I was seeing w/ qemu-x86) you can
>>>>>>>>>> simply not set efiout var and have things working as before, so you
>>>>>>>>>> don't loose any existing functionality (although, like I said, if the
>>>>>>>>>> two different consoles have different sizes things aren't going to
>>>>>>>>>> work properly for anything other than simple cases).
>>>>>>>>>>
>>>>>>>>>> In most cases, the display driver should be able to detect whether a
>>>>>>>>>> display is connected.. this is what I've done on dragonboard410c, so
>>>>>>>>>> if no display plugged in, 'efiout=vidconsole' fails and you fall back
>>>>>>>>>> to serial, else you get efi on screen like you would on a "real"
>>>>>>>>>> computer.  For boards that have a display driver that isn't able to do
>>>>>>>>>> the basic check of whether a cable is plugged in, just don't set
>>>>>>>>>> "efiout" (or fix the display driver) ;-)
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Are you sure that's what happens on a "real" computer? As far as I
>>>>>>>>> remember from all ARM servers running edk2 based firmware that I've
>>>>>>>>> touched so far, the default is always to display on serial *and*
>>>>>>>>> graphical output at the same time.
>>>>>>>>
>>>>>>>>
>>>>>>>> Well, I suppose some of the arm64 server vendors have done a better
>>>>>>>> job than others on firmware.. you'd hope they would probe EDID, and
>>>>>>>> report correct console dimensions based on display resolution, etc.
>>>>>>>>
>>>>>>>> Doing both serial and display works for simple stuff, but it goes
>>>>>>>> badly once the efi payload starts trying to change the cursor position
>>>>>>>> and write to specific parts of the screen (which both Shell.efi and
>>>>>>>> grub try to do).
>>>>>>>>
>>>>>>>> BR,
>>>>>>>> -R
>>>>>>>>
>>>>>>> Hello Rob,
>>>>>>>
>>>>>>> I do not know which program you use for connecting to your serial
>>>>>>> console. I
>>>>>>> use minicom which is a Debian/Ubuntu package. I had no problem using
>>>>>>> grub,
>>>>>>> vim, nano or any other console program.
>>>>>>>
>>>>>>> Minicom just provides a VT100 emulation and that is close enough to what
>>>>>>> Linux expects.
>>>>>>
>>>>>> fwiw, I generally use kermit so my terminal emulator is whatever
>>>>>> "xterm" type app I'm using.  (Currently a big fan of Tilix).. but that
>>>>>> isn't so much the issue..
>>>>>>
>>>>>>> So I would not see what should be so special about Shell.efi.
>>>>>>
>>>>>> I'm not explaining the problem well, but you can see basically the
>>>>>> same issue if you resize your terminal emulator to something smaller
>>>>>> than what grub/shell/etc think you are using.
>>>>>>
>>>>>> I guess if they just fall back to assuming 80x25 like agraf mentioned,
>>>>>> that would kind of work.  It just means shell or grub will only use
>>>>>> the tiny upper-left corner of your monitor.
>>>>>>
>>>>>>> My U-Boot system all have video but I never have a monitor connected.
>>>>>>>
>>>>>>> So being able to use serial even if video is available is a necessity.
>>>>>>
>>>>>> If the video driver doesn't detect that it is unconnected, someone
>>>>>> should really fix that, otherwise you'll have problems booting an
>>>>>> image where grub tries to use gfxterm if GOP is present (but we are
>>>>>> really getting off topic here)
>>>>>>
>>>>>> Either way, you still have the option of not setting efiout (or
>>>>>> setting it to serial)
>>>>>>
>>>>>> But for end users (at least of boards that I care about), if they plug
>>>>>> in a monitor they should get grub on screen.  Not everyone has a
>>>>>> serial cable attached.
>>>>>
>>>>>
>>>>> I fully agree there. The same applies the other way around too. Even if they
>>>>> have a monitor attached, they should get grub on serial if serial is a valid
>>>>> output :). Just attaching a monitor doesn't mean you only use that monitor
>>>>> to control the system.
>>>>
>>>> We could, I suppose, try probing the serial console's size, as an
>>>> approximation of hotplug detect for serial.  If we timeout without
>>>> getting a response, assume no serial console.
>>>
>>> Your assumption is illegal:
>>>
>>> If no terminal emulation is used don't expect any reply unless the user
>>> (or the control program at the other end of the line) is typing.
>>> Typically there is not even flow control on the serial connection.
>>>
>>> Only if a terminal emulation is active you may be able to determine the
>>> console size by putting the cursor into the lower right corner. Then
>>> send ESC[6n. An ANSI terminal will respond by ESC[n;mR, where n is the
>>> row and m is the column.
>>
>> I think I'm ok with the requirement of a terminal emulator, at least
>> for sane default behavior.. things aren't really going to work without
>> a terminal emulator anyways.  You aren't going to be able to query the
>> terminal size, and you are going to see a whole lot of jibberish when
>> grub/shell/etc attempt to set the cursor position and set attributes.
>>
>> We can make something like efiout=serial just force serial, term
>> emulator or not.  A sane default behavior doesn't have to be exclusive
>> to catering to someone's crazy oddball setup.  People with oddball
>> setups can set an env var.
>>
>
> I thought you were close to finishing off this patch series.
>
> Is this patch essential?
>
> Or could you simply resubmit the series without this patch and sort the
> questions about this patch out later?
>

I talked to agraf on IRC.. there were a couple patches that I
suggested to pull in asap for 2017.11.. the rest of the new
proto's/etc for Shell.efi, including this, aren't really immediately
useful for end users, so I suggested a separate efi-next-for-2018.1
(?) which we can start to pull these patches into, as well as other
things you are working on, to better coordinate our work on further
UEFI features independently of fixes destined for 2017.11.  At this
point, the new protocol stuff I mostly wanted to get into *some*
branch so we aren't stepping on each other's toes.

For this particular patch, IMHO the main prerequisite is to fix
u-boot's output layer so puts() == fputs(stdout), which I'm not quite
yet sure how to do.  Once that is done, this patch changes *no*
behaviour if you don't set efiout/efiin variables, so there should be
no controversy.  Although I do like the idea of expanding this to (at
least for default behavior, not preventing anyone to override it for
special cases) to try to detect if a serial console is attached.. that
would let us improve the default behavior to cater to both u-boot
dev's who like their serial ports and end users (who are the real
target audience) in a more sane way..

BR,
-R

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 07/11] efi_loader: fix events
  2017-10-10 12:23 ` [U-Boot] [PATCH 07/11] efi_loader: fix events Rob Clark
  2017-10-10 22:40   ` Heinrich Schuchardt
  2017-10-11 14:49   ` Alexander Graf
@ 2017-10-13  5:24   ` Heinrich Schuchardt
  2017-10-13 14:08     ` Rob Clark
  2 siblings, 1 reply; 75+ messages in thread
From: Heinrich Schuchardt @ 2017-10-13  5:24 UTC (permalink / raw)
  To: u-boot



On 10/10/2017 02:23 PM, Rob Clark wrote:
> An event can be created with type==0, Shell.efi does this for an event
> that is set when Ctrl-C is typed.  So our current approach of having a
> fixed set of timer slots, and determining which slots are unused by
> type==0 doesn't work so well.  But we don't have any particularly good
> reason to have a fixed table of events, so just dynamically allocate
> them and keep a list.
> 
> Also fixes an incorrect implementation of CheckEvent() which was (a)
> incorrectly returning an error if type==0, and (b) didn't handle the
> case of an unsignaled event with a notify callback.
> 
> With these fixes (plus implementation of SIMPLE_TEXT_INPUT_EX protocol),
> Ctrl-C works in Shell.efi.
> 
> Signed-off-by: Rob Clark <robdclark@gmail.com>
> ---
>   include/efi_loader.h          |   1 +
>   lib/efi_loader/efi_boottime.c | 217 +++++++++++++++++++++---------------------
>   2 files changed, 111 insertions(+), 107 deletions(-)
> 
> diff --git a/include/efi_loader.h b/include/efi_loader.h
> index e6e55d2cb4..2232caca44 100644
> --- a/include/efi_loader.h
> +++ b/include/efi_loader.h
> @@ -154,6 +154,7 @@ struct efi_event {
>   	enum efi_timer_delay trigger_type;
>   	bool is_queued;
>   	bool is_signaled;
> +	struct list_head link;
>   };
>   
>   
> diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
> index 39dcc72648..19fafe546c 100644
> --- a/lib/efi_loader/efi_boottime.c
> +++ b/lib/efi_loader/efi_boottime.c
> @@ -350,11 +350,26 @@ static efi_status_t efi_create_handle(void **handle)
>   	return r;
>   }
>   
> +static LIST_HEAD(efi_events);
> +
>   /*
> - * Our event capabilities are very limited. Only a small limited
> - * number of events is allowed to coexist.
> + * Check if a pointer is a valid event.
> + *
> + * It might be nice at some point to extend this to a more general
> + * mechanism to check if pointers passed from the EFI world are
> + * valid objects of a particular type.
>    */
> -static struct efi_event efi_events[16];
> +static bool efi_is_event(const void *obj)
> +{
> +	struct efi_event *evt;
> +
> +	list_for_each_entry(evt, &efi_events, link) {
> +		if (evt == obj)
> +			return true;
> +	}
> +
> +	return false;
> +}
>   
>   /*
>    * Create an event.
> @@ -377,7 +392,7 @@ efi_status_t efi_create_event(uint32_t type, UINTN notify_tpl,
>   					void *context),
>   			      void *notify_context, struct efi_event **event)
>   {
> -	int i;
> +	struct efi_event *evt;
>   
>   	if (event == NULL)
>   		return EFI_INVALID_PARAMETER;
> @@ -389,21 +404,24 @@ efi_status_t efi_create_event(uint32_t type, UINTN notify_tpl,
>   	    notify_function == NULL)
>   		return EFI_INVALID_PARAMETER;
>   
> -	for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
> -		if (efi_events[i].type)
> -			continue;
> -		efi_events[i].type = type;
> -		efi_events[i].notify_tpl = notify_tpl;
> -		efi_events[i].notify_function = notify_function;
> -		efi_events[i].notify_context = notify_context;
> -		/* Disable timers on bootup */
> -		efi_events[i].trigger_next = -1ULL;
> -		efi_events[i].is_queued = false;
> -		efi_events[i].is_signaled = false;
> -		*event = &efi_events[i];
> -		return EFI_SUCCESS;
> -	}
> -	return EFI_OUT_OF_RESOURCES;
> +	evt = calloc(1, sizeof(*evt));
> +	if (!evt)
> +		return EFI_OUT_OF_RESOURCES;
> +
> +	evt->type = type;
> +	evt->notify_tpl = notify_tpl;
> +	evt->notify_function = notify_function;
> +	evt->notify_context = notify_context;
> +	/* Disable timers on bootup */
> +	evt->trigger_next = -1ULL;
> +	evt->is_queued = false;
> +	evt->is_signaled = false;
> +
> +	list_add_tail(&evt->link, &efi_events);
> +
> +	*event = evt;
> +
> +	return EFI_SUCCESS;
>   }
>   
>   /*
> @@ -443,30 +461,31 @@ static efi_status_t EFIAPI efi_create_event_ext(
>    */
>   void efi_timer_check(void)
>   {
> -	int i;
> +	struct efi_event *evt;
>   	u64 now = timer_get_us();
>   
> -	for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
> -		if (!efi_events[i].type)
> -			continue;
> -		if (efi_events[i].is_queued)
> -			efi_signal_event(&efi_events[i]);
> -		if (!(efi_events[i].type & EVT_TIMER) ||
> -		    now < efi_events[i].trigger_next)
> +	/*
> +	 * TODO perhaps optimize a bit and track the time of next
> +	 * timer to expire?
> +	 */
> +	list_for_each_entry(evt, &efi_events, link) {
> +		if (evt->is_queued)
> +			efi_signal_event(evt);
> +		if (!(evt->type & EVT_TIMER) ||
> +		    now < evt->trigger_next)
>   			continue;
> -		switch (efi_events[i].trigger_type) {
> +		switch (evt->trigger_type) {
>   		case EFI_TIMER_RELATIVE:
> -			efi_events[i].trigger_type = EFI_TIMER_STOP;
> +			evt->trigger_type = EFI_TIMER_STOP;
>   			break;
>   		case EFI_TIMER_PERIODIC:
> -			efi_events[i].trigger_next +=
> -				efi_events[i].trigger_time;
> +			evt->trigger_next += evt->trigger_time;
>   			break;
>   		default:
>   			continue;
>   		}
> -		efi_events[i].is_signaled = true;
> -		efi_signal_event(&efi_events[i]);
> +		evt->is_signaled = true;
> +		efi_signal_event(evt);
>   	}
>   	WATCHDOG_RESET();
>   }
> @@ -485,7 +504,8 @@ void efi_timer_check(void)
>   efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type,
>   			   uint64_t trigger_time)
>   {
> -	int i;
> +	if (!efi_is_event(event))
> +		return EFI_INVALID_PARAMETER;
>   
>   	/*
>   	 * The parameter defines a multiple of 100ns.
> @@ -493,30 +513,25 @@ efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type,
>   	 */
>   	do_div(trigger_time, 10);
>   
> -	for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
> -		if (event != &efi_events[i])
> -			continue;
> +	if (!(event->type & EVT_TIMER))
> +		return EFI_INVALID_PARAMETER;
>   
> -		if (!(event->type & EVT_TIMER))
> -			break;
> -		switch (type) {
> -		case EFI_TIMER_STOP:
> -			event->trigger_next = -1ULL;
> -			break;
> -		case EFI_TIMER_PERIODIC:
> -		case EFI_TIMER_RELATIVE:
> -			event->trigger_next =
> -				timer_get_us() + trigger_time;
> -			break;
> -		default:
> -			return EFI_INVALID_PARAMETER;
> -		}
> -		event->trigger_type = type;
> -		event->trigger_time = trigger_time;
> -		event->is_signaled = false;
> -		return EFI_SUCCESS;
> +	switch (type) {
> +	case EFI_TIMER_STOP:
> +		event->trigger_next = -1ULL;
> +		break;
> +	case EFI_TIMER_PERIODIC:
> +	case EFI_TIMER_RELATIVE:
> +		event->trigger_next = timer_get_us() + trigger_time;
> +		break;
> +	default:
> +		return EFI_INVALID_PARAMETER;
>   	}
> -	return EFI_INVALID_PARAMETER;
> +	event->trigger_type = type;
> +	event->trigger_time = trigger_time;
> +	event->is_signaled = false;
> +
> +	return EFI_SUCCESS;
>   }
>   
>   /*
> @@ -555,7 +570,7 @@ static efi_status_t EFIAPI efi_wait_for_event(unsigned long num_events,
>   					      struct efi_event **event,
>   					      size_t *index)
>   {
> -	int i, j;
> +	int i;
>   
>   	EFI_ENTRY("%ld, %p, %p", num_events, event, index);
>   
> @@ -566,12 +581,8 @@ static efi_status_t EFIAPI efi_wait_for_event(unsigned long num_events,
>   	if (efi_tpl != TPL_APPLICATION)
>   		return EFI_EXIT(EFI_UNSUPPORTED);
>   	for (i = 0; i < num_events; ++i) {
> -		for (j = 0; j < ARRAY_SIZE(efi_events); ++j) {
> -			if (event[i] == &efi_events[j])
> -				goto known_event;
> -		}
> -		return EFI_EXIT(EFI_INVALID_PARAMETER);
> -known_event:
> +		if (!efi_is_event(event[i]))
> +			return EFI_EXIT(EFI_INVALID_PARAMETER);
>   		if (!event[i]->type || event[i]->type & EVT_NOTIFY_SIGNAL)
>   			return EFI_EXIT(EFI_INVALID_PARAMETER);
>   		if (!event[i]->is_signaled)
> @@ -614,19 +625,12 @@ out:
>    */
>   static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event)
>   {
> -	int i;
> -
>   	EFI_ENTRY("%p", event);
> -	for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
> -		if (event != &efi_events[i])
> -			continue;
> -		if (event->is_signaled)
> -			break;
> -		event->is_signaled = true;
> -		if (event->type & EVT_NOTIFY_SIGNAL)
> -			efi_signal_event(event);
> -		break;
> -	}
> +	if (!efi_is_event(event))
> +		return EFI_EXIT(EFI_INVALID_PARAMETER);
> +	event->is_signaled = true;
> +	if (event->type & EVT_NOTIFY_SIGNAL)
> +		efi_signal_event(event);
>   	return EFI_EXIT(EFI_SUCCESS);
>   }
>   
> @@ -642,19 +646,10 @@ static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event)
>    */
>   static efi_status_t EFIAPI efi_close_event(struct efi_event *event)
>   {
> -	int i;
> -
>   	EFI_ENTRY("%p", event);
> -	for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
> -		if (event == &efi_events[i]) {
> -			event->type = 0;
> -			event->trigger_next = -1ULL;
> -			event->is_queued = false;
> -			event->is_signaled = false;
> -			return EFI_EXIT(EFI_SUCCESS);
> -		}
> -	}
> -	return EFI_EXIT(EFI_INVALID_PARAMETER);
> +	list_del(&event->link);
> +	free(event);
> +	return EFI_EXIT(EFI_SUCCESS);
>   }
>   
>   /*
> @@ -664,29 +659,37 @@ static efi_status_t EFIAPI efi_close_event(struct efi_event *event)
>    * See the Unified Extensible Firmware Interface (UEFI) specification
>    * for details.
>    *
> - * If an event is not signaled yet the notification function is queued.
> + * - If Event is in the signaled state, it is cleared and EFI_SUCCESS
> + *   is returned.
> + *
> + * - If Event is not in the signaled state and has no notification
> + *   function, EFI_NOT_READY is returned.
> + *
> + * - If Event is not in the signaled state but does have a notification
> + *   function, the notification function is queued at the event’s
> + *   notification task priority level. If the execution of the
> + *   notification function causes Event to be signaled, then the signaled
> + *   state is cleared and EFI_SUCCESS is returned; if the Event is not
> + *   signaled, then EFI_NOT_READY is returned.
>    *
>    * @event	event to check
>    * @return	status code
>    */
> -static efi_status_t EFIAPI efi_check_event(struct efi_event *event)
> +/*
> + */
> +static efi_status_t EFIAPI efi_check_event(struct efi_event *evt)
>   {
> -	int i;
> -
> -	EFI_ENTRY("%p", event);
> +	EFI_ENTRY("%p", evt);
>   	efi_timer_check();
> -	for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
> -		if (event != &efi_events[i])
> -			continue;
> -		if (!event->type || event->type & EVT_NOTIFY_SIGNAL)
> -			break;
> -		if (!event->is_signaled)
> -			efi_signal_event(event);
> -		if (event->is_signaled)
> -			return EFI_EXIT(EFI_SUCCESS);
> -		return EFI_EXIT(EFI_NOT_READY);
> +	if (!efi_is_event(evt) || (evt->type & EVT_NOTIFY_SIGNAL))
> +		return EFI_EXIT(EFI_INVALID_PARAMETER);
> +	if (!evt->is_signaled && evt->notify_function)
> +		EFI_CALL_VOID(evt->notify_function(evt, evt->notify_context));

Here you are doing the contrary of what you describe above:

You do not check the task priority level. You call the notification 
function irrespective of the TPL.

You should queue the notification function if the current TPL is greater 
or equal to the TPL of the notification functions. This is what the 
removed call to function efi_signal_event was doing before your patch.

Could you, please, describe the rationale of this change. Where did you 
get problems with the queuing logic?

Regards

Heinrich

> +	if (evt->is_signaled) {
> +		evt->is_signaled = true;
> +		return EFI_EXIT(EFI_SUCCESS);
>   	}
> -	return EFI_EXIT(EFI_INVALID_PARAMETER);
> +	return EFI_EXIT(EFI_NOT_READY);
>   }
>   
>   /*
> @@ -1440,15 +1443,15 @@ static void efi_exit_caches(void)
>   static efi_status_t EFIAPI efi_exit_boot_services(void *image_handle,
>   						  unsigned long map_key)
>   {
> -	int i;
> +	struct efi_event *evt;
>   
>   	EFI_ENTRY("%p, %ld", image_handle, map_key);
>   
>   	/* Notify that ExitBootServices is invoked. */
> -	for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
> -		if (efi_events[i].type != EVT_SIGNAL_EXIT_BOOT_SERVICES)
> +	list_for_each_entry(evt, &efi_events, link) {
> +		if (evt->type != EVT_SIGNAL_EXIT_BOOT_SERVICES)
>   			continue;
> -		efi_signal_event(&efi_events[i]);
> +		efi_signal_event(evt);
>   	}
>   	/* Make sure that notification functions are not called anymore */
>   	efi_tpl = TPL_HIGH_LEVEL;
> 

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 07/11] efi_loader: fix events
  2017-10-13  5:24   ` Heinrich Schuchardt
@ 2017-10-13 14:08     ` Rob Clark
  0 siblings, 0 replies; 75+ messages in thread
From: Rob Clark @ 2017-10-13 14:08 UTC (permalink / raw)
  To: u-boot

On Fri, Oct 13, 2017 at 1:24 AM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>
>
> On 10/10/2017 02:23 PM, Rob Clark wrote:
>>
>> An event can be created with type==0, Shell.efi does this for an event
>> that is set when Ctrl-C is typed.  So our current approach of having a
>> fixed set of timer slots, and determining which slots are unused by
>> type==0 doesn't work so well.  But we don't have any particularly good
>> reason to have a fixed table of events, so just dynamically allocate
>> them and keep a list.
>>
>> Also fixes an incorrect implementation of CheckEvent() which was (a)
>> incorrectly returning an error if type==0, and (b) didn't handle the
>> case of an unsignaled event with a notify callback.
>>
>> With these fixes (plus implementation of SIMPLE_TEXT_INPUT_EX protocol),
>> Ctrl-C works in Shell.efi.
>>
>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>> ---
>>   include/efi_loader.h          |   1 +
>>   lib/efi_loader/efi_boottime.c | 217
>> +++++++++++++++++++++---------------------
>>   2 files changed, 111 insertions(+), 107 deletions(-)
>>
>> diff --git a/include/efi_loader.h b/include/efi_loader.h
>> index e6e55d2cb4..2232caca44 100644
>> --- a/include/efi_loader.h
>> +++ b/include/efi_loader.h
>> @@ -154,6 +154,7 @@ struct efi_event {
>>         enum efi_timer_delay trigger_type;
>>         bool is_queued;
>>         bool is_signaled;
>> +       struct list_head link;
>>   };
>>     diff --git a/lib/efi_loader/efi_boottime.c
>> b/lib/efi_loader/efi_boottime.c
>> index 39dcc72648..19fafe546c 100644
>> --- a/lib/efi_loader/efi_boottime.c
>> +++ b/lib/efi_loader/efi_boottime.c
>> @@ -350,11 +350,26 @@ static efi_status_t efi_create_handle(void **handle)
>>         return r;
>>   }
>>   +static LIST_HEAD(efi_events);
>> +
>>   /*
>> - * Our event capabilities are very limited. Only a small limited
>> - * number of events is allowed to coexist.
>> + * Check if a pointer is a valid event.
>> + *
>> + * It might be nice at some point to extend this to a more general
>> + * mechanism to check if pointers passed from the EFI world are
>> + * valid objects of a particular type.
>>    */
>> -static struct efi_event efi_events[16];
>> +static bool efi_is_event(const void *obj)
>> +{
>> +       struct efi_event *evt;
>> +
>> +       list_for_each_entry(evt, &efi_events, link) {
>> +               if (evt == obj)
>> +                       return true;
>> +       }
>> +
>> +       return false;
>> +}
>>     /*
>>    * Create an event.
>> @@ -377,7 +392,7 @@ efi_status_t efi_create_event(uint32_t type, UINTN
>> notify_tpl,
>>                                         void *context),
>>                               void *notify_context, struct efi_event
>> **event)
>>   {
>> -       int i;
>> +       struct efi_event *evt;
>>         if (event == NULL)
>>                 return EFI_INVALID_PARAMETER;
>> @@ -389,21 +404,24 @@ efi_status_t efi_create_event(uint32_t type, UINTN
>> notify_tpl,
>>             notify_function == NULL)
>>                 return EFI_INVALID_PARAMETER;
>>   -     for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
>> -               if (efi_events[i].type)
>> -                       continue;
>> -               efi_events[i].type = type;
>> -               efi_events[i].notify_tpl = notify_tpl;
>> -               efi_events[i].notify_function = notify_function;
>> -               efi_events[i].notify_context = notify_context;
>> -               /* Disable timers on bootup */
>> -               efi_events[i].trigger_next = -1ULL;
>> -               efi_events[i].is_queued = false;
>> -               efi_events[i].is_signaled = false;
>> -               *event = &efi_events[i];
>> -               return EFI_SUCCESS;
>> -       }
>> -       return EFI_OUT_OF_RESOURCES;
>> +       evt = calloc(1, sizeof(*evt));
>> +       if (!evt)
>> +               return EFI_OUT_OF_RESOURCES;
>> +
>> +       evt->type = type;
>> +       evt->notify_tpl = notify_tpl;
>> +       evt->notify_function = notify_function;
>> +       evt->notify_context = notify_context;
>> +       /* Disable timers on bootup */
>> +       evt->trigger_next = -1ULL;
>> +       evt->is_queued = false;
>> +       evt->is_signaled = false;
>> +
>> +       list_add_tail(&evt->link, &efi_events);
>> +
>> +       *event = evt;
>> +
>> +       return EFI_SUCCESS;
>>   }
>>     /*
>> @@ -443,30 +461,31 @@ static efi_status_t EFIAPI efi_create_event_ext(
>>    */
>>   void efi_timer_check(void)
>>   {
>> -       int i;
>> +       struct efi_event *evt;
>>         u64 now = timer_get_us();
>>   -     for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
>> -               if (!efi_events[i].type)
>> -                       continue;
>> -               if (efi_events[i].is_queued)
>> -                       efi_signal_event(&efi_events[i]);
>> -               if (!(efi_events[i].type & EVT_TIMER) ||
>> -                   now < efi_events[i].trigger_next)
>> +       /*
>> +        * TODO perhaps optimize a bit and track the time of next
>> +        * timer to expire?
>> +        */
>> +       list_for_each_entry(evt, &efi_events, link) {
>> +               if (evt->is_queued)
>> +                       efi_signal_event(evt);
>> +               if (!(evt->type & EVT_TIMER) ||
>> +                   now < evt->trigger_next)
>>                         continue;
>> -               switch (efi_events[i].trigger_type) {
>> +               switch (evt->trigger_type) {
>>                 case EFI_TIMER_RELATIVE:
>> -                       efi_events[i].trigger_type = EFI_TIMER_STOP;
>> +                       evt->trigger_type = EFI_TIMER_STOP;
>>                         break;
>>                 case EFI_TIMER_PERIODIC:
>> -                       efi_events[i].trigger_next +=
>> -                               efi_events[i].trigger_time;
>> +                       evt->trigger_next += evt->trigger_time;
>>                         break;
>>                 default:
>>                         continue;
>>                 }
>> -               efi_events[i].is_signaled = true;
>> -               efi_signal_event(&efi_events[i]);
>> +               evt->is_signaled = true;
>> +               efi_signal_event(evt);
>>         }
>>         WATCHDOG_RESET();
>>   }
>> @@ -485,7 +504,8 @@ void efi_timer_check(void)
>>   efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay
>> type,
>>                            uint64_t trigger_time)
>>   {
>> -       int i;
>> +       if (!efi_is_event(event))
>> +               return EFI_INVALID_PARAMETER;
>>         /*
>>          * The parameter defines a multiple of 100ns.
>> @@ -493,30 +513,25 @@ efi_status_t efi_set_timer(struct efi_event *event,
>> enum efi_timer_delay type,
>>          */
>>         do_div(trigger_time, 10);
>>   -     for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
>> -               if (event != &efi_events[i])
>> -                       continue;
>> +       if (!(event->type & EVT_TIMER))
>> +               return EFI_INVALID_PARAMETER;
>>   -             if (!(event->type & EVT_TIMER))
>> -                       break;
>> -               switch (type) {
>> -               case EFI_TIMER_STOP:
>> -                       event->trigger_next = -1ULL;
>> -                       break;
>> -               case EFI_TIMER_PERIODIC:
>> -               case EFI_TIMER_RELATIVE:
>> -                       event->trigger_next =
>> -                               timer_get_us() + trigger_time;
>> -                       break;
>> -               default:
>> -                       return EFI_INVALID_PARAMETER;
>> -               }
>> -               event->trigger_type = type;
>> -               event->trigger_time = trigger_time;
>> -               event->is_signaled = false;
>> -               return EFI_SUCCESS;
>> +       switch (type) {
>> +       case EFI_TIMER_STOP:
>> +               event->trigger_next = -1ULL;
>> +               break;
>> +       case EFI_TIMER_PERIODIC:
>> +       case EFI_TIMER_RELATIVE:
>> +               event->trigger_next = timer_get_us() + trigger_time;
>> +               break;
>> +       default:
>> +               return EFI_INVALID_PARAMETER;
>>         }
>> -       return EFI_INVALID_PARAMETER;
>> +       event->trigger_type = type;
>> +       event->trigger_time = trigger_time;
>> +       event->is_signaled = false;
>> +
>> +       return EFI_SUCCESS;
>>   }
>>     /*
>> @@ -555,7 +570,7 @@ static efi_status_t EFIAPI efi_wait_for_event(unsigned
>> long num_events,
>>                                               struct efi_event **event,
>>                                               size_t *index)
>>   {
>> -       int i, j;
>> +       int i;
>>         EFI_ENTRY("%ld, %p, %p", num_events, event, index);
>>   @@ -566,12 +581,8 @@ static efi_status_t EFIAPI
>> efi_wait_for_event(unsigned long num_events,
>>         if (efi_tpl != TPL_APPLICATION)
>>                 return EFI_EXIT(EFI_UNSUPPORTED);
>>         for (i = 0; i < num_events; ++i) {
>> -               for (j = 0; j < ARRAY_SIZE(efi_events); ++j) {
>> -                       if (event[i] == &efi_events[j])
>> -                               goto known_event;
>> -               }
>> -               return EFI_EXIT(EFI_INVALID_PARAMETER);
>> -known_event:
>> +               if (!efi_is_event(event[i]))
>> +                       return EFI_EXIT(EFI_INVALID_PARAMETER);
>>                 if (!event[i]->type || event[i]->type & EVT_NOTIFY_SIGNAL)
>>                         return EFI_EXIT(EFI_INVALID_PARAMETER);
>>                 if (!event[i]->is_signaled)
>> @@ -614,19 +625,12 @@ out:
>>    */
>>   static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event)
>>   {
>> -       int i;
>> -
>>         EFI_ENTRY("%p", event);
>> -       for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
>> -               if (event != &efi_events[i])
>> -                       continue;
>> -               if (event->is_signaled)
>> -                       break;
>> -               event->is_signaled = true;
>> -               if (event->type & EVT_NOTIFY_SIGNAL)
>> -                       efi_signal_event(event);
>> -               break;
>> -       }
>> +       if (!efi_is_event(event))
>> +               return EFI_EXIT(EFI_INVALID_PARAMETER);
>> +       event->is_signaled = true;
>> +       if (event->type & EVT_NOTIFY_SIGNAL)
>> +               efi_signal_event(event);
>>         return EFI_EXIT(EFI_SUCCESS);
>>   }
>>   @@ -642,19 +646,10 @@ static efi_status_t EFIAPI
>> efi_signal_event_ext(struct efi_event *event)
>>    */
>>   static efi_status_t EFIAPI efi_close_event(struct efi_event *event)
>>   {
>> -       int i;
>> -
>>         EFI_ENTRY("%p", event);
>> -       for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
>> -               if (event == &efi_events[i]) {
>> -                       event->type = 0;
>> -                       event->trigger_next = -1ULL;
>> -                       event->is_queued = false;
>> -                       event->is_signaled = false;
>> -                       return EFI_EXIT(EFI_SUCCESS);
>> -               }
>> -       }
>> -       return EFI_EXIT(EFI_INVALID_PARAMETER);
>> +       list_del(&event->link);
>> +       free(event);
>> +       return EFI_EXIT(EFI_SUCCESS);
>>   }
>>     /*
>> @@ -664,29 +659,37 @@ static efi_status_t EFIAPI efi_close_event(struct
>> efi_event *event)
>>    * See the Unified Extensible Firmware Interface (UEFI) specification
>>    * for details.
>>    *
>> - * If an event is not signaled yet the notification function is queued.
>> + * - If Event is in the signaled state, it is cleared and EFI_SUCCESS
>> + *   is returned.
>> + *
>> + * - If Event is not in the signaled state and has no notification
>> + *   function, EFI_NOT_READY is returned.
>> + *
>> + * - If Event is not in the signaled state but does have a notification
>> + *   function, the notification function is queued at the event’s
>> + *   notification task priority level. If the execution of the
>> + *   notification function causes Event to be signaled, then the signaled
>> + *   state is cleared and EFI_SUCCESS is returned; if the Event is not
>> + *   signaled, then EFI_NOT_READY is returned.
>>    *
>>    * @event     event to check
>>    * @return    status code
>>    */
>> -static efi_status_t EFIAPI efi_check_event(struct efi_event *event)
>> +/*
>> + */
>> +static efi_status_t EFIAPI efi_check_event(struct efi_event *evt)
>>   {
>> -       int i;
>> -
>> -       EFI_ENTRY("%p", event);
>> +       EFI_ENTRY("%p", evt);
>>         efi_timer_check();
>> -       for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
>> -               if (event != &efi_events[i])
>> -                       continue;
>> -               if (!event->type || event->type & EVT_NOTIFY_SIGNAL)
>> -                       break;
>> -               if (!event->is_signaled)
>> -                       efi_signal_event(event);
>> -               if (event->is_signaled)
>> -                       return EFI_EXIT(EFI_SUCCESS);
>> -               return EFI_EXIT(EFI_NOT_READY);
>> +       if (!efi_is_event(evt) || (evt->type & EVT_NOTIFY_SIGNAL))
>> +               return EFI_EXIT(EFI_INVALID_PARAMETER);
>> +       if (!evt->is_signaled && evt->notify_function)
>> +               EFI_CALL_VOID(evt->notify_function(evt,
>> evt->notify_context));
>
>
> Here you are doing the contrary of what you describe above:
>
> You do not check the task priority level. You call the notification function
> irrespective of the TPL.
>
> You should queue the notification function if the current TPL is greater or
> equal to the TPL of the notification functions. This is what the removed
> call to function efi_signal_event was doing before your patch.
>
> Could you, please, describe the rationale of this change. Where did you get
> problems with the queuing logic?
>

When I originally wrote this patch (prior to your addition of TPL
handling), we weren't handling the 3rd case mentioned in the comment I
added, IIRC.  (We also were running into a problem with an event that
shell was creating with type==0 that it would signal when the user hit
ctrl-c to interrupt a command, which was what prompted the switch to a
list.)

Looks like you fixed the first issue in efi_signal_event(), which I
overlooked when rebasing this patch.

BR,
-R

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [U-Boot, 04/11] efi_loader: SIMPLE_TEXT_INPUT_EX plus wire up objects properly
  2017-10-10 12:23 ` [U-Boot] [PATCH 04/11] efi_loader: SIMPLE_TEXT_INPUT_EX plus wire up objects properly Rob Clark
  2017-10-11 14:39   ` Alexander Graf
@ 2018-09-04 14:07   ` Alexander Graf
  1 sibling, 0 replies; 75+ messages in thread
From: Alexander Graf @ 2018-09-04 14:07 UTC (permalink / raw)
  To: u-boot

> We need the _EX version for SCT.. and we need to wire up the
> corresponding objects in the systab properly, as well as dealing
> with the console_in object advertising multiple protocols.
> 
> Signed-off-by: Rob Clark <robdclark@gmail.com>
> Reviewed-by: Alexander Graf <agraf@suse.de>

Thanks, applied to efi-next

Alex

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 02/11] efi_loader: Initial HII protocols
  2017-10-10 12:22 ` [U-Boot] [PATCH 02/11] efi_loader: Initial HII protocols Rob Clark
  2017-10-11 14:30   ` Alexander Graf
@ 2018-09-22 10:34   ` Heinrich Schuchardt
  2018-09-23 10:11     ` Alexander Graf
  1 sibling, 1 reply; 75+ messages in thread
From: Heinrich Schuchardt @ 2018-09-22 10:34 UTC (permalink / raw)
  To: u-boot

On 10/10/2017 02:22 PM, Rob Clark wrote:
> From: Leif Lindholm <leif.lindholm@linaro.org>
> 
> Enough implementation of the following protocols to run Shell.efi and
> SCT.efi:
> 
>   EfiHiiConfigRoutingProtocolGuid
>   EfiHiiDatabaseProtocol
>   EfiHiiStringProtocol

The i386 Shell.efi also tries to open these before failing:

EfiHiiFontProtocol
EfiHiiImageProtocol

Best regards

Heinrich Schuchardt

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 02/11] efi_loader: Initial HII protocols
  2018-09-22 10:34   ` Heinrich Schuchardt
@ 2018-09-23 10:11     ` Alexander Graf
  2018-10-03  7:39       ` AKASHI, Takahiro
  0 siblings, 1 reply; 75+ messages in thread
From: Alexander Graf @ 2018-09-23 10:11 UTC (permalink / raw)
  To: u-boot



On 22.09.18 12:34, Heinrich Schuchardt wrote:
> On 10/10/2017 02:22 PM, Rob Clark wrote:
>> From: Leif Lindholm <leif.lindholm@linaro.org>
>>
>> Enough implementation of the following protocols to run Shell.efi and
>> SCT.efi:
>>
>>   EfiHiiConfigRoutingProtocolGuid
>>   EfiHiiDatabaseProtocol
>>   EfiHiiStringProtocol
> 
> The i386 Shell.efi also tries to open these before failing:
> 
> EfiHiiFontProtocol
> EfiHiiImageProtocol

That sounds like a bug. The UEFI spec only mandates the following in
section 2.6.2:

2. If a platform includes a configuration infrastructure, then the
EFI_HII_DATABASE_PROTOCOL, EFI_HII_STRING_PROTOCOL,
EFI_HII_CONFIG_ROUTING_PROTOCOL, and EFI_HII_CONFIG_ACCESS_PROTOCOL are
required. If you support bitmapped fonts, you must support
EFI_HII_FONT_PROTOCOL.

Well, in my book the whole fact that the UEFI shell requires HII sounds
like a bad design decision, but it should at least not require the font
protocol :).

Also, I have built my own x86_64 shell.efi from latest edk2 git manually
and that works fine (even in sandbox). Maybe that is only the minimal
shell though? Their build system is still a bit of a mystery to me :).


Alex

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 02/11] efi_loader: Initial HII protocols
  2018-09-23 10:11     ` Alexander Graf
@ 2018-10-03  7:39       ` AKASHI, Takahiro
  2018-10-05  8:52         ` AKASHI, Takahiro
  0 siblings, 1 reply; 75+ messages in thread
From: AKASHI, Takahiro @ 2018-10-03  7:39 UTC (permalink / raw)
  To: u-boot

Alex,

On Sun, Sep 23, 2018 at 12:11:08PM +0200, Alexander Graf wrote:
> 
> 
> On 22.09.18 12:34, Heinrich Schuchardt wrote:
> > On 10/10/2017 02:22 PM, Rob Clark wrote:
> >> From: Leif Lindholm <leif.lindholm@linaro.org>
> >>
> >> Enough implementation of the following protocols to run Shell.efi and
> >> SCT.efi:
> >>
> >>   EfiHiiConfigRoutingProtocolGuid
> >>   EfiHiiDatabaseProtocol
> >>   EfiHiiStringProtocol
> > 
> > The i386 Shell.efi also tries to open these before failing:
> > 
> > EfiHiiFontProtocol
> > EfiHiiImageProtocol
> 
> That sounds like a bug. The UEFI spec only mandates the following in
> section 2.6.2:
> 
> 2. If a platform includes a configuration infrastructure, then the
> EFI_HII_DATABASE_PROTOCOL, EFI_HII_STRING_PROTOCOL,
> EFI_HII_CONFIG_ROUTING_PROTOCOL, and EFI_HII_CONFIG_ACCESS_PROTOCOL are
> required.

Do you think efi implementation on u-boot also wants those protocols?
(Apparently, config access protocol can be optional for shell unless
we want driver configuration?)

Among others, UEFI spec defines lots of "packages" for HII database:
   string, guid, font, image, device path, keyboard layout and etc.

Do you expect all of them be supported from the beginning?
If not, what criteria do you think is reasonable so that you feel
comfortable in accepting an initial commit of HII database support?

Thanks,
-Takahiro Akashi

> If you support bitmapped fonts, you must support
> EFI_HII_FONT_PROTOCOL.

> Well, in my book the whole fact that the UEFI shell requires HII sounds
> like a bad design decision, but it should at least not require the font
> protocol :).
> 
> Also, I have built my own x86_64 shell.efi from latest edk2 git manually
> and that works fine (even in sandbox). Maybe that is only the minimal
> shell though? Their build system is still a bit of a mystery to me :).
> 
> 
> Alex

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 02/11] efi_loader: Initial HII protocols
  2018-10-03  7:39       ` AKASHI, Takahiro
@ 2018-10-05  8:52         ` AKASHI, Takahiro
  2018-10-05  9:49           ` Leif Lindholm
  0 siblings, 1 reply; 75+ messages in thread
From: AKASHI, Takahiro @ 2018-10-05  8:52 UTC (permalink / raw)
  To: u-boot

On Wed, 3 Oct 2018 at 16:37, AKASHI, Takahiro
<takahiro.akashi@linaro.org> wrote:
>
> Alex,
>
> On Sun, Sep 23, 2018 at 12:11:08PM +0200, Alexander Graf wrote:
> >
> >
> > On 22.09.18 12:34, Heinrich Schuchardt wrote:
> > > On 10/10/2017 02:22 PM, Rob Clark wrote:
> > >> From: Leif Lindholm <leif.lindholm@linaro.org>
> > >>
> > >> Enough implementation of the following protocols to run Shell.efi and
> > >> SCT.efi:
> > >>
> > >>   EfiHiiConfigRoutingProtocolGuid
> > >>   EfiHiiDatabaseProtocol
> > >>   EfiHiiStringProtocol
> > >
> > > The i386 Shell.efi also tries to open these before failing:
> > >
> > > EfiHiiFontProtocol
> > > EfiHiiImageProtocol
> >
> > That sounds like a bug. The UEFI spec only mandates the following in
> > section 2.6.2:
> >
> > 2. If a platform includes a configuration infrastructure, then the
> > EFI_HII_DATABASE_PROTOCOL, EFI_HII_STRING_PROTOCOL,
> > EFI_HII_CONFIG_ROUTING_PROTOCOL, and EFI_HII_CONFIG_ACCESS_PROTOCOL are
> > required.
>
> Do you think efi implementation on u-boot also wants those protocols?
> (Apparently, config access protocol can be optional for shell unless
> we want driver configuration?)

One more question:
Does u-boot support any kind of "UEFI driver"?
If yes, is there any good example?
If no, do you expect that it should be supported?

Thanks,
-Takahiro Akashi

> Among others, UEFI spec defines lots of "packages" for HII database:
>    string, guid, font, image, device path, keyboard layout and etc.
>
> Do you expect all of them be supported from the beginning?
> If not, what criteria do you think is reasonable so that you feel
> comfortable in accepting an initial commit of HII database support?
>
> Thanks,
> -Takahiro Akashi
>
> > If you support bitmapped fonts, you must support
> > EFI_HII_FONT_PROTOCOL.
>
> > Well, in my book the whole fact that the UEFI shell requires HII sounds
> > like a bad design decision, but it should at least not require the font
> > protocol :).
> >
> > Also, I have built my own x86_64 shell.efi from latest edk2 git manually
> > and that works fine (even in sandbox). Maybe that is only the minimal
> > shell though? Their build system is still a bit of a mystery to me :).
> >
> >
> > Alex

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 02/11] efi_loader: Initial HII protocols
  2018-10-05  8:52         ` AKASHI, Takahiro
@ 2018-10-05  9:49           ` Leif Lindholm
  2018-10-05 13:06             ` Alexander Graf
  2018-10-05 16:24             ` Heinrich Schuchardt
  0 siblings, 2 replies; 75+ messages in thread
From: Leif Lindholm @ 2018-10-05  9:49 UTC (permalink / raw)
  To: u-boot

On Fri, Oct 05, 2018 at 05:52:09PM +0900, AKASHI, Takahiro wrote:
> > > 2. If a platform includes a configuration infrastructure, then the
> > > EFI_HII_DATABASE_PROTOCOL, EFI_HII_STRING_PROTOCOL,
> > > EFI_HII_CONFIG_ROUTING_PROTOCOL, and EFI_HII_CONFIG_ACCESS_PROTOCOL are
> > > required.
> >
> > Do you think efi implementation on u-boot also wants those protocols?
> > (Apparently, config access protocol can be optional for shell unless
> > we want driver configuration?)
> 
> One more question:
> Does u-boot support any kind of "UEFI driver"?
> If yes, is there any good example?
> If no, do you expect that it should be supported?

I don't think full-on option ROMs with configuration menus are
something we care about for EBBR-style implementations.
What could be useful is things like shim - a simple driver installing
a protocol that lets other applications running at boot-time access
it. But I think that is already (mostly?) supported.

If someone at a later date decides that they want to support option
ROMs, basically using U-Boot for an SBBR implementation, that will
come with additional work required for the menu support. And should be
possible to configure out at build time for users who don't want it.

/
    Leif

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 02/11] efi_loader: Initial HII protocols
  2018-10-05  9:49           ` Leif Lindholm
@ 2018-10-05 13:06             ` Alexander Graf
  2018-10-09  7:24               ` AKASHI, Takahiro
  2018-10-05 16:24             ` Heinrich Schuchardt
  1 sibling, 1 reply; 75+ messages in thread
From: Alexander Graf @ 2018-10-05 13:06 UTC (permalink / raw)
  To: u-boot

On 10/05/2018 11:49 AM, Leif Lindholm wrote:
> On Fri, Oct 05, 2018 at 05:52:09PM +0900, AKASHI, Takahiro wrote:
>>>> 2. If a platform includes a configuration infrastructure, then the
>>>> EFI_HII_DATABASE_PROTOCOL, EFI_HII_STRING_PROTOCOL,
>>>> EFI_HII_CONFIG_ROUTING_PROTOCOL, and EFI_HII_CONFIG_ACCESS_PROTOCOL are
>>>> required.
>>> Do you think efi implementation on u-boot also wants those protocols?
>>> (Apparently, config access protocol can be optional for shell unless
>>> we want driver configuration?)
>> One more question:
>> Does u-boot support any kind of "UEFI driver"?
>> If yes, is there any good example?
>> If no, do you expect that it should be supported?
> I don't think full-on option ROMs with configuration menus are
> something we care about for EBBR-style implementations.
> What could be useful is things like shim - a simple driver installing
> a protocol that lets other applications running at boot-time access
> it. But I think that is already (mostly?) supported.

That works, iPXE also works. But neither use HII from what I'm aware of.

> If someone at a later date decides that they want to support option
> ROMs, basically using U-Boot for an SBBR implementation, that will
> come with additional work required for the menu support. And should be
> possible to configure out at build time for users who don't want it.

Yeah, IMHO for HII we can treat it as a Shell.efi only wart we have to 
live with, but implement as little as we can get away with.


Alex

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 02/11] efi_loader: Initial HII protocols
  2018-10-05  9:49           ` Leif Lindholm
  2018-10-05 13:06             ` Alexander Graf
@ 2018-10-05 16:24             ` Heinrich Schuchardt
  1 sibling, 0 replies; 75+ messages in thread
From: Heinrich Schuchardt @ 2018-10-05 16:24 UTC (permalink / raw)
  To: u-boot

On 10/05/2018 11:49 AM, Leif Lindholm wrote:
> On Fri, Oct 05, 2018 at 05:52:09PM +0900, AKASHI, Takahiro wrote:
>>>> 2. If a platform includes a configuration infrastructure, then the
>>>> EFI_HII_DATABASE_PROTOCOL, EFI_HII_STRING_PROTOCOL,
>>>> EFI_HII_CONFIG_ROUTING_PROTOCOL, and EFI_HII_CONFIG_ACCESS_PROTOCOL are
>>>> required.
>>>
>>> Do you think efi implementation on u-boot also wants those protocols?
>>> (Apparently, config access protocol can be optional for shell unless
>>> we want driver configuration?)
>>
>> One more question:
>> Does u-boot support any kind of "UEFI driver"?

I am currently working on patches to fix StartImage(), Exit(), and
UnloadImage() that will enable installing EFI drivers.

Currently the image handle is destroyed when a driver calls Exit().

Regards

Heinrich

>> If yes, is there any good example?
>> If no, do you expect that it should be supported?
> 
> I don't think full-on option ROMs with configuration menus are
> something we care about for EBBR-style implementations.
> What could be useful is things like shim - a simple driver installing
> a protocol that lets other applications running at boot-time access
> it. But I think that is already (mostly?) supported.
> 
> If someone at a later date decides that they want to support option
> ROMs, basically using U-Boot for an SBBR implementation, that will
> come with additional work required for the menu support. And should be
> possible to configure out at build time for users who don't want it.
> 
> /
>     Leif
> 

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 02/11] efi_loader: Initial HII protocols
  2018-10-05 13:06             ` Alexander Graf
@ 2018-10-09  7:24               ` AKASHI, Takahiro
  2018-10-09 17:19                 ` Heinrich Schuchardt
  0 siblings, 1 reply; 75+ messages in thread
From: AKASHI, Takahiro @ 2018-10-09  7:24 UTC (permalink / raw)
  To: u-boot

On Fri, Oct 05, 2018 at 03:06:52PM +0200, Alexander Graf wrote:
> On 10/05/2018 11:49 AM, Leif Lindholm wrote:
> >On Fri, Oct 05, 2018 at 05:52:09PM +0900, AKASHI, Takahiro wrote:
> >>>>2. If a platform includes a configuration infrastructure, then the
> >>>>EFI_HII_DATABASE_PROTOCOL, EFI_HII_STRING_PROTOCOL,
> >>>>EFI_HII_CONFIG_ROUTING_PROTOCOL, and EFI_HII_CONFIG_ACCESS_PROTOCOL are
> >>>>required.
> >>>Do you think efi implementation on u-boot also wants those protocols?
> >>>(Apparently, config access protocol can be optional for shell unless
> >>>we want driver configuration?)
> >>One more question:
> >>Does u-boot support any kind of "UEFI driver"?
> >>If yes, is there any good example?
> >>If no, do you expect that it should be supported?
> >I don't think full-on option ROMs with configuration menus are
> >something we care about for EBBR-style implementations.
> >What could be useful is things like shim - a simple driver installing
> >a protocol that lets other applications running at boot-time access
> >it. But I think that is already (mostly?) supported.
> 
> That works, iPXE also works. But neither use HII from what I'm aware of.

After all, do both of you say that we neither have to have
Config Routing nor Config Access Protocol for now?

> >If someone at a later date decides that they want to support option
> >ROMs, basically using U-Boot for an SBBR implementation, that will
> >come with additional work required for the menu support. And should be
> >possible to configure out at build time for users who don't want it.
> 
> Yeah, IMHO for HII we can treat it as a Shell.efi only wart we have to live
> with, but implement as little as we can get away with.

Do you have any specific idea about what is really missing
in Leif's/Rob's HII patch?
(My original question.)

-Takahiro Akashi

> 
> Alex
> 

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 02/11] efi_loader: Initial HII protocols
  2018-10-09  7:24               ` AKASHI, Takahiro
@ 2018-10-09 17:19                 ` Heinrich Schuchardt
  2018-10-10  0:54                   ` AKASHI, Takahiro
  0 siblings, 1 reply; 75+ messages in thread
From: Heinrich Schuchardt @ 2018-10-09 17:19 UTC (permalink / raw)
  To: u-boot

On 10/09/2018 09:24 AM, AKASHI, Takahiro wrote:
> Do you have any specific idea about what is really missing
> in Leif's/Rob's HII patch?
> (My original question.)
> 
> -Takahiro Akashi

Please, see https://patchwork.ozlabs.org/patch/823807/

Open topics were:
- usage of bitfields
- incorrect determination of string lengths
- too deep nesting of of loops and ifs
- incomplete implementation of the protocols

As other protocols are based on the HII database protocol we should
start with this protocol in a separate patch. We should have a unit test
in lib/efi_selftest/ for all methods of the protocol.

Best regards

Heinrich

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [U-Boot] [PATCH 02/11] efi_loader: Initial HII protocols
  2018-10-09 17:19                 ` Heinrich Schuchardt
@ 2018-10-10  0:54                   ` AKASHI, Takahiro
  0 siblings, 0 replies; 75+ messages in thread
From: AKASHI, Takahiro @ 2018-10-10  0:54 UTC (permalink / raw)
  To: u-boot

Heinrich,

On Tue, Oct 09, 2018 at 07:19:58PM +0200, Heinrich Schuchardt wrote:
> On 10/09/2018 09:24 AM, AKASHI, Takahiro wrote:
> > Do you have any specific idea about what is really missing
> > in Leif's/Rob's HII patch?
> > (My original question.)
> > 
> > -Takahiro Akashi
> 
> Please, see https://patchwork.ozlabs.org/patch/823807/

Thanks, I didn't notice this thread.

> Open topics were:
> - usage of bitfields
> - incorrect determination of string lengths
> - too deep nesting of of loops and ifs

Okay, those seem to be easily fixable at a glance.

> - incomplete implementation of the protocols

That is a matter I'm concerned about.
There's no consensus yet about what should be in an "initial" port.

BTW, you said there were some missing protocols to run i386 version
of Shell: EFI HII font protocol and EFI HII Image protocol.
Do you still believe so even after Alex's comment?

Thanks,
-Takahiro Akashi

> As other protocols are based on the HII database protocol we should
> start with this protocol in a separate patch. We should have a unit test
> in lib/efi_selftest/ for all methods of the protocol.
> 
> Best regards
> 
> Heinrich

^ permalink raw reply	[flat|nested] 75+ messages in thread

end of thread, other threads:[~2018-10-10  0:54 UTC | newest]

Thread overview: 75+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-10-10 12:22 [U-Boot] [PATCH 00/11] efi_loader: patches for Shell.efi Rob Clark
2017-10-10 12:22 ` [U-Boot] [PATCH 01/11] efi_loader: Initial EFI_DEVICE_PATH_UTILITIES_PROTOCOL Rob Clark
2017-10-11  0:03   ` Heinrich Schuchardt
2017-10-11 14:07   ` Alexander Graf
2017-10-11 20:32     ` Rob Clark
2017-10-12  6:51       ` Heinrich Schuchardt
2017-10-10 12:22 ` [U-Boot] [PATCH 02/11] efi_loader: Initial HII protocols Rob Clark
2017-10-11 14:30   ` Alexander Graf
2017-10-11 22:02     ` Rob Clark
2017-10-12  7:13       ` Alexander Graf
2017-10-12  9:55         ` Rob Clark
2017-10-12  9:59           ` Alexander Graf
2018-09-22 10:34   ` Heinrich Schuchardt
2018-09-23 10:11     ` Alexander Graf
2018-10-03  7:39       ` AKASHI, Takahiro
2018-10-05  8:52         ` AKASHI, Takahiro
2018-10-05  9:49           ` Leif Lindholm
2018-10-05 13:06             ` Alexander Graf
2018-10-09  7:24               ` AKASHI, Takahiro
2018-10-09 17:19                 ` Heinrich Schuchardt
2018-10-10  0:54                   ` AKASHI, Takahiro
2018-10-05 16:24             ` Heinrich Schuchardt
2017-10-10 12:22 ` [U-Boot] [PATCH 03/11] efi_loader: Initial EFI_UNICODE_COLLATION_PROTOCOL Rob Clark
2017-10-11 14:36   ` Alexander Graf
2017-10-11 20:30     ` Rob Clark
2017-10-11 20:47       ` Alexander Graf
2017-10-12 11:54         ` Alexander Graf
2017-10-10 12:23 ` [U-Boot] [PATCH 04/11] efi_loader: SIMPLE_TEXT_INPUT_EX plus wire up objects properly Rob Clark
2017-10-11 14:39   ` Alexander Graf
2018-09-04 14:07   ` [U-Boot] [U-Boot, " Alexander Graf
2017-10-10 12:23 ` [U-Boot] [PATCH 05/11] efi_loader: console support for color attributes Rob Clark
2017-10-10 23:41   ` Heinrich Schuchardt
2017-10-11 14:41   ` Alexander Graf
2017-10-12 15:24   ` [U-Boot] [U-Boot, " Alexander Graf
2017-10-10 12:23 ` [U-Boot] [PATCH 06/11] efi_loader: Decouple EFI input/output from stdin/stdout Rob Clark
2017-10-11 14:45   ` Alexander Graf
2017-10-11 22:07     ` Rob Clark
2017-10-12  7:15       ` Alexander Graf
2017-10-12 12:48         ` Rob Clark
2017-10-12 13:05           ` Heinrich Schuchardt
2017-10-12 13:40             ` Rob Clark
2017-10-12 13:50               ` Alexander Graf
2017-10-12 14:28                 ` Rob Clark
2017-10-12 14:31                   ` Alexander Graf
2017-10-12 16:00                   ` Mark Kettenis
2017-10-12 16:25                     ` Alexander Graf
2017-10-12 22:38                   ` Heinrich Schuchardt
2017-10-12 21:26                     ` Rob Clark
2017-10-12 23:48                       ` Heinrich Schuchardt
2017-10-13  0:41                         ` Rob Clark
2017-10-12 13:11           ` Alexander Graf
2017-10-12 13:42             ` Rob Clark
2017-10-12 13:44           ` Mark Kettenis
2017-10-12 14:24             ` Rob Clark
2017-10-10 12:23 ` [U-Boot] [PATCH 07/11] efi_loader: fix events Rob Clark
2017-10-10 22:40   ` Heinrich Schuchardt
2017-10-11 14:49   ` Alexander Graf
2017-10-11 22:09     ` Rob Clark
2017-10-13  5:24   ` Heinrich Schuchardt
2017-10-13 14:08     ` Rob Clark
2017-10-10 12:23 ` [U-Boot] [PATCH 08/11] efi_loader: implement SetWatchdogTimer Rob Clark
2017-10-11 14:55   ` Alexander Graf
2017-10-10 12:23 ` [U-Boot] [PATCH 09/11] efi_loader: Fix disk dp's for pre-DM/legacy devices Rob Clark
2017-10-11 14:56   ` Alexander Graf
2017-10-10 12:23 ` [U-Boot] [PATCH 10/11] efi_loader: Add mem-mapped for fallback Rob Clark
2017-10-10 22:31   ` Heinrich Schuchardt
2017-10-11 14:59   ` Alexander Graf
2017-10-11 22:14     ` Rob Clark
2017-10-12 15:24   ` [U-Boot] [U-Boot, " Alexander Graf
2017-10-10 12:23 ` [U-Boot] [PATCH 11/11] efi_loader: exclude openrd devices Rob Clark
2017-10-10 22:28   ` Heinrich Schuchardt
2017-10-10 22:50     ` Rob Clark
2017-10-11  7:07       ` Stefan Roese
2017-10-11  7:22         ` Alexander Graf
2017-10-11  0:24 ` [U-Boot] [PATCH 00/11] efi_loader: patches for Shell.efi Heinrich Schuchardt

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.