diff --git a/include/efi_api.h b/include/efi_api.h
index 36764a5c6bbb..a7b917e59bda 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -699,6 +699,163 @@ struct efi_device_path_utilities_protocol {
 };
 
 typedef u16 efi_string_id_t;
+typedef u16 efi_question_id_t;
+typedef u16 efi_image_id_t;
+typedef u16 efi_form_id_t;
+
+#define EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID \
+	EFI_GUID(0x587e72d7, 0xcc50, 0x4f79, \
+		 0x82, 0x09, 0xca, 0x29, 0x1f, 0xc1, 0xa1, 0x0f)
+
+struct efi_hii_config_routing_protocol {
+	efi_status_t(EFIAPI *extract_config)(
+		const struct efi_hii_config_routing_protocol *this,
+		const efi_string_t request,
+		efi_string_t *progress,
+		efi_string_t *results);
+	efi_status_t(EFIAPI *export_config)(
+		const struct efi_hii_config_routing_protocol *this,
+		efi_string_t *results);
+	efi_status_t(EFIAPI *route_config)(
+		const struct efi_hii_config_routing_protocol *this,
+		const efi_string_t configuration,
+		efi_string_t *progress);
+	efi_status_t(EFIAPI *block_to_config)(
+		const struct efi_hii_config_routing_protocol *this,
+		const efi_string_t config_request,
+		const uint8_t *block,
+		const efi_uintn_t block_size,
+		efi_string_t *config,
+		efi_string_t *progress);
+	efi_status_t(EFIAPI *config_to_block)(
+		const struct efi_hii_config_routing_protocol *this,
+		const efi_string_t config_resp,
+		const uint8_t *block,
+		const efi_uintn_t *block_size,
+		efi_string_t *progress);
+	efi_status_t(EFIAPI *get_alt_config)(
+		const struct efi_hii_config_routing_protocol *this,
+		const efi_string_t config_resp,
+		const efi_guid_t *guid,
+		const efi_string_t name,
+		const struct efi_device_path *device_path,
+		const efi_string_t alt_cfg_id,
+		efi_string_t *alt_cfg_resp);
+};
+
+#define EFI_HII_CONFIG_ACCESS_PROTOCOL_GUID \
+	EFI_GUID(0x330d4706, 0xf2a0, 0x4e4f, \
+		 0xa3, 0x69, 0xb6, 0x6f, 0xa8, 0xd5, 0x43, 0x85)
+
+struct efi_hii_time {
+	u8 hour;
+	u8 minute;
+	u8 second;
+};
+
+struct efi_hii_date {
+	u16 year;
+	u8 month;
+	u8 day;
+};
+
+struct efi_hii_ref {
+	efi_question_id_t question_id;
+	efi_form_id_t form_id;
+	efi_guid_t form_set_guid;
+	efi_string_id_t device_path;
+};
+
+union efi_ifr_type_value {
+	u8 u8;				// EFI_IFR_TYPE_NUM_SIZE_8
+	u16 u16;			// EFI_IFR_TYPE_NUM_SIZE_16
+	u32 u32;			// EFI_IFR_TYPE_NUM_SIZE_32
+	u64 u64;			// EFI_IFR_TYPE_NUM_SIZE_64
+	bool b;				// EFI_IFR_TYPE_BOOLEAN
+	struct efi_hii_time time;	// EFI_IFR_TYPE_TIME
+	struct efi_hii_date date;	// EFI_IFR_TYPE_DATE
+	efi_string_id_t string;	// EFI_IFR_TYPE_STRING, EFI_IFR_TYPE_ACTION
+	struct efi_hii_ref ref;		// EFI_IFR_TYPE_REF
+	// u8 buffer[];			// EFI_IFR_TYPE_BUFFER
+};
+
+#define EFI_IFR_TYPE_NUM_SIZE_8		0x00
+#define EFI_IFR_TYPE_NUM_SIZE_16	0x01
+#define EFI_IFR_TYPE_NUM_SIZE_32	0x02
+#define EFI_IFR_TYPE_NUM_SIZE_64	0x03
+#define EFI_IFR_TYPE_BOOLEAN		0x04
+#define EFI_IFR_TYPE_TIME		0x05
+#define EFI_IFR_TYPE_DATE		0x06
+#define EFI_IFR_TYPE_STRING		0x07
+#define EFI_IFR_TYPE_OTHER		0x08
+#define EFI_IFR_TYPE_UNDEFINED		0x09
+#define EFI_IFR_TYPE_ACTION		0x0A
+#define EFI_IFR_TYPE_BUFFER		0x0B
+#define EFI_IFR_TYPE_REF		0x0C
+#define EFI_IFR_OPTION_DEFAULT		0x10
+#define EFI_IFR_OPTION_DEFAULT_MFG	0x20
+
+#define EFI_IFR_ONE_OF_OPTION_OP	0x09
+
+struct efi_ifr_op_header {
+	u8 opCode;
+	u8 length:7;
+	u8 scope:1;
+};
+
+struct efi_ifr_one_of_option {
+	struct efi_ifr_op_header header;
+	efi_string_id_t option;
+	u8 flags;
+	u8 type;
+	union efi_ifr_type_value value;
+};
+
+typedef efi_uintn_t efi_browser_action_t;
+
+#define EFI_BROWSER_ACTION_REQUEST_NONE			0
+#define EFI_BROWSER_ACTION_REQUEST_RESET		1
+#define EFI_BROWSER_ACTION_REQUEST_SUBMIT		2
+#define EFI_BROWSER_ACTION_REQUEST_EXIT			3
+#define EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT	4
+#define EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT	5
+#define EFI_BROWSER_ACTION_REQUEST_FORM_APPLY		6
+#define EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD		7
+#define EFI_BROWSER_ACTION_REQUEST_RECONNECT		8
+
+typedef efi_uintn_t efi_browser_action_request_t;
+
+#define EFI_BROWSER_ACTION_CHANGING			0
+#define EFI_BROWSER_ACTION_CHANGED			1
+#define EFI_BROWSER_ACTION_RETRIEVE			2
+#define EFI_BROWSER_ACTION_FORM_OPEN			3
+#define EFI_BROWSER_ACTION_FORM_CLOSE			4
+#define EFI_BROWSER_ACTION_SUBMITTED			5
+#define EFI_BROWSER_ACTION_DEFAULT_STANDARD		0x1000
+#define EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING	0x1001
+#define EFI_BROWSER_ACTION_DEFAULT_SAFE			0x1002
+#define EFI_BROWSER_ACTION_DEFAULT_PLATFORM		0x2000
+#define EFI_BROWSER_ACTION_DEFAULT_HARDWARE		0x3000
+#define EFI_BROWSER_ACTION_DEFAULT_FIRMWARE		0x4000
+
+struct efi_hii_config_access_protocol {
+	efi_status_t(EFIAPI *extract_config_access)(
+		const struct efi_hii_config_access_protocol *this,
+		const efi_string_t request,
+		efi_string_t *progress,
+		efi_string_t *results);
+	efi_status_t(EFIAPI *route_config_access)(
+		const struct efi_hii_config_access_protocol *this,
+		const efi_string_t configuration,
+		efi_string_t *progress);
+	efi_status_t(EFIAPI *form_callback)(
+		const struct efi_hii_config_access_protocol *this,
+		efi_browser_action_t action,
+		efi_question_id_t question_id,
+		u8 type,
+		union efi_ifr_type_value *value,
+		efi_browser_action_request_t *action_request);
+};
 
 #define EFI_HII_DATABASE_PROTOCOL_GUID	     \
 	EFI_GUID(0xef9fc172, 0xa1b2, 0x4693, \
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 615314909b17..ce0f420b5004 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -106,6 +106,8 @@ extern const struct efi_device_path_utilities_protocol
 /* Implementation of the EFI_UNICODE_COLLATION_PROTOCOL */
 extern const struct efi_unicode_collation_protocol
 					efi_unicode_collation_protocol;
+extern const struct efi_hii_config_routing_protocol efi_hii_config_routing;
+extern const struct efi_hii_config_access_protocol efi_hii_config_access;
 extern const struct efi_hii_database_protocol efi_hii_database;
 extern const struct efi_hii_string_protocol efi_hii_string;
 
@@ -141,6 +143,8 @@ extern const efi_guid_t efi_file_system_info_guid;
 extern const efi_guid_t efi_guid_device_path_utilities_protocol;
 /* GUID of the Unicode collation protocol */
 extern const efi_guid_t efi_guid_unicode_collation_protocol;
+extern const efi_guid_t efi_guid_hii_config_routing_protocol;
+extern const efi_guid_t efi_guid_hii_config_access_protocol;
 extern const efi_guid_t efi_guid_hii_database_protocol;
 extern const efi_guid_t efi_guid_hii_string_protocol;
 
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
index e508481fdeeb..26b999bf7c51 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -24,7 +24,7 @@ obj-y += efi_device_path.o
 obj-y += efi_device_path_to_text.o
 obj-y += efi_device_path_utilities.o
 obj-y += efi_file.o
-obj-y += efi_hii.o
+obj-y += efi_hii.o efi_hii_config.o
 obj-y += efi_image_loader.o
 obj-y += efi_memory.o
 obj-y += efi_root_node.o
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index b1d7f6b36f89..8a43a5a84091 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -1562,6 +1562,12 @@ efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path,
 	if (ret != EFI_SUCCESS)
 		goto failure;
 
+	ret = efi_add_protocol(&obj->header,
+			       &efi_guid_hii_config_routing_protocol,
+			       (void *)&efi_hii_config_routing);
+	if (ret != EFI_SUCCESS)
+		goto failure;
+
 	return ret;
 failure:
 	printf("ERROR: Failure to install protocols for loaded image\n");
diff --git a/lib/efi_loader/efi_hii_config.c b/lib/efi_loader/efi_hii_config.c
new file mode 100644
index 000000000000..f4b1f026c1bd
--- /dev/null
+++ b/lib/efi_loader/efi_hii_config.c
@@ -0,0 +1,146 @@
+// SPDX-License-Identifier:     GPL-2.0+
+/*
+ *  EFI Human Interface Infrastructure ... Configuration
+ *
+ *  Copyright (c) 2017 Leif Lindholm
+ *  Copyright (c) 2018 AKASHI Takahiro, Linaro Limited
+ */
+
+#include <common.h>
+#include <efi_loader.h>
+
+const efi_guid_t efi_guid_hii_config_routing_protocol
+		= EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID;
+const efi_guid_t efi_guid_hii_config_access_protocol
+		= EFI_HII_CONFIG_ACCESS_PROTOCOL_GUID;
+
+/*
+ * EFI_HII_CONFIG_ROUTING_PROTOCOL
+ */
+
+static efi_status_t EFIAPI
+extract_config(const struct efi_hii_config_routing_protocol *this,
+	       const efi_string_t request,
+	       efi_string_t *progress,
+	       efi_string_t *results)
+{
+	EFI_ENTRY("%p, \"%ls\", %p, %p", this, request, progress, results);
+
+	return EFI_EXIT(EFI_OUT_OF_RESOURCES);
+}
+
+static efi_status_t EFIAPI
+export_config(const struct efi_hii_config_routing_protocol *this,
+	      efi_string_t *results)
+{
+	EFI_ENTRY("%p, %p", this, results);
+
+	return EFI_EXIT(EFI_OUT_OF_RESOURCES);
+}
+
+static efi_status_t EFIAPI
+route_config(const struct efi_hii_config_routing_protocol *this,
+	     const efi_string_t configuration,
+	     efi_string_t *progress)
+{
+	EFI_ENTRY("%p, \"%ls\", %p", this, configuration, progress);
+
+	return EFI_EXIT(EFI_OUT_OF_RESOURCES);
+}
+
+static efi_status_t EFIAPI
+block_to_config(const struct efi_hii_config_routing_protocol *this,
+		const efi_string_t config_request,
+		const u8 *block,
+		const efi_uintn_t block_size,
+		efi_string_t *config,
+		efi_string_t *progress)
+{
+	EFI_ENTRY("%p, \"%ls\", %p, %zu, %p, %p", this, config_request,
+		  block, block_size, config, progress);
+
+	return EFI_EXIT(EFI_OUT_OF_RESOURCES);
+}
+
+static efi_status_t EFIAPI
+config_to_block(const struct efi_hii_config_routing_protocol *this,
+		const efi_string_t config_resp,
+		const u8 *block,
+		const efi_uintn_t *block_size,
+		efi_string_t *progress)
+{
+	EFI_ENTRY("%p, \"%ls\", %p, %p, %p", this, config_resp,
+		  block, block_size, progress);
+
+	return EFI_EXIT(EFI_OUT_OF_RESOURCES);
+}
+
+static efi_status_t EFIAPI
+get_alt_config(const struct efi_hii_config_routing_protocol *this,
+	       const efi_string_t config_resp,
+	       const efi_guid_t *guid,
+	       const efi_string_t name,
+	       const struct efi_device_path *device_path,
+	       const efi_string_t alt_cfg_id,
+	       efi_string_t *alt_cfg_resp)
+{
+	EFI_ENTRY("%p, \"%ls\", %pUl, \"%ls\", %p, \"%ls\", %p",
+		  this, config_resp, guid, name, device_path,
+		  alt_cfg_id, alt_cfg_resp);
+
+	return EFI_EXIT(EFI_OUT_OF_RESOURCES);
+}
+
+/*
+ * EFI_HII_ACCESS_PROTOCOL
+ */
+
+efi_status_t EFIAPI
+extract_config_access(const struct efi_hii_config_access_protocol *this,
+		      const efi_string_t request,
+		      efi_string_t *progress,
+		      efi_string_t *results)
+{
+	EFI_ENTRY("%p, \"%ls\", %p, %p", this, request, progress, results);
+
+	return EFI_EXIT(EFI_OUT_OF_RESOURCES);
+};
+
+efi_status_t EFIAPI
+route_config_access(const struct efi_hii_config_access_protocol *this,
+		    const efi_string_t configuration,
+		    efi_string_t *progress)
+{
+	EFI_ENTRY("%p, \"%ls\", %p", this, configuration, progress);
+
+	return EFI_EXIT(EFI_OUT_OF_RESOURCES);
+};
+
+efi_status_t EFIAPI
+form_callback(const struct efi_hii_config_access_protocol *this,
+	      efi_browser_action_t action,
+	      efi_question_id_t question_id,
+	      u8 type,
+	      union efi_ifr_type_value *value,
+	      efi_browser_action_request_t *action_request)
+{
+	EFI_ENTRY("%p, 0x%lx, 0x%x, 0x%x, %p, %p", this, action,
+		  question_id, type, value, action_request);
+
+	return EFI_EXIT(EFI_DEVICE_ERROR);
+};
+
+const struct efi_hii_config_routing_protocol efi_hii_config_routing = {
+	.extract_config = extract_config,
+	.export_config = export_config,
+	.route_config = route_config,
+	.block_to_config = block_to_config,
+	.config_to_block = config_to_block,
+	.get_alt_config = get_alt_config
+};
+
+const struct efi_hii_config_access_protocol efi_hii_config_access = {
+	.extract_config_access = extract_config_access,
+	.route_config_access = route_config_access,
+	.form_callback = form_callback
+};
