All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH 0/9] EFI payload / application support
@ 2015-12-22 13:57 Alexander Graf
  2015-12-22 13:57 ` [U-Boot] [PATCH 1/9] disk/part.c: Expose a list of available block drivers Alexander Graf
                   ` (12 more replies)
  0 siblings, 13 replies; 70+ messages in thread
From: Alexander Graf @ 2015-12-22 13:57 UTC (permalink / raw)
  To: u-boot

This is my Christmas present for my openSUSE friends :).

U-Boot is a great project for embedded devices. However, convincing
everyone involved that only for "a few oddball ARM devices" we need to
support different configuration formats from grub2 when all other platforms
(PPC, System Z, x86) are standardized on a single format is a nightmare.

So we started to explore alternatives. At first, people tried to get
grub2 running using the u-boot api interface. However, FWIW that one
doesn't support relocations, so you need to know where to link grub2 to
at compile time. It also seems to be broken more often than not. And on
top of it all, it's a one-off interface, so yet another thing to maintain.

That led to a nifty idea. What if we can just implement the EFI application
protocol on top of U-Boot? Then we could compile a single grub2 binary for
uEFI based systems and U-Boot based systems and as soon as that one's loaded,
everything looks and feels (almost) the same.

This patch set is the result of pursuing this endeavor.

  - I am successfully able to run grub2 and Linux EFI binaries with this code.
  - When enabled, the resulting U-Boot binary only grows by ~10kb,
    so it's very light weight.
  - It works on 32bit ARM and AArch64. 
  - All storage devices are directly accessible
  - No runtime services (all calls return unimplemented)
  - No EFI variables

Of course, there are still a few things one could do on top:

  - Implement removable media booting (search for /efi/boot/boota{a64,rm}.efi)
  - Improve disk media detection (don't scan, use what information we have)
  - Add EFI variable support using NVRAM
  - Add GFX support
  - Make EFI Shell work ;)

But so far, I'm very happy with the state of the patches. They completely
eliminate potential arguments against U-Boot internally and give users the
chance to run with the same level of comfort on all firmware types.


Alex

Alexander Graf (9):
  disk/part.c: Expose a list of available block drivers
  include/efi_api.h: Add more detailed API definitions
  efi_loader: Add PE image loader
  efi_loader: Add boot time services
  efi_loader: Add console interface
  efi_loader: Add runtime services
  efi_loader: Add disk interfaces
  efi_loader: Add "bootefi" command
  efi_loader: hook up in build environment

 arch/arm/cpu/armv8/u-boot.lds     |   8 +
 arch/arm/cpu/u-boot.lds           |  13 +
 arch/arm/lib/sections.c           |   2 +
 common/Makefile                   |   1 +
 common/cmd_bootefi.c              | 168 ++++++++
 disk/part.c                       |  25 ++
 include/efi_api.h                 | 197 +++++++--
 include/efi_loader.h              |  87 ++++
 include/part.h                    |   2 +
 include/pe.h                      | 277 +++++++++++++
 lib/Kconfig                       |   1 +
 lib/Makefile                      |   1 +
 lib/efi_loader/Kconfig            |   8 +
 lib/efi_loader/Makefile           |  11 +
 lib/efi_loader/efi_boottime.c     | 838 ++++++++++++++++++++++++++++++++++++++
 lib/efi_loader/efi_console.c      | 371 +++++++++++++++++
 lib/efi_loader/efi_disk.c         | 227 +++++++++++
 lib/efi_loader/efi_image_loader.c | 203 +++++++++
 lib/efi_loader/efi_runtime.c      |  59 +++
 19 files changed, 2462 insertions(+), 37 deletions(-)
 create mode 100644 common/cmd_bootefi.c
 create mode 100644 include/efi_loader.h
 create mode 100644 include/pe.h
 create mode 100644 lib/efi_loader/Kconfig
 create mode 100644 lib/efi_loader/Makefile
 create mode 100644 lib/efi_loader/efi_boottime.c
 create mode 100644 lib/efi_loader/efi_console.c
 create mode 100644 lib/efi_loader/efi_disk.c
 create mode 100644 lib/efi_loader/efi_image_loader.c
 create mode 100644 lib/efi_loader/efi_runtime.c

-- 
2.1.4

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

* [U-Boot] [PATCH 1/9] disk/part.c: Expose a list of available block drivers
  2015-12-22 13:57 [U-Boot] [PATCH 0/9] EFI payload / application support Alexander Graf
@ 2015-12-22 13:57 ` Alexander Graf
  2016-01-14 19:18   ` Tom Rini
  2016-01-14 23:11   ` Simon Glass
  2015-12-22 13:57 ` [U-Boot] [PATCH 2/9] include/efi_api.h: Add more detailed API definitions Alexander Graf
                   ` (11 subsequent siblings)
  12 siblings, 2 replies; 70+ messages in thread
From: Alexander Graf @ 2015-12-22 13:57 UTC (permalink / raw)
  To: u-boot

We have a pretty nice and generic interface to ask for a specific block
device. However, that one is still based around the magic notion that
we know the driver name.

In order to be able to write fully generic disk access code, expose a list
of all available block drivers.

Signed-off-by: Alexander Graf <agraf@suse.de>
---
 disk/part.c    | 25 +++++++++++++++++++++++++
 include/part.h |  2 ++
 2 files changed, 27 insertions(+)

diff --git a/disk/part.c b/disk/part.c
index 909712e..5bc64c7 100644
--- a/disk/part.c
+++ b/disk/part.c
@@ -26,6 +26,31 @@ struct block_drvr {
 	int (*select_hwpart)(int dev_num, int hwpart);
 };
 
+const char *available_block_drvrs[] = {
+#if defined(CONFIG_CMD_IDE)
+	"ide",
+#endif
+#if defined(CONFIG_CMD_SATA)
+	"sata",
+#endif
+#if defined(CONFIG_CMD_SCSI)
+	"scsi",
+#endif
+#if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_STORAGE)
+	"usb",
+#endif
+#if defined(CONFIG_MMC)
+	"mmc",
+#endif
+#if defined(CONFIG_SYSTEMACE)
+	"ace",
+#endif
+#if defined(CONFIG_SANDBOX)
+	"host",
+#endif
+	NULL,
+};
+
 static const struct block_drvr block_drvr[] = {
 #if defined(CONFIG_CMD_IDE)
 	{ .name = "ide", .get_dev = ide_get_dev, },
diff --git a/include/part.h b/include/part.h
index 720a867..dc2a78b 100644
--- a/include/part.h
+++ b/include/part.h
@@ -122,6 +122,8 @@ int get_device(const char *ifname, const char *dev_str,
 int get_device_and_partition(const char *ifname, const char *dev_part_str,
 			     block_dev_desc_t **dev_desc,
 			     disk_partition_t *info, int allow_whole_dev);
+
+extern const char *available_block_drvrs[];
 #else
 static inline block_dev_desc_t *get_dev(const char *ifname, int dev)
 { return NULL; }
-- 
2.1.4

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

* [U-Boot] [PATCH 2/9] include/efi_api.h: Add more detailed API definitions
  2015-12-22 13:57 [U-Boot] [PATCH 0/9] EFI payload / application support Alexander Graf
  2015-12-22 13:57 ` [U-Boot] [PATCH 1/9] disk/part.c: Expose a list of available block drivers Alexander Graf
@ 2015-12-22 13:57 ` Alexander Graf
  2015-12-22 13:57 ` [U-Boot] [PATCH 3/9] efi_loader: Add PE image loader Alexander Graf
                   ` (10 subsequent siblings)
  12 siblings, 0 replies; 70+ messages in thread
From: Alexander Graf @ 2015-12-22 13:57 UTC (permalink / raw)
  To: u-boot

The EFI API header is great, but missing a good chunk of function prototype,
GUID defines and enum declarations.

This patch extends it to cover more of the EFI API. It's still not 100%
complete, but sufficient enough for our EFI payload interface.

Signed-off-by: Alexander Graf <agraf@suse.de>
---
 include/efi_api.h | 197 ++++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 160 insertions(+), 37 deletions(-)

diff --git a/include/efi_api.h b/include/efi_api.h
index 4fd17d6..917781f 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -17,11 +17,18 @@
 
 #include <efi.h>
 
+/* Types and defines for EFI CreateEvent */
+enum efi_event_type {
+	EFI_TIMER_STOP = 0,
+	EFI_TIMER_PERIODIC = 1,
+	EFI_TIMER_RELATIVE = 2
+};
+
 /* EFI Boot Services table */
 struct efi_boot_services {
 	struct efi_table_hdr hdr;
-	void *raise_tpl;
-	void *restore_tpl;
+	efi_status_t (EFIAPI *raise_tpl)(unsigned long new_tpl);
+	void (EFIAPI *restore_tpl)(unsigned long old_tpl);
 
 	efi_status_t (EFIAPI *allocate_pages)(int, int, unsigned long,
 					      efi_physical_addr_t *);
@@ -32,21 +39,32 @@ struct efi_boot_services {
 	efi_status_t (EFIAPI *allocate_pool)(int, unsigned long, void **);
 	efi_status_t (EFIAPI *free_pool)(void *);
 
-	void *create_event;
-	void *set_timer;
-	efi_status_t(EFIAPI *wait_for_event)(unsigned long number_of_events,
-					     void *event, unsigned long *index);
-	void *signal_event;
-	void *close_event;
-	void *check_event;
-
-	void *install_protocol_interface;
-	void *reinstall_protocol_interface;
-	void *uninstall_protocol_interface;
+	efi_status_t (EFIAPI *create_event)(enum efi_event_type type,
+			unsigned long notify_tpl,
+			void (*notify_function) (void *event, void *context),
+			void *notify_context, void **event);
+	efi_status_t (EFIAPI *set_timer)(void *event, int type,
+			uint64_t trigger_time);
+	efi_status_t (EFIAPI *wait_for_event)(unsigned long number_of_events,
+			void *event, unsigned long *index);
+	efi_status_t (EFIAPI *signal_event)(void *event);
+	efi_status_t (EFIAPI *close_event)(void *event);
+	efi_status_t (EFIAPI *check_event)(void *event);
+
+	efi_status_t (EFIAPI *install_protocol_interface)(
+			void **handle, efi_guid_t *protocol,
+			int protocol_interface_type, void *protocol_interface);
+	efi_status_t (EFIAPI *reinstall_protocol_interface)(
+			void *handle, efi_guid_t *protocol,
+			void *old_interface, void *new_interface);
+	efi_status_t (EFIAPI *uninstall_protocol_interface)(void *handle,
+			efi_guid_t *protocol, void *protocol_interface);
 	efi_status_t (EFIAPI *handle_protocol)(efi_handle_t, efi_guid_t *,
 					       void **);
 	void *reserved;
-	void *register_protocol_notify;
+	efi_status_t (EFIAPI *register_protocol_notify)(
+			efi_guid_t *protocol, void *event,
+			void **registration);
 	efi_status_t (EFIAPI *locate_handle)(
 			enum efi_locate_search_type search_type,
 			efi_guid_t *protocol, void *search_key,
@@ -54,7 +72,8 @@ struct efi_boot_services {
 	efi_status_t (EFIAPI *locate_device_path)(efi_guid_t *protocol,
 			struct efi_device_path **device_path,
 			efi_handle_t *device);
-	void *install_configuration_table;
+	efi_status_t (EFIAPI *install_configuration_table)(
+			efi_guid_t *guid, void *table);
 
 	efi_status_t (EFIAPI *load_image)(bool boot_policiy,
 			efi_handle_t parent_image,
@@ -66,17 +85,20 @@ struct efi_boot_services {
 	efi_status_t (EFIAPI *exit)(efi_handle_t handle,
 				    efi_status_t exit_status,
 				    unsigned long exitdata_size, s16 *exitdata);
-	void *unload_image;
+	efi_status_t (EFIAPI *unload_image)(void *image_handle);
 	efi_status_t (EFIAPI *exit_boot_services)(efi_handle_t, unsigned long);
 
 	efi_status_t (EFIAPI *get_next_monotonic_count)(u64 *count);
 	efi_status_t (EFIAPI *stall)(unsigned long usecs);
-	void *set_watchdog_timer;
+	efi_status_t (EFIAPI *set_watchdog_timer)(unsigned long timeout,
+			uint64_t watchdog_code, unsigned long data_size,
+			uint16_t *watchdog_data);
 	efi_status_t(EFIAPI *connect_controller)(efi_handle_t controller_handle,
 			efi_handle_t *driver_image_handle,
 			struct efi_device_path *remaining_device_path,
 			bool recursive);
-	void *disconnect_controller;
+	efi_status_t (EFIAPI *disconnect_controller)(void *controller_handle,
+			void *driver_image_handle, void *child_handle);
 #define EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL  0x00000001
 #define EFI_OPEN_PROTOCOL_GET_PROTOCOL        0x00000002
 #define EFI_OPEN_PROTOCOL_TEST_PROTOCOL       0x00000004
@@ -87,7 +109,9 @@ struct efi_boot_services {
 			efi_guid_t *protocol, void **interface,
 			efi_handle_t agent_handle,
 			efi_handle_t controller_handle, u32 attributes);
-	void *close_protocol;
+	efi_status_t (EFIAPI *close_protocol)(void *handle,
+			efi_guid_t *protocol, void *agent_handle,
+			void *controller_handle);
 	efi_status_t(EFIAPI *open_protocol_information)(efi_handle_t handle,
 			efi_guid_t *protocol,
 			struct efi_open_protocol_info_entry **entry_buffer,
@@ -99,12 +123,18 @@ struct efi_boot_services {
 			enum efi_locate_search_type search_type,
 			efi_guid_t *protocol, void *search_key,
 			unsigned long *no_handles, efi_handle_t **buffer);
-	void *locate_protocol;
-	void *install_multiple_protocol_interfaces;
-	void *uninstall_multiple_protocol_interfaces;
-	void *calculate_crc32;
-	void *copy_mem;
-	void *set_mem;
+	efi_status_t (EFIAPI *locate_protocol)(efi_guid_t *protocol,
+			void *registration, void **protocol_interface);
+	efi_status_t (EFIAPI *install_multiple_protocol_interfaces)(
+			void **handle, ...);
+	efi_status_t (EFIAPI *uninstall_multiple_protocol_interfaces)(
+			void *handle, ...);
+	efi_status_t (EFIAPI *calculate_crc32)(void *data,
+			unsigned long data_size, uint32_t *crc32);
+	void (EFIAPI *copy_mem)(void *destination, void *source,
+			unsigned long length);
+	void (EFIAPI *set_mem)(void *buffer, unsigned long size,
+			uint8_t value);
 	void *create_event_ex;
 };
 
@@ -121,12 +151,19 @@ enum efi_reset_type {
 
 struct efi_runtime_services {
 	struct efi_table_hdr hdr;
-	void *get_time;
-	void *set_time;
-	void *get_wakeup_time;
-	void *set_wakeup_time;
-	void *set_virtual_address_map;
-	void *convert_pointer;
+	efi_status_t (EFIAPI *get_time)(struct efi_time *time,
+			struct efi_time_cap *capabilities);
+	efi_status_t (EFIAPI *set_time)(struct efi_time *time);
+	efi_status_t (EFIAPI *get_wakeup_time)(char *enabled, char *pending,
+			struct efi_time *time);
+	efi_status_t (EFIAPI *set_wakeup_time)(char enabled,
+			struct efi_time *time);
+	efi_status_t (EFIAPI *set_virtual_address_map)(
+			unsigned long memory_map_size,
+			unsigned long descriptor_size,
+			uint32_t descriptor_version,
+			struct efi_mem_desc *virtmap);
+	efi_status_t (*convert_pointer)(unsigned long dbg, void **address);
 	efi_status_t (EFIAPI *get_variable)(s16 *variable_name,
 			efi_guid_t *vendor, u32 *attributes,
 			unsigned long *data_size, void *data);
@@ -136,7 +173,8 @@ struct efi_runtime_services {
 	efi_status_t (EFIAPI *set_variable)(s16 *variable_name,
 			efi_guid_t *vendor, u32 attributes,
 			unsigned long data_size, void *data);
-	void *get_next_high_mono_count;
+	efi_status_t (EFIAPI *get_next_high_mono_count)(
+			uint32_t *high_count);
 	void (EFIAPI *reset_system)(enum efi_reset_type reset_type,
 				    efi_status_t reset_status,
 				    unsigned long data_size, void *reset_data);
@@ -154,6 +192,18 @@ struct efi_runtime_services {
 	EFI_GUID(0x5b1b31a1, 0x9562, 0x11d2, 0x8e, 0x3f, \
 		 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
 
+#define EFI_FDT_GUID \
+	EFI_GUID(0xb1b621d5, 0xf19c, 0x41a5, \
+		 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0)
+
+struct efi_configuration_table
+{
+	efi_guid_t guid;
+	void *table;
+};
+
+#define EFI_SYSTEM_TABLE_SIGNATURE ((u64)0x5453595320494249ULL)
+
 struct efi_system_table {
 	struct efi_table_hdr hdr;
 	unsigned long fw_vendor;   /* physical addr of wchar_t vendor string */
@@ -163,13 +213,17 @@ struct efi_system_table {
 	unsigned long con_out_handle;
 	struct efi_simple_text_output_protocol *con_out;
 	unsigned long stderr_handle;
-	unsigned long std_err;
+	struct efi_simple_text_output_protocol *std_err;
 	struct efi_runtime_services *runtime;
 	struct efi_boot_services *boottime;
 	unsigned long nr_tables;
-	unsigned long tables;
+	struct efi_configuration_table *tables;
 };
 
+#define LOADED_IMAGE_GUID \
+	EFI_GUID(0x5b1b31a1, 0x9562, 0x11d2, \
+		 0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
+
 struct efi_loaded_image {
 	u32 revision;
 	void *parent_handle;
@@ -186,12 +240,60 @@ struct efi_loaded_image {
 	unsigned long unload;
 };
 
+#define DEVICE_PATH_GUID \
+	EFI_GUID(0x09576e91, 0x6d3f, 0x11d2, \
+		 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b )
+
+#define DEVICE_PATH_TYPE_END			0x7f
+#  define DEVICE_PATH_SUB_TYPE_END		0xff
+
 struct efi_device_path {
 	u8 type;
 	u8 sub_type;
 	u16 length;
 };
 
+#define DEVICE_PATH_TYPE_MEDIA_DEVICE		0x04
+#  define DEVICE_PATH_SUB_TYPE_FILE_PATH	0x04
+
+struct efi_device_path_file_path {
+	struct efi_device_path dp;
+	u16 str[16];
+};
+
+#define BLOCK_IO_GUID \
+	EFI_GUID(0x964e5b21, 0x6459, 0x11d2, \
+		 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
+
+struct efi_block_io_media
+{
+	u32 media_id;
+	char removable_media;
+	char media_present;
+	char logical_partition;
+	char read_only;
+	char write_caching;
+	u8 pad[3];
+	u32 block_size;
+	u32 io_align;
+	u8 pad2[4];
+	u64 last_block;
+};
+
+struct efi_block_io {
+	u64 revision;
+	struct efi_block_io_media *media;
+	efi_status_t (EFIAPI *reset)(struct efi_block_io *this,
+			char extended_verification);
+	efi_status_t (EFIAPI *read_blocks)(struct efi_block_io *this,
+			u32 media_id, u64 lba, unsigned long buffer_size,
+			void *buffer);
+	efi_status_t (EFIAPI *write_blocks)(struct efi_block_io *this,
+			u32 media_id, u64 lba, unsigned long buffer_size,
+			void *buffer);
+	efi_status_t (EFIAPI *flush_blocks)(struct efi_block_io *this);
+};
+
 struct simple_text_output_mode {
 	s32 max_mode;
 	s32 mode;
@@ -206,8 +308,9 @@ struct efi_simple_text_output_protocol {
 	efi_status_t (EFIAPI *output_string)(
 			struct efi_simple_text_output_protocol *this,
 			const unsigned short *str);
-	void *test_string;
-
+	efi_status_t (EFIAPI *test_string)(
+			struct efi_simple_text_output_protocol *this,
+			const unsigned short *str);
 	efi_status_t(EFIAPI *query_mode)(
 			struct efi_simple_text_output_protocol *this,
 			unsigned long mode_number, unsigned long *columns,
@@ -223,7 +326,9 @@ struct efi_simple_text_output_protocol {
 	efi_status_t(EFIAPI *set_cursor_position) (
 			struct efi_simple_text_output_protocol *this,
 			unsigned long column, unsigned long row);
-	efi_status_t(EFIAPI *enable_cursor)(void *, bool enable);
+	efi_status_t(EFIAPI *enable_cursor)(
+			struct efi_simple_text_output_protocol *this,
+			bool enable);
 	struct simple_text_output_mode *mode;
 };
 
@@ -241,4 +346,22 @@ struct efi_simple_input_interface {
 	void *wait_for_key;
 };
 
+#define CONSOLE_CONTROL_GUID \
+	EFI_GUID(0xf42f7782, 0x12e, 0x4c12, \
+		 0x99, 0x56, 0x49, 0xf9, 0x43, 0x4, 0xf7, 0x21)
+#define EFI_CONSOLE_MODE_TEXT	0
+#define EFI_CONSOLE_MODE_GFX	1
+
+struct efi_console_control_protocol
+{
+	efi_status_t (EFIAPI *get_mode)(
+			struct efi_console_control_protocol *this, int *mode,
+			char *uga_exists, char *std_in_locked);
+	efi_status_t (EFIAPI *set_mode)(
+			struct efi_console_control_protocol *this, int mode);
+	efi_status_t (EFIAPI *lock_std_in)(
+			struct efi_console_control_protocol *this,
+			uint16_t *password);
+};
+
 #endif
-- 
2.1.4

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

* [U-Boot] [PATCH 3/9] efi_loader: Add PE image loader
  2015-12-22 13:57 [U-Boot] [PATCH 0/9] EFI payload / application support Alexander Graf
  2015-12-22 13:57 ` [U-Boot] [PATCH 1/9] disk/part.c: Expose a list of available block drivers Alexander Graf
  2015-12-22 13:57 ` [U-Boot] [PATCH 2/9] include/efi_api.h: Add more detailed API definitions Alexander Graf
@ 2015-12-22 13:57 ` Alexander Graf
  2015-12-26 16:26   ` Leif Lindholm
  2015-12-22 13:57 ` [U-Boot] [PATCH 4/9] efi_loader: Add boot time services Alexander Graf
                   ` (9 subsequent siblings)
  12 siblings, 1 reply; 70+ messages in thread
From: Alexander Graf @ 2015-12-22 13:57 UTC (permalink / raw)
  To: u-boot

EFI uses the PE binary format for its application images. Add support to EFI PE
binaries as well as all necessary bits for the "EFI image loader" interfaces.

Signed-off-by: Alexander Graf <agraf@suse.de>
---
 include/efi_loader.h              |  37 +++++
 include/pe.h                      | 277 ++++++++++++++++++++++++++++++++++++++
 lib/efi_loader/efi_image_loader.c | 203 ++++++++++++++++++++++++++++
 3 files changed, 517 insertions(+)
 create mode 100644 include/efi_loader.h
 create mode 100644 include/pe.h
 create mode 100644 lib/efi_loader/efi_image_loader.c

diff --git a/include/efi_loader.h b/include/efi_loader.h
new file mode 100644
index 0000000..da82354
--- /dev/null
+++ b/include/efi_loader.h
@@ -0,0 +1,37 @@
+/*
+ *  EFI application loader
+ *
+ *  Copyright (c) 2015 Alexander Graf
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ *  SPDX-License-Identifier:     LGPL-2.1+
+ */
+
+#include <part_efi.h>
+#include <efi_api.h>
+#include <linux/list.h>
+
+extern const efi_guid_t efi_guid_device_path;
+extern const efi_guid_t efi_guid_loaded_image;
+
+efi_status_t efi_return_handle(void *handle,
+		efi_guid_t *protocol, void **protocol_interface,
+		void *agent_handle, void *controller_handle,
+		uint32_t attributes);
+void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info);
+
+#define EFI_LOADER_POOL_SIZE (128 * 1024 * 1024)
+void *efi_loader_alloc(uint64_t len);
diff --git a/include/pe.h b/include/pe.h
new file mode 100644
index 0000000..009b0c5
--- /dev/null
+++ b/include/pe.h
@@ -0,0 +1,277 @@
+/*
+ *  Portable Executable binary format structures
+ *
+ *  Copyright (c) 2015 Alexander Graf
+ *
+ *  Based on wine code
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ *  SPDX-License-Identifier:     LGPL-2.1+
+ */
+
+#ifndef _PE_H
+#define _PE_H
+
+typedef struct _IMAGE_DOS_HEADER {
+	uint16_t e_magic;      /* 00: MZ Header signature */
+	uint16_t e_cblp;       /* 02: Bytes on last page of file */
+	uint16_t e_cp;         /* 04: Pages in file */
+	uint16_t e_crlc;       /* 06: Relocations */
+	uint16_t e_cparhdr;    /* 08: Size of header in paragraphs */
+	uint16_t e_minalloc;   /* 0a: Minimum extra paragraphs needed */
+	uint16_t e_maxalloc;   /* 0c: Maximum extra paragraphs needed */
+	uint16_t e_ss;         /* 0e: Initial (relative) SS value */
+	uint16_t e_sp;         /* 10: Initial SP value */
+	uint16_t e_csum;       /* 12: Checksum */
+	uint16_t e_ip;         /* 14: Initial IP value */
+	uint16_t e_cs;         /* 16: Initial (relative) CS value */
+	uint16_t e_lfarlc;     /* 18: File address of relocation table */
+	uint16_t e_ovno;       /* 1a: Overlay number */
+	uint16_t e_res[4];     /* 1c: Reserved words */
+	uint16_t e_oemid;      /* 24: OEM identifier (for e_oeminfo) */
+	uint16_t e_oeminfo;    /* 26: OEM information; e_oemid specific */
+	uint16_t e_res2[10];   /* 28: Reserved words */
+	uint32_t e_lfanew;     /* 3c: Offset to extended header */
+} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
+
+#define IMAGE_DOS_SIGNATURE		0x5A4D     /* MZ   */
+#define IMAGE_NT_SIGNATURE		0x00004550 /* PE00 */
+
+#define IMAGE_FILE_MACHINE_ARM		0x01c0
+#define IMAGE_FILE_MACHINE_THUMB	0x01c2
+#define IMAGE_FILE_MACHINE_ARMNT	0x01c4
+#define IMAGE_FILE_MACHINE_AMD64	0x8664
+#define IMAGE_FILE_MACHINE_ARM64	0xaa64
+#define IMAGE_NT_OPTIONAL_HDR32_MAGIC	0x10b
+#define IMAGE_NT_OPTIONAL_HDR64_MAGIC	0x20b
+#define IMAGE_SUBSYSTEM_EFI_APPLICATION	10
+
+typedef struct _IMAGE_FILE_HEADER {
+	uint16_t  Machine;
+	uint16_t  NumberOfSections;
+	uint32_t TimeDateStamp;
+	uint32_t PointerToSymbolTable;
+	uint32_t NumberOfSymbols;
+	uint16_t  SizeOfOptionalHeader;
+	uint16_t  Characteristics;
+} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
+
+typedef struct _IMAGE_DATA_DIRECTORY {
+	uint32_t VirtualAddress;
+	uint32_t Size;
+} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
+
+#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
+
+typedef struct _IMAGE_OPTIONAL_HEADER64 {
+	uint16_t  Magic; /* 0x20b */
+	uint8_t MajorLinkerVersion;
+	uint8_t MinorLinkerVersion;
+	uint32_t SizeOfCode;
+	uint32_t SizeOfInitializedData;
+	uint32_t SizeOfUninitializedData;
+	uint32_t AddressOfEntryPoint;
+	uint32_t BaseOfCode;
+	uint64_t ImageBase;
+	uint32_t SectionAlignment;
+	uint32_t FileAlignment;
+	uint16_t MajorOperatingSystemVersion;
+	uint16_t MinorOperatingSystemVersion;
+	uint16_t MajorImageVersion;
+	uint16_t MinorImageVersion;
+	uint16_t MajorSubsystemVersion;
+	uint16_t MinorSubsystemVersion;
+	uint32_t Win32VersionValue;
+	uint32_t SizeOfImage;
+	uint32_t SizeOfHeaders;
+	uint32_t CheckSum;
+	uint16_t Subsystem;
+	uint16_t DllCharacteristics;
+	uint64_t SizeOfStackReserve;
+	uint64_t SizeOfStackCommit;
+	uint64_t SizeOfHeapReserve;
+	uint64_t SizeOfHeapCommit;
+	uint32_t LoaderFlags;
+	uint32_t NumberOfRvaAndSizes;
+	IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
+} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;
+
+typedef struct _IMAGE_NT_HEADERS64 {
+	uint32_t Signature;
+	IMAGE_FILE_HEADER FileHeader;
+	IMAGE_OPTIONAL_HEADER64 OptionalHeader;
+} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;
+
+typedef struct _IMAGE_OPTIONAL_HEADER {
+
+	/* Standard fields */
+
+	uint16_t  Magic; /* 0x10b or 0x107 */     /* 0x00 */
+	uint8_t  MajorLinkerVersion;
+	uint8_t  MinorLinkerVersion;
+	uint32_t SizeOfCode;
+	uint32_t SizeOfInitializedData;
+	uint32_t SizeOfUninitializedData;
+	uint32_t AddressOfEntryPoint;            /* 0x10 */
+	uint32_t BaseOfCode;
+	uint32_t BaseOfData;
+
+	/* NT additional fields */
+
+	uint32_t ImageBase;
+	uint32_t SectionAlignment;               /* 0x20 */
+	uint32_t FileAlignment;
+	uint16_t  MajorOperatingSystemVersion;
+	uint16_t  MinorOperatingSystemVersion;
+	uint16_t  MajorImageVersion;
+	uint16_t  MinorImageVersion;
+	uint16_t  MajorSubsystemVersion;          /* 0x30 */
+	uint16_t  MinorSubsystemVersion;
+	uint32_t Win32VersionValue;
+	uint32_t SizeOfImage;
+	uint32_t SizeOfHeaders;
+	uint32_t CheckSum;                       /* 0x40 */
+	uint16_t  Subsystem;
+	uint16_t  DllCharacteristics;
+	uint32_t SizeOfStackReserve;
+	uint32_t SizeOfStackCommit;
+	uint32_t SizeOfHeapReserve;              /* 0x50 */
+	uint32_t SizeOfHeapCommit;
+	uint32_t LoaderFlags;
+	uint32_t NumberOfRvaAndSizes;
+	IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; /* 0x60 */
+	/* 0xE0 */
+} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
+
+typedef struct _IMAGE_NT_HEADERS {
+	uint32_t Signature; /* "PE"\0\0 */       /* 0x00 */
+	IMAGE_FILE_HEADER FileHeader;         /* 0x04 */
+	IMAGE_OPTIONAL_HEADER32 OptionalHeader;       /* 0x18 */
+} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
+
+#define IMAGE_SIZEOF_SHORT_NAME 8
+
+typedef struct _IMAGE_SECTION_HEADER {
+	uint8_t	Name[IMAGE_SIZEOF_SHORT_NAME];
+	union {
+		uint32_t PhysicalAddress;
+		uint32_t VirtualSize;
+	} Misc;
+	uint32_t VirtualAddress;
+	uint32_t SizeOfRawData;
+	uint32_t PointerToRawData;
+	uint32_t PointerToRelocations;
+	uint32_t PointerToLinenumbers;
+	uint16_t	NumberOfRelocations;
+	uint16_t	NumberOfLinenumbers;
+	uint32_t Characteristics;
+} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
+
+#define IMAGE_DIRECTORY_ENTRY_BASERELOC         5
+
+typedef struct _IMAGE_BASE_RELOCATION
+{
+        uint32_t VirtualAddress;
+        uint32_t SizeOfBlock;
+        /* WORD TypeOffset[1]; */
+} IMAGE_BASE_RELOCATION,*PIMAGE_BASE_RELOCATION;
+
+typedef struct _IMAGE_RELOCATION
+{
+	union {
+		uint32_t   VirtualAddress;
+		uint32_t   RelocCount;
+	} DUMMYUNIONNAME;
+	uint32_t   SymbolTableIndex;
+	uint16_t	Type;
+} IMAGE_RELOCATION, *PIMAGE_RELOCATION;
+
+#define IMAGE_SIZEOF_RELOCATION 10
+
+/* generic relocation types */
+#define IMAGE_REL_BASED_ABSOLUTE                0
+#define IMAGE_REL_BASED_HIGH                    1
+#define IMAGE_REL_BASED_LOW                     2
+#define IMAGE_REL_BASED_HIGHLOW                 3
+#define IMAGE_REL_BASED_HIGHADJ                 4
+#define IMAGE_REL_BASED_MIPS_JMPADDR            5
+#define IMAGE_REL_BASED_ARM_MOV32A              5 /* yes, 5 too */
+#define IMAGE_REL_BASED_ARM_MOV32               5 /* yes, 5 too */
+#define IMAGE_REL_BASED_SECTION                 6
+#define IMAGE_REL_BASED_REL                     7
+#define IMAGE_REL_BASED_ARM_MOV32T              7 /* yes, 7 too */
+#define IMAGE_REL_BASED_THUMB_MOV32             7 /* yes, 7 too */
+#define IMAGE_REL_BASED_MIPS_JMPADDR16          9
+#define IMAGE_REL_BASED_IA64_IMM64              9 /* yes, 9 too */
+#define IMAGE_REL_BASED_DIR64                   10
+#define IMAGE_REL_BASED_HIGH3ADJ                11
+
+/* ARM relocation types */
+#define IMAGE_REL_ARM_ABSOLUTE          0x0000
+#define IMAGE_REL_ARM_ADDR              0x0001
+#define IMAGE_REL_ARM_ADDR32NB          0x0002
+#define IMAGE_REL_ARM_BRANCH24          0x0003
+#define IMAGE_REL_ARM_BRANCH11          0x0004
+#define IMAGE_REL_ARM_TOKEN             0x0005
+#define IMAGE_REL_ARM_GPREL12           0x0006
+#define IMAGE_REL_ARM_GPREL7            0x0007
+#define IMAGE_REL_ARM_BLX24             0x0008
+#define IMAGE_REL_ARM_BLX11             0x0009
+#define IMAGE_REL_ARM_SECTION           0x000E
+#define IMAGE_REL_ARM_SECREL            0x000F
+#define IMAGE_REL_ARM_MOV32A            0x0010
+#define IMAGE_REL_ARM_MOV32T            0x0011
+#define IMAGE_REL_ARM_BRANCH20T 0x0012
+#define IMAGE_REL_ARM_BRANCH24T 0x0014
+#define IMAGE_REL_ARM_BLX23T            0x0015
+
+/* ARM64 relocation types */
+#define IMAGE_REL_ARM64_ABSOLUTE        0x0000
+#define IMAGE_REL_ARM64_ADDR32          0x0001
+#define IMAGE_REL_ARM64_ADDR32NB        0x0002
+#define IMAGE_REL_ARM64_BRANCH26        0x0003
+#define IMAGE_REL_ARM64_PAGEBASE_REL21  0x0004
+#define IMAGE_REL_ARM64_REL21           0x0005
+#define IMAGE_REL_ARM64_PAGEOFFSET_12A  0x0006
+#define IMAGE_REL_ARM64_PAGEOFFSET_12L  0x0007
+#define IMAGE_REL_ARM64_SECREL          0x0008
+#define IMAGE_REL_ARM64_SECREL_LOW12A   0x0009
+#define IMAGE_REL_ARM64_SECREL_HIGH12A  0x000A
+#define IMAGE_REL_ARM64_SECREL_LOW12L   0x000B
+#define IMAGE_REL_ARM64_TOKEN           0x000C
+#define IMAGE_REL_ARM64_SECTION         0x000D
+#define IMAGE_REL_ARM64_ADDR64          0x000E
+
+/* AMD64 relocation types */
+#define IMAGE_REL_AMD64_ABSOLUTE        0x0000
+#define IMAGE_REL_AMD64_ADDR64          0x0001
+#define IMAGE_REL_AMD64_ADDR32          0x0002
+#define IMAGE_REL_AMD64_ADDR32NB        0x0003
+#define IMAGE_REL_AMD64_REL32           0x0004
+#define IMAGE_REL_AMD64_REL32_1         0x0005
+#define IMAGE_REL_AMD64_REL32_2         0x0006
+#define IMAGE_REL_AMD64_REL32_3         0x0007
+#define IMAGE_REL_AMD64_REL32_4         0x0008
+#define IMAGE_REL_AMD64_REL32_5         0x0009
+#define IMAGE_REL_AMD64_SECTION         0x000A
+#define IMAGE_REL_AMD64_SECREL          0x000B
+#define IMAGE_REL_AMD64_SECREL7         0x000C
+#define IMAGE_REL_AMD64_TOKEN           0x000D
+#define IMAGE_REL_AMD64_SREL32          0x000E
+#define IMAGE_REL_AMD64_PAIR            0x000F
+#define IMAGE_REL_AMD64_SSPAN32         0x0010
+
+#endif /* _PE_H */
diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c
new file mode 100644
index 0000000..688e177
--- /dev/null
+++ b/lib/efi_loader/efi_image_loader.c
@@ -0,0 +1,203 @@
+/*
+ *  EFI image loader
+ *
+ *  based partly on wine code
+ *
+ *  Copyright (c) 2015 Alexander Graf
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ *  SPDX-License-Identifier:     LGPL-2.1+
+ */
+
+#include <common.h>
+#include <pe.h>
+#include <efi_loader.h>
+#include <asm/global_data.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define ROUND_UP(val, round) ((val + (round - 1)) & ~(round - 1))
+#define MB (1024 * 1024)
+
+const efi_guid_t efi_guid_device_path = DEVICE_PATH_GUID;
+const efi_guid_t efi_guid_loaded_image = LOADED_IMAGE_GUID;
+
+efi_status_t efi_return_handle(void *handle, efi_guid_t *protocol,
+			void **protocol_interface, void *agent_handle,
+			void *controller_handle, uint32_t attributes)
+{
+	*protocol_interface = handle;
+	return EFI_SUCCESS;
+}
+
+/*
+ * EFI payloads potentially want to load pretty big images into memory,
+ * so our small malloc region isn't enough for them. However, they usually
+ * don't need a smart allocator either.
+ *
+ * So instead give them a really dumb one. We just reserve EFI_LOADER_POOL_SIZE
+ * bytes from 16MB below the malloc region start to give the stack some space.
+ * Then every allocation gets a 4k aligned chunk from it. We never free.
+ */
+void *efi_loader_alloc(uint64_t len)
+{
+	static unsigned long loader_pool;
+	void *r;
+
+	if (!loader_pool) {
+		loader_pool = gd->relocaddr - TOTAL_MALLOC_LEN -
+			      EFI_LOADER_POOL_SIZE - (16 * MB);
+	}
+
+	len = ROUND_UP(len, 4096);
+	/* Out of memory */
+	if ((loader_pool + len) >= (gd->relocaddr - TOTAL_MALLOC_LEN))
+		return NULL;
+
+	r = (void *)loader_pool;
+	loader_pool += len;
+
+	return r;
+}
+
+/*
+ * This function loads all sections from a PE binary into a newly reserved
+ * piece of memory. On successful load it then returns the entry point for
+ * the binary. Otherwise NULL.
+ */
+void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info)
+{
+	IMAGE_NT_HEADERS32 *nt;
+	IMAGE_DOS_HEADER *dos;
+	IMAGE_SECTION_HEADER *sections;
+	int num_sections;
+	void *efi_reloc;
+	int i;
+	const uint16_t *relocs;
+	const IMAGE_BASE_RELOCATION *rel;
+	const IMAGE_BASE_RELOCATION *end;
+	unsigned long rel_size;
+	int rel_idx = IMAGE_DIRECTORY_ENTRY_BASERELOC;
+	void *entry;
+	uint64_t image_size;
+	unsigned long virt_size = 0;
+
+	dos = efi;
+	if (dos->e_magic != IMAGE_DOS_SIGNATURE) {
+		printf("%s: Invalid DOS Signature\n", __func__);
+		return NULL;
+	}
+
+	nt = (void *) ((char *)efi + dos->e_lfanew);
+	if (nt->Signature != IMAGE_NT_SIGNATURE) {
+		printf("%s: Invalid NT Signature\n", __func__);
+		return NULL;
+	}
+
+	/* Calculate upper virtual address boundary */
+	num_sections = nt->FileHeader.NumberOfSections;
+	sections = (void *)&nt->OptionalHeader +
+			    nt->FileHeader.SizeOfOptionalHeader;
+
+	for (i = num_sections - 1; i >= 0; i--) {
+		IMAGE_SECTION_HEADER *sec = &sections[i];
+		virt_size = max_t(unsigned long, virt_size,
+				  sec->VirtualAddress + sec->Misc.VirtualSize);
+	}
+
+	/* Read 32/64bit specific header bits */
+	if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
+		IMAGE_NT_HEADERS64 *nt64 = (void *)nt;
+		IMAGE_OPTIONAL_HEADER64 *opt = &nt64->OptionalHeader;
+		image_size = opt->SizeOfImage;
+		efi_reloc = efi_loader_alloc(virt_size);
+		if (!efi_reloc) {
+			printf("%s: Could not allocate %ld bytes\n",
+				__func__, virt_size);
+			return NULL;
+		}
+		entry = efi_reloc + opt->AddressOfEntryPoint;
+		rel_size = opt->DataDirectory[rel_idx].Size;
+		rel = efi_reloc + opt->DataDirectory[rel_idx].VirtualAddress;
+	} else {
+		IMAGE_OPTIONAL_HEADER32 *opt = &nt->OptionalHeader;
+		image_size = opt->SizeOfImage;
+		efi_reloc = efi_loader_alloc(virt_size);
+		if (!efi_reloc) {
+			printf("%s: Could not allocate %ld bytes\n",
+				__func__, virt_size);
+			return NULL;
+		}
+		entry = efi_reloc + opt->AddressOfEntryPoint;
+		rel_size = opt->DataDirectory[rel_idx].Size;
+		rel = efi_reloc + opt->DataDirectory[rel_idx].VirtualAddress;
+	}
+
+	/* Load sections into RAM */
+	for (i = num_sections - 1; i >= 0; i--) {
+		IMAGE_SECTION_HEADER *sec = &sections[i];
+		memset(efi_reloc + sec->VirtualAddress, 0,
+		       sec->Misc.VirtualSize);
+		memcpy(efi_reloc + sec->VirtualAddress,
+		       efi + sec->PointerToRawData,
+		       sec->SizeOfRawData);
+	}
+
+
+	/* Run through relocations */
+	end = (const IMAGE_BASE_RELOCATION *)((const char *)rel + rel_size);
+
+	while (rel < end - 1 && rel->SizeOfBlock) {
+		relocs = (const uint16_t *)(rel + 1);
+		i = (rel->SizeOfBlock - sizeof(*rel)) / sizeof(uint16_t);
+		while (i--) {
+			uint16_t offset = (*relocs & 0xfff) + rel->VirtualAddress;
+			int type = *relocs >> 12;
+			unsigned long delta = (unsigned long)efi_reloc;
+			uint64_t *x64 = efi_reloc + offset;
+			uint32_t *x32 = efi_reloc + offset;
+			uint16_t *x16 = efi_reloc + offset;
+
+			switch (type) {
+			case IMAGE_REL_BASED_ABSOLUTE:
+				break;
+			case IMAGE_REL_BASED_HIGH:
+				*x16 += ((uint32_t)delta) >> 16;
+				break;
+			case IMAGE_REL_BASED_LOW:
+				*x16 += (uint16_t)delta;
+				break;
+			case IMAGE_REL_BASED_HIGHLOW:
+				*x32 += (uint32_t)delta;
+				break;
+			case IMAGE_REL_BASED_DIR64:
+				*x64 += (uint64_t)delta;
+				break;
+			default:
+				printf("Unknown Relocation off %x type %x\n",
+				       offset, type);
+			}
+			relocs++;
+		}
+		rel = (const IMAGE_BASE_RELOCATION *)relocs;
+	}
+
+	/* Populate the loaded image interface bits */
+	loaded_image_info->image_base = efi;
+	loaded_image_info->image_size = image_size;
+
+	return entry;
+}
-- 
2.1.4

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

* [U-Boot] [PATCH 4/9] efi_loader: Add boot time services
  2015-12-22 13:57 [U-Boot] [PATCH 0/9] EFI payload / application support Alexander Graf
                   ` (2 preceding siblings ...)
  2015-12-22 13:57 ` [U-Boot] [PATCH 3/9] efi_loader: Add PE image loader Alexander Graf
@ 2015-12-22 13:57 ` Alexander Graf
  2015-12-22 14:15   ` Andreas Färber
  2015-12-26 18:09   ` Leif Lindholm
  2015-12-22 13:57 ` [U-Boot] [PATCH 5/9] efi_loader: Add console interface Alexander Graf
                   ` (8 subsequent siblings)
  12 siblings, 2 replies; 70+ messages in thread
From: Alexander Graf @ 2015-12-22 13:57 UTC (permalink / raw)
  To: u-boot

When an EFI application runs, it has access to a few descriptor and callback
tables to instruct the EFI compliant firmware to do things for it. The bulk
of those interfaces are "boot time services". They handle all object management,
and memory allocation.

This patch adds support for the boot time services and also exposes a system
table, which is the point of entry descriptor table for EFI payloads.

Signed-off-by: Alexander Graf <agraf@suse.de>
---
 include/efi_loader.h          |  41 +++
 lib/efi_loader/efi_boottime.c | 838 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 879 insertions(+)
 create mode 100644 lib/efi_loader/efi_boottime.c

diff --git a/include/efi_loader.h b/include/efi_loader.h
index da82354..ed7c389 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -24,14 +24,55 @@
 #include <efi_api.h>
 #include <linux/list.h>
 
+/* #define DEBUG_EFI */
+
+#ifdef DEBUG_EFI
+#define EFI_ENTRY(format, ...) do { \
+	efi_restore_gd(); \
+	printf("EFI: Entry %s(" format ")\n", __func__, ##__VA_ARGS__); \
+	} while(0)
+#else
+#define EFI_ENTRY(format, ...) do { \
+	efi_restore_gd(); \
+	} while(0)
+#endif
+
+#define EFI_EXIT(ret) efi_exit_func(ret);
+
+extern struct efi_system_table systab;
+
 extern const efi_guid_t efi_guid_device_path;
 extern const efi_guid_t efi_guid_loaded_image;
 
+struct efi_class_map {
+	const efi_guid_t *guid;
+	const void *interface;
+};
+
+struct efi_handler {
+	const efi_guid_t *guid;
+	efi_status_t (EFIAPI *open)(void *handle,
+			efi_guid_t *protocol, void **protocol_interface,
+			void *agent_handle, void *controller_handle,
+			uint32_t attributes);
+};
+
+struct efi_object {
+	struct list_head link;
+	struct efi_handler protocols[4];
+	void *handle;
+};
+extern struct list_head efi_obj_list;
+
 efi_status_t efi_return_handle(void *handle,
 		efi_guid_t *protocol, void **protocol_interface,
 		void *agent_handle, void *controller_handle,
 		uint32_t attributes);
+void efi_timer_check(void);
 void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info);
+void efi_save_gd(void);
+void efi_restore_gd(void);
+efi_status_t efi_exit_func(efi_status_t ret);
 
 #define EFI_LOADER_POOL_SIZE (128 * 1024 * 1024)
 void *efi_loader_alloc(uint64_t len);
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
new file mode 100644
index 0000000..ed95962
--- /dev/null
+++ b/lib/efi_loader/efi_boottime.c
@@ -0,0 +1,838 @@
+/*
+ *  EFI application boot time services
+ *
+ *  Copyright (c) 2015 Alexander Graf
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ *  SPDX-License-Identifier:     LGPL-2.1+
+ */
+
+#define DEBUG_EFI
+
+#include <common.h>
+#include <efi_loader.h>
+#include <malloc.h>
+#include <asm/global_data.h>
+#include <libfdt_env.h>
+#include <u-boot/crc.h>
+#include <bootm.h>
+#include <inttypes.h>
+#include <watchdog.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * EFI can pass arbitrary additional "tables" containing vendor specific
+ * information to the payload. One such table is the FDT table which contains
+ * a pointer to a flattened device tree blob.
+ *
+ * In most cases we want to pass an FDT to the payload, so reserve one slot of
+ * config table space for it. The pointer gets populated by do_bootefi_exec().
+ */
+static struct efi_configuration_table efi_conf_table[] = {
+	{
+		.guid = EFI_FDT_GUID,
+	},
+};
+
+/*
+ * The "gd" pointer lives in a register on ARM and AArch64 that we declare
+ * fixed when compiling U-Boot. However, the payload does now know about that
+ * restriction so we need to manually swap its and our view of that register on
+ * EFI callback entry/exit.
+ */
+static volatile void *efi_gd, *app_gd;
+
+/* Called from do_bootefi_exec() */
+void efi_save_gd(void)
+{
+	efi_gd = gd;
+}
+
+/* Called on every callback entry */
+void efi_restore_gd(void)
+{
+	if (gd != efi_gd)
+		app_gd = gd;
+	gd = efi_gd;
+}
+
+/* Called on every callback exit */
+efi_status_t efi_exit_func(efi_status_t ret)
+{
+	gd = app_gd;
+	return ret;
+}
+
+static efi_status_t efi_unsupported(const char *funcname)
+{
+#ifdef DEBUG_EFI
+	printf("EFI: App called into unimplemented function %s\n", funcname);
+#endif
+	return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+static unsigned long efi_raise_tpl(unsigned long new_tpl)
+{
+	EFI_ENTRY("0x%lx", new_tpl);
+	return EFI_EXIT(efi_unsupported(__func__));
+}
+
+static void efi_restore_tpl(unsigned long old_tpl)
+{
+	EFI_ENTRY("0x%lx", old_tpl);
+	EFI_EXIT(efi_unsupported(__func__));
+}
+
+static void *efi_alloc(uint64_t len, int memory_type)
+{
+	switch (memory_type) {
+	case EFI_LOADER_DATA:
+		return efi_loader_alloc(len);
+	default:
+		return malloc(len);
+	}
+}
+
+static efi_status_t efi_allocate_pages(int type, int memory_type,
+				       unsigned long pages, uint64_t *memory)
+{
+	u64 len = pages << 12;
+	efi_status_t r = EFI_SUCCESS;
+
+	EFI_ENTRY("%d, %d, 0x%lx, %p", type, memory_type, pages, memory);
+
+	switch (type) {
+	case 0:
+		/* Any page means we can go to efi_alloc */
+		*memory = (unsigned long)efi_alloc(len, memory_type);
+		break;
+	case 1:
+		/* Max address */
+		if (gd->relocaddr < *memory) {
+			*memory = (unsigned long)efi_alloc(len, memory_type);
+			break;
+		}
+		r = EFI_UNSUPPORTED;
+		break;
+	case 2:
+		/* Exact address, grant it. The addr is already in *memory. */
+		break;
+	default:
+		r = EFI_UNSUPPORTED;
+		break;
+	}
+
+	return EFI_EXIT(r);
+}
+
+static efi_status_t efi_free_pages(uint64_t memory, unsigned long pages)
+{
+	/* We don't free, let's cross our fingers we have plenty RAM */
+	EFI_ENTRY("%"PRIx64", 0x%lx", memory, pages);
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+/*
+ * Returns the EFI memory map. In our case, this looks pretty simple:
+ *
+ *  ____________________________    TOM
+ * |                            |
+ * |    Second half of U-Boot   |
+ * |____________________________|   &__efi_runtime_stop
+ * |                            |
+ * |    EFI Runtime Services    |
+ * |____________________________|   &__efi_runtime_start
+ * |                            |
+ * |    First half of U-Boot    |
+ * |____________________________|   start of EFI loader allocation space
+ * |                            |
+ * |          Free RAM          |
+ * |____________________________|   CONFIG_SYS_SDRAM_BASE
+ *
+ * All pointers are extended to live on a 4k boundary. After exiting the boot
+ * services, only the EFI Runtime Services chunk of memory stays alive.
+ */
+static efi_status_t efi_get_memory_map(unsigned long *memory_map_size,
+			       struct efi_mem_desc *memory_map,
+			       unsigned long *map_key,
+			       unsigned long *descriptor_size,
+			       uint32_t *descriptor_version)
+{
+	struct efi_mem_desc efi_memory_map[] = {
+		{
+			/* RAM before U-Boot */
+			.type = EFI_CONVENTIONAL_MEMORY,
+			.attribute = 1 << EFI_MEMORY_WB_SHIFT,
+		},
+		{
+			/* First half of U-Boot */
+			.type = EFI_LOADER_DATA,
+			.attribute = 1 << EFI_MEMORY_WB_SHIFT,
+		},
+		{
+			/* EFI Runtime Services */
+			.type = EFI_RUNTIME_SERVICES_CODE,
+			.attribute = 1 << EFI_MEMORY_WB_SHIFT,
+		},
+		{
+			/* Second half of U-Boot */
+			.type = EFI_LOADER_DATA,
+			.attribute = 1 << EFI_MEMORY_WB_SHIFT,
+		},
+	};
+	ulong runtime_start, runtime_end, runtime_len_pages, runtime_len;
+
+	EFI_ENTRY("%p, %p, %p, %p, %p", memory_map_size, memory_map, map_key,
+		  descriptor_size, descriptor_version);
+
+	runtime_start = (ulong)&__efi_runtime_start & ~0xfffULL;
+	runtime_end = ((ulong)&__efi_runtime_stop + 0xfff) & ~0xfffULL;
+	runtime_len_pages = (runtime_end - runtime_start) >> 12;
+	runtime_len = runtime_len_pages << 12;
+
+	/* Fill in where normal RAM is (up to U-Boot) */
+	efi_memory_map[0].num_pages = gd->relocaddr >> 12;
+#ifdef CONFIG_SYS_SDRAM_BASE
+	efi_memory_map[0].physical_start = CONFIG_SYS_SDRAM_BASE;
+	efi_memory_map[0].virtual_start = CONFIG_SYS_SDRAM_BASE;
+	efi_memory_map[0].num_pages -= CONFIG_SYS_SDRAM_BASE >> 12;
+#endif
+
+	/* Remove U-Boot from the available RAM view */
+	efi_memory_map[0].num_pages -= gd->mon_len >> 12;
+
+	/* Remove the malloc area from the available RAM view */
+	efi_memory_map[0].num_pages -= TOTAL_MALLOC_LEN >> 12;
+
+	/* Give us some space for the stack */
+	efi_memory_map[0].num_pages -= (16 * 1024 * 1024) >> 12;
+
+	/* Reserve the EFI loader pool */
+	efi_memory_map[0].num_pages -= EFI_LOADER_POOL_SIZE >> 12;
+
+	/* Cut out the runtime services */
+	efi_memory_map[2].physical_start = runtime_start;
+	efi_memory_map[2].virtual_start = efi_memory_map[2].physical_start;
+	efi_memory_map[2].num_pages = runtime_len_pages;
+
+	/* Allocate the rest to U-Boot */
+	efi_memory_map[1].physical_start = efi_memory_map[0].physical_start +
+					   (efi_memory_map[0].num_pages << 12);
+	efi_memory_map[1].virtual_start = efi_memory_map[1].physical_start;
+	efi_memory_map[1].num_pages = (runtime_start -
+				       efi_memory_map[1].physical_start) >> 12;
+
+	efi_memory_map[3].physical_start = runtime_start + runtime_len;
+	efi_memory_map[3].virtual_start = efi_memory_map[3].physical_start;
+	efi_memory_map[3].num_pages = (gd->ram_top -
+				       efi_memory_map[3].physical_start) >> 12;
+
+	*memory_map_size = sizeof(efi_memory_map);
+
+	if (descriptor_size)
+		*descriptor_size = sizeof(struct efi_mem_desc);
+
+	if (*memory_map_size < sizeof(efi_memory_map)) {
+		return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
+	}
+
+	if (memory_map)
+		memcpy(memory_map, efi_memory_map, sizeof(efi_memory_map));
+
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t efi_allocate_pool(int pool_type, unsigned long size, void **buffer)
+{
+	return efi_allocate_pages(0, pool_type, (size + 0xfff) >> 12, (void*)buffer);
+}
+
+static efi_status_t efi_free_pool(void *buffer)
+{
+	return efi_free_pages((ulong)buffer, 0);
+}
+
+/*
+ * Our event capabilities are very limited. Only support a single
+ * event to exist, so we don't need to maintain lists.
+ */
+static struct {
+	enum efi_event_type type;
+	u32 trigger_type;
+	u32 trigger_time;
+	u64 trigger_next;
+	unsigned long notify_tpl;
+	void (*notify_function) (void *event, void *context);
+	void *notify_context;
+} efi_event;
+
+static efi_status_t efi_create_event(enum efi_event_type type, ulong notify_tpl,
+			     void (*notify_function) (void *event,
+						      void *context),
+			     void *notify_context, void **event)
+{
+	EFI_ENTRY("%d, 0x%lx, %p, %p", type, notify_tpl, notify_function,
+		  notify_context);
+	if (efi_event.notify_function) {
+		/* We only support one event at a time */
+		return EFI_EXIT(EFI_UNSUPPORTED);
+	}
+
+	efi_event.type = type;
+	efi_event.notify_tpl = notify_tpl;
+	efi_event.notify_function = notify_function;
+	efi_event.notify_context = notify_context;
+	*event = &efi_event;
+
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+/*
+ * Our timers have to work without interrupts, so we check whenever keyboard
+ * input or disk accesses happen if enough time elapsed for it to fire.
+ */
+void efi_timer_check(void)
+{
+	u64 now = timer_get_us();
+
+	if (now >= efi_event.trigger_next) {
+		/* Triggering! */
+		if (efi_event.trigger_type == EFI_TIMER_PERIODIC)
+			efi_event.trigger_next += efi_event.trigger_time / 10;
+		efi_event.notify_function(&efi_event, efi_event.notify_context);
+	}
+
+	WATCHDOG_RESET();
+}
+
+static efi_status_t efi_set_timer(void *event, int type, uint64_t trigger_time)
+{
+	/* We don't have 64bit division available everywhere, so limit timer
+	 * distances to 32bit bits. */
+	u32 trigger32 = trigger_time;
+
+	EFI_ENTRY("%p, %d, %"PRIx64, event, type, trigger_time);
+	if (event != &efi_event) {
+		/* We only support one event at a time */
+		return EFI_EXIT(EFI_UNSUPPORTED);
+	}
+
+	switch (type) {
+	case EFI_TIMER_STOP:
+		efi_event.trigger_next = -1ULL;
+		break;
+	case EFI_TIMER_PERIODIC:
+	case EFI_TIMER_RELATIVE:
+		efi_event.trigger_next = timer_get_us() + (trigger32 / 10);
+		break;
+	default:
+		return EFI_EXIT(EFI_UNSUPPORTED);
+	}
+	efi_event.trigger_type = type;
+	efi_event.trigger_time = trigger_time;
+
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t efi_wait_for_event(unsigned long num_events, void *event,
+			       unsigned long *index)
+{
+	EFI_ENTRY("%ld, %p, %p", num_events, event, index);
+	return EFI_EXIT(efi_unsupported(__func__));
+}
+
+static efi_status_t efi_signal_event(void *event)
+{
+	EFI_ENTRY("%p", event);
+	return EFI_EXIT(efi_unsupported(__func__));
+}
+
+static efi_status_t efi_close_event(void *event)
+{
+	EFI_ENTRY("%p", event);
+	return EFI_EXIT(efi_unsupported(__func__));
+}
+
+static efi_status_t efi_check_event(void *event)
+{
+	EFI_ENTRY("%p", event);
+	return EFI_EXIT(efi_unsupported(__func__));
+}
+
+static efi_status_t efi_install_protocol_interface(void **handle,
+					   efi_guid_t *protocol,
+					   int protocol_interface_type,
+					   void *protocol_interface)
+{
+	EFI_ENTRY("%p, %p, %d, %p", handle, protocol, protocol_interface_type,
+		  protocol_interface);
+	return EFI_EXIT(efi_unsupported(__func__));
+}
+static efi_status_t efi_reinstall_protocol_interface(void *handle,
+					     efi_guid_t *protocol,
+					     void *old_interface,
+					     void *new_interface)
+{
+	EFI_ENTRY("%p, %p, %p, %p", handle, protocol, old_interface,
+		  new_interface);
+	return EFI_EXIT(efi_unsupported(__func__));
+}
+
+static efi_status_t efi_uninstall_protocol_interface(void *handle,
+					     efi_guid_t *protocol,
+					     void *protocol_interface)
+{
+	EFI_ENTRY("%p, %p, %p", handle, protocol, protocol_interface);
+	return EFI_EXIT(efi_unsupported(__func__));
+}
+
+static efi_status_t efi_register_protocol_notify(efi_guid_t *protocol,
+					 void *event, void **registration)
+{
+	EFI_ENTRY("%p, %p, %p", protocol, event, registration);
+	return EFI_EXIT(efi_unsupported(__func__));
+}
+
+static int efi_search(enum efi_locate_search_type search_type,
+			efi_guid_t *protocol, void *search_key,
+			struct efi_object *efiobj)
+{
+	int i;
+
+	switch (search_type) {
+	case all_handles:
+		return 0;
+	case by_register_notify:
+		return -1;
+	case by_protocol:
+		for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) {
+			const efi_guid_t *guid = efiobj->protocols[i].guid;
+			if (guid && !memcmp(guid, protocol, sizeof(efi_guid_t)))
+				return 0;
+		}
+		return -1;
+	}
+
+	return -1;
+}
+
+static efi_status_t efi_locate_handle(enum efi_locate_search_type search_type,
+			efi_guid_t *protocol, void *search_key,
+			unsigned long *buffer_size, efi_handle_t *buffer)
+{
+	struct list_head *lhandle;
+	unsigned long size = 0;
+
+	EFI_ENTRY("%d, %p, %p, %p, %p", search_type, protocol, search_key,
+		  buffer_size, buffer);
+
+	/* Count how much space we need */
+	list_for_each(lhandle, &efi_obj_list) {
+		struct efi_object *efiobj;
+		efiobj = list_entry(lhandle, struct efi_object, link);
+		if (!efi_search(search_type, protocol, search_key, efiobj)) {
+			size += sizeof(void*);
+		}
+	}
+
+	if (*buffer_size < size) {
+		*buffer_size = size;
+		return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
+	}
+
+	/* Then fill the array */
+	list_for_each(lhandle, &efi_obj_list) {
+		struct efi_object *efiobj;
+		efiobj = list_entry(lhandle, struct efi_object, link);
+		if (!efi_search(search_type, protocol, search_key, efiobj)) {
+			*(buffer++) = efiobj->handle;
+		}
+	}
+
+	*buffer_size = size;
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t efi_locate_device_path(efi_guid_t *protocol,
+				   struct efi_device_path **device_path,
+				   efi_handle_t *device)
+{
+	EFI_ENTRY("%p, %p, %p", protocol, device_path, device);
+	return EFI_EXIT(efi_unsupported(__func__));
+}
+
+static efi_status_t efi_install_configuration_table(efi_guid_t *guid, void *table)
+{
+	EFI_ENTRY("%p, %p", guid, table);
+	/* Only allow overriding of the FDT */
+	if (memcmp(guid, &efi_conf_table[0].guid, sizeof(efi_guid_t)))
+		return EFI_EXIT(EFI_UNSUPPORTED);
+
+	efi_conf_table[0].table = table;
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t efi_load_image(bool boot_policy, efi_handle_t parent_image,
+			   struct efi_device_path *file_path,
+			   void *source_buffer, unsigned long source_size,
+			   efi_handle_t *image_handle)
+{
+	static struct efi_object loaded_image_info_obj = {
+		.protocols = {
+			{
+				.guid = &efi_guid_loaded_image,
+				.open = &efi_return_handle,
+			},
+		},
+	};
+	struct efi_loaded_image *info;
+	struct efi_object *obj;
+
+	EFI_ENTRY("%d, %p, %p, %p, %ld, %p", boot_policy, parent_image,
+		  file_path, source_buffer, source_size, image_handle);
+	info = malloc(sizeof(*info));
+	obj = malloc(sizeof(loaded_image_info_obj));
+	memset(info, 0, sizeof(*info));
+	memcpy(obj, &loaded_image_info_obj, sizeof(loaded_image_info_obj));
+	obj->handle = info;
+	info->file_path = file_path;
+	info->reserved = efi_load_pe(source_buffer, info);
+	if (!info->reserved) {
+		free(info);
+		free(obj);
+		return EFI_EXIT(EFI_UNSUPPORTED);
+	}
+
+	*image_handle = info;
+	list_add_tail(&obj->link, &efi_obj_list);
+
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t efi_start_image(efi_handle_t image_handle,
+			    unsigned long *exit_data_size,
+			    s16 **exit_data)
+{
+	ulong (*entry)(void *image_handle, struct efi_system_table *st);
+	struct efi_loaded_image *info = image_handle;
+
+	EFI_ENTRY("%p, %p, %p", image_handle, exit_data_size, exit_data);
+	entry = info->reserved;
+
+	/* call the image! */
+	entry(image_handle, &systab);
+
+	/* Should usually never get here */
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t efi_exit(void *image_handle, long exit_status,
+		     unsigned long exit_data_size,
+		     uint16_t *exit_data)
+{
+	EFI_ENTRY("%p, %ld, %ld, %p", image_handle, exit_status,
+		  exit_data_size, exit_data);
+	return EFI_EXIT(efi_unsupported(__func__));
+}
+
+static struct efi_object *efi_search_obj(void *handle)
+{
+	struct list_head *lhandle;
+
+	list_for_each(lhandle, &efi_obj_list) {
+		struct efi_object *efiobj;
+		efiobj = list_entry(lhandle, struct efi_object, link);
+		if (efiobj->handle == handle)
+			return efiobj;
+	}
+
+	return NULL;
+}
+
+static efi_status_t efi_unload_image(void *image_handle)
+{
+	struct efi_object *efiobj;
+
+	EFI_ENTRY("%p", image_handle);
+	efiobj = efi_search_obj(image_handle);
+	if (efiobj)
+		list_del(&efiobj->link);
+
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t efi_exit_boot_services(void *image_handle,
+				   unsigned long map_key)
+{
+	EFI_ENTRY("%p, %ld", image_handle, map_key);
+
+	/* This stops all lingering devices */
+	bootm_disable_interrupts();
+
+	/* Give the payload some time to boot */
+	WATCHDOG_RESET();
+
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t efi_get_next_monotonic_count(uint64_t *count)
+{
+	EFI_ENTRY("%p", count);
+	*count = timer_get_us();
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t efi_stall(unsigned long microseconds)
+{
+	EFI_ENTRY("%ld", microseconds);
+	udelay(microseconds);
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t efi_set_watchdog_timer(unsigned long timeout,
+				   uint64_t watchdog_code,
+				   unsigned long data_size,
+				   uint16_t *watchdog_data)
+{
+	EFI_ENTRY("%ld, 0x%"PRIx64", %ld, %p", timeout, watchdog_code,
+		  data_size, watchdog_data);
+	return EFI_EXIT(efi_unsupported(__func__));
+}
+
+static efi_status_t efi_connect_controller(efi_handle_t controller_handle,
+				   efi_handle_t *driver_image_handle,
+				   struct efi_device_path *remain_device_path,
+				   bool recursive)
+{
+	EFI_ENTRY("%p, %p, %p, %d", controller_handle, driver_image_handle,
+		  remain_device_path, recursive);
+	return EFI_EXIT(efi_unsupported(__func__));
+}
+
+static efi_status_t efi_disconnect_controller(void *controller_handle,
+				      void *driver_image_handle,
+				      void *child_handle)
+{
+	EFI_ENTRY("%p, %p, %p", controller_handle, driver_image_handle,
+		  child_handle);
+	return EFI_EXIT(efi_unsupported(__func__));
+}
+
+static efi_status_t efi_close_protocol(void *handle, efi_guid_t *protocol,
+			       void *agent_handle, void *controller_handle)
+{
+	EFI_ENTRY("%p, %p, %p, %p", handle, protocol, agent_handle,
+		  controller_handle);
+	return EFI_EXIT(efi_unsupported(__func__));
+}
+
+static efi_status_t efi_open_protocol_information(efi_handle_t handle,
+					  efi_guid_t *protocol,
+					  struct efi_open_protocol_info_entry **entry_buffer,
+					  unsigned long *entry_count)
+{
+	EFI_ENTRY("%p, %p, %p, %p", handle, protocol, entry_buffer,
+		  entry_count);
+	return EFI_EXIT(efi_unsupported(__func__));
+}
+
+static efi_status_t efi_protocols_per_handle(void *handle,
+				     efi_guid_t ***protocol_buffer,
+				     unsigned long *protocol_buffer_count)
+{
+	EFI_ENTRY("%p, %p, %p", handle, protocol_buffer,
+		  protocol_buffer_count);
+	return EFI_EXIT(efi_unsupported(__func__));
+}
+
+static efi_status_t efi_locate_handle_buffer(
+			enum efi_locate_search_type search_type,
+			efi_guid_t *protocol, void *search_key,
+			unsigned long *no_handles, efi_handle_t **buffer)
+{
+	EFI_ENTRY("%d, %p, %p, %p, %p", search_type, protocol, search_key,
+		  no_handles, buffer);
+	return EFI_EXIT(efi_unsupported(__func__));
+}
+
+static struct efi_class_map efi_class_maps[] = {
+	{
+		.guid = &efi_guid_console_control,
+		.interface = &efi_console_control
+	},
+};
+
+static efi_status_t efi_locate_protocol(efi_guid_t *protocol, void *registration,
+			        void **protocol_interface)
+{
+	efi_status_t r = EFI_UNSUPPORTED;
+	int i;
+
+	EFI_ENTRY("%p, %p, %p", protocol, registration, protocol_interface);
+	for (i = 0; i < ARRAY_SIZE(efi_class_maps); i++) {
+		struct efi_class_map *curmap = &efi_class_maps[i];
+		if (!memcmp(protocol, curmap->guid, sizeof(efi_guid_t))) {
+			*protocol_interface = (void*)curmap->interface;
+			return EFI_EXIT(EFI_SUCCESS);
+		}
+	}
+
+	return EFI_EXIT(r);
+}
+
+static efi_status_t efi_install_multiple_protocol_interfaces(void **handle, ...)
+{
+	EFI_ENTRY("%p", handle);
+	return EFI_EXIT(efi_unsupported(__func__));
+}
+
+static efi_status_t efi_uninstall_multiple_protocol_interfaces(void *handle, ...)
+{
+	EFI_ENTRY("%p", handle);
+	return EFI_EXIT(efi_unsupported(__func__));
+}
+
+static efi_status_t efi_calculate_crc32(void *data, unsigned long data_size,
+				uint32_t *crc32_p)
+{
+	EFI_ENTRY("%p, %ld", data, data_size);
+	*crc32_p = crc32(0, data, data_size);
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+static void efi_copy_mem(void *destination, void *source, unsigned long length)
+{
+	EFI_ENTRY("%p, %p, %ld", destination, source, length);
+	memcpy(destination, source, length);
+}
+
+static void efi_set_mem(void *buffer, unsigned long size, uint8_t value)
+{
+	EFI_ENTRY("%p, %ld, 0x%x", buffer, size, value);
+	memset(buffer, value, size);
+}
+
+static efi_status_t efi_open_protocol(void *handle, efi_guid_t *protocol,
+			       void **protocol_interface, void *agent_handle,
+			       void *controller_handle, uint32_t attributes)
+{
+	struct list_head *lhandle;
+	int i;
+	efi_status_t r = EFI_UNSUPPORTED;
+
+	EFI_ENTRY("%p, %p, %p, %p, %p, 0x%x", handle, protocol,
+		  protocol_interface, agent_handle, controller_handle,
+		  attributes);
+	list_for_each(lhandle, &efi_obj_list) {
+		struct efi_object *efiobj;
+		efiobj = list_entry(lhandle, struct efi_object, link);
+
+		if (efiobj->handle != handle)
+			continue;
+
+		for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) {
+			struct efi_handler *handler = &efiobj->protocols[i];
+			const efi_guid_t *hprotocol = handler->guid;
+			if (!hprotocol)
+				break;
+			if (!memcmp(hprotocol, protocol, sizeof(efi_guid_t))) {
+				r = handler->open(handle, protocol,
+				    protocol_interface, agent_handle,
+				    controller_handle, attributes);
+				goto out;
+			}
+		}
+	}
+
+out:
+	return EFI_EXIT(r);
+}
+
+static efi_status_t efi_handle_protocol(void *handle, efi_guid_t *protocol,
+				void **protocol_interface)
+{
+	EFI_ENTRY("%p, %p, %p", handle, protocol, protocol_interface);
+	return efi_open_protocol(handle, protocol, protocol_interface,
+				 NULL, NULL, 0);
+}
+
+static const struct efi_boot_services efi_boot_services = {
+	.hdr = {
+		.headersize = sizeof(struct efi_table_hdr),
+	},
+	.raise_tpl = efi_raise_tpl,
+	.restore_tpl = efi_restore_tpl,
+	.allocate_pages = efi_allocate_pages,
+	.free_pages = efi_free_pages,
+	.get_memory_map = efi_get_memory_map,
+	.allocate_pool = efi_allocate_pool,
+	.free_pool = efi_free_pool,
+	.create_event = efi_create_event,
+	.set_timer = efi_set_timer,
+	.wait_for_event = efi_wait_for_event,
+	.signal_event = efi_signal_event,
+	.close_event = efi_close_event,
+	.check_event = efi_check_event,
+	.install_protocol_interface = efi_install_protocol_interface,
+	.reinstall_protocol_interface = efi_reinstall_protocol_interface,
+	.uninstall_protocol_interface = efi_uninstall_protocol_interface,
+	.handle_protocol = efi_handle_protocol,
+	.reserved = NULL,
+	.register_protocol_notify = efi_register_protocol_notify,
+	.locate_handle = efi_locate_handle,
+	.locate_device_path = efi_locate_device_path,
+	.install_configuration_table = efi_install_configuration_table,
+	.load_image = efi_load_image,
+	.start_image = efi_start_image,
+	.exit = (void*)efi_exit,
+	.unload_image = efi_unload_image,
+	.exit_boot_services = efi_exit_boot_services,
+	.get_next_monotonic_count = efi_get_next_monotonic_count,
+	.stall = efi_stall,
+	.set_watchdog_timer = efi_set_watchdog_timer,
+	.connect_controller = efi_connect_controller,
+	.disconnect_controller = efi_disconnect_controller,
+	.open_protocol = efi_open_protocol,
+	.close_protocol = efi_close_protocol,
+	.open_protocol_information = efi_open_protocol_information,
+	.protocols_per_handle = efi_protocols_per_handle,
+	.locate_handle_buffer = efi_locate_handle_buffer,
+	.locate_protocol = efi_locate_protocol,
+	.install_multiple_protocol_interfaces = efi_install_multiple_protocol_interfaces,
+	.uninstall_multiple_protocol_interfaces = efi_uninstall_multiple_protocol_interfaces,
+	.calculate_crc32 = efi_calculate_crc32,
+	.copy_mem = efi_copy_mem,
+	.set_mem = efi_set_mem,
+};
+
+
+static uint16_t firmware_vendor[] = { 'U','-','b','o','o','t',0 };
+struct efi_system_table systab = {
+	.hdr = {
+		.signature = EFI_SYSTEM_TABLE_SIGNATURE,
+		.revision = 0x20000, /* 2.0 */
+		.headersize = sizeof(struct efi_table_hdr),
+	},
+	.fw_vendor = (long)firmware_vendor,
+	.con_in = (void*)&efi_con_in,
+	.con_out = (void*)&efi_con_out,
+	.std_err = (void*)&efi_con_out,
+	.runtime = (void*)&efi_runtime_services,
+	.boottime = (void*)&efi_boot_services,
+	.nr_tables = 1,
+	.tables = (void*)efi_conf_table,
+};
-- 
2.1.4

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

* [U-Boot] [PATCH 5/9] efi_loader: Add console interface
  2015-12-22 13:57 [U-Boot] [PATCH 0/9] EFI payload / application support Alexander Graf
                   ` (3 preceding siblings ...)
  2015-12-22 13:57 ` [U-Boot] [PATCH 4/9] efi_loader: Add boot time services Alexander Graf
@ 2015-12-22 13:57 ` Alexander Graf
  2015-12-22 13:57 ` [U-Boot] [PATCH 6/9] efi_loader: Add runtime services Alexander Graf
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 70+ messages in thread
From: Alexander Graf @ 2015-12-22 13:57 UTC (permalink / raw)
  To: u-boot

One of the basic EFI interfaces is the console interface. Using it an EFI
application can interface with the user. This patch implements an EFI console
interface using getc() and putc().

Today, we only implement text based consoles. We also convert the EFI Unicode
characters to UTF-8 on the fly, hoping that everyone managed to jump on the
train by now.

Signed-off-by: Alexander Graf <agraf@suse.de>
---
 include/efi_loader.h         |   5 +
 lib/efi_loader/efi_console.c | 371 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 376 insertions(+)
 create mode 100644 lib/efi_loader/efi_console.c

diff --git a/include/efi_loader.h b/include/efi_loader.h
index ed7c389..7fb2106 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -41,6 +41,11 @@
 
 extern struct efi_system_table systab;
 
+extern const struct efi_simple_text_output_protocol efi_con_out;
+extern const struct efi_simple_input_interface efi_con_in;
+extern const struct efi_console_control_protocol efi_console_control;
+
+extern const efi_guid_t efi_guid_console_control;
 extern const efi_guid_t efi_guid_device_path;
 extern const efi_guid_t efi_guid_loaded_image;
 
diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
new file mode 100644
index 0000000..45112e7
--- /dev/null
+++ b/lib/efi_loader/efi_console.c
@@ -0,0 +1,371 @@
+/*
+ *  EFI application console interface
+ *
+ *  Copyright (c) 2015 Alexander Graf
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ *  SPDX-License-Identifier:     LGPL-2.1+
+ */
+
+#include <common.h>
+#include <efi_loader.h>
+
+/* If we can't determine the console size, default to 80x24 */
+static int console_columns = 80;
+static int console_rows = 24;
+static bool console_size_queried;
+
+const efi_guid_t efi_guid_console_control = CONSOLE_CONTROL_GUID;
+
+#define cESC '\x1b'
+#define ESC "\x1b"
+
+static efi_status_t efi_cin_get_mode(struct efi_console_control_protocol *this,
+				     int *mode, char *uga_exists,
+				     char *std_in_locked)
+{
+	EFI_ENTRY("%p, %p, %p, %p", this, mode, uga_exists, std_in_locked);
+
+	if (mode)
+		*mode = EFI_CONSOLE_MODE_TEXT;
+	if (uga_exists)
+		*uga_exists = 0;
+	if (std_in_locked)
+		*std_in_locked = 0;
+
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t efi_cin_set_mode(struct efi_console_control_protocol *this,
+				     int mode)
+{
+	EFI_ENTRY("%p, %d", this, mode);
+	return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+static efi_status_t efi_cin_lock_std_in(struct efi_console_control_protocol *this,
+					uint16_t *password)
+{
+	EFI_ENTRY("%p, %p", this, password);
+	return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+const struct efi_console_control_protocol efi_console_control = {
+	.get_mode = efi_cin_get_mode,
+	.set_mode = efi_cin_set_mode,
+	.lock_std_in = efi_cin_lock_std_in,
+};
+
+static struct simple_text_output_mode efi_con_mode = {
+	.max_mode = 0,
+	.mode = 0,
+	.attribute = 0,
+	.cursor_column = 0,
+	.cursor_row = 0,
+	.cursor_visible = 1,
+};
+
+static int term_read_reply(int *n, int maxnum, char end_char)
+{
+	char c;
+	int i = 0;
+
+	c = getc();
+	if (c != cESC)
+		return -1;
+	c = getc();
+	if (c != '[')
+		return -1;
+
+	n[0] = 0;
+	while (1) {
+		c = getc();
+		if (c == ';') {
+			i++;
+			if (i >= maxnum)
+				return -1;
+			n[i] = 0;
+			continue;
+		} else if (c == end_char) {
+			break;
+		} else if (c > '9' || c < '0') {
+			return -1;
+		}
+
+		/* Read one more decimal position */
+		n[i] *= 10;
+		n[i] += c - '0';
+	}
+
+	return 0;
+}
+
+static efi_status_t efi_cout_reset(struct efi_simple_text_output_protocol *this,
+				   char extended_verification)
+{
+	EFI_ENTRY("%p, %d", this, extended_verification);
+	return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+static void print_unicode_in_utf8(u16 c)
+{
+	char utf8[4] = { 0 };
+	char *b = utf8;
+
+	if (c < 0x80) {
+		*(b++) = c;
+	} else if (c < 0x800) {
+		*(b++) = 192 + c / 64;
+		*(b++) = 128 + c % 64;
+	} else {
+		*(b++) = 224 + c / 4096;
+		*(b++) = 128 + c / 64 % 64;
+		*(b++) = 128 + c % 64;
+	}
+
+	puts(utf8);
+}
+
+static efi_status_t efi_cout_output_string(
+			struct efi_simple_text_output_protocol *this,
+			const unsigned short *string)
+{
+	u16 ch;
+
+	EFI_ENTRY("%p, %p", this, string);
+	for (;(ch = *string); string++) {
+		print_unicode_in_utf8(ch);
+		efi_con_mode.cursor_column++;
+		if (ch == '\n') {
+			efi_con_mode.cursor_column = 1;
+			efi_con_mode.cursor_row++;
+		} else if (efi_con_mode.cursor_column > console_columns) {
+			efi_con_mode.cursor_column = 1;
+			efi_con_mode.cursor_row++;
+		}
+		if (efi_con_mode.cursor_row > console_rows) {
+			efi_con_mode.cursor_row = console_rows;
+		}
+	}
+
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t efi_cout_test_string(
+			struct efi_simple_text_output_protocol *this,
+			const unsigned short *string)
+{
+	EFI_ENTRY("%p, %p", this, string);
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t efi_cout_query_mode(
+			struct efi_simple_text_output_protocol *this,
+			unsigned long mode_number, unsigned long *columns,
+			unsigned long *rows)
+{
+	EFI_ENTRY("%p, %ld, %p, %p", this, mode_number, columns, rows);
+
+	if (!console_size_queried) {
+		/* Ask the terminal about its size */
+		int n[3];
+		u64 timeout;
+
+		console_size_queried = true;
+
+		/* Empty input buffer */
+		while (tstc())
+			getc();
+
+		printf(ESC"[18t");
+
+		/* Check if we have a terminal that understands */
+		timeout = timer_get_us() + 1000000;
+		while (!tstc())
+			if (timer_get_us() > timeout)
+				goto out;
+
+		/* Read {depth,rows,cols} */
+		if (term_read_reply(n, 3, 't')) {
+			goto out;
+		}
+
+		console_columns = n[2];
+		console_rows = n[1];
+	}
+
+out:
+	if (columns)
+		*columns = console_columns;
+	if (rows)
+		*rows = console_rows;
+
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t efi_cout_set_mode(
+			struct efi_simple_text_output_protocol *this,
+			unsigned long mode_number)
+{
+	EFI_ENTRY("%p, %ld", this, mode_number);
+
+	/* We only support text output for now */
+	if (mode_number == EFI_CONSOLE_MODE_TEXT)
+		return EFI_EXIT(EFI_SUCCESS);
+
+	return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+static efi_status_t efi_cout_set_attribute(
+			struct efi_simple_text_output_protocol *this,
+			unsigned long attribute)
+{
+	EFI_ENTRY("%p, %lx", this, attribute);
+
+	/* Just ignore attributes (colors) for now */
+	return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+static efi_status_t efi_cout_clear_screen(
+			struct efi_simple_text_output_protocol *this)
+{
+	EFI_ENTRY("%p", this);
+
+	printf(ESC"[2J");
+
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t efi_cout_set_cursor_position(
+			struct efi_simple_text_output_protocol *this,
+			unsigned long column, unsigned long row)
+{
+	EFI_ENTRY("%p, %ld, %ld", this, column, row);
+
+	printf(ESC"[%d;%df", (int)row, (int)column);
+	efi_con_mode.cursor_column = column;
+	efi_con_mode.cursor_row = row;
+
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t efi_cout_enable_cursor(
+			struct efi_simple_text_output_protocol *this,
+			bool enable)
+{
+	EFI_ENTRY("%p, %d", this, enable);
+
+	printf(ESC"[?25%c", enable ? 'h' : 'l');
+
+	return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+const struct efi_simple_text_output_protocol efi_con_out = {
+	.reset = efi_cout_reset,
+	.output_string = efi_cout_output_string,
+	.test_string = efi_cout_test_string,
+	.query_mode = efi_cout_query_mode,
+	.set_mode = efi_cout_set_mode,
+	.set_attribute = efi_cout_set_attribute,
+	.clear_screen = efi_cout_clear_screen,
+	.set_cursor_position = efi_cout_set_cursor_position,
+	.enable_cursor = efi_cout_enable_cursor,
+	.mode = (void*)&efi_con_mode,
+};
+
+static efi_status_t efi_cin_reset(struct efi_simple_input_interface *this,
+				  bool extended_verification)
+{
+	EFI_ENTRY("%p, %d", this, extended_verification);
+	return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+static efi_status_t efi_cin_read_key_stroke(
+			struct efi_simple_input_interface *this,
+			struct efi_input_key *key)
+{
+	struct efi_input_key pressed_key = {
+		.scan_code = 0,
+		.unicode_char = 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);
+	}
+
+	ch = getc();
+	if (ch == cESC) {
+		/* Escape Sequence */
+		ch = getc();
+		switch (ch) {
+		case cESC: /* ESC */
+			pressed_key.scan_code = 23;
+			break;
+		case 'O': /* F1 - F4 */
+			pressed_key.scan_code = getc() - 'P' + 11;
+			break;
+		case 'a'...'z':
+			ch = ch - 'a';
+			break;
+		case '[':
+			ch = getc();
+			switch (ch) {
+			case 'A'...'D': /* up, down right, left */
+				pressed_key.scan_code = ch - 'A' + 1;
+				break;
+			case 'F': /* End */
+				pressed_key.scan_code = 6;
+				break;
+			case 'H': /* Home */
+				pressed_key.scan_code = 5;
+				break;
+			case '1': /* F5 - F8 */
+				pressed_key.scan_code = getc() - '0' + 11;
+				getc();
+				break;
+			case '2': /* F9 - F12 */
+				pressed_key.scan_code = getc() - '0' + 19;
+				getc();
+				break;
+			case '3': /* DEL */
+				pressed_key.scan_code = 8;
+				getc();
+				break;
+			}
+			break;
+		}
+	} else if (ch == 0x7f) {
+		/* Backspace */
+		ch = 0x08;
+	}
+	pressed_key.unicode_char = ch;
+	*key = pressed_key;
+
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+const struct efi_simple_input_interface efi_con_in = {
+	.reset = efi_cin_reset,
+	.read_key_stroke = efi_cin_read_key_stroke,
+	.wait_for_key = NULL,
+};
-- 
2.1.4

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

* [U-Boot] [PATCH 6/9] efi_loader: Add runtime services
  2015-12-22 13:57 [U-Boot] [PATCH 0/9] EFI payload / application support Alexander Graf
                   ` (4 preceding siblings ...)
  2015-12-22 13:57 ` [U-Boot] [PATCH 5/9] efi_loader: Add console interface Alexander Graf
@ 2015-12-22 13:57 ` Alexander Graf
  2015-12-26 18:33   ` Leif Lindholm
  2015-12-22 13:57 ` [U-Boot] [PATCH 7/9] efi_loader: Add disk interfaces Alexander Graf
                   ` (6 subsequent siblings)
  12 siblings, 1 reply; 70+ messages in thread
From: Alexander Graf @ 2015-12-22 13:57 UTC (permalink / raw)
  To: u-boot

After booting has finished, EFI allows firmware to still interact with the OS
using the "runtime services". These callbacks live in a separate address space,
since they are available long after U-Boot has been overwritten by the OS.

However, since U-Boot has no notion of RTS, we just create an extremely minimal
RTS stub that just declares all functions as unsupported. We could in the future
map U-boot environment variables to EFI variables here.

Signed-off-by: Alexander Graf <agraf@suse.de>
---
 arch/arm/cpu/armv8/u-boot.lds |  8 ++++++
 arch/arm/cpu/u-boot.lds       | 13 ++++++++++
 arch/arm/lib/sections.c       |  2 ++
 include/efi_loader.h          |  3 +++
 lib/efi_loader/efi_runtime.c  | 59 +++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 85 insertions(+)
 create mode 100644 lib/efi_loader/efi_runtime.c

diff --git a/arch/arm/cpu/armv8/u-boot.lds b/arch/arm/cpu/armv8/u-boot.lds
index 4c12222..7c5b032 100644
--- a/arch/arm/cpu/armv8/u-boot.lds
+++ b/arch/arm/cpu/armv8/u-boot.lds
@@ -42,6 +42,14 @@ SECTIONS
 
 	. = ALIGN(8);
 
+	.efi_runtime : {
+                __efi_runtime_start = .;
+		*(efi_runtime)
+                __efi_runtime_stop = .;
+	}
+
+	. = ALIGN(8);
+
 	.image_copy_end :
 	{
 		*(.__image_copy_end)
diff --git a/arch/arm/cpu/u-boot.lds b/arch/arm/cpu/u-boot.lds
index d48a905..b5198d0 100644
--- a/arch/arm/cpu/u-boot.lds
+++ b/arch/arm/cpu/u-boot.lds
@@ -89,6 +89,19 @@ SECTIONS
 
 	. = ALIGN(4);
 
+	.__efi_runtime_start : {
+		*(.__efi_runtime_start)
+	}
+
+	.efi_runtime : {
+		*(efi_runtime)
+	}
+
+	.__efi_runtime_stop : {
+		*(.__efi_runtime_stop)
+	}
+	. = ALIGN(4);
+
 	.image_copy_end :
 	{
 		*(.__image_copy_end)
diff --git a/arch/arm/lib/sections.c b/arch/arm/lib/sections.c
index a1205c3..21b3066 100644
--- a/arch/arm/lib/sections.c
+++ b/arch/arm/lib/sections.c
@@ -27,4 +27,6 @@ char __rel_dyn_start[0] __attribute__((section(".__rel_dyn_start")));
 char __rel_dyn_end[0] __attribute__((section(".__rel_dyn_end")));
 char __secure_start[0] __attribute__((section(".__secure_start")));
 char __secure_end[0] __attribute__((section(".__secure_end")));
+char __efi_runtime_start[0] __attribute__((section(".__efi_runtime_start")));
+char __efi_runtime_stop[0] __attribute__((section(".__efi_runtime_stop")));
 char _end[0] __attribute__((section(".__end")));
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 7fb2106..af1c88f 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -39,6 +39,7 @@
 
 #define EFI_EXIT(ret) efi_exit_func(ret);
 
+extern const struct efi_runtime_services efi_runtime_services;
 extern struct efi_system_table systab;
 
 extern const struct efi_simple_text_output_protocol efi_con_out;
@@ -49,6 +50,8 @@ extern const efi_guid_t efi_guid_console_control;
 extern const efi_guid_t efi_guid_device_path;
 extern const efi_guid_t efi_guid_loaded_image;
 
+extern unsigned int __efi_runtime_start, __efi_runtime_stop;
+
 struct efi_class_map {
 	const efi_guid_t *guid;
 	const void *interface;
diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c
new file mode 100644
index 0000000..214e1f5
--- /dev/null
+++ b/lib/efi_loader/efi_runtime.c
@@ -0,0 +1,59 @@
+/*
+ *  EFI application runtime services
+ *
+ *  Copyright (c) 2015 Alexander Graf
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ *  SPDX-License-Identifier:     LGPL-2.1+
+ */
+
+#include <common.h>
+#include <efi_loader.h>
+
+/*
+ * EFI Runtime code is still alive when U-Boot is long overwritten. To isolate
+ * this code from the rest, we put it into a special section.
+ *
+ *        !!WARNING!!
+ *
+ * This means that we can not rely on any code outside of this file at runtime.
+ * Please keep it fully self-contained.
+ */
+asm(".section efi_runtime,\"a\"");
+
+static efi_status_t efi_unimplemented(void)
+{
+	return EFI_UNSUPPORTED;
+}
+
+const struct efi_runtime_services efi_runtime_services = {
+	.hdr = {
+		.signature = EFI_RUNTIME_SERVICES_SIGNATURE,
+		.revision = EFI_RUNTIME_SERVICES_REVISION,
+		.headersize = sizeof(struct efi_table_hdr),
+	},
+	.get_time = (void *)&efi_unimplemented,
+	.set_time = (void *)&efi_unimplemented,
+	.get_wakeup_time = (void *)&efi_unimplemented,
+	.set_wakeup_time = (void *)&efi_unimplemented,
+	.set_virtual_address_map = (void *)&efi_unimplemented,
+	.convert_pointer = (void *)&efi_unimplemented,
+	.get_variable = (void *)&efi_unimplemented,
+	.get_next_variable = (void *)&efi_unimplemented,
+	.set_variable = (void *)&efi_unimplemented,
+	.get_next_high_mono_count = (void *)&efi_unimplemented,
+	.reset_system = (void *)&efi_unimplemented,
+};
-- 
2.1.4

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

* [U-Boot] [PATCH 7/9] efi_loader: Add disk interfaces
  2015-12-22 13:57 [U-Boot] [PATCH 0/9] EFI payload / application support Alexander Graf
                   ` (5 preceding siblings ...)
  2015-12-22 13:57 ` [U-Boot] [PATCH 6/9] efi_loader: Add runtime services Alexander Graf
@ 2015-12-22 13:57 ` Alexander Graf
  2016-01-15  1:37   ` Simon Glass
  2015-12-22 13:57 ` [U-Boot] [PATCH 8/9] efi_loader: Add "bootefi" command Alexander Graf
                   ` (5 subsequent siblings)
  12 siblings, 1 reply; 70+ messages in thread
From: Alexander Graf @ 2015-12-22 13:57 UTC (permalink / raw)
  To: u-boot

A EFI applications usually want to access storage devices to load data from.

This patch adds support for EFI disk interfaces. It loops through all block
storage interfaces known to U-Boot and creates an EFI object for each existing
one. EFI applications can then through these objects call U-Boot's read and
write functions.

Signed-off-by: Alexander Graf <agraf@suse.de>
---
 include/efi_loader.h      |   1 +
 lib/efi_loader/efi_disk.c | 227 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 228 insertions(+)
 create mode 100644 lib/efi_loader/efi_disk.c

diff --git a/include/efi_loader.h b/include/efi_loader.h
index af1c88f..7e821e5 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -72,6 +72,7 @@ struct efi_object {
 };
 extern struct list_head efi_obj_list;
 
+int efi_disk_register(void);
 efi_status_t efi_return_handle(void *handle,
 		efi_guid_t *protocol, void **protocol_interface,
 		void *agent_handle, void *controller_handle,
diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
new file mode 100644
index 0000000..1804e3e
--- /dev/null
+++ b/lib/efi_loader/efi_disk.c
@@ -0,0 +1,227 @@
+/*
+ *  EFI application disk support
+ *
+ *  Copyright (c) 2015 Alexander Graf
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ *  SPDX-License-Identifier:     LGPL-2.1+
+ */
+
+#include <common.h>
+#include <efi_loader.h>
+#include <part.h>
+#include <malloc.h>
+#include <inttypes.h>
+
+static const efi_guid_t efi_block_io_guid = BLOCK_IO_GUID;
+
+struct efi_disk_obj {
+	struct efi_object parent;
+	struct efi_block_io ops;
+	const char *ifname;
+	int dev_index;
+	struct efi_block_io_media media;
+	struct efi_device_path_file_path *dp;
+};
+
+static void ascii2unicode(u16 *unicode, char *ascii)
+{
+	while (*ascii)
+		*(unicode++) = *(ascii++);
+}
+
+static efi_status_t efi_disk_open_block(void *handle, efi_guid_t *protocol,
+			void **protocol_interface, void *agent_handle,
+			void *controller_handle, uint32_t attributes)
+{
+	struct efi_disk_obj *diskobj = handle;
+
+	*protocol_interface = &diskobj->ops;
+
+	return EFI_SUCCESS;
+}
+
+static efi_status_t efi_disk_open_dp(void *handle, efi_guid_t *protocol,
+			void **protocol_interface, void *agent_handle,
+			void *controller_handle, uint32_t attributes)
+{
+	struct efi_disk_obj *diskobj = handle;
+
+	*protocol_interface = diskobj->dp;
+
+	return EFI_SUCCESS;
+}
+
+static efi_status_t efi_disk_reset(struct efi_block_io *this,
+			char extended_verification)
+{
+	EFI_ENTRY("%p, %x", this, extended_verification);
+	return EFI_EXIT(EFI_DEVICE_ERROR);
+}
+
+enum efi_disk_direction {
+	EFI_DISK_READ,
+	EFI_DISK_WRITE,
+};
+
+static efi_status_t efi_disk_rw_blocks(struct efi_block_io *this,
+			u32 media_id, u64 lba, unsigned long buffer_size,
+			void *buffer, enum efi_disk_direction direction)
+{
+	struct efi_disk_obj *diskobj;
+	struct block_dev_desc *desc;
+	int blksz;
+	int blocks;
+	unsigned long n;
+
+	EFI_ENTRY("%p, %x, %"PRIx64", %lx, %p", this, media_id, lba,
+		  buffer_size, buffer);
+
+	diskobj = container_of(this, struct efi_disk_obj, ops);
+	if (!(desc = get_dev(diskobj->ifname, diskobj->dev_index)))
+		return EFI_EXIT(EFI_DEVICE_ERROR);
+	blksz = desc->blksz;
+	blocks = buffer_size / blksz;
+
+#ifdef DEBUG_EFI
+	printf("EFI: %s:%d blocks=%x lba=%"PRIx64" blksz=%x dir=%d\n", __func__,
+	       __LINE__, blocks, lba, blksz, direction);
+#endif
+
+	/* We only support full block access */
+	if (buffer_size & (blksz - 1))
+		return EFI_EXIT(EFI_DEVICE_ERROR);
+
+	if (direction == EFI_DISK_READ)
+		n = desc->block_read(desc->dev, lba, blocks, buffer);
+	else
+		n = desc->block_write(desc->dev, lba, blocks, buffer);
+
+	/* We don't do interrupts, so check for timers cooperatively */
+	efi_timer_check();
+
+#ifdef DEBUG_EFI
+	printf("EFI: %s:%d n=%lx blocks=%x\n", __func__, __LINE__, n, blocks);
+#endif
+	if (n != blocks)
+		return EFI_EXIT(EFI_DEVICE_ERROR);
+
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t efi_disk_read_blocks(struct efi_block_io *this,
+			u32 media_id, u64 lba, unsigned long buffer_size,
+			void *buffer)
+{
+	return efi_disk_rw_blocks(this, media_id, lba, buffer_size, buffer,
+				  EFI_DISK_READ);
+}
+
+static efi_status_t efi_disk_write_blocks(struct efi_block_io *this,
+			u32 media_id, u64 lba, unsigned long buffer_size,
+			void *buffer)
+{
+	return efi_disk_rw_blocks(this, media_id, lba, buffer_size, buffer,
+				  EFI_DISK_WRITE);
+}
+
+static efi_status_t efi_disk_flush_blocks(struct efi_block_io *this)
+{
+	/* We always write synchronously */
+	return EFI_SUCCESS;
+}
+
+static const struct efi_block_io block_io_disk_template = {
+	.reset = &efi_disk_reset,
+	.read_blocks = &efi_disk_read_blocks,
+	.write_blocks = &efi_disk_write_blocks,
+	.flush_blocks = &efi_disk_flush_blocks,
+};
+
+/*
+ * U-Boot doesn't have a list of all online disk devices. So when running our
+ * EFI payload, we scan through all of the potentially available ones and
+ * store them in our object pool.
+ *
+ * This gets called from do_bootefi_exec().
+ */
+int efi_disk_register(void)
+{
+	const char **cur_drvr;
+	int i;
+	int disks = 0;
+
+	/* Search for all available disk devices */
+	for (cur_drvr = available_block_drvrs; *cur_drvr; cur_drvr++) {
+		printf("Scanning disks on %s...\n", *cur_drvr);
+		for (i = 0; i < 4; i++) {
+			block_dev_desc_t *desc;
+			struct efi_disk_obj *diskobj;
+			struct efi_device_path_file_path *dp;
+			int objlen = sizeof(*diskobj) + (sizeof(*dp) * 2);
+			char devname[16];
+
+			desc = get_dev(*cur_drvr, i);
+			if (!desc)
+				continue;
+
+			diskobj = malloc(objlen);
+			memset(diskobj, 0, objlen);
+
+			/* Fill in object data */
+
+			diskobj->parent.protocols[0].guid = &efi_block_io_guid;
+			diskobj->parent.protocols[0].open = efi_disk_open_block;
+			diskobj->parent.protocols[1].guid = &efi_guid_device_path;
+			diskobj->parent.protocols[1].open = efi_disk_open_dp;
+			diskobj->parent.handle = diskobj;
+			diskobj->ops = block_io_disk_template;
+			diskobj->ifname = *cur_drvr;
+			diskobj->dev_index = i;
+
+			/* Fill in EFI IO Media info (for read/write callbacks) */
+
+			diskobj->media.removable_media = desc->removable;
+			diskobj->media.media_present = 1;
+			diskobj->media.block_size = desc->blksz;
+			diskobj->media.io_align = desc->blksz;
+			diskobj->media.last_block = desc->lba;
+			diskobj->ops.media = &diskobj->media;
+
+			/* Fill in device path */
+
+			dp = (void*)&diskobj[1];
+			diskobj->dp = dp;
+			dp[0].dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
+			dp[0].dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH;
+			dp[0].dp.length = sizeof(*dp);
+			sprintf(devname, "%s%d", *cur_drvr, i);
+			ascii2unicode(dp[0].str, devname);
+
+			dp[1].dp.type = DEVICE_PATH_TYPE_END;
+			dp[1].dp.sub_type = DEVICE_PATH_SUB_TYPE_END;
+			dp[1].dp.length = sizeof(*dp);
+
+			/* Hook up to the device list */
+
+			list_add_tail(&diskobj->parent.link, &efi_obj_list);
+			disks++;
+		}
+	}
+	printf("Found %d disks\n", disks);
+
+	return 0;
+}
-- 
2.1.4

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

* [U-Boot] [PATCH 8/9] efi_loader: Add "bootefi" command
  2015-12-22 13:57 [U-Boot] [PATCH 0/9] EFI payload / application support Alexander Graf
                   ` (6 preceding siblings ...)
  2015-12-22 13:57 ` [U-Boot] [PATCH 7/9] efi_loader: Add disk interfaces Alexander Graf
@ 2015-12-22 13:57 ` Alexander Graf
  2015-12-24 11:15   ` Matwey V. Kornilov
  2015-12-22 13:57 ` [U-Boot] [PATCH 9/9] efi_loader: hook up in build environment Alexander Graf
                   ` (4 subsequent siblings)
  12 siblings, 1 reply; 70+ messages in thread
From: Alexander Graf @ 2015-12-22 13:57 UTC (permalink / raw)
  To: u-boot

In order to execute an EFI application, we need to bridge the gap between
U-Boot's notion of executing images and EFI's notion of doing the same.

The best path forward IMHO here is to stick completely to the way U-Boot
deals with payloads. You manually load them using whatever method to RAM
and then have a simple boot command to execute them. So in our case, you
would do

  # load mmc 0:1 $loadaddr grub.efi
  # bootefi $loadaddr

which then gets you into a grub shell. Fdt information known to U-boot
via the fdt addr command is also passed to the EFI payload.

Signed-off-by: Alexander Graf <agraf@suse.de>
---
 common/Makefile      |   1 +
 common/cmd_bootefi.c | 168 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 169 insertions(+)
 create mode 100644 common/cmd_bootefi.c

diff --git a/common/Makefile b/common/Makefile
index 2a1d9f8..a7a728a 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -67,6 +67,7 @@ obj-$(CONFIG_CMD_SOURCE) += cmd_source.o
 obj-$(CONFIG_CMD_BDI) += cmd_bdinfo.o
 obj-$(CONFIG_CMD_BEDBUG) += bedbug.o cmd_bedbug.o
 obj-$(CONFIG_CMD_BMP) += cmd_bmp.o
+obj-$(CONFIG_EFI_LOADER) += cmd_bootefi.o
 obj-$(CONFIG_CMD_BOOTMENU) += cmd_bootmenu.o
 obj-$(CONFIG_CMD_BOOTLDR) += cmd_bootldr.o
 obj-$(CONFIG_CMD_BOOTSTAGE) += cmd_bootstage.o
diff --git a/common/cmd_bootefi.c b/common/cmd_bootefi.c
new file mode 100644
index 0000000..8d872d0
--- /dev/null
+++ b/common/cmd_bootefi.c
@@ -0,0 +1,168 @@
+/*
+ *  EFI application loader
+ *
+ *  Copyright (c) 2015 Alexander Graf
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ *  SPDX-License-Identifier:     LGPL-2.1+
+ */
+
+#include <common.h>
+#include <command.h>
+#include <efi_loader.h>
+#include <libfdt_env.h>
+
+/* This list contains all the EFI objects our payload has access to */
+LIST_HEAD(efi_obj_list);
+
+/*
+ * When booting using the "bootefi" command, we don't know which
+ * physical device the file came from. So we create a pseudo-device
+ * called "bootefi" with the device path /bootefi.
+ *
+ * In addition to the originating device we also declare the file path
+ * of "bootefi" based loads to be /bootefi.
+ */
+static struct efi_device_path_file_path bootefi_dummy_path[] = {
+	{
+		.dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE,
+		.dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH,
+		.dp.length = sizeof(bootefi_dummy_path[0]),
+		.str = { 'b','o','o','t','e','f','i' },
+	}, {
+		.dp.type = DEVICE_PATH_TYPE_END,
+		.dp.sub_type = DEVICE_PATH_SUB_TYPE_END,
+		.dp.length = sizeof(bootefi_dummy_path[0]),
+	}
+};
+
+static efi_status_t bootefi_open_dp(void *handle, efi_guid_t *protocol,
+			void **protocol_interface, void *agent_handle,
+			void *controller_handle, uint32_t attributes)
+{
+	*protocol_interface = bootefi_dummy_path;
+	return EFI_SUCCESS;
+}
+
+/* The EFI loaded_image interface for the image executed via "bootefi" */
+static struct efi_loaded_image loaded_image_info = {
+	.device_handle = bootefi_dummy_path,
+	.file_path = bootefi_dummy_path,
+};
+
+/* The EFI object struct for the image executed via "bootefi" */
+static struct efi_object loaded_image_info_obj = {
+	.handle = &loaded_image_info,
+	.protocols = {
+		{
+			/* When asking for the loaded_image interface, just
+			 * return handle which points to loaded_image_info */
+			.guid = &efi_guid_loaded_image,
+			.open = &efi_return_handle,
+		},
+		{
+			/* When asking for the device path interface, return
+			 * bootefi_dummy_path */
+			.guid = &efi_guid_device_path,
+			.open = &bootefi_open_dp,
+		},
+	},
+};
+
+/* The EFI object struct for the device the "bootefi" image was loaded from */
+static struct efi_object bootefi_device_obj = {
+	.handle = bootefi_dummy_path,
+	.protocols = {
+		{
+			/* When asking for the device path interface, return
+			 * bootefi_dummy_path */
+			.guid = &efi_guid_device_path,
+			.open = &bootefi_open_dp,
+		}
+	},
+};
+
+/*
+ * Load an EFI payload into a newly allocated piece of memory, register all
+ * EFI objects it would want to access and jump to it.
+ */
+static unsigned long do_bootefi_exec(void *efi)
+{
+	ulong (*entry)(void *image_handle, struct efi_system_table *st);
+
+	/*
+	 * gd lives in a fixed register which may get clobbered while we execute
+	 * the payload. So save it here and restore it on every callback entry
+	 */
+	efi_save_gd();
+
+	/* Update system table to point to our currently loaded FDT */
+	systab.tables[0].table = working_fdt;
+
+	if (!working_fdt) {
+		printf("WARNING: No device tree loaded, expect boot to fail\n");
+		systab.nr_tables = 0;
+	}
+
+	/* Load the EFI payload */
+	entry = efi_load_pe(efi, &loaded_image_info);
+	if (!entry)
+		return -1;
+
+	/* Initialize and populate EFI object list */
+	INIT_LIST_HEAD(&efi_obj_list);
+	list_add_tail(&loaded_image_info_obj.link, &efi_obj_list);
+	list_add_tail(&bootefi_device_obj.link, &efi_obj_list);
+#ifdef CONFIG_PARTITIONS
+	efi_disk_register();
+#endif
+
+	/* Call our payload! */
+#ifdef DEBUG_EFI
+	printf("%s:%d Jumping to 0x%lx\n", __func__, __LINE__, (long)entry);
+#endif
+	return entry(&loaded_image_info, &systab);
+}
+
+
+/* Interpreter command to boot an arbitrary EFI image from memory */
+static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	char *saddr;
+	unsigned long addr;
+	int r = 0;
+
+	if (argc < 2)
+		return 1;
+	saddr = argv[1];
+
+	addr = simple_strtoul(saddr, NULL, 16);
+
+	printf("## Starting EFI application@0x%08lx ...\n", addr);
+	r = do_bootefi_exec((void *)addr);
+	printf("## Application terminated, r = %d\n", r);
+
+	if (r != 0)
+		r = 1;
+
+	return r;
+}
+
+U_BOOT_CMD(
+	bootefi, 2, 0, do_bootefi,
+	"Boot from an EFI image in memory",
+	"<image address>\n"
+);
-- 
2.1.4

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

* [U-Boot] [PATCH 9/9] efi_loader: hook up in build environment
  2015-12-22 13:57 [U-Boot] [PATCH 0/9] EFI payload / application support Alexander Graf
                   ` (7 preceding siblings ...)
  2015-12-22 13:57 ` [U-Boot] [PATCH 8/9] efi_loader: Add "bootefi" command Alexander Graf
@ 2015-12-22 13:57 ` Alexander Graf
  2015-12-22 18:28 ` [U-Boot] [PATCH 0/9] EFI payload / application support Matwey V. Kornilov
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 70+ messages in thread
From: Alexander Graf @ 2015-12-22 13:57 UTC (permalink / raw)
  To: u-boot

Now that we have all the bits and pieces ready for EFI payload loading
support, hook them up in Makefiles and KConfigs so that we can build.

Signed-off-by: Alexander Graf <agraf@suse.de>
---
 lib/Kconfig             |  1 +
 lib/Makefile            |  1 +
 lib/efi_loader/Kconfig  |  8 ++++++++
 lib/efi_loader/Makefile | 11 +++++++++++
 4 files changed, 21 insertions(+)
 create mode 100644 lib/efi_loader/Kconfig
 create mode 100644 lib/efi_loader/Makefile

diff --git a/lib/Kconfig b/lib/Kconfig
index 9d580e4..3efe075 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -138,5 +138,6 @@ config ERRNO_STR
 	  - if errno is negative - a pointer to errno related message
 
 source lib/efi/Kconfig
+source lib/efi_loader/Kconfig
 
 endmenu
diff --git a/lib/Makefile b/lib/Makefile
index dd36f25..3a9f304 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -8,6 +8,7 @@
 ifndef CONFIG_SPL_BUILD
 
 obj-$(CONFIG_EFI) += efi/
+obj-$(CONFIG_EFI_LOADER) += efi_loader/
 obj-$(CONFIG_RSA) += rsa/
 obj-$(CONFIG_LZMA) += lzma/
 obj-$(CONFIG_LZO) += lzo/
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
new file mode 100644
index 0000000..870f1f7
--- /dev/null
+++ b/lib/efi_loader/Kconfig
@@ -0,0 +1,8 @@
+config EFI_LOADER
+	bool "Support running EFI Applications in U-Boot"
+	depends on ARM64 ||?ARM
+	help
+	  Select this option if you want to run EFI applications (like grub2)
+	  on top of U-Boot. If this option is enabled, U-Boot will expose EFI
+	  interfaces to a loaded EFI application, enabling it to reuse U-Boot's
+	  device drivers.
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
new file mode 100644
index 0000000..1df595b
--- /dev/null
+++ b/lib/efi_loader/Makefile
@@ -0,0 +1,11 @@
+#
+# (C) Copyright 2015 Alexander Graf
+#
+#  SPDX-License-Identifier:     LGPL-2.1+
+#
+
+# This file only gets included with CONFIG_EFI_LOADER set, so all
+# object inclusion implicitly depends on it
+
+obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o
+obj-$(CONFIG_PARTITIONS) += efi_disk.o
-- 
2.1.4

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

* [U-Boot] [PATCH 4/9] efi_loader: Add boot time services
  2015-12-22 13:57 ` [U-Boot] [PATCH 4/9] efi_loader: Add boot time services Alexander Graf
@ 2015-12-22 14:15   ` Andreas Färber
  2015-12-22 14:31     ` Alexander Graf
  2015-12-26 18:09   ` Leif Lindholm
  1 sibling, 1 reply; 70+ messages in thread
From: Andreas Färber @ 2015-12-22 14:15 UTC (permalink / raw)
  To: u-boot

Am 22.12.2015 um 14:57 schrieb Alexander Graf:
> diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
> new file mode 100644
> index 0000000..ed95962
> --- /dev/null
> +++ b/lib/efi_loader/efi_boottime.c
[...]
> +/*
> + * The "gd" pointer lives in a register on ARM and AArch64 that we declare
> + * fixed when compiling U-Boot. However, the payload does now know about that

"does not"?

> + * restriction so we need to manually swap its and our view of that register on
> + * EFI callback entry/exit.
> + */
> +static volatile void *efi_gd, *app_gd;
[snip]

Cheers,
Andreas

-- 
SUSE Linux GmbH, Maxfeldstr. 5, 90409 N?rnberg, Germany
GF: Felix Imend?rffer, Jane Smithard, Graham Norton; HRB 21284 (AG N?rnberg)

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

* [U-Boot] [PATCH 4/9] efi_loader: Add boot time services
  2015-12-22 14:15   ` Andreas Färber
@ 2015-12-22 14:31     ` Alexander Graf
  0 siblings, 0 replies; 70+ messages in thread
From: Alexander Graf @ 2015-12-22 14:31 UTC (permalink / raw)
  To: u-boot



On 22.12.15 15:15, Andreas F?rber wrote:
> Am 22.12.2015 um 14:57 schrieb Alexander Graf:
>> diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
>> new file mode 100644
>> index 0000000..ed95962
>> --- /dev/null
>> +++ b/lib/efi_loader/efi_boottime.c
> [...]
>> +/*
>> + * The "gd" pointer lives in a register on ARM and AArch64 that we declare
>> + * fixed when compiling U-Boot. However, the payload does now know about that
> 
> "does not"?

Yup, fixed for v2, thanks :).


Alex

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

* [U-Boot] [PATCH 0/9] EFI payload / application support
  2015-12-22 13:57 [U-Boot] [PATCH 0/9] EFI payload / application support Alexander Graf
                   ` (8 preceding siblings ...)
  2015-12-22 13:57 ` [U-Boot] [PATCH 9/9] efi_loader: hook up in build environment Alexander Graf
@ 2015-12-22 18:28 ` Matwey V. Kornilov
  2015-12-22 20:32   ` Alexander Graf
  2015-12-25  3:29 ` Tom Rini
                   ` (2 subsequent siblings)
  12 siblings, 1 reply; 70+ messages in thread
From: Matwey V. Kornilov @ 2015-12-22 18:28 UTC (permalink / raw)
  To: u-boot

2015-12-22 16:57 GMT+03:00 Alexander Graf <agraf@suse.de>:
> This is my Christmas present for my openSUSE friends :).
>

Santa, do you have u-boot rpm packed with the patches to test?

-- 
With best regards,
Matwey V. Kornilov
http://blog.matwey.name
xmpp://0x2207 at jabber.ru

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

* [U-Boot] [PATCH 0/9] EFI payload / application support
  2015-12-22 18:28 ` [U-Boot] [PATCH 0/9] EFI payload / application support Matwey V. Kornilov
@ 2015-12-22 20:32   ` Alexander Graf
  0 siblings, 0 replies; 70+ messages in thread
From: Alexander Graf @ 2015-12-22 20:32 UTC (permalink / raw)
  To: u-boot



On 22.12.15 19:28, Matwey V. Kornilov wrote:
> 2015-12-22 16:57 GMT+03:00 Alexander Graf <agraf@suse.de>:
>> This is my Christmas present for my openSUSE friends :).
>>
> 
> Santa, do you have u-boot rpm packed with the patches to test?

Once OBS has finished compiling, they should be available here:

  https://build.opensuse.org/project/show/home:algraf:branches:Base:System

If you also want a 32bit ARM grub2 binary, check out

  https://build.opensuse.org/project/show/devel:ARM:Factory:Contrib:HIP04D01


Merry Christmas ;)

Alex

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

* [U-Boot] [PATCH 8/9] efi_loader: Add "bootefi" command
  2015-12-22 13:57 ` [U-Boot] [PATCH 8/9] efi_loader: Add "bootefi" command Alexander Graf
@ 2015-12-24 11:15   ` Matwey V. Kornilov
  2015-12-25  9:02     ` Alexander Graf
  2015-12-25 16:58     ` Tom Rini
  0 siblings, 2 replies; 70+ messages in thread
From: Matwey V. Kornilov @ 2015-12-24 11:15 UTC (permalink / raw)
  To: u-boot

Why just not to implement standard EFI behaviour when EFI looks for
boot-efi partition and proceed?

If ARM board developers will enable EFI support in the future, we can
have single one JeOS having all possible dtb in KIWI image.
BeagleBone Black has its own u-boot on eMMC, and the user need to push
S2 button to force hardware to use our openSUSE u-boot from SD card.
Maybe something like that is for other boards. If the single one
required u-boot feature is to run EFI grub, then we can even don't
touch preinstalled bootloader, that is not possible now, because we
need our openSUSE boot scripts.

2015-12-22 16:57 GMT+03:00 Alexander Graf <agraf@suse.de>:
> In order to execute an EFI application, we need to bridge the gap between
> U-Boot's notion of executing images and EFI's notion of doing the same.
>
> The best path forward IMHO here is to stick completely to the way U-Boot
> deals with payloads. You manually load them using whatever method to RAM
> and then have a simple boot command to execute them. So in our case, you
> would do
>
>   # load mmc 0:1 $loadaddr grub.efi
>   # bootefi $loadaddr
>
> which then gets you into a grub shell. Fdt information known to U-boot
> via the fdt addr command is also passed to the EFI payload.
>
> Signed-off-by: Alexander Graf <agraf@suse.de>
> ---
>  common/Makefile      |   1 +
>  common/cmd_bootefi.c | 168 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 169 insertions(+)
>  create mode 100644 common/cmd_bootefi.c
>
> diff --git a/common/Makefile b/common/Makefile
> index 2a1d9f8..a7a728a 100644
> --- a/common/Makefile
> +++ b/common/Makefile
> @@ -67,6 +67,7 @@ obj-$(CONFIG_CMD_SOURCE) += cmd_source.o
>  obj-$(CONFIG_CMD_BDI) += cmd_bdinfo.o
>  obj-$(CONFIG_CMD_BEDBUG) += bedbug.o cmd_bedbug.o
>  obj-$(CONFIG_CMD_BMP) += cmd_bmp.o
> +obj-$(CONFIG_EFI_LOADER) += cmd_bootefi.o
>  obj-$(CONFIG_CMD_BOOTMENU) += cmd_bootmenu.o
>  obj-$(CONFIG_CMD_BOOTLDR) += cmd_bootldr.o
>  obj-$(CONFIG_CMD_BOOTSTAGE) += cmd_bootstage.o
> diff --git a/common/cmd_bootefi.c b/common/cmd_bootefi.c
> new file mode 100644
> index 0000000..8d872d0
> --- /dev/null
> +++ b/common/cmd_bootefi.c
> @@ -0,0 +1,168 @@
> +/*
> + *  EFI application loader
> + *
> + *  Copyright (c) 2015 Alexander Graf
> + *
> + *  This library is free software; you can redistribute it and/or
> + *  modify it under the terms of the GNU Lesser General Public
> + *  License as published by the Free Software Foundation; either
> + *  version 2.1 of the License, or (at your option) any later version.
> + *
> + *  This library is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + *  Lesser General Public License for more details.
> + *
> + *  You should have received a copy of the GNU Lesser General Public
> + *  License along with this library; if not, write to the Free Software
> + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
> + *
> + *  SPDX-License-Identifier:     LGPL-2.1+
> + */
> +
> +#include <common.h>
> +#include <command.h>
> +#include <efi_loader.h>
> +#include <libfdt_env.h>
> +
> +/* This list contains all the EFI objects our payload has access to */
> +LIST_HEAD(efi_obj_list);
> +
> +/*
> + * When booting using the "bootefi" command, we don't know which
> + * physical device the file came from. So we create a pseudo-device
> + * called "bootefi" with the device path /bootefi.
> + *
> + * In addition to the originating device we also declare the file path
> + * of "bootefi" based loads to be /bootefi.
> + */
> +static struct efi_device_path_file_path bootefi_dummy_path[] = {
> +       {
> +               .dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE,
> +               .dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH,
> +               .dp.length = sizeof(bootefi_dummy_path[0]),
> +               .str = { 'b','o','o','t','e','f','i' },
> +       }, {
> +               .dp.type = DEVICE_PATH_TYPE_END,
> +               .dp.sub_type = DEVICE_PATH_SUB_TYPE_END,
> +               .dp.length = sizeof(bootefi_dummy_path[0]),
> +       }
> +};
> +
> +static efi_status_t bootefi_open_dp(void *handle, efi_guid_t *protocol,
> +                       void **protocol_interface, void *agent_handle,
> +                       void *controller_handle, uint32_t attributes)
> +{
> +       *protocol_interface = bootefi_dummy_path;
> +       return EFI_SUCCESS;
> +}
> +
> +/* The EFI loaded_image interface for the image executed via "bootefi" */
> +static struct efi_loaded_image loaded_image_info = {
> +       .device_handle = bootefi_dummy_path,
> +       .file_path = bootefi_dummy_path,
> +};
> +
> +/* The EFI object struct for the image executed via "bootefi" */
> +static struct efi_object loaded_image_info_obj = {
> +       .handle = &loaded_image_info,
> +       .protocols = {
> +               {
> +                       /* When asking for the loaded_image interface, just
> +                        * return handle which points to loaded_image_info */
> +                       .guid = &efi_guid_loaded_image,
> +                       .open = &efi_return_handle,
> +               },
> +               {
> +                       /* When asking for the device path interface, return
> +                        * bootefi_dummy_path */
> +                       .guid = &efi_guid_device_path,
> +                       .open = &bootefi_open_dp,
> +               },
> +       },
> +};
> +
> +/* The EFI object struct for the device the "bootefi" image was loaded from */
> +static struct efi_object bootefi_device_obj = {
> +       .handle = bootefi_dummy_path,
> +       .protocols = {
> +               {
> +                       /* When asking for the device path interface, return
> +                        * bootefi_dummy_path */
> +                       .guid = &efi_guid_device_path,
> +                       .open = &bootefi_open_dp,
> +               }
> +       },
> +};
> +
> +/*
> + * Load an EFI payload into a newly allocated piece of memory, register all
> + * EFI objects it would want to access and jump to it.
> + */
> +static unsigned long do_bootefi_exec(void *efi)
> +{
> +       ulong (*entry)(void *image_handle, struct efi_system_table *st);
> +
> +       /*
> +        * gd lives in a fixed register which may get clobbered while we execute
> +        * the payload. So save it here and restore it on every callback entry
> +        */
> +       efi_save_gd();
> +
> +       /* Update system table to point to our currently loaded FDT */
> +       systab.tables[0].table = working_fdt;
> +
> +       if (!working_fdt) {
> +               printf("WARNING: No device tree loaded, expect boot to fail\n");
> +               systab.nr_tables = 0;
> +       }
> +
> +       /* Load the EFI payload */
> +       entry = efi_load_pe(efi, &loaded_image_info);
> +       if (!entry)
> +               return -1;
> +
> +       /* Initialize and populate EFI object list */
> +       INIT_LIST_HEAD(&efi_obj_list);
> +       list_add_tail(&loaded_image_info_obj.link, &efi_obj_list);
> +       list_add_tail(&bootefi_device_obj.link, &efi_obj_list);
> +#ifdef CONFIG_PARTITIONS
> +       efi_disk_register();
> +#endif
> +
> +       /* Call our payload! */
> +#ifdef DEBUG_EFI
> +       printf("%s:%d Jumping to 0x%lx\n", __func__, __LINE__, (long)entry);
> +#endif
> +       return entry(&loaded_image_info, &systab);
> +}
> +
> +
> +/* Interpreter command to boot an arbitrary EFI image from memory */
> +static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
> +{
> +       char *saddr;
> +       unsigned long addr;
> +       int r = 0;
> +
> +       if (argc < 2)
> +               return 1;
> +       saddr = argv[1];
> +
> +       addr = simple_strtoul(saddr, NULL, 16);
> +
> +       printf("## Starting EFI application at 0x%08lx ...\n", addr);
> +       r = do_bootefi_exec((void *)addr);
> +       printf("## Application terminated, r = %d\n", r);
> +
> +       if (r != 0)
> +               r = 1;
> +
> +       return r;
> +}
> +
> +U_BOOT_CMD(
> +       bootefi, 2, 0, do_bootefi,
> +       "Boot from an EFI image in memory",
> +       "<image address>\n"
> +);
> --
> 2.1.4
>



-- 
With best regards,
Matwey V. Kornilov
http://blog.matwey.name
xmpp://0x2207 at jabber.ru

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

* [U-Boot] [PATCH 0/9] EFI payload / application support
  2015-12-22 13:57 [U-Boot] [PATCH 0/9] EFI payload / application support Alexander Graf
                   ` (9 preceding siblings ...)
  2015-12-22 18:28 ` [U-Boot] [PATCH 0/9] EFI payload / application support Matwey V. Kornilov
@ 2015-12-25  3:29 ` Tom Rini
  2015-12-25  8:53   ` Alexander Graf
  2015-12-25 19:34 ` Blibbet
  2015-12-26 15:31 ` Leif Lindholm
  12 siblings, 1 reply; 70+ messages in thread
From: Tom Rini @ 2015-12-25  3:29 UTC (permalink / raw)
  To: u-boot

On Tue, Dec 22, 2015 at 02:57:47PM +0100, Alexander Graf wrote:

> This is my Christmas present for my openSUSE friends :).
> 
> U-Boot is a great project for embedded devices. However, convincing
> everyone involved that only for "a few oddball ARM devices" we need to
> support different configuration formats from grub2 when all other platforms
> (PPC, System Z, x86) are standardized on a single format is a nightmare.
> 
> So we started to explore alternatives. At first, people tried to get
> grub2 running using the u-boot api interface. However, FWIW that one
> doesn't support relocations, so you need to know where to link grub2 to
> at compile time. It also seems to be broken more often than not. And on
> top of it all, it's a one-off interface, so yet another thing to maintain.
> 
> That led to a nifty idea. What if we can just implement the EFI application
> protocol on top of U-Boot? Then we could compile a single grub2 binary for
> uEFI based systems and U-Boot based systems and as soon as that one's loaded,
> everything looks and feels (almost) the same.
> 
> This patch set is the result of pursuing this endeavor.

So, I owe the whole codebase a real review.  My very quick question
however is, aside from what you had to borrow from wine, can you license
everything else as GPL v2 or later rather than LGPL?

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20151224/047af028/attachment.sig>

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

* [U-Boot] [PATCH 0/9] EFI payload / application support
  2015-12-25  3:29 ` Tom Rini
@ 2015-12-25  8:53   ` Alexander Graf
  2015-12-25 16:50     ` Tom Rini
  0 siblings, 1 reply; 70+ messages in thread
From: Alexander Graf @ 2015-12-25  8:53 UTC (permalink / raw)
  To: u-boot



On 25.12.15 04:29, Tom Rini wrote:
> On Tue, Dec 22, 2015 at 02:57:47PM +0100, Alexander Graf wrote:
> 
>> This is my Christmas present for my openSUSE friends :).
>>
>> U-Boot is a great project for embedded devices. However, convincing
>> everyone involved that only for "a few oddball ARM devices" we need to
>> support different configuration formats from grub2 when all other platforms
>> (PPC, System Z, x86) are standardized on a single format is a nightmare.
>>
>> So we started to explore alternatives. At first, people tried to get
>> grub2 running using the u-boot api interface. However, FWIW that one
>> doesn't support relocations, so you need to know where to link grub2 to
>> at compile time. It also seems to be broken more often than not. And on
>> top of it all, it's a one-off interface, so yet another thing to maintain.
>>
>> That led to a nifty idea. What if we can just implement the EFI application
>> protocol on top of U-Boot? Then we could compile a single grub2 binary for
>> uEFI based systems and U-Boot based systems and as soon as that one's loaded,
>> everything looks and feels (almost) the same.
>>
>> This patch set is the result of pursuing this endeavor.
> 
> So, I owe the whole codebase a real review.  My very quick question
> however is, aside from what you had to borrow from wine, can you license
> everything else as GPL v2 or later rather than LGPL?

I'm personally a pretty big fan of the LGPL, since it's a very
reasonable compromise between closed and open source IMHO ;).

Is there a particular reason you're asking for this? LGPL code is fully
compatible with GPL code and the resulting binary would be GPL anyway
because FWIW you can't compile U-Boot without GPL code inside.


Alex

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

* [U-Boot] [PATCH 8/9] efi_loader: Add "bootefi" command
  2015-12-24 11:15   ` Matwey V. Kornilov
@ 2015-12-25  9:02     ` Alexander Graf
  2015-12-25  9:25       ` Andreas Färber
  2015-12-26 18:45       ` Leif Lindholm
  2015-12-25 16:58     ` Tom Rini
  1 sibling, 2 replies; 70+ messages in thread
From: Alexander Graf @ 2015-12-25  9:02 UTC (permalink / raw)
  To: u-boot



On 24.12.15 12:15, Matwey V. Kornilov wrote:
> Why just not to implement standard EFI behaviour when EFI looks for
> boot-efi partition and proceed?

Well, what is "standard EFI behavior"?

There are 2 standard ways I'm aware of:

  1) NVRAM

The default case for 99.9% of the boots on normal EFI systems is based
on variables in NVRAM that tell EFI which boot device to boot from.
Since we don't implement EFI variables today, we can't really make use
of this feature. And because you want to change the default boot device
at runtime, we'd have to have runtime services be able to modify them
after exiting boot services.

  2) Removable Media

There is another way implemented for "Removable Media" - mostly intended
for USB sticks and the likes. Here EFI searches for a defined file name
(EFI/boot/boot{arm,a64,x64}.efi) on the ESP partition and boots it.

Part 1 is very difficult to do without major rework of a few U-Boot
components. If EFI becomes the de-facto standard way of booting with
U-Boot, I think we'll walk down that road, but it's nothing I want to
have to deal with in the initial enablement discussion.

Part 2 is easy to do. But then again it's also easy to do it using a
boot script. Or a compiled in bootcmd. If it's really desired.

Which brings me to the next idea. What if we just implement exlinux.conf
support for EFI binaries? Then all you need to do is have an
extlinux.conf available on your generic EFI media that tells U-Boot
where to load the grub binary from.

That way we wouldn't bend U-Boot completely away from its heritage, make
use of its flexibility and all distributions that actually care about
booting from U-Boot would easily be able to just put such a file in an
rpm an install it always.

> If ARM board developers will enable EFI support in the future, we can
> have single one JeOS having all possible dtb in KIWI image.
> BeagleBone Black has its own u-boot on eMMC, and the user need to push
> S2 button to force hardware to use our openSUSE u-boot from SD card.
> Maybe something like that is for other boards. If the single one
> required u-boot feature is to run EFI grub, then we can even don't
> touch preinstalled bootloader, that is not possible now, because we
> need our openSUSE boot scripts.

There are more things we need to solve before we can truly get to a
universal booting solution. But one step at a time :).

The reason I implemented "bootefi" was really because it's the natural
fit into how U-Boot handles all other formats today. I don't think this
is going to be the last patch set around EFI support.


Alex

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

* [U-Boot] [PATCH 8/9] efi_loader: Add "bootefi" command
  2015-12-25  9:02     ` Alexander Graf
@ 2015-12-25  9:25       ` Andreas Färber
  2015-12-25  9:40         ` Matwey V. Kornilov
  2015-12-26 18:55         ` Leif Lindholm
  2015-12-26 18:45       ` Leif Lindholm
  1 sibling, 2 replies; 70+ messages in thread
From: Andreas Färber @ 2015-12-25  9:25 UTC (permalink / raw)
  To: u-boot

Am 25.12.2015 um 10:02 schrieb Alexander Graf:
[snip]
> The reason I implemented "bootefi" was really because it's the natural
> fit into how U-Boot handles all other formats today. I don't think this
> is going to be the last patch set around EFI support.

I think what Matwey was suggesting is integrating your "bootefi" into
the standard "distro" boot sequence environment, so that it probes each
device for an EFI binary and if it finds one runs load and bootefi,
without the need for any boot.scr.

That would be a follow-up patch.

It however conflicts with your idea of having some potentially
board-specific code mess with "fdt addr" command before running "bootefi".

My solution would be to give boot.scr preference over *.efi, so that the
user has a way to load dtb and run "bootefi" on his own, and otherwise
fall back to just "bootefi" which'll spit a warning about lack of fdt if
I read that correctly.

Cheers,
Andreas

-- 
SUSE Linux GmbH, Maxfeldstr. 5, 90409 N?rnberg, Germany
GF: Felix Imend?rffer, Jane Smithard, Graham Norton; HRB 21284 (AG N?rnberg)

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

* [U-Boot] [PATCH 8/9] efi_loader: Add "bootefi" command
  2015-12-25  9:25       ` Andreas Färber
@ 2015-12-25  9:40         ` Matwey V. Kornilov
  2015-12-25 17:04           ` Tom Rini
  2015-12-26 18:55         ` Leif Lindholm
  1 sibling, 1 reply; 70+ messages in thread
From: Matwey V. Kornilov @ 2015-12-25  9:40 UTC (permalink / raw)
  To: u-boot

2015-12-25 12:25 GMT+03:00 Andreas F?rber <afaerber@suse.de>:
> Am 25.12.2015 um 10:02 schrieb Alexander Graf:
> [snip]
>> The reason I implemented "bootefi" was really because it's the natural
>> fit into how U-Boot handles all other formats today. I don't think this
>> is going to be the last patch set around EFI support.
>
> I think what Matwey was suggesting is integrating your "bootefi" into
> the standard "distro" boot sequence environment, so that it probes each
> device for an EFI binary and if it finds one runs load and bootefi,
> without the need for any boot.scr.

I have no problem if boot{arm,a64,x64}.efi search is implemented via
standard bootscript.
But I like idea about extlinux.conf too.

>
> That would be a follow-up patch.
>
> It however conflicts with your idea of having some potentially
> board-specific code mess with "fdt addr" command before running "bootefi".
>
> My solution would be to give boot.scr preference over *.efi, so that the
> user has a way to load dtb and run "bootefi" on his own, and otherwise
> fall back to just "bootefi" which'll spit a warning about lack of fdt if
> I read that correctly.
>

Yeah, dtb should be anyhow controlled by the user to make workarounds possible.
Funny story about how u-boot detects dtb:
http://lists.denx.de/pipermail/u-boot/2015-December/237604.html

> Cheers,
> Andreas
>
> --
> SUSE Linux GmbH, Maxfeldstr. 5, 90409 N?rnberg, Germany
> GF: Felix Imend?rffer, Jane Smithard, Graham Norton; HRB 21284 (AG N?rnberg)



-- 
With best regards,
Matwey V. Kornilov
http://blog.matwey.name
xmpp://0x2207 at jabber.ru

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

* [U-Boot] [PATCH 0/9] EFI payload / application support
  2015-12-25  8:53   ` Alexander Graf
@ 2015-12-25 16:50     ` Tom Rini
  2015-12-25 16:53       ` Matwey V. Kornilov
  2016-01-15  3:00       ` Alexander Graf
  0 siblings, 2 replies; 70+ messages in thread
From: Tom Rini @ 2015-12-25 16:50 UTC (permalink / raw)
  To: u-boot

On Fri, Dec 25, 2015 at 09:53:22AM +0100, Alexander Graf wrote:
> 
> 
> On 25.12.15 04:29, Tom Rini wrote:
> > On Tue, Dec 22, 2015 at 02:57:47PM +0100, Alexander Graf wrote:
> > 
> >> This is my Christmas present for my openSUSE friends :).
> >>
> >> U-Boot is a great project for embedded devices. However, convincing
> >> everyone involved that only for "a few oddball ARM devices" we need to
> >> support different configuration formats from grub2 when all other platforms
> >> (PPC, System Z, x86) are standardized on a single format is a nightmare.
> >>
> >> So we started to explore alternatives. At first, people tried to get
> >> grub2 running using the u-boot api interface. However, FWIW that one
> >> doesn't support relocations, so you need to know where to link grub2 to
> >> at compile time. It also seems to be broken more often than not. And on
> >> top of it all, it's a one-off interface, so yet another thing to maintain.
> >>
> >> That led to a nifty idea. What if we can just implement the EFI application
> >> protocol on top of U-Boot? Then we could compile a single grub2 binary for
> >> uEFI based systems and U-Boot based systems and as soon as that one's loaded,
> >> everything looks and feels (almost) the same.
> >>
> >> This patch set is the result of pursuing this endeavor.
> > 
> > So, I owe the whole codebase a real review.  My very quick question
> > however is, aside from what you had to borrow from wine, can you license
> > everything else as GPL v2 or later rather than LGPL?
> 
> I'm personally a pretty big fan of the LGPL, since it's a very
> reasonable compromise between closed and open source IMHO ;).
> 
> Is there a particular reason you're asking for this? LGPL code is fully
> compatible with GPL code and the resulting binary would be GPL anyway
> because FWIW you can't compile U-Boot without GPL code inside.

The general rules for U-Boot code are to be GPL v2 or later.  U-Boot is
(and always will be) a GPL v2 only project as there's simply too much
Linux kernel code that we want to leverage.  We do make special
exceptions at times for very good reasons (like include/android_image.h
is the authorative BSD-2 clause copy of that information) and I've even
told some companies that for crypto-auth-sensitive stuff they can do GPL
v2 only in their submission (again, due to U-Boot always being a v2 only
project).

So, I'm not gonig to reject the EFI loader code if you say no, you won't
re-license it as GPL v2 (or v2 and later) but I'd really appreciate it.
Thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20151225/f5ff075f/attachment.sig>

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

* [U-Boot] [PATCH 0/9] EFI payload / application support
  2015-12-25 16:50     ` Tom Rini
@ 2015-12-25 16:53       ` Matwey V. Kornilov
  2015-12-25 17:00         ` Tom Rini
  2016-01-15  3:00       ` Alexander Graf
  1 sibling, 1 reply; 70+ messages in thread
From: Matwey V. Kornilov @ 2015-12-25 16:53 UTC (permalink / raw)
  To: u-boot

2015-12-25 19:50 GMT+03:00 Tom Rini <trini@konsulko.com>:
> On Fri, Dec 25, 2015 at 09:53:22AM +0100, Alexander Graf wrote:
>>
>>
>> On 25.12.15 04:29, Tom Rini wrote:
>> > On Tue, Dec 22, 2015 at 02:57:47PM +0100, Alexander Graf wrote:
>> >
>> >> This is my Christmas present for my openSUSE friends :).
>> >>
>> >> U-Boot is a great project for embedded devices. However, convincing
>> >> everyone involved that only for "a few oddball ARM devices" we need to
>> >> support different configuration formats from grub2 when all other platforms
>> >> (PPC, System Z, x86) are standardized on a single format is a nightmare.
>> >>
>> >> So we started to explore alternatives. At first, people tried to get
>> >> grub2 running using the u-boot api interface. However, FWIW that one
>> >> doesn't support relocations, so you need to know where to link grub2 to
>> >> at compile time. It also seems to be broken more often than not. And on
>> >> top of it all, it's a one-off interface, so yet another thing to maintain.
>> >>
>> >> That led to a nifty idea. What if we can just implement the EFI application
>> >> protocol on top of U-Boot? Then we could compile a single grub2 binary for
>> >> uEFI based systems and U-Boot based systems and as soon as that one's loaded,
>> >> everything looks and feels (almost) the same.
>> >>
>> >> This patch set is the result of pursuing this endeavor.
>> >
>> > So, I owe the whole codebase a real review.  My very quick question
>> > however is, aside from what you had to borrow from wine, can you license
>> > everything else as GPL v2 or later rather than LGPL?
>>
>> I'm personally a pretty big fan of the LGPL, since it's a very
>> reasonable compromise between closed and open source IMHO ;).
>>
>> Is there a particular reason you're asking for this? LGPL code is fully
>> compatible with GPL code and the resulting binary would be GPL anyway
>> because FWIW you can't compile U-Boot without GPL code inside.
>
> The general rules for U-Boot code are to be GPL v2 or later.  U-Boot is
> (and always will be) a GPL v2 only project as there's simply too much
> Linux kernel code that we want to leverage.  We do make special
> exceptions at times for very good reasons (like include/android_image.h
> is the authorative BSD-2 clause copy of that information) and I've even
> told some companies that for crypto-auth-sensitive stuff they can do GPL
> v2 only in their submission (again, due to U-Boot always being a v2 only
> project).
>
> So, I'm not gonig to reject the EFI loader code if you say no, you won't
> re-license it as GPL v2 (or v2 and later) but I'd really appreciate it.
> Thanks!

If EFI loader is GPLed, then is it possible to use it to run non-GPLed
(proprietary) EFI applications?

-- 
With best regards,
Matwey V. Kornilov
http://blog.matwey.name
xmpp://0x2207 at jabber.ru

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

* [U-Boot] [PATCH 8/9] efi_loader: Add "bootefi" command
  2015-12-24 11:15   ` Matwey V. Kornilov
  2015-12-25  9:02     ` Alexander Graf
@ 2015-12-25 16:58     ` Tom Rini
  1 sibling, 0 replies; 70+ messages in thread
From: Tom Rini @ 2015-12-25 16:58 UTC (permalink / raw)
  To: u-boot

On Thu, Dec 24, 2015 at 02:15:52PM +0300, Matwey V. Kornilov wrote:

> Why just not to implement standard EFI behaviour when EFI looks for
> boot-efi partition and proceed?
> 
> If ARM board developers will enable EFI support in the future, we can
> have single one JeOS having all possible dtb in KIWI image.
> BeagleBone Black has its own u-boot on eMMC, and the user need to push
> S2 button to force hardware to use our openSUSE u-boot from SD card.
> Maybe something like that is for other boards. If the single one
> required u-boot feature is to run EFI grub, then we can even don't
> touch preinstalled bootloader, that is not possible now, because we
> need our openSUSE boot scripts.

AFAICT once we have the general support in we can simply extend the
current generic distro framework to have an iteration on "does the
device have the expected EFI boot stuff?" and if so, boot it.  Nothing
we need to do in C code here.

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20151225/513e92d9/attachment.sig>

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

* [U-Boot] [PATCH 0/9] EFI payload / application support
  2015-12-25 16:53       ` Matwey V. Kornilov
@ 2015-12-25 17:00         ` Tom Rini
  0 siblings, 0 replies; 70+ messages in thread
From: Tom Rini @ 2015-12-25 17:00 UTC (permalink / raw)
  To: u-boot

On Fri, Dec 25, 2015 at 07:53:24PM +0300, Matwey V. Kornilov wrote:
> 2015-12-25 19:50 GMT+03:00 Tom Rini <trini@konsulko.com>:
> > On Fri, Dec 25, 2015 at 09:53:22AM +0100, Alexander Graf wrote:
> >>
> >>
> >> On 25.12.15 04:29, Tom Rini wrote:
> >> > On Tue, Dec 22, 2015 at 02:57:47PM +0100, Alexander Graf wrote:
> >> >
> >> >> This is my Christmas present for my openSUSE friends :).
> >> >>
> >> >> U-Boot is a great project for embedded devices. However, convincing
> >> >> everyone involved that only for "a few oddball ARM devices" we need to
> >> >> support different configuration formats from grub2 when all other platforms
> >> >> (PPC, System Z, x86) are standardized on a single format is a nightmare.
> >> >>
> >> >> So we started to explore alternatives. At first, people tried to get
> >> >> grub2 running using the u-boot api interface. However, FWIW that one
> >> >> doesn't support relocations, so you need to know where to link grub2 to
> >> >> at compile time. It also seems to be broken more often than not. And on
> >> >> top of it all, it's a one-off interface, so yet another thing to maintain.
> >> >>
> >> >> That led to a nifty idea. What if we can just implement the EFI application
> >> >> protocol on top of U-Boot? Then we could compile a single grub2 binary for
> >> >> uEFI based systems and U-Boot based systems and as soon as that one's loaded,
> >> >> everything looks and feels (almost) the same.
> >> >>
> >> >> This patch set is the result of pursuing this endeavor.
> >> >
> >> > So, I owe the whole codebase a real review.  My very quick question
> >> > however is, aside from what you had to borrow from wine, can you license
> >> > everything else as GPL v2 or later rather than LGPL?
> >>
> >> I'm personally a pretty big fan of the LGPL, since it's a very
> >> reasonable compromise between closed and open source IMHO ;).
> >>
> >> Is there a particular reason you're asking for this? LGPL code is fully
> >> compatible with GPL code and the resulting binary would be GPL anyway
> >> because FWIW you can't compile U-Boot without GPL code inside.
> >
> > The general rules for U-Boot code are to be GPL v2 or later.  U-Boot is
> > (and always will be) a GPL v2 only project as there's simply too much
> > Linux kernel code that we want to leverage.  We do make special
> > exceptions at times for very good reasons (like include/android_image.h
> > is the authorative BSD-2 clause copy of that information) and I've even
> > told some companies that for crypto-auth-sensitive stuff they can do GPL
> > v2 only in their submission (again, due to U-Boot always being a v2 only
> > project).
> >
> > So, I'm not gonig to reject the EFI loader code if you say no, you won't
> > re-license it as GPL v2 (or v2 and later) but I'd really appreciate it.
> > Thanks!
> 
> If EFI loader is GPLed, then is it possible to use it to run non-GPLed
> (proprietary) EFI applications?

Yes.  Absolutely.  We've (pratically) always supported running non-GPL
payloads.  VxWorks has been supported for ages and ages and ages for
example.  There may be a thought experiment or two required about
callbacks but that's part of why we've had CONFIG_API, iirc.

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20151225/f7c35b63/attachment.sig>

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

* [U-Boot] [PATCH 8/9] efi_loader: Add "bootefi" command
  2015-12-25  9:40         ` Matwey V. Kornilov
@ 2015-12-25 17:04           ` Tom Rini
  0 siblings, 0 replies; 70+ messages in thread
From: Tom Rini @ 2015-12-25 17:04 UTC (permalink / raw)
  To: u-boot

On Fri, Dec 25, 2015 at 12:40:25PM +0300, Matwey V. Kornilov wrote:
> 2015-12-25 12:25 GMT+03:00 Andreas F?rber <afaerber@suse.de>:
> > Am 25.12.2015 um 10:02 schrieb Alexander Graf:
> > [snip]
> >> The reason I implemented "bootefi" was really because it's the natural
> >> fit into how U-Boot handles all other formats today. I don't think this
> >> is going to be the last patch set around EFI support.
> >
> > I think what Matwey was suggesting is integrating your "bootefi" into
> > the standard "distro" boot sequence environment, so that it probes each
> > device for an EFI binary and if it finds one runs load and bootefi,
> > without the need for any boot.scr.
> 
> I have no problem if boot{arm,a64,x64}.efi search is implemented via
> standard bootscript.
> But I like idea about extlinux.conf too.
> 
> >
> > That would be a follow-up patch.
> >
> > It however conflicts with your idea of having some potentially
> > board-specific code mess with "fdt addr" command before running "bootefi".
> >
> > My solution would be to give boot.scr preference over *.efi, so that the
> > user has a way to load dtb and run "bootefi" on his own, and otherwise
> > fall back to just "bootefi" which'll spit a warning about lack of fdt if
> > I read that correctly.
> >
> 
> Yeah, dtb should be anyhow controlled by the user to make workarounds possible.
> Funny story about how u-boot detects dtb:
> http://lists.denx.de/pipermail/u-boot/2015-December/237604.html

Yeah.  And frankly that's about how it's supposed to work too.  That's a
very "funny" Beaglbone Black clone you found there (they neither
verbatim copied the EEPROM contents nor followed the guidelines on how
to get their own name in there). :)

But, in the end it's all a solvable set of problems, after the initial
work is in.

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20151225/87e5f746/attachment.sig>

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

* [U-Boot] [PATCH 0/9] EFI payload / application support
  2015-12-22 13:57 [U-Boot] [PATCH 0/9] EFI payload / application support Alexander Graf
                   ` (10 preceding siblings ...)
  2015-12-25  3:29 ` Tom Rini
@ 2015-12-25 19:34 ` Blibbet
  2015-12-26 15:31 ` Leif Lindholm
  12 siblings, 0 replies; 70+ messages in thread
From: Blibbet @ 2015-12-25 19:34 UTC (permalink / raw)
  To: u-boot



On 12/22/2015 05:57 AM, Alexander Graf wrote:
> This is my Christmas present for my openSUSE friends :).
>
> U-Boot is a great project for embedded devices. However, convincing
> everyone involved that only for "a few oddball ARM devices" we need to
> support different configuration formats from grub2 when all other
platforms
> (PPC, System Z, x86) are standardized on a single format is a nightmare.

This is a very exciting patch!

The potential to one day run CHIPSEC on U-Boot systems is VERY EXCITING!
https://github.com/chipsec/chipsec
CHIPSEC is a UEFI-centric. Though I've heard someone got it to work on
coreboot-based Intel-based Android system, not sure how.

After UEFI Shell works, I hope a goal is to get UEFI port of CPython
2.7x working, and Intel CHIPSEC running. CHIPSEC is a hardware/firmware
vulnerability detection tool, GPL open source. As I've heard them say,
the Intel CHIPSEC team is open to patches from all architectures for all
firmware targets, not just Intel x86/x64.

Linaro has started to investigate port of CHIPSEC from x86/x64 to
AArch64, as part of port of LUV (Linux UEFI Validation) project. Once
CPython and CHIPSEC run on U-Boot, this enables a whole new level of
hardware/firmware security detection! Once ported to AArch64, the ARM
security teams needs to add some AArch64-centric security test modules
to CHIPSEC, as it'll do little good on ARM, except for a few portable
UEFI variable and SPI tests, otherwise.
https://wiki.linaro.org/LEG/Engineering/luvOS
Hopefully ARM can fund Linaro to also port LUV/CHIPSEC to AArch32, all
of their products need hardware/firmware vulnerability detection
software, not just the latest 64-bit ones.

For U-Boot on MIPS, there is an unofficial UEFI MIPS port, but nobody
has touched it in a while, and CHIPSEC hasn't yet been ported there.
https://github.com/kontais/EFI-MIPS

I didn't think U-Boot ran on OpenPOWER, if it does, I missed that,
sorry. If so, there are two ports of UEFI to OpenPOWER by different
developers at IBM, but (AFAIK) no official OpenPOWER interest in UEFI,
and no CHIPSEC port to OpenPOWER yet. And no OpenPOWER-centric security
modules.
http://firmwaresecurity.com/2015/10/12/tianocore-for-openpower/
http://firmwaresecurity.com/2015/10/12/second-port-of-tianocore-to-openpower/

For other architectures that U-Boot runs on, I'm afraid porting UEFI
will be necessary before CHIPSEC can be attempted. :-( Is there any
marketshare data that shows which architectures coverage by U-Boot?

Dumb question: it appears Intel is not involved in U-Boot's x86/x64
port, or maybe I've just missed their involvement. I see Intel very
involved with coreboot and UEFI, but not U-Boot, even though U-Boot is
targetting Intel platforms. Can someone explain that to me? :-)

Thanks,
Lee Fisher
RSS: http://firmwaresecurity.com/feed

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

* [U-Boot] [PATCH 0/9] EFI payload / application support
  2015-12-22 13:57 [U-Boot] [PATCH 0/9] EFI payload / application support Alexander Graf
                   ` (11 preceding siblings ...)
  2015-12-25 19:34 ` Blibbet
@ 2015-12-26 15:31 ` Leif Lindholm
  2015-12-26 16:27   ` Alexander Graf
  2015-12-27 18:10   ` Tom Rini
  12 siblings, 2 replies; 70+ messages in thread
From: Leif Lindholm @ 2015-12-26 15:31 UTC (permalink / raw)
  To: u-boot

On Tue, Dec 22, 2015 at 02:57:47PM +0100, Alexander Graf wrote:
> This is my Christmas present for my openSUSE friends :).
> 
> U-Boot is a great project for embedded devices. However, convincing
> everyone involved that only for "a few oddball ARM devices" we need to
> support different configuration formats from grub2 when all other platforms
> (PPC, System Z, x86) are standardized on a single format is a nightmare.
> 
> So we started to explore alternatives. At first, people tried to get
> grub2 running using the u-boot api interface. However, FWIW that one
> doesn't support relocations, so you need to know where to link grub2 to
> at compile time. It also seems to be broken more often than not. And on
> top of it all, it's a one-off interface, so yet another thing to maintain.
> 
> That led to a nifty idea. What if we can just implement the EFI application
> protocol on top of U-Boot? Then we could compile a single grub2 binary for
> uEFI based systems and U-Boot based systems and as soon as that one's loaded,
> everything looks and feels (almost) the same.
> 
> This patch set is the result of pursuing this endeavor.

Thanks, this is a very cool thing.
I meant to reply sooner, but Christmas got in the way.

>   - I am successfully able to run grub2 and Linux EFI binaries with this code.
>   - When enabled, the resulting U-Boot binary only grows by ~10kb,
>     so it's very light weight.
>   - It works on 32bit ARM and AArch64. 
>   - All storage devices are directly accessible
>   - No runtime services (all calls return unimplemented)

Yeah, this is a bit of a pain point. The time services, virtual memory
services and reset being the key ones.

>   - No EFI variables

This would obviously (from my point of view) be desirable, but at
least initially, we can do most things without persistent variables.

> Of course, there are still a few things one could do on top:
> 
>   - Implement removable media booting (search for /efi/boot/boota{a64,rm}.efi)

Yeah, that would be top of my wishlist.

>   - Improve disk media detection (don't scan, use what information we have)
>   - Add EFI variable support using NVRAM
>   - Add GFX support

GFX support was actually never implemented for U-Boot GRUB, so from
this p.o.v. it is not a shortcoming over the existing impementation.

>   - Make EFI Shell work ;)

    - Network device support.

I also spotted a couple of minor things while playing around (things
like image exit being missing), but these will be easy to flush out.


I'll leave reviewing of the u-boot side of things to people who know
the codebase better, and restrict myself to commenting on the
UEFIness.

/
    Leif

> But so far, I'm very happy with the state of the patches. They completely
> eliminate potential arguments against U-Boot internally and give users the
> chance to run with the same level of comfort on all firmware types.
> 
> 
> Alex
> 
> Alexander Graf (9):
>   disk/part.c: Expose a list of available block drivers
>   include/efi_api.h: Add more detailed API definitions
>   efi_loader: Add PE image loader
>   efi_loader: Add boot time services
>   efi_loader: Add console interface
>   efi_loader: Add runtime services
>   efi_loader: Add disk interfaces
>   efi_loader: Add "bootefi" command
>   efi_loader: hook up in build environment
> 
>  arch/arm/cpu/armv8/u-boot.lds     |   8 +
>  arch/arm/cpu/u-boot.lds           |  13 +
>  arch/arm/lib/sections.c           |   2 +
>  common/Makefile                   |   1 +
>  common/cmd_bootefi.c              | 168 ++++++++
>  disk/part.c                       |  25 ++
>  include/efi_api.h                 | 197 +++++++--
>  include/efi_loader.h              |  87 ++++
>  include/part.h                    |   2 +
>  include/pe.h                      | 277 +++++++++++++
>  lib/Kconfig                       |   1 +
>  lib/Makefile                      |   1 +
>  lib/efi_loader/Kconfig            |   8 +
>  lib/efi_loader/Makefile           |  11 +
>  lib/efi_loader/efi_boottime.c     | 838 ++++++++++++++++++++++++++++++++++++++
>  lib/efi_loader/efi_console.c      | 371 +++++++++++++++++
>  lib/efi_loader/efi_disk.c         | 227 +++++++++++
>  lib/efi_loader/efi_image_loader.c | 203 +++++++++
>  lib/efi_loader/efi_runtime.c      |  59 +++
>  19 files changed, 2462 insertions(+), 37 deletions(-)
>  create mode 100644 common/cmd_bootefi.c
>  create mode 100644 include/efi_loader.h
>  create mode 100644 include/pe.h
>  create mode 100644 lib/efi_loader/Kconfig
>  create mode 100644 lib/efi_loader/Makefile
>  create mode 100644 lib/efi_loader/efi_boottime.c
>  create mode 100644 lib/efi_loader/efi_console.c
>  create mode 100644 lib/efi_loader/efi_disk.c
>  create mode 100644 lib/efi_loader/efi_image_loader.c
>  create mode 100644 lib/efi_loader/efi_runtime.c
> 
> -- 
> 2.1.4
> 

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

* [U-Boot] [PATCH 3/9] efi_loader: Add PE image loader
  2015-12-22 13:57 ` [U-Boot] [PATCH 3/9] efi_loader: Add PE image loader Alexander Graf
@ 2015-12-26 16:26   ` Leif Lindholm
  2016-01-14 23:45     ` Alexander Graf
  0 siblings, 1 reply; 70+ messages in thread
From: Leif Lindholm @ 2015-12-26 16:26 UTC (permalink / raw)
  To: u-boot

On Tue, Dec 22, 2015 at 02:57:50PM +0100, Alexander Graf wrote:
> EFI uses the PE binary format for its application images. Add support to EFI PE
> binaries as well as all necessary bits for the "EFI image loader" interfaces.
> 
> Signed-off-by: Alexander Graf <agraf@suse.de>
> ---
>  include/efi_loader.h              |  37 +++++
>  include/pe.h                      | 277 ++++++++++++++++++++++++++++++++++++++
>  lib/efi_loader/efi_image_loader.c | 203 ++++++++++++++++++++++++++++
>  3 files changed, 517 insertions(+)
>  create mode 100644 include/efi_loader.h
>  create mode 100644 include/pe.h
>  create mode 100644 lib/efi_loader/efi_image_loader.c
> 
> diff --git a/include/efi_loader.h b/include/efi_loader.h
> new file mode 100644
> index 0000000..da82354
> --- /dev/null
> +++ b/include/efi_loader.h
> @@ -0,0 +1,37 @@
> +/*
> + *  EFI application loader
> + *
> + *  Copyright (c) 2015 Alexander Graf
> + *
> + *  This library is free software; you can redistribute it and/or
> + *  modify it under the terms of the GNU Lesser General Public
> + *  License as published by the Free Software Foundation; either
> + *  version 2.1 of the License, or (at your option) any later version.
> + *
> + *  This library is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + *  Lesser General Public License for more details.
> + *
> + *  You should have received a copy of the GNU Lesser General Public
> + *  License along with this library; if not, write to the Free Software
> + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
> + *
> + *  SPDX-License-Identifier:     LGPL-2.1+
> + */
> +
> +#include <part_efi.h>
> +#include <efi_api.h>
> +#include <linux/list.h>
> +
> +extern const efi_guid_t efi_guid_device_path;
> +extern const efi_guid_t efi_guid_loaded_image;
> +
> +efi_status_t efi_return_handle(void *handle,
> +		efi_guid_t *protocol, void **protocol_interface,
> +		void *agent_handle, void *controller_handle,
> +		uint32_t attributes);
> +void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info);
> +
> +#define EFI_LOADER_POOL_SIZE (128 * 1024 * 1024)
> +void *efi_loader_alloc(uint64_t len);
> diff --git a/include/pe.h b/include/pe.h
> new file mode 100644
> index 0000000..009b0c5
> --- /dev/null
> +++ b/include/pe.h
> @@ -0,0 +1,277 @@
> +/*
> + *  Portable Executable binary format structures
> + *
> + *  Copyright (c) 2015 Alexander Graf
> + *
> + *  Based on wine code
> + *
> + *  This library is free software; you can redistribute it and/or
> + *  modify it under the terms of the GNU Lesser General Public
> + *  License as published by the Free Software Foundation; either
> + *  version 2.1 of the License, or (at your option) any later version.
> + *
> + *  This library is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + *  Lesser General Public License for more details.
> + *
> + *  You should have received a copy of the GNU Lesser General Public
> + *  License along with this library; if not, write to the Free Software
> + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
> + *
> + *  SPDX-License-Identifier:     LGPL-2.1+
> + */
> +
> +#ifndef _PE_H
> +#define _PE_H
> +
> +typedef struct _IMAGE_DOS_HEADER {
> +	uint16_t e_magic;      /* 00: MZ Header signature */
> +	uint16_t e_cblp;       /* 02: Bytes on last page of file */
> +	uint16_t e_cp;         /* 04: Pages in file */
> +	uint16_t e_crlc;       /* 06: Relocations */
> +	uint16_t e_cparhdr;    /* 08: Size of header in paragraphs */
> +	uint16_t e_minalloc;   /* 0a: Minimum extra paragraphs needed */
> +	uint16_t e_maxalloc;   /* 0c: Maximum extra paragraphs needed */
> +	uint16_t e_ss;         /* 0e: Initial (relative) SS value */
> +	uint16_t e_sp;         /* 10: Initial SP value */
> +	uint16_t e_csum;       /* 12: Checksum */
> +	uint16_t e_ip;         /* 14: Initial IP value */
> +	uint16_t e_cs;         /* 16: Initial (relative) CS value */
> +	uint16_t e_lfarlc;     /* 18: File address of relocation table */
> +	uint16_t e_ovno;       /* 1a: Overlay number */
> +	uint16_t e_res[4];     /* 1c: Reserved words */
> +	uint16_t e_oemid;      /* 24: OEM identifier (for e_oeminfo) */
> +	uint16_t e_oeminfo;    /* 26: OEM information; e_oemid specific */
> +	uint16_t e_res2[10];   /* 28: Reserved words */
> +	uint32_t e_lfanew;     /* 3c: Offset to extended header */
> +} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
> +
> +#define IMAGE_DOS_SIGNATURE		0x5A4D     /* MZ   */
> +#define IMAGE_NT_SIGNATURE		0x00004550 /* PE00 */
> +
> +#define IMAGE_FILE_MACHINE_ARM		0x01c0
> +#define IMAGE_FILE_MACHINE_THUMB	0x01c2
> +#define IMAGE_FILE_MACHINE_ARMNT	0x01c4
> +#define IMAGE_FILE_MACHINE_AMD64	0x8664
> +#define IMAGE_FILE_MACHINE_ARM64	0xaa64
> +#define IMAGE_NT_OPTIONAL_HDR32_MAGIC	0x10b
> +#define IMAGE_NT_OPTIONAL_HDR64_MAGIC	0x20b
> +#define IMAGE_SUBSYSTEM_EFI_APPLICATION	10
> +
> +typedef struct _IMAGE_FILE_HEADER {
> +	uint16_t  Machine;
> +	uint16_t  NumberOfSections;
> +	uint32_t TimeDateStamp;
> +	uint32_t PointerToSymbolTable;
> +	uint32_t NumberOfSymbols;
> +	uint16_t  SizeOfOptionalHeader;
> +	uint16_t  Characteristics;
> +} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
> +
> +typedef struct _IMAGE_DATA_DIRECTORY {
> +	uint32_t VirtualAddress;
> +	uint32_t Size;
> +} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
> +
> +#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
> +
> +typedef struct _IMAGE_OPTIONAL_HEADER64 {
> +	uint16_t  Magic; /* 0x20b */
> +	uint8_t MajorLinkerVersion;
> +	uint8_t MinorLinkerVersion;
> +	uint32_t SizeOfCode;
> +	uint32_t SizeOfInitializedData;
> +	uint32_t SizeOfUninitializedData;
> +	uint32_t AddressOfEntryPoint;
> +	uint32_t BaseOfCode;
> +	uint64_t ImageBase;
> +	uint32_t SectionAlignment;
> +	uint32_t FileAlignment;
> +	uint16_t MajorOperatingSystemVersion;
> +	uint16_t MinorOperatingSystemVersion;
> +	uint16_t MajorImageVersion;
> +	uint16_t MinorImageVersion;
> +	uint16_t MajorSubsystemVersion;
> +	uint16_t MinorSubsystemVersion;
> +	uint32_t Win32VersionValue;
> +	uint32_t SizeOfImage;
> +	uint32_t SizeOfHeaders;
> +	uint32_t CheckSum;
> +	uint16_t Subsystem;
> +	uint16_t DllCharacteristics;
> +	uint64_t SizeOfStackReserve;
> +	uint64_t SizeOfStackCommit;
> +	uint64_t SizeOfHeapReserve;
> +	uint64_t SizeOfHeapCommit;
> +	uint32_t LoaderFlags;
> +	uint32_t NumberOfRvaAndSizes;
> +	IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
> +} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;
> +
> +typedef struct _IMAGE_NT_HEADERS64 {
> +	uint32_t Signature;
> +	IMAGE_FILE_HEADER FileHeader;
> +	IMAGE_OPTIONAL_HEADER64 OptionalHeader;
> +} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;
> +
> +typedef struct _IMAGE_OPTIONAL_HEADER {
> +
> +	/* Standard fields */
> +
> +	uint16_t  Magic; /* 0x10b or 0x107 */     /* 0x00 */
> +	uint8_t  MajorLinkerVersion;
> +	uint8_t  MinorLinkerVersion;
> +	uint32_t SizeOfCode;
> +	uint32_t SizeOfInitializedData;
> +	uint32_t SizeOfUninitializedData;
> +	uint32_t AddressOfEntryPoint;            /* 0x10 */
> +	uint32_t BaseOfCode;
> +	uint32_t BaseOfData;
> +
> +	/* NT additional fields */
> +
> +	uint32_t ImageBase;
> +	uint32_t SectionAlignment;               /* 0x20 */
> +	uint32_t FileAlignment;
> +	uint16_t  MajorOperatingSystemVersion;
> +	uint16_t  MinorOperatingSystemVersion;
> +	uint16_t  MajorImageVersion;
> +	uint16_t  MinorImageVersion;
> +	uint16_t  MajorSubsystemVersion;          /* 0x30 */
> +	uint16_t  MinorSubsystemVersion;
> +	uint32_t Win32VersionValue;
> +	uint32_t SizeOfImage;
> +	uint32_t SizeOfHeaders;
> +	uint32_t CheckSum;                       /* 0x40 */
> +	uint16_t  Subsystem;
> +	uint16_t  DllCharacteristics;
> +	uint32_t SizeOfStackReserve;
> +	uint32_t SizeOfStackCommit;
> +	uint32_t SizeOfHeapReserve;              /* 0x50 */
> +	uint32_t SizeOfHeapCommit;
> +	uint32_t LoaderFlags;
> +	uint32_t NumberOfRvaAndSizes;
> +	IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; /* 0x60 */
> +	/* 0xE0 */
> +} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
> +
> +typedef struct _IMAGE_NT_HEADERS {
> +	uint32_t Signature; /* "PE"\0\0 */       /* 0x00 */
> +	IMAGE_FILE_HEADER FileHeader;         /* 0x04 */
> +	IMAGE_OPTIONAL_HEADER32 OptionalHeader;       /* 0x18 */
> +} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
> +
> +#define IMAGE_SIZEOF_SHORT_NAME 8
> +
> +typedef struct _IMAGE_SECTION_HEADER {
> +	uint8_t	Name[IMAGE_SIZEOF_SHORT_NAME];
> +	union {
> +		uint32_t PhysicalAddress;
> +		uint32_t VirtualSize;
> +	} Misc;
> +	uint32_t VirtualAddress;
> +	uint32_t SizeOfRawData;
> +	uint32_t PointerToRawData;
> +	uint32_t PointerToRelocations;
> +	uint32_t PointerToLinenumbers;
> +	uint16_t	NumberOfRelocations;
> +	uint16_t	NumberOfLinenumbers;
> +	uint32_t Characteristics;
> +} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
> +
> +#define IMAGE_DIRECTORY_ENTRY_BASERELOC         5
> +
> +typedef struct _IMAGE_BASE_RELOCATION
> +{
> +        uint32_t VirtualAddress;
> +        uint32_t SizeOfBlock;
> +        /* WORD TypeOffset[1]; */
> +} IMAGE_BASE_RELOCATION,*PIMAGE_BASE_RELOCATION;
> +
> +typedef struct _IMAGE_RELOCATION
> +{
> +	union {
> +		uint32_t   VirtualAddress;
> +		uint32_t   RelocCount;
> +	} DUMMYUNIONNAME;
> +	uint32_t   SymbolTableIndex;
> +	uint16_t	Type;
> +} IMAGE_RELOCATION, *PIMAGE_RELOCATION;
> +
> +#define IMAGE_SIZEOF_RELOCATION 10
> +
> +/* generic relocation types */
> +#define IMAGE_REL_BASED_ABSOLUTE                0
> +#define IMAGE_REL_BASED_HIGH                    1
> +#define IMAGE_REL_BASED_LOW                     2
> +#define IMAGE_REL_BASED_HIGHLOW                 3
> +#define IMAGE_REL_BASED_HIGHADJ                 4
> +#define IMAGE_REL_BASED_MIPS_JMPADDR            5
> +#define IMAGE_REL_BASED_ARM_MOV32A              5 /* yes, 5 too */
> +#define IMAGE_REL_BASED_ARM_MOV32               5 /* yes, 5 too */
> +#define IMAGE_REL_BASED_SECTION                 6
> +#define IMAGE_REL_BASED_REL                     7
> +#define IMAGE_REL_BASED_ARM_MOV32T              7 /* yes, 7 too */
> +#define IMAGE_REL_BASED_THUMB_MOV32             7 /* yes, 7 too */
> +#define IMAGE_REL_BASED_MIPS_JMPADDR16          9
> +#define IMAGE_REL_BASED_IA64_IMM64              9 /* yes, 9 too */
> +#define IMAGE_REL_BASED_DIR64                   10
> +#define IMAGE_REL_BASED_HIGH3ADJ                11
> +
> +/* ARM relocation types */
> +#define IMAGE_REL_ARM_ABSOLUTE          0x0000
> +#define IMAGE_REL_ARM_ADDR              0x0001
> +#define IMAGE_REL_ARM_ADDR32NB          0x0002
> +#define IMAGE_REL_ARM_BRANCH24          0x0003
> +#define IMAGE_REL_ARM_BRANCH11          0x0004
> +#define IMAGE_REL_ARM_TOKEN             0x0005
> +#define IMAGE_REL_ARM_GPREL12           0x0006
> +#define IMAGE_REL_ARM_GPREL7            0x0007
> +#define IMAGE_REL_ARM_BLX24             0x0008
> +#define IMAGE_REL_ARM_BLX11             0x0009
> +#define IMAGE_REL_ARM_SECTION           0x000E
> +#define IMAGE_REL_ARM_SECREL            0x000F
> +#define IMAGE_REL_ARM_MOV32A            0x0010
> +#define IMAGE_REL_ARM_MOV32T            0x0011
> +#define IMAGE_REL_ARM_BRANCH20T 0x0012
> +#define IMAGE_REL_ARM_BRANCH24T 0x0014
> +#define IMAGE_REL_ARM_BLX23T            0x0015
> +
> +/* ARM64 relocation types */
> +#define IMAGE_REL_ARM64_ABSOLUTE        0x0000
> +#define IMAGE_REL_ARM64_ADDR32          0x0001
> +#define IMAGE_REL_ARM64_ADDR32NB        0x0002
> +#define IMAGE_REL_ARM64_BRANCH26        0x0003
> +#define IMAGE_REL_ARM64_PAGEBASE_REL21  0x0004
> +#define IMAGE_REL_ARM64_REL21           0x0005
> +#define IMAGE_REL_ARM64_PAGEOFFSET_12A  0x0006
> +#define IMAGE_REL_ARM64_PAGEOFFSET_12L  0x0007
> +#define IMAGE_REL_ARM64_SECREL          0x0008
> +#define IMAGE_REL_ARM64_SECREL_LOW12A   0x0009
> +#define IMAGE_REL_ARM64_SECREL_HIGH12A  0x000A
> +#define IMAGE_REL_ARM64_SECREL_LOW12L   0x000B
> +#define IMAGE_REL_ARM64_TOKEN           0x000C
> +#define IMAGE_REL_ARM64_SECTION         0x000D
> +#define IMAGE_REL_ARM64_ADDR64          0x000E
> +
> +/* AMD64 relocation types */
> +#define IMAGE_REL_AMD64_ABSOLUTE        0x0000
> +#define IMAGE_REL_AMD64_ADDR64          0x0001
> +#define IMAGE_REL_AMD64_ADDR32          0x0002
> +#define IMAGE_REL_AMD64_ADDR32NB        0x0003
> +#define IMAGE_REL_AMD64_REL32           0x0004
> +#define IMAGE_REL_AMD64_REL32_1         0x0005
> +#define IMAGE_REL_AMD64_REL32_2         0x0006
> +#define IMAGE_REL_AMD64_REL32_3         0x0007
> +#define IMAGE_REL_AMD64_REL32_4         0x0008
> +#define IMAGE_REL_AMD64_REL32_5         0x0009
> +#define IMAGE_REL_AMD64_SECTION         0x000A
> +#define IMAGE_REL_AMD64_SECREL          0x000B
> +#define IMAGE_REL_AMD64_SECREL7         0x000C
> +#define IMAGE_REL_AMD64_TOKEN           0x000D
> +#define IMAGE_REL_AMD64_SREL32          0x000E
> +#define IMAGE_REL_AMD64_PAIR            0x000F
> +#define IMAGE_REL_AMD64_SSPAN32         0x0010
> +
> +#endif /* _PE_H */
> diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c
> new file mode 100644
> index 0000000..688e177
> --- /dev/null
> +++ b/lib/efi_loader/efi_image_loader.c
> @@ -0,0 +1,203 @@
> +/*
> + *  EFI image loader
> + *
> + *  based partly on wine code
> + *
> + *  Copyright (c) 2015 Alexander Graf
> + *
> + *  This library is free software; you can redistribute it and/or
> + *  modify it under the terms of the GNU Lesser General Public
> + *  License as published by the Free Software Foundation; either
> + *  version 2.1 of the License, or (at your option) any later version.
> + *
> + *  This library is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + *  Lesser General Public License for more details.
> + *
> + *  You should have received a copy of the GNU Lesser General Public
> + *  License along with this library; if not, write to the Free Software
> + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
> + *
> + *  SPDX-License-Identifier:     LGPL-2.1+
> + */
> +
> +#include <common.h>
> +#include <pe.h>
> +#include <efi_loader.h>
> +#include <asm/global_data.h>
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +#define ROUND_UP(val, round) ((val + (round - 1)) & ~(round - 1))
> +#define MB (1024 * 1024)
> +
> +const efi_guid_t efi_guid_device_path = DEVICE_PATH_GUID;
> +const efi_guid_t efi_guid_loaded_image = LOADED_IMAGE_GUID;
> +
> +efi_status_t efi_return_handle(void *handle, efi_guid_t *protocol,
> +			void **protocol_interface, void *agent_handle,
> +			void *controller_handle, uint32_t attributes)
> +{
> +	*protocol_interface = handle;
> +	return EFI_SUCCESS;
> +}
> +
> +/*
> + * EFI payloads potentially want to load pretty big images into memory,
> + * so our small malloc region isn't enough for them. However, they usually
> + * don't need a smart allocator either.
> + *
> + * So instead give them a really dumb one. We just reserve EFI_LOADER_POOL_SIZE
> + * bytes from 16MB below the malloc region start to give the stack some space.

Is there any chance you could break out the memory allocation and
memory map management as a separate patch, rather than spread across
3,4 and 6?

Assigning a specific 128MB pool for LOADER_DATA memory can have
unexpected side effects.

> + * Then every allocation gets a 4k aligned chunk from it. We never free.

Never freeing LOADER_DATA should not be an issue in and of itself. It
all gets zapped by the OS anyway.

> + */
> +void *efi_loader_alloc(uint64_t len)
> +{
> +	static unsigned long loader_pool;
> +	void *r;
> +
> +	if (!loader_pool) {
> +		loader_pool = gd->relocaddr - TOTAL_MALLOC_LEN -
> +			      EFI_LOADER_POOL_SIZE - (16 * MB);
> +	}
> +
> +	len = ROUND_UP(len, 4096);
> +	/* Out of memory */
> +	if ((loader_pool + len) >= (gd->relocaddr - TOTAL_MALLOC_LEN))
> +		return NULL;
> +
> +	r = (void *)loader_pool;
> +	loader_pool += len;
> +
> +	return r;
> +}
> +
> +/*
> + * This function loads all sections from a PE binary into a newly reserved
> + * piece of memory. On successful load it then returns the entry point for
> + * the binary. Otherwise NULL.
> + */
> +void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info)
> +{
> +	IMAGE_NT_HEADERS32 *nt;
> +	IMAGE_DOS_HEADER *dos;
> +	IMAGE_SECTION_HEADER *sections;
> +	int num_sections;
> +	void *efi_reloc;
> +	int i;
> +	const uint16_t *relocs;
> +	const IMAGE_BASE_RELOCATION *rel;
> +	const IMAGE_BASE_RELOCATION *end;
> +	unsigned long rel_size;
> +	int rel_idx = IMAGE_DIRECTORY_ENTRY_BASERELOC;
> +	void *entry;
> +	uint64_t image_size;
> +	unsigned long virt_size = 0;
> +
> +	dos = efi;
> +	if (dos->e_magic != IMAGE_DOS_SIGNATURE) {
> +		printf("%s: Invalid DOS Signature\n", __func__);
> +		return NULL;
> +	}
> +
> +	nt = (void *) ((char *)efi + dos->e_lfanew);
> +	if (nt->Signature != IMAGE_NT_SIGNATURE) {
> +		printf("%s: Invalid NT Signature\n", __func__);
> +		return NULL;
> +	}
> +
> +	/* Calculate upper virtual address boundary */
> +	num_sections = nt->FileHeader.NumberOfSections;
> +	sections = (void *)&nt->OptionalHeader +
> +			    nt->FileHeader.SizeOfOptionalHeader;
> +
> +	for (i = num_sections - 1; i >= 0; i--) {
> +		IMAGE_SECTION_HEADER *sec = &sections[i];
> +		virt_size = max_t(unsigned long, virt_size,
> +				  sec->VirtualAddress + sec->Misc.VirtualSize);
> +	}
> +
> +	/* Read 32/64bit specific header bits */

I guess x86 may support 32-on-64 or 64-on-32, but ARM won't - so could
probably be compile-time conditionalised somehow.
(CONFIG_EFI_SUPPORTS_PE32/CONFIG_EFI_SUPPORTS_PE64)

> +	if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
> +		IMAGE_NT_HEADERS64 *nt64 = (void *)nt;
> +		IMAGE_OPTIONAL_HEADER64 *opt = &nt64->OptionalHeader;
> +		image_size = opt->SizeOfImage;
> +		efi_reloc = efi_loader_alloc(virt_size);
> +		if (!efi_reloc) {
> +			printf("%s: Could not allocate %ld bytes\n",
> +				__func__, virt_size);
> +			return NULL;
> +		}
> +		entry = efi_reloc + opt->AddressOfEntryPoint;
> +		rel_size = opt->DataDirectory[rel_idx].Size;
> +		rel = efi_reloc + opt->DataDirectory[rel_idx].VirtualAddress;
> +	} else {

...and should still check the magic value for 32-bit?

> +		IMAGE_OPTIONAL_HEADER32 *opt = &nt->OptionalHeader;
> +		image_size = opt->SizeOfImage;
> +		efi_reloc = efi_loader_alloc(virt_size);
> +		if (!efi_reloc) {
> +			printf("%s: Could not allocate %ld bytes\n",
> +				__func__, virt_size);
> +			return NULL;
> +		}
> +		entry = efi_reloc + opt->AddressOfEntryPoint;
> +		rel_size = opt->DataDirectory[rel_idx].Size;
> +		rel = efi_reloc + opt->DataDirectory[rel_idx].VirtualAddress;
> +	}
> +
> +	/* Load sections into RAM */
> +	for (i = num_sections - 1; i >= 0; i--) {
> +		IMAGE_SECTION_HEADER *sec = &sections[i];
> +		memset(efi_reloc + sec->VirtualAddress, 0,
> +		       sec->Misc.VirtualSize);
> +		memcpy(efi_reloc + sec->VirtualAddress,
> +		       efi + sec->PointerToRawData,
> +		       sec->SizeOfRawData);
> +	}
> +
> +
> +	/* Run through relocations */
> +	end = (const IMAGE_BASE_RELOCATION *)((const char *)rel + rel_size);
> +
> +	while (rel < end - 1 && rel->SizeOfBlock) {
> +		relocs = (const uint16_t *)(rel + 1);
> +		i = (rel->SizeOfBlock - sizeof(*rel)) / sizeof(uint16_t);
> +		while (i--) {
> +			uint16_t offset = (*relocs & 0xfff) + rel->VirtualAddress;
> +			int type = *relocs >> 12;
> +			unsigned long delta = (unsigned long)efi_reloc;
> +			uint64_t *x64 = efi_reloc + offset;
> +			uint32_t *x32 = efi_reloc + offset;
> +			uint16_t *x16 = efi_reloc + offset;
> +
> +			switch (type) {
> +			case IMAGE_REL_BASED_ABSOLUTE:
> +				break;
> +			case IMAGE_REL_BASED_HIGH:
> +				*x16 += ((uint32_t)delta) >> 16;
> +				break;
> +			case IMAGE_REL_BASED_LOW:
> +				*x16 += (uint16_t)delta;
> +				break;
> +			case IMAGE_REL_BASED_HIGHLOW:
> +				*x32 += (uint32_t)delta;
> +				break;
> +			case IMAGE_REL_BASED_DIR64:
> +				*x64 += (uint64_t)delta;
> +				break;
> +			default:
> +				printf("Unknown Relocation off %x type %x\n",
> +				       offset, type);
> +			}
> +			relocs++;
> +		}
> +		rel = (const IMAGE_BASE_RELOCATION *)relocs;
> +	}
> +
> +	/* Populate the loaded image interface bits */
> +	loaded_image_info->image_base = efi;
> +	loaded_image_info->image_size = image_size;
> +
> +	return entry;
> +}
> -- 
> 2.1.4
> 

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

* [U-Boot] [PATCH 0/9] EFI payload / application support
  2015-12-26 15:31 ` Leif Lindholm
@ 2015-12-26 16:27   ` Alexander Graf
  2015-12-26 19:34     ` Leif Lindholm
  2015-12-27 18:10   ` Tom Rini
  1 sibling, 1 reply; 70+ messages in thread
From: Alexander Graf @ 2015-12-26 16:27 UTC (permalink / raw)
  To: u-boot



On 26.12.15 16:31, Leif Lindholm wrote:
> On Tue, Dec 22, 2015 at 02:57:47PM +0100, Alexander Graf wrote:
>> This is my Christmas present for my openSUSE friends :).
>>
>> U-Boot is a great project for embedded devices. However, convincing
>> everyone involved that only for "a few oddball ARM devices" we need to
>> support different configuration formats from grub2 when all other platforms
>> (PPC, System Z, x86) are standardized on a single format is a nightmare.
>>
>> So we started to explore alternatives. At first, people tried to get
>> grub2 running using the u-boot api interface. However, FWIW that one
>> doesn't support relocations, so you need to know where to link grub2 to
>> at compile time. It also seems to be broken more often than not. And on
>> top of it all, it's a one-off interface, so yet another thing to maintain.
>>
>> That led to a nifty idea. What if we can just implement the EFI application
>> protocol on top of U-Boot? Then we could compile a single grub2 binary for
>> uEFI based systems and U-Boot based systems and as soon as that one's loaded,
>> everything looks and feels (almost) the same.
>>
>> This patch set is the result of pursuing this endeavor.
> 
> Thanks, this is a very cool thing.
> I meant to reply sooner, but Christmas got in the way.
> 
>>   - I am successfully able to run grub2 and Linux EFI binaries with this code.
>>   - When enabled, the resulting U-Boot binary only grows by ~10kb,
>>     so it's very light weight.
>>   - It works on 32bit ARM and AArch64. 
>>   - All storage devices are directly accessible
>>   - No runtime services (all calls return unimplemented)
> 
> Yeah, this is a bit of a pain point. The time services, virtual memory
> services and reset being the key ones.

I guess reset should be pretty well doable. What are virtual memory
services? The bits that translate RTS code to run in virtual address
space somewhere else?

> 
>>   - No EFI variables
> 
> This would obviously (from my point of view) be desirable, but at
> least initially, we can do most things without persistent variables.

Doing EFI variables before exiting boot services is easy - we could even
just map U-Boot variables to EFI variables. That could come in handy for
cases where you want U-Boot to tell you which board you're on so you can
refer to different dtb files in your grub.cfg (if you need to override
the dtb).

Making them persistent is another difficult question - U-Boot usually
splits "modify variable" from "store variable pool to nvram".

And the hardest part would obviously be to make all of this work while
Linux is running ;). I'd definitely prefer to defer that bit to later.

> 
>> Of course, there are still a few things one could do on top:
>>
>>   - Implement removable media booting (search for /efi/boot/boota{a64,rm}.efi)
> 
> Yeah, that would be top of my wishlist.

That should be pretty simple to do - maybe we can even get away without
any C code for it.

> 
>>   - Improve disk media detection (don't scan, use what information we have)
>>   - Add EFI variable support using NVRAM
>>   - Add GFX support
> 
> GFX support was actually never implemented for U-Boot GRUB, so from
> this p.o.v. it is not a shortcoming over the existing impementation.

Heh ;). My goal here really is to make U-Boot based systems be en par
with TianoCore based ones in terms of usability.

> 
>>   - Make EFI Shell work ;)
> 
>     - Network device support.

Oh, good point. I forgot about that one.

> I also spotted a couple of minor things while playing around (things
> like image exit being missing), but these will be easy to flush out.

Awesome, looking forward to the review! :)

Thanks a lot for taking the time to look at this patch set.


Alex

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

* [U-Boot] [PATCH 4/9] efi_loader: Add boot time services
  2015-12-22 13:57 ` [U-Boot] [PATCH 4/9] efi_loader: Add boot time services Alexander Graf
  2015-12-22 14:15   ` Andreas Färber
@ 2015-12-26 18:09   ` Leif Lindholm
  2016-01-15  0:13     ` Alexander Graf
  2016-01-15  3:40     ` Alexander Graf
  1 sibling, 2 replies; 70+ messages in thread
From: Leif Lindholm @ 2015-12-26 18:09 UTC (permalink / raw)
  To: u-boot

On Tue, Dec 22, 2015 at 02:57:51PM +0100, Alexander Graf wrote:
> When an EFI application runs, it has access to a few descriptor and callback
> tables to instruct the EFI compliant firmware to do things for it. The bulk
> of those interfaces are "boot time services". They handle all object management,
> and memory allocation.
> 
> This patch adds support for the boot time services and also exposes a system
> table, which is the point of entry descriptor table for EFI payloads.

One overall observation, and I may help track these down - but not all
for this review: this code uses EFI_UNSUPPORTED as a default
"something went wrong" error code, but this is not actually supported
by the specification. I'm pointing out a few of these, but it would be
preferable if we could crowdsource this a bit since there are quire a
few instances...

> Signed-off-by: Alexander Graf <agraf@suse.de>
> ---
>  include/efi_loader.h          |  41 +++
>  lib/efi_loader/efi_boottime.c | 838 ++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 879 insertions(+)
>  create mode 100644 lib/efi_loader/efi_boottime.c
> 
> diff --git a/include/efi_loader.h b/include/efi_loader.h
> index da82354..ed7c389 100644
> --- a/include/efi_loader.h
> +++ b/include/efi_loader.h
> @@ -24,14 +24,55 @@
>  #include <efi_api.h>
>  #include <linux/list.h>
>  
> +/* #define DEBUG_EFI */
> +
> +#ifdef DEBUG_EFI
> +#define EFI_ENTRY(format, ...) do { \
> +	efi_restore_gd(); \
> +	printf("EFI: Entry %s(" format ")\n", __func__, ##__VA_ARGS__); \
> +	} while(0)
> +#else
> +#define EFI_ENTRY(format, ...) do { \
> +	efi_restore_gd(); \
> +	} while(0)
> +#endif
> +
> +#define EFI_EXIT(ret) efi_exit_func(ret);
> +
> +extern struct efi_system_table systab;
> +
>  extern const efi_guid_t efi_guid_device_path;
>  extern const efi_guid_t efi_guid_loaded_image;
>  
> +struct efi_class_map {
> +	const efi_guid_t *guid;
> +	const void *interface;
> +};
> +
> +struct efi_handler {
> +	const efi_guid_t *guid;
> +	efi_status_t (EFIAPI *open)(void *handle,
> +			efi_guid_t *protocol, void **protocol_interface,
> +			void *agent_handle, void *controller_handle,
> +			uint32_t attributes);
> +};
> +
> +struct efi_object {
> +	struct list_head link;
> +	struct efi_handler protocols[4];
> +	void *handle;
> +};
> +extern struct list_head efi_obj_list;
> +
>  efi_status_t efi_return_handle(void *handle,
>  		efi_guid_t *protocol, void **protocol_interface,
>  		void *agent_handle, void *controller_handle,
>  		uint32_t attributes);
> +void efi_timer_check(void);
>  void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info);
> +void efi_save_gd(void);
> +void efi_restore_gd(void);
> +efi_status_t efi_exit_func(efi_status_t ret);
>  
>  #define EFI_LOADER_POOL_SIZE (128 * 1024 * 1024)
>  void *efi_loader_alloc(uint64_t len);
> diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
> new file mode 100644
> index 0000000..ed95962
> --- /dev/null
> +++ b/lib/efi_loader/efi_boottime.c
> @@ -0,0 +1,838 @@
> +/*
> + *  EFI application boot time services
> + *
> + *  Copyright (c) 2015 Alexander Graf
> + *
> + *  This library is free software; you can redistribute it and/or
> + *  modify it under the terms of the GNU Lesser General Public
> + *  License as published by the Free Software Foundation; either
> + *  version 2.1 of the License, or (at your option) any later version.
> + *
> + *  This library is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + *  Lesser General Public License for more details.
> + *
> + *  You should have received a copy of the GNU Lesser General Public
> + *  License along with this library; if not, write to the Free Software
> + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
> + *
> + *  SPDX-License-Identifier:     LGPL-2.1+
> + */
> +
> +#define DEBUG_EFI
> +
> +#include <common.h>
> +#include <efi_loader.h>
> +#include <malloc.h>
> +#include <asm/global_data.h>
> +#include <libfdt_env.h>
> +#include <u-boot/crc.h>
> +#include <bootm.h>
> +#include <inttypes.h>
> +#include <watchdog.h>
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +/*
> + * EFI can pass arbitrary additional "tables" containing vendor specific
> + * information to the payload. One such table is the FDT table which contains
> + * a pointer to a flattened device tree blob.
> + *
> + * In most cases we want to pass an FDT to the payload, so reserve one slot of
> + * config table space for it. The pointer gets populated by do_bootefi_exec().
> + */
> +static struct efi_configuration_table efi_conf_table[] = {
> +	{
> +		.guid = EFI_FDT_GUID,
> +	},
> +};
> +
> +/*
> + * The "gd" pointer lives in a register on ARM and AArch64 that we declare
> + * fixed when compiling U-Boot. However, the payload does now know about that
> + * restriction so we need to manually swap its and our view of that register on
> + * EFI callback entry/exit.
> + */
> +static volatile void *efi_gd, *app_gd;
> +
> +/* Called from do_bootefi_exec() */
> +void efi_save_gd(void)
> +{
> +	efi_gd = gd;
> +}
> +
> +/* Called on every callback entry */
> +void efi_restore_gd(void)
> +{
> +	if (gd != efi_gd)
> +		app_gd = gd;
> +	gd = efi_gd;
> +}
> +
> +/* Called on every callback exit */
> +efi_status_t efi_exit_func(efi_status_t ret)
> +{
> +	gd = app_gd;
> +	return ret;
> +}
> +
> +static efi_status_t efi_unsupported(const char *funcname)
> +{
> +#ifdef DEBUG_EFI
> +	printf("EFI: App called into unimplemented function %s\n", funcname);
> +#endif
> +	return EFI_EXIT(EFI_UNSUPPORTED);

Not always a legal return status.

> +}
> +
> +static unsigned long efi_raise_tpl(unsigned long new_tpl)
> +{
> +	EFI_ENTRY("0x%lx", new_tpl);
> +	return EFI_EXIT(efi_unsupported(__func__));

"Unlike other UEFI interface functions, EFI_BOOT_SERVICES.RaiseTPL()
does not return a status code. Instead, it returns the previous task
priority level, which is to be restored later with a matching call to
RestoreTPL()."

> +}
> +
> +static void efi_restore_tpl(unsigned long old_tpl)
> +{
> +	EFI_ENTRY("0x%lx", old_tpl);
> +	EFI_EXIT(efi_unsupported(__func__));

(void function, nothing to return)

> +}
> +
> +static void *efi_alloc(uint64_t len, int memory_type)
> +{
> +	switch (memory_type) {
> +	case EFI_LOADER_DATA:
> +		return efi_loader_alloc(len);
> +	default:
> +		return malloc(len);
> +	}
> +}
> +
> +static efi_status_t efi_allocate_pages(int type, int memory_type,
> +				       unsigned long pages, uint64_t *memory)
> +{
> +	u64 len = pages << 12;
> +	efi_status_t r = EFI_SUCCESS;
> +
> +	EFI_ENTRY("%d, %d, 0x%lx, %p", type, memory_type, pages, memory);
> +
> +	switch (type) {
> +	case 0:
> +		/* Any page means we can go to efi_alloc */
> +		*memory = (unsigned long)efi_alloc(len, memory_type);
> +		break;
> +	case 1:
> +		/* Max address */
> +		if (gd->relocaddr < *memory) {
> +			*memory = (unsigned long)efi_alloc(len, memory_type);
> +			break;
> +		}
> +		r = EFI_UNSUPPORTED;

EFI_OUT_OF_RESOURCES/EFI_NOT_FOUND?

> +		break;
> +	case 2:
> +		/* Exact address, grant it. The addr is already in *memory. */

As far as I can tell, this is why GRUB works. Because it filters
through the memory map manually, requesting to allocate its heap at an
exact address in a region of free memory in the UEFI memory map.

The key is that EFI_LOADER_MEMORY will be used by applications loaded
as well as by U-Boot to load applications into. A simple example where
this could be problematic would be a large(ish) initrd loaded via initrd=
on kernel (stub loader) command line rather than via GRUB.

> +		break;
> +	default:

It would actually be fair here to state that the above are the only
types supported by the UEFI specification, as opposed to not being
implemented.

> +		r = EFI_UNSUPPORTED;

Actually, not a valid return value.
EFI_INVALID_PARAMETER

> +		break;
> +	}
> +
> +	return EFI_EXIT(r);
> +}
> +
> +static efi_status_t efi_free_pages(uint64_t memory, unsigned long pages)
> +{
> +	/* We don't free, let's cross our fingers we have plenty RAM */
> +	EFI_ENTRY("%"PRIx64", 0x%lx", memory, pages);
> +	return EFI_EXIT(EFI_SUCCESS);
> +}
> +
> +/*
> + * Returns the EFI memory map. In our case, this looks pretty simple:
> + *
> + *  ____________________________    TOM
> + * |                            |
> + * |    Second half of U-Boot   |
> + * |____________________________|   &__efi_runtime_stop
> + * |                            |
> + * |    EFI Runtime Services    |
> + * |____________________________|   &__efi_runtime_start
> + * |                            |
> + * |    First half of U-Boot    |
> + * |____________________________|   start of EFI loader allocation space
> + * |                            |
> + * |          Free RAM          |
> + * |____________________________|   CONFIG_SYS_SDRAM_BASE
> + *
> + * All pointers are extended to live on a 4k boundary. After exiting the boot
> + * services, only the EFI Runtime Services chunk of memory stays alive.
> + */
> +static efi_status_t efi_get_memory_map(unsigned long *memory_map_size,
> +			       struct efi_mem_desc *memory_map,
> +			       unsigned long *map_key,
> +			       unsigned long *descriptor_size,
> +			       uint32_t *descriptor_version)
> +{
> +	struct efi_mem_desc efi_memory_map[] = {
> +		{
> +			/* RAM before U-Boot */
> +			.type = EFI_CONVENTIONAL_MEMORY,
> +			.attribute = 1 << EFI_MEMORY_WB_SHIFT,
> +		},
> +		{
> +			/* First half of U-Boot */
> +			.type = EFI_LOADER_DATA,
> +			.attribute = 1 << EFI_MEMORY_WB_SHIFT,
> +		},
> +		{
> +			/* EFI Runtime Services */
> +			.type = EFI_RUNTIME_SERVICES_CODE,
> +			.attribute = 1 << EFI_MEMORY_WB_SHIFT,
> +		},
> +		{
> +			/* Second half of U-Boot */
> +			.type = EFI_LOADER_DATA,
> +			.attribute = 1 << EFI_MEMORY_WB_SHIFT,
> +		},
> +	};
> +	ulong runtime_start, runtime_end, runtime_len_pages, runtime_len;
> +
> +	EFI_ENTRY("%p, %p, %p, %p, %p", memory_map_size, memory_map, map_key,
> +		  descriptor_size, descriptor_version);
> +
> +	runtime_start = (ulong)&__efi_runtime_start & ~0xfffULL;
> +	runtime_end = ((ulong)&__efi_runtime_stop + 0xfff) & ~0xfffULL;
> +	runtime_len_pages = (runtime_end - runtime_start) >> 12;
> +	runtime_len = runtime_len_pages << 12;
> +
> +	/* Fill in where normal RAM is (up to U-Boot) */
> +	efi_memory_map[0].num_pages = gd->relocaddr >> 12;

U-Boot question: is gd->relocaddr always the offset from start of RAM?
How does this work with gaps in memory map?

> +#ifdef CONFIG_SYS_SDRAM_BASE
> +	efi_memory_map[0].physical_start = CONFIG_SYS_SDRAM_BASE;
> +	efi_memory_map[0].virtual_start = CONFIG_SYS_SDRAM_BASE;
> +	efi_memory_map[0].num_pages -= CONFIG_SYS_SDRAM_BASE >> 12;
#else
#error "..."
?
> +#endif
> +
> +	/* Remove U-Boot from the available RAM view */
> +	efi_memory_map[0].num_pages -= gd->mon_len >> 12;
> +
> +	/* Remove the malloc area from the available RAM view */
> +	efi_memory_map[0].num_pages -= TOTAL_MALLOC_LEN >> 12;
> +
> +	/* Give us some space for the stack */
> +	efi_memory_map[0].num_pages -= (16 * 1024 * 1024) >> 12;
> +
> +	/* Reserve the EFI loader pool */
> +	efi_memory_map[0].num_pages -= EFI_LOADER_POOL_SIZE >> 12;
> +
> +	/* Cut out the runtime services */
> +	efi_memory_map[2].physical_start = runtime_start;
> +	efi_memory_map[2].virtual_start = efi_memory_map[2].physical_start;
> +	efi_memory_map[2].num_pages = runtime_len_pages;
> +
> +	/* Allocate the rest to U-Boot */
> +	efi_memory_map[1].physical_start = efi_memory_map[0].physical_start +
> +					   (efi_memory_map[0].num_pages << 12);
> +	efi_memory_map[1].virtual_start = efi_memory_map[1].physical_start;
> +	efi_memory_map[1].num_pages = (runtime_start -
> +				       efi_memory_map[1].physical_start) >> 12;
> +
> +	efi_memory_map[3].physical_start = runtime_start + runtime_len;
> +	efi_memory_map[3].virtual_start = efi_memory_map[3].physical_start;
> +	efi_memory_map[3].num_pages = (gd->ram_top -
> +				       efi_memory_map[3].physical_start) >> 12;
> +
> +	*memory_map_size = sizeof(efi_memory_map);
> +
> +	if (descriptor_size)
> +		*descriptor_size = sizeof(struct efi_mem_desc);
> +
> +	if (*memory_map_size < sizeof(efi_memory_map)) {
> +		return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
> +	}
> +
> +	if (memory_map)
> +		memcpy(memory_map, efi_memory_map, sizeof(efi_memory_map));
> +
> +	return EFI_EXIT(EFI_SUCCESS);
> +}
> +
> +static efi_status_t efi_allocate_pool(int pool_type, unsigned long size, void **buffer)
> +{
> +	return efi_allocate_pages(0, pool_type, (size + 0xfff) >> 12, (void*)buffer);
> +}
> +
> +static efi_status_t efi_free_pool(void *buffer)
> +{
> +	return efi_free_pages((ulong)buffer, 0);
> +}
> +
> +/*
> + * Our event capabilities are very limited. Only support a single
> + * event to exist, so we don't need to maintain lists.
> + */
> +static struct {
> +	enum efi_event_type type;
> +	u32 trigger_type;
> +	u32 trigger_time;
> +	u64 trigger_next;
> +	unsigned long notify_tpl;
> +	void (*notify_function) (void *event, void *context);
> +	void *notify_context;
> +} efi_event;
> +
> +static efi_status_t efi_create_event(enum efi_event_type type, ulong notify_tpl,
> +			     void (*notify_function) (void *event,
> +						      void *context),
> +			     void *notify_context, void **event)
> +{
> +	EFI_ENTRY("%d, 0x%lx, %p, %p", type, notify_tpl, notify_function,
> +		  notify_context);
> +	if (efi_event.notify_function) {
> +		/* We only support one event at a time */
> +		return EFI_EXIT(EFI_UNSUPPORTED);

EFI_OUT_OF_RESOURCES would be a better return value here.

> +	}
> +
> +	efi_event.type = type;
> +	efi_event.notify_tpl = notify_tpl;
> +	efi_event.notify_function = notify_function;
> +	efi_event.notify_context = notify_context;
> +	*event = &efi_event;
> +
> +	return EFI_EXIT(EFI_SUCCESS);
> +}
> +
> +/*
> + * Our timers have to work without interrupts, so we check whenever keyboard
> + * input or disk accesses happen if enough time elapsed for it to fire.
> + */
> +void efi_timer_check(void)
> +{
> +	u64 now = timer_get_us();
> +
> +	if (now >= efi_event.trigger_next) {
> +		/* Triggering! */
> +		if (efi_event.trigger_type == EFI_TIMER_PERIODIC)
> +			efi_event.trigger_next += efi_event.trigger_time / 10;
> +		efi_event.notify_function(&efi_event, efi_event.notify_context);
> +	}
> +
> +	WATCHDOG_RESET();
> +}
> +
> +static efi_status_t efi_set_timer(void *event, int type, uint64_t trigger_time)
> +{
> +	/* We don't have 64bit division available everywhere, so limit timer
> +	 * distances to 32bit bits. */
> +	u32 trigger32 = trigger_time;

Add a warning message if this limit is exceeded?

> +
> +	EFI_ENTRY("%p, %d, %"PRIx64, event, type, trigger_time);
> +	if (event != &efi_event) {
> +		/* We only support one event at a time */
> +		return EFI_EXIT(EFI_UNSUPPORTED);

This function should only ever be called with an event successfully
created via create_event (and stored into efi_event). If we're called
with another event handle, EFI_INVALID_PARAMETER is the appropriate
error code.

> +	}
> +
> +	switch (type) {
> +	case EFI_TIMER_STOP:
> +		efi_event.trigger_next = -1ULL;
> +		break;
> +	case EFI_TIMER_PERIODIC:
> +	case EFI_TIMER_RELATIVE:
> +		efi_event.trigger_next = timer_get_us() + (trigger32 / 10);
> +		break;
> +	default:
> +		return EFI_EXIT(EFI_UNSUPPORTED);
> +	}
> +	efi_event.trigger_type = type;
> +	efi_event.trigger_time = trigger_time;
> +
> +	return EFI_EXIT(EFI_SUCCESS);
> +}
> +
> +static efi_status_t efi_wait_for_event(unsigned long num_events, void *event,
> +			       unsigned long *index)
> +{
> +	EFI_ENTRY("%ld, %p, %p", num_events, event, index);
> +	return EFI_EXIT(efi_unsupported(__func__));
> +}
> +
> +static efi_status_t efi_signal_event(void *event)
> +{
> +	EFI_ENTRY("%p", event);
> +	return EFI_EXIT(efi_unsupported(__func__));
> +}
> +
> +static efi_status_t efi_close_event(void *event)
> +{
> +	EFI_ENTRY("%p", event);
> +	return EFI_EXIT(efi_unsupported(__func__));
> +}
> +
> +static efi_status_t efi_check_event(void *event)
> +{
> +	EFI_ENTRY("%p", event);
> +	return EFI_EXIT(efi_unsupported(__func__));
> +}
> +
> +static efi_status_t efi_install_protocol_interface(void **handle,
> +					   efi_guid_t *protocol,
> +					   int protocol_interface_type,
> +					   void *protocol_interface)
> +{
> +	EFI_ENTRY("%p, %p, %d, %p", handle, protocol, protocol_interface_type,
> +		  protocol_interface);
> +	return EFI_EXIT(efi_unsupported(__func__));
> +}
> +static efi_status_t efi_reinstall_protocol_interface(void *handle,
> +					     efi_guid_t *protocol,
> +					     void *old_interface,
> +					     void *new_interface)
> +{
> +	EFI_ENTRY("%p, %p, %p, %p", handle, protocol, old_interface,
> +		  new_interface);
> +	return EFI_EXIT(efi_unsupported(__func__));
> +}
> +
> +static efi_status_t efi_uninstall_protocol_interface(void *handle,
> +					     efi_guid_t *protocol,
> +					     void *protocol_interface)
> +{
> +	EFI_ENTRY("%p, %p, %p", handle, protocol, protocol_interface);
> +	return EFI_EXIT(efi_unsupported(__func__));
> +}
> +
> +static efi_status_t efi_register_protocol_notify(efi_guid_t *protocol,
> +					 void *event, void **registration)
> +{
> +	EFI_ENTRY("%p, %p, %p", protocol, event, registration);
> +	return EFI_EXIT(efi_unsupported(__func__));
> +}
> +
> +static int efi_search(enum efi_locate_search_type search_type,
> +			efi_guid_t *protocol, void *search_key,
> +			struct efi_object *efiobj)
> +{
> +	int i;
> +
> +	switch (search_type) {
> +	case all_handles:
> +		return 0;
> +	case by_register_notify:
> +		return -1;
> +	case by_protocol:
> +		for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) {
> +			const efi_guid_t *guid = efiobj->protocols[i].guid;
> +			if (guid && !memcmp(guid, protocol, sizeof(efi_guid_t)))
> +				return 0;
> +		}
> +		return -1;
> +	}
> +
> +	return -1;
> +}
> +
> +static efi_status_t efi_locate_handle(enum efi_locate_search_type search_type,
> +			efi_guid_t *protocol, void *search_key,
> +			unsigned long *buffer_size, efi_handle_t *buffer)
> +{
> +	struct list_head *lhandle;
> +	unsigned long size = 0;
> +
> +	EFI_ENTRY("%d, %p, %p, %p, %p", search_type, protocol, search_key,
> +		  buffer_size, buffer);
> +
> +	/* Count how much space we need */
> +	list_for_each(lhandle, &efi_obj_list) {
> +		struct efi_object *efiobj;
> +		efiobj = list_entry(lhandle, struct efi_object, link);
> +		if (!efi_search(search_type, protocol, search_key, efiobj)) {
> +			size += sizeof(void*);
> +		}
> +	}
> +
> +	if (*buffer_size < size) {
> +		*buffer_size = size;
> +		return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
> +	}
> +
> +	/* Then fill the array */
> +	list_for_each(lhandle, &efi_obj_list) {
> +		struct efi_object *efiobj;
> +		efiobj = list_entry(lhandle, struct efi_object, link);
> +		if (!efi_search(search_type, protocol, search_key, efiobj)) {
> +			*(buffer++) = efiobj->handle;
> +		}
> +	}
> +
> +	*buffer_size = size;
> +	return EFI_EXIT(EFI_SUCCESS);
> +}
> +
> +static efi_status_t efi_locate_device_path(efi_guid_t *protocol,
> +				   struct efi_device_path **device_path,
> +				   efi_handle_t *device)
> +{
> +	EFI_ENTRY("%p, %p, %p", protocol, device_path, device);
> +	return EFI_EXIT(efi_unsupported(__func__));
> +}
> +
> +static efi_status_t efi_install_configuration_table(efi_guid_t *guid, void *table)
> +{
> +	EFI_ENTRY("%p, %p", guid, table);
> +	/* Only allow overriding of the FDT */
> +	if (memcmp(guid, &efi_conf_table[0].guid, sizeof(efi_guid_t)))
> +		return EFI_EXIT(EFI_UNSUPPORTED);
> +
> +	efi_conf_table[0].table = table;
> +	return EFI_EXIT(EFI_SUCCESS);
> +}
> +
> +static efi_status_t efi_load_image(bool boot_policy, efi_handle_t parent_image,
> +			   struct efi_device_path *file_path,
> +			   void *source_buffer, unsigned long source_size,
> +			   efi_handle_t *image_handle)
> +{
> +	static struct efi_object loaded_image_info_obj = {
> +		.protocols = {
> +			{
> +				.guid = &efi_guid_loaded_image,
> +				.open = &efi_return_handle,
> +			},
> +		},
> +	};
> +	struct efi_loaded_image *info;
> +	struct efi_object *obj;
> +
> +	EFI_ENTRY("%d, %p, %p, %p, %ld, %p", boot_policy, parent_image,
> +		  file_path, source_buffer, source_size, image_handle);
> +	info = malloc(sizeof(*info));
> +	obj = malloc(sizeof(loaded_image_info_obj));
> +	memset(info, 0, sizeof(*info));
> +	memcpy(obj, &loaded_image_info_obj, sizeof(loaded_image_info_obj));
> +	obj->handle = info;
> +	info->file_path = file_path;
> +	info->reserved = efi_load_pe(source_buffer, info);
> +	if (!info->reserved) {
> +		free(info);
> +		free(obj);
> +		return EFI_EXIT(EFI_UNSUPPORTED);
> +	}
> +
> +	*image_handle = info;
> +	list_add_tail(&obj->link, &efi_obj_list);
> +
> +	return EFI_EXIT(EFI_SUCCESS);
> +}
> +
> +static efi_status_t efi_start_image(efi_handle_t image_handle,
> +			    unsigned long *exit_data_size,
> +			    s16 **exit_data)
> +{
> +	ulong (*entry)(void *image_handle, struct efi_system_table *st);
> +	struct efi_loaded_image *info = image_handle;
> +
> +	EFI_ENTRY("%p, %p, %p", image_handle, exit_data_size, exit_data);
> +	entry = info->reserved;
> +
> +	/* call the image! */
> +	entry(image_handle, &systab);
> +
> +	/* Should usually never get here */
> +	return EFI_EXIT(EFI_SUCCESS);
> +}
> +
> +static efi_status_t efi_exit(void *image_handle, long exit_status,
> +		     unsigned long exit_data_size,
> +		     uint16_t *exit_data)
> +{
> +	EFI_ENTRY("%p, %ld, %ld, %p", image_handle, exit_status,
> +		  exit_data_size, exit_data);
> +	return EFI_EXIT(efi_unsupported(__func__));
> +}
> +
> +static struct efi_object *efi_search_obj(void *handle)
> +{
> +	struct list_head *lhandle;
> +
> +	list_for_each(lhandle, &efi_obj_list) {
> +		struct efi_object *efiobj;
> +		efiobj = list_entry(lhandle, struct efi_object, link);
> +		if (efiobj->handle == handle)
> +			return efiobj;
> +	}
> +
> +	return NULL;
> +}
> +
> +static efi_status_t efi_unload_image(void *image_handle)
> +{
> +	struct efi_object *efiobj;
> +
> +	EFI_ENTRY("%p", image_handle);
> +	efiobj = efi_search_obj(image_handle);
> +	if (efiobj)
> +		list_del(&efiobj->link);
> +
> +	return EFI_EXIT(EFI_SUCCESS);
> +}
> +
> +static efi_status_t efi_exit_boot_services(void *image_handle,
> +				   unsigned long map_key)
> +{
> +	EFI_ENTRY("%p, %ld", image_handle, map_key);
> +
> +	/* This stops all lingering devices */
> +	bootm_disable_interrupts();
> +
> +	/* Give the payload some time to boot */
> +	WATCHDOG_RESET();
> +
> +	return EFI_EXIT(EFI_SUCCESS);
> +}
> +
> +static efi_status_t efi_get_next_monotonic_count(uint64_t *count)
> +{
> +	EFI_ENTRY("%p", count);
> +	*count = timer_get_us();
> +	return EFI_EXIT(EFI_SUCCESS);
> +}
> +
> +static efi_status_t efi_stall(unsigned long microseconds)
> +{
> +	EFI_ENTRY("%ld", microseconds);
> +	udelay(microseconds);
> +	return EFI_EXIT(EFI_SUCCESS);
> +}
> +
> +static efi_status_t efi_set_watchdog_timer(unsigned long timeout,
> +				   uint64_t watchdog_code,
> +				   unsigned long data_size,
> +				   uint16_t *watchdog_data)
> +{
> +	EFI_ENTRY("%ld, 0x%"PRIx64", %ld, %p", timeout, watchdog_code,
> +		  data_size, watchdog_data);
> +	return EFI_EXIT(efi_unsupported(__func__));
> +}
> +
> +static efi_status_t efi_connect_controller(efi_handle_t controller_handle,
> +				   efi_handle_t *driver_image_handle,
> +				   struct efi_device_path *remain_device_path,
> +				   bool recursive)
> +{
> +	EFI_ENTRY("%p, %p, %p, %d", controller_handle, driver_image_handle,
> +		  remain_device_path, recursive);
> +	return EFI_EXIT(efi_unsupported(__func__));
> +}
> +
> +static efi_status_t efi_disconnect_controller(void *controller_handle,
> +				      void *driver_image_handle,
> +				      void *child_handle)
> +{
> +	EFI_ENTRY("%p, %p, %p", controller_handle, driver_image_handle,
> +		  child_handle);
> +	return EFI_EXIT(efi_unsupported(__func__));
> +}
> +
> +static efi_status_t efi_close_protocol(void *handle, efi_guid_t *protocol,
> +			       void *agent_handle, void *controller_handle)
> +{
> +	EFI_ENTRY("%p, %p, %p, %p", handle, protocol, agent_handle,
> +		  controller_handle);
> +	return EFI_EXIT(efi_unsupported(__func__));
> +}
> +
> +static efi_status_t efi_open_protocol_information(efi_handle_t handle,
> +					  efi_guid_t *protocol,
> +					  struct efi_open_protocol_info_entry **entry_buffer,
> +					  unsigned long *entry_count)
> +{
> +	EFI_ENTRY("%p, %p, %p, %p", handle, protocol, entry_buffer,
> +		  entry_count);
> +	return EFI_EXIT(efi_unsupported(__func__));
> +}
> +
> +static efi_status_t efi_protocols_per_handle(void *handle,
> +				     efi_guid_t ***protocol_buffer,
> +				     unsigned long *protocol_buffer_count)
> +{
> +	EFI_ENTRY("%p, %p, %p", handle, protocol_buffer,
> +		  protocol_buffer_count);
> +	return EFI_EXIT(efi_unsupported(__func__));
> +}
> +
> +static efi_status_t efi_locate_handle_buffer(
> +			enum efi_locate_search_type search_type,
> +			efi_guid_t *protocol, void *search_key,
> +			unsigned long *no_handles, efi_handle_t **buffer)
> +{
> +	EFI_ENTRY("%d, %p, %p, %p, %p", search_type, protocol, search_key,
> +		  no_handles, buffer);
> +	return EFI_EXIT(efi_unsupported(__func__));
> +}
> +
> +static struct efi_class_map efi_class_maps[] = {
> +	{
> +		.guid = &efi_guid_console_control,
> +		.interface = &efi_console_control
> +	},
> +};
> +
> +static efi_status_t efi_locate_protocol(efi_guid_t *protocol, void *registration,
> +			        void **protocol_interface)
> +{
> +	efi_status_t r = EFI_UNSUPPORTED;

EFI_NOT_FOUND

> +	int i;
> +
> +	EFI_ENTRY("%p, %p, %p", protocol, registration, protocol_interface);
> +	for (i = 0; i < ARRAY_SIZE(efi_class_maps); i++) {
> +		struct efi_class_map *curmap = &efi_class_maps[i];
> +		if (!memcmp(protocol, curmap->guid, sizeof(efi_guid_t))) {
> +			*protocol_interface = (void*)curmap->interface;
> +			return EFI_EXIT(EFI_SUCCESS);
> +		}
> +	}
> +
> +	return EFI_EXIT(r);
> +}
> +
> +static efi_status_t efi_install_multiple_protocol_interfaces(void **handle, ...)
> +{
> +	EFI_ENTRY("%p", handle);
> +	return EFI_EXIT(efi_unsupported(__func__));
> +}
> +
> +static efi_status_t efi_uninstall_multiple_protocol_interfaces(void *handle, ...)
> +{
> +	EFI_ENTRY("%p", handle);
> +	return EFI_EXIT(efi_unsupported(__func__));
> +}
> +
> +static efi_status_t efi_calculate_crc32(void *data, unsigned long data_size,
> +				uint32_t *crc32_p)
> +{
> +	EFI_ENTRY("%p, %ld", data, data_size);
> +	*crc32_p = crc32(0, data, data_size);
> +	return EFI_EXIT(EFI_SUCCESS);
> +}
> +
> +static void efi_copy_mem(void *destination, void *source, unsigned long length)
> +{
> +	EFI_ENTRY("%p, %p, %ld", destination, source, length);
> +	memcpy(destination, source, length);
> +}
> +
> +static void efi_set_mem(void *buffer, unsigned long size, uint8_t value)
> +{
> +	EFI_ENTRY("%p, %ld, 0x%x", buffer, size, value);
> +	memset(buffer, value, size);
> +}
> +
> +static efi_status_t efi_open_protocol(void *handle, efi_guid_t *protocol,
> +			       void **protocol_interface, void *agent_handle,
> +			       void *controller_handle, uint32_t attributes)
> +{
> +	struct list_head *lhandle;
> +	int i;
> +	efi_status_t r = EFI_UNSUPPORTED;

(Correct use of EFI_UNSUPPORTED.)

> +
> +	EFI_ENTRY("%p, %p, %p, %p, %p, 0x%x", handle, protocol,
> +		  protocol_interface, agent_handle, controller_handle,
> +		  attributes);
> +	list_for_each(lhandle, &efi_obj_list) {
> +		struct efi_object *efiobj;
> +		efiobj = list_entry(lhandle, struct efi_object, link);
> +
> +		if (efiobj->handle != handle)
> +			continue;
> +
> +		for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) {
> +			struct efi_handler *handler = &efiobj->protocols[i];
> +			const efi_guid_t *hprotocol = handler->guid;
> +			if (!hprotocol)
> +				break;
> +			if (!memcmp(hprotocol, protocol, sizeof(efi_guid_t))) {
> +				r = handler->open(handle, protocol,
> +				    protocol_interface, agent_handle,
> +				    controller_handle, attributes);
> +				goto out;
> +			}
> +		}
> +	}
> +
> +out:
> +	return EFI_EXIT(r);
> +}
> +
> +static efi_status_t efi_handle_protocol(void *handle, efi_guid_t *protocol,
> +				void **protocol_interface)
> +{
> +	EFI_ENTRY("%p, %p, %p", handle, protocol, protocol_interface);
> +	return efi_open_protocol(handle, protocol, protocol_interface,
> +				 NULL, NULL, 0);
> +}
> +
> +static const struct efi_boot_services efi_boot_services = {
> +	.hdr = {
> +		.headersize = sizeof(struct efi_table_hdr),
> +	},
> +	.raise_tpl = efi_raise_tpl,
> +	.restore_tpl = efi_restore_tpl,
> +	.allocate_pages = efi_allocate_pages,
> +	.free_pages = efi_free_pages,
> +	.get_memory_map = efi_get_memory_map,
> +	.allocate_pool = efi_allocate_pool,
> +	.free_pool = efi_free_pool,
> +	.create_event = efi_create_event,
> +	.set_timer = efi_set_timer,
> +	.wait_for_event = efi_wait_for_event,
> +	.signal_event = efi_signal_event,
> +	.close_event = efi_close_event,
> +	.check_event = efi_check_event,
> +	.install_protocol_interface = efi_install_protocol_interface,
> +	.reinstall_protocol_interface = efi_reinstall_protocol_interface,
> +	.uninstall_protocol_interface = efi_uninstall_protocol_interface,
> +	.handle_protocol = efi_handle_protocol,
> +	.reserved = NULL,
> +	.register_protocol_notify = efi_register_protocol_notify,
> +	.locate_handle = efi_locate_handle,
> +	.locate_device_path = efi_locate_device_path,
> +	.install_configuration_table = efi_install_configuration_table,
> +	.load_image = efi_load_image,
> +	.start_image = efi_start_image,
> +	.exit = (void*)efi_exit,
> +	.unload_image = efi_unload_image,
> +	.exit_boot_services = efi_exit_boot_services,
> +	.get_next_monotonic_count = efi_get_next_monotonic_count,
> +	.stall = efi_stall,
> +	.set_watchdog_timer = efi_set_watchdog_timer,
> +	.connect_controller = efi_connect_controller,
> +	.disconnect_controller = efi_disconnect_controller,
> +	.open_protocol = efi_open_protocol,
> +	.close_protocol = efi_close_protocol,
> +	.open_protocol_information = efi_open_protocol_information,
> +	.protocols_per_handle = efi_protocols_per_handle,
> +	.locate_handle_buffer = efi_locate_handle_buffer,
> +	.locate_protocol = efi_locate_protocol,
> +	.install_multiple_protocol_interfaces = efi_install_multiple_protocol_interfaces,
> +	.uninstall_multiple_protocol_interfaces = efi_uninstall_multiple_protocol_interfaces,
> +	.calculate_crc32 = efi_calculate_crc32,
> +	.copy_mem = efi_copy_mem,
> +	.set_mem = efi_set_mem,
> +};
> +
> +
> +static uint16_t firmware_vendor[] = { 'U','-','b','o','o','t',0 };

Surely, if we're being formal, that should be 'D', 'a', 's', ' ',
... :)

> +struct efi_system_table systab = {
> +	.hdr = {
> +		.signature = EFI_SYSTEM_TABLE_SIGNATURE,
> +		.revision = 0x20000, /* 2.0 */

Really, this should claim to support revision 2.5, if not 2.6 (soon
to be released). AArch64 support was only introduced in 2.4.

> +		.headersize = sizeof(struct efi_table_hdr),
> +	},
> +	.fw_vendor = (long)firmware_vendor,
> +	.con_in = (void*)&efi_con_in,
> +	.con_out = (void*)&efi_con_out,
> +	.std_err = (void*)&efi_con_out,
> +	.runtime = (void*)&efi_runtime_services,
> +	.boottime = (void*)&efi_boot_services,
> +	.nr_tables = 1,
> +	.tables = (void*)efi_conf_table,
> +};
> -- 
> 2.1.4

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

* [U-Boot] [PATCH 6/9] efi_loader: Add runtime services
  2015-12-22 13:57 ` [U-Boot] [PATCH 6/9] efi_loader: Add runtime services Alexander Graf
@ 2015-12-26 18:33   ` Leif Lindholm
  2016-01-15  0:26     ` Alexander Graf
  0 siblings, 1 reply; 70+ messages in thread
From: Leif Lindholm @ 2015-12-26 18:33 UTC (permalink / raw)
  To: u-boot

On Tue, Dec 22, 2015 at 02:57:53PM +0100, Alexander Graf wrote:
> After booting has finished, EFI allows firmware to still interact with the OS
> using the "runtime services". These callbacks live in a separate address space,
> since they are available long after U-Boot has been overwritten by the OS.
> 
> However, since U-Boot has no notion of RTS, we just create an extremely minimal
> RTS stub that just declares all functions as unsupported. We could in the future
> map U-boot environment variables to EFI variables here.
> 
> Signed-off-by: Alexander Graf <agraf@suse.de>
> ---
>  arch/arm/cpu/armv8/u-boot.lds |  8 ++++++
>  arch/arm/cpu/u-boot.lds       | 13 ++++++++++
>  arch/arm/lib/sections.c       |  2 ++
>  include/efi_loader.h          |  3 +++
>  lib/efi_loader/efi_runtime.c  | 59 +++++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 85 insertions(+)
>  create mode 100644 lib/efi_loader/efi_runtime.c
> 
> diff --git a/arch/arm/cpu/armv8/u-boot.lds b/arch/arm/cpu/armv8/u-boot.lds
> index 4c12222..7c5b032 100644
> --- a/arch/arm/cpu/armv8/u-boot.lds
> +++ b/arch/arm/cpu/armv8/u-boot.lds
> @@ -42,6 +42,14 @@ SECTIONS
>  
>  	. = ALIGN(8);
>  
> +	.efi_runtime : {
> +                __efi_runtime_start = .;
> +		*(efi_runtime)
> +                __efi_runtime_stop = .;
> +	}
> +
> +	. = ALIGN(8);
> +
>  	.image_copy_end :
>  	{
>  		*(.__image_copy_end)
> diff --git a/arch/arm/cpu/u-boot.lds b/arch/arm/cpu/u-boot.lds
> index d48a905..b5198d0 100644
> --- a/arch/arm/cpu/u-boot.lds
> +++ b/arch/arm/cpu/u-boot.lds
> @@ -89,6 +89,19 @@ SECTIONS
>  
>  	. = ALIGN(4);
>  
> +	.__efi_runtime_start : {
> +		*(.__efi_runtime_start)
> +	}
> +
> +	.efi_runtime : {
> +		*(efi_runtime)
> +	}
> +
> +	.__efi_runtime_stop : {
> +		*(.__efi_runtime_stop)
> +	}
> +	. = ALIGN(4);
> +
>  	.image_copy_end :
>  	{
>  		*(.__image_copy_end)
> diff --git a/arch/arm/lib/sections.c b/arch/arm/lib/sections.c
> index a1205c3..21b3066 100644
> --- a/arch/arm/lib/sections.c
> +++ b/arch/arm/lib/sections.c
> @@ -27,4 +27,6 @@ char __rel_dyn_start[0] __attribute__((section(".__rel_dyn_start")));
>  char __rel_dyn_end[0] __attribute__((section(".__rel_dyn_end")));
>  char __secure_start[0] __attribute__((section(".__secure_start")));
>  char __secure_end[0] __attribute__((section(".__secure_end")));
> +char __efi_runtime_start[0] __attribute__((section(".__efi_runtime_start")));
> +char __efi_runtime_stop[0] __attribute__((section(".__efi_runtime_stop")));
>  char _end[0] __attribute__((section(".__end")));
> diff --git a/include/efi_loader.h b/include/efi_loader.h
> index 7fb2106..af1c88f 100644
> --- a/include/efi_loader.h
> +++ b/include/efi_loader.h
> @@ -39,6 +39,7 @@
>  
>  #define EFI_EXIT(ret) efi_exit_func(ret);
>  
> +extern const struct efi_runtime_services efi_runtime_services;
>  extern struct efi_system_table systab;
>  
>  extern const struct efi_simple_text_output_protocol efi_con_out;
> @@ -49,6 +50,8 @@ extern const efi_guid_t efi_guid_console_control;
>  extern const efi_guid_t efi_guid_device_path;
>  extern const efi_guid_t efi_guid_loaded_image;
>  
> +extern unsigned int __efi_runtime_start, __efi_runtime_stop;
> +
>  struct efi_class_map {
>  	const efi_guid_t *guid;
>  	const void *interface;
> diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c
> new file mode 100644
> index 0000000..214e1f5
> --- /dev/null
> +++ b/lib/efi_loader/efi_runtime.c
> @@ -0,0 +1,59 @@
> +/*
> + *  EFI application runtime services
> + *
> + *  Copyright (c) 2015 Alexander Graf
> + *
> + *  This library is free software; you can redistribute it and/or
> + *  modify it under the terms of the GNU Lesser General Public
> + *  License as published by the Free Software Foundation; either
> + *  version 2.1 of the License, or (at your option) any later version.
> + *
> + *  This library is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + *  Lesser General Public License for more details.
> + *
> + *  You should have received a copy of the GNU Lesser General Public
> + *  License along with this library; if not, write to the Free Software
> + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
> + *
> + *  SPDX-License-Identifier:     LGPL-2.1+
> + */
> +
> +#include <common.h>
> +#include <efi_loader.h>
> +
> +/*
> + * EFI Runtime code is still alive when U-Boot is long overwritten. To isolate
> + * this code from the rest, we put it into a special section.
> + *
> + *        !!WARNING!!
> + *
> + * This means that we can not rely on any code outside of this file at runtime.
> + * Please keep it fully self-contained.
> + */
> +asm(".section efi_runtime,\"a\"");
> +
> +static efi_status_t efi_unimplemented(void)
> +{
> +	return EFI_UNSUPPORTED;

Again, EFI_UNSUPPORTED is not necessarily a valid return value for all
runtime services.

> +}
> +
> +const struct efi_runtime_services efi_runtime_services = {
> +	.hdr = {
> +		.signature = EFI_RUNTIME_SERVICES_SIGNATURE,
> +		.revision = EFI_RUNTIME_SERVICES_REVISION,
> +		.headersize = sizeof(struct efi_table_hdr),
> +	},
> +	.get_time = (void *)&efi_unimplemented,

EFI_DEVICE_ERROR

> +	.set_time = (void *)&efi_unimplemented,

EFI_DEVICE_ERROR

> +	.get_wakeup_time = (void *)&efi_unimplemented,
> +	.set_wakeup_time = (void *)&efi_unimplemented,

Both of these are fine, and correct, to return EFI_UNSUPPORTED.

> +	.set_virtual_address_map = (void *)&efi_unimplemented,
> +	.convert_pointer = (void *)&efi_unimplemented,

There really isn't a way to gracefully decline these two functions.
All valid error codes refer to invalid inputs.

> +	.get_variable = (void *)&efi_unimplemented,

EFI_DEVICE_ERROR would probably be the closest thing to a correct
return code in this instance.

> +	.get_next_variable = (void *)&efi_unimplemented,

(get_next_variable_name?)
Again, EFI_DEVICE_ERROR, is probably the least wrong return value.

> +	.set_variable = (void *)&efi_unimplemented,

EFI_DEVICE_ERROR

> +	.get_next_high_mono_count = (void *)&efi_unimplemented,

EFI_DEVICE_ERROR

> +	.reset_system = (void *)&efi_unimplemented,

"The ResetSystem() function does not return."

> +};
> -- 
> 2.1.4

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

* [U-Boot] [PATCH 8/9] efi_loader: Add "bootefi" command
  2015-12-25  9:02     ` Alexander Graf
  2015-12-25  9:25       ` Andreas Färber
@ 2015-12-26 18:45       ` Leif Lindholm
  1 sibling, 0 replies; 70+ messages in thread
From: Leif Lindholm @ 2015-12-26 18:45 UTC (permalink / raw)
  To: u-boot

On Fri, Dec 25, 2015 at 10:02:44AM +0100, Alexander Graf wrote:
> On 24.12.15 12:15, Matwey V. Kornilov wrote:
> > Why just not to implement standard EFI behaviour when EFI looks for
> > boot-efi partition and proceed?
> 
> Well, what is "standard EFI behavior"?
> 
> There are 2 standard ways I'm aware of:
> 
>   1) NVRAM
> 
> The default case for 99.9% of the boots on normal EFI systems is based
> on variables in NVRAM that tell EFI which boot device to boot from.
> Since we don't implement EFI variables today, we can't really make use
> of this feature. And because you want to change the default boot device
> at runtime, we'd have to have runtime services be able to modify them
> after exiting boot services.
> 
>   2) Removable Media
> 
> There is another way implemented for "Removable Media" - mostly intended
> for USB sticks and the likes. Here EFI searches for a defined file name
> (EFI/boot/boot{arm,a64,x64}.efi) on the ESP partition and boots it.
> 
> Part 1 is very difficult to do without major rework of a few U-Boot
> components. If EFI becomes the de-facto standard way of booting with
> U-Boot, I think we'll walk down that road, but it's nothing I want to
> have to deal with in the initial enablement discussion.
> 
> Part 2 is easy to do. But then again it's also easy to do it using a
> boot script. Or a compiled in bootcmd. If it's really desired.

Sure, I've seen a lot more complicated boot operations than that
shipped in the default environment of many platforms.

> Which brings me to the next idea. What if we just implement exlinux.conf
> support for EFI binaries? Then all you need to do is have an
> extlinux.conf available on your generic EFI media that tells U-Boot
> where to load the grub binary from.

The problem with this is that you're adding things unrelated to UEFI
into a UEFI boot scenario. Now, depending on what you're looking for,
this may be fine - but it will not leave you with the ability to rely
on being able to "just work" with the UEFI support provided by
UEFI-aware operating systems and their installation media.

Basically, it comes down to preference - is this about:
- Leveraging the benefits of UEFI while staying with the U-Boot
  codebase.
or
- Leveraging some of the benefits of UEFI in order to give distros a
  more device-independent way of supporting U-Boot platforms.

> That way we wouldn't bend U-Boot completely away from its heritage, make
> use of its flexibility and all distributions that actually care about
> booting from U-Boot would easily be able to just put such a file in an
> rpm an install it always.

You would also need a way to distinguish whether booting with UEFI or
U-Boot efiload.

Sure, compared to stuff like flash-kernel, this is hardly rocket
science, but would be worth standardising early and hard.

> > If ARM board developers will enable EFI support in the future, we can
> > have single one JeOS having all possible dtb in KIWI image.
> > BeagleBone Black has its own u-boot on eMMC, and the user need to push
> > S2 button to force hardware to use our openSUSE u-boot from SD card.
> > Maybe something like that is for other boards. If the single one
> > required u-boot feature is to run EFI grub, then we can even don't
> > touch preinstalled bootloader, that is not possible now, because we
> > need our openSUSE boot scripts.
> 
> There are more things we need to solve before we can truly get to a
> universal booting solution. But one step at a time :).
> 
> The reason I implemented "bootefi" was really because it's the natural
> fit into how U-Boot handles all other formats today. I don't think this
> is going to be the last patch set around EFI support.
> 
> 
> Alex

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

* [U-Boot] [PATCH 8/9] efi_loader: Add "bootefi" command
  2015-12-25  9:25       ` Andreas Färber
  2015-12-25  9:40         ` Matwey V. Kornilov
@ 2015-12-26 18:55         ` Leif Lindholm
  2015-12-27 15:33           ` Alexander Graf
  1 sibling, 1 reply; 70+ messages in thread
From: Leif Lindholm @ 2015-12-26 18:55 UTC (permalink / raw)
  To: u-boot

On Fri, Dec 25, 2015 at 10:25:22AM +0100, Andreas F?rber wrote:
> Am 25.12.2015 um 10:02 schrieb Alexander Graf:
> [snip]
> > The reason I implemented "bootefi" was really because it's the natural
> > fit into how U-Boot handles all other formats today. I don't think this
> > is going to be the last patch set around EFI support.
> 
> I think what Matwey was suggesting is integrating your "bootefi" into
> the standard "distro" boot sequence environment, so that it probes each
> device for an EFI binary and if it finds one runs load and bootefi,
> without the need for any boot.scr.
> 
> That would be a follow-up patch.
> 
> It however conflicts with your idea of having some potentially
> board-specific code mess with "fdt addr" command before running "bootefi".

This could however be resolved by moving to a model where the
device-tree was considered a component of the firmware (which is how
we treat it in UEFI). If U-Boot had an awareness (if it does not
already) of an FDT being something it should have and know about, then
this could trivially be passed onto bootefi.
This could means a "default_fdt" environment variable which is loaded
automatically before bootcmd is executed.

> My solution would be to give boot.scr preference over *.efi, so that the
> user has a way to load dtb and run "bootefi" on his own, and otherwise
> fall back to just "bootefi" which'll spit a warning about lack of fdt if
> I read that correctly.

An explicit bootscript should always override a fallback boot option.
And booting the "removable boot path" is a fallback boot option.

Regards,

Leif

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

* [U-Boot] [PATCH 0/9] EFI payload / application support
  2015-12-26 16:27   ` Alexander Graf
@ 2015-12-26 19:34     ` Leif Lindholm
  2016-01-04 16:25       ` Alexander Graf
  0 siblings, 1 reply; 70+ messages in thread
From: Leif Lindholm @ 2015-12-26 19:34 UTC (permalink / raw)
  To: u-boot

On Sat, Dec 26, 2015 at 05:27:48PM +0100, Alexander Graf wrote:
> >> This patch set is the result of pursuing this endeavor.
> > 
> > Thanks, this is a very cool thing.
> > I meant to reply sooner, but Christmas got in the way.
> > 
> >>   - I am successfully able to run grub2 and Linux EFI binaries with this code.
> >>   - When enabled, the resulting U-Boot binary only grows by ~10kb,
> >>     so it's very light weight.
> >>   - It works on 32bit ARM and AArch64. 
> >>   - All storage devices are directly accessible
> >>   - No runtime services (all calls return unimplemented)
> > 
> > Yeah, this is a bit of a pain point. The time services, virtual memory
> > services and reset being the key ones.
> 
> I guess reset should be pretty well doable. What are virtual memory
> services? The bits that translate RTS code to run in virtual address
> space somewhere else?

Yup.

> > 
> >>   - No EFI variables
> > 
> > This would obviously (from my point of view) be desirable, but at
> > least initially, we can do most things without persistent variables.
> 
> Doing EFI variables before exiting boot services is easy - we could even
> just map U-Boot variables to EFI variables. That could come in handy for
> cases where you want U-Boot to tell you which board you're on so you can
> refer to different dtb files in your grub.cfg (if you need to override
> the dtb).
> 
> Making them persistent is another difficult question - U-Boot usually
> splits "modify variable" from "store variable pool to nvram".

Indeed.
UEFI might as well, but in more convoluted ways.

> And the hardest part would obviously be to make all of this work while
> Linux is running ;). I'd definitely prefer to defer that bit to later.

Of course.

And again - depending on ambition levels, implementing a version of
efibootmgr that ended up simply tweaking a /boot/uEnv.txt (or similar)
if U-Boot boot environment was detected would be entirely achievable.

> >> Of course, there are still a few things one could do on top:
> >>
> >>   - Implement removable media booting (search for /efi/boot/boota{a64,rm}.efi)
> > 
> > Yeah, that would be top of my wishlist.
> 
> That should be pretty simple to do - maybe we can even get away without
> any C code for it.

Should be possible.

> > 
> >>   - Improve disk media detection (don't scan, use what information we have)
> >>   - Add EFI variable support using NVRAM
> >>   - Add GFX support
> > 
> > GFX support was actually never implemented for U-Boot GRUB, so from
> > this p.o.v. it is not a shortcoming over the existing impementation.
> 
> Heh ;). My goal here really is to make U-Boot based systems be en par
> with TianoCore based ones in terms of usability.

Sure. Just setting the nearer goal post of "where can we replace
U-Boot API in GRUB".

> > 
> >>   - Make EFI Shell work ;)
> > 
> >     - Network device support.
> 
> Oh, good point. I forgot about that one.
> 
> > I also spotted a couple of minor things while playing around (things
> > like image exit being missing), but these will be easy to flush out.
> 
> Awesome, looking forward to the review! :)
> 
> Thanks a lot for taking the time to look at this patch set.

Sure, this is a very useful thing.

Even at the most cynical possible position (which isn't where I am),
this means additional interface testing using a completely separate
codebase.

/
    Leif

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

* [U-Boot] [PATCH 8/9] efi_loader: Add "bootefi" command
  2015-12-26 18:55         ` Leif Lindholm
@ 2015-12-27 15:33           ` Alexander Graf
  0 siblings, 0 replies; 70+ messages in thread
From: Alexander Graf @ 2015-12-27 15:33 UTC (permalink / raw)
  To: u-boot



On 26.12.15 19:55, Leif Lindholm wrote:
> On Fri, Dec 25, 2015 at 10:25:22AM +0100, Andreas F?rber wrote:
>> Am 25.12.2015 um 10:02 schrieb Alexander Graf:
>> [snip]
>>> The reason I implemented "bootefi" was really because it's the natural
>>> fit into how U-Boot handles all other formats today. I don't think this
>>> is going to be the last patch set around EFI support.
>>
>> I think what Matwey was suggesting is integrating your "bootefi" into
>> the standard "distro" boot sequence environment, so that it probes each
>> device for an EFI binary and if it finds one runs load and bootefi,
>> without the need for any boot.scr.
>>
>> That would be a follow-up patch.
>>
>> It however conflicts with your idea of having some potentially
>> board-specific code mess with "fdt addr" command before running "bootefi".
> 
> This could however be resolved by moving to a model where the
> device-tree was considered a component of the firmware (which is how
> we treat it in UEFI). If U-Boot had an awareness (if it does not
> already) of an FDT being something it should have and know about, then
> this could trivially be passed onto bootefi.
> This could means a "default_fdt" environment variable which is loaded
> automatically before bootcmd is executed.

That part is already the case in my patches :).

The difficult bit is what to do when it doesn't work, because the kernel
guys consider a dtb to be a "Linux configuration" framework rather than
the "hardware description" framework it's supposed to be.


Alex

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

* [U-Boot] [PATCH 0/9] EFI payload / application support
  2015-12-26 15:31 ` Leif Lindholm
  2015-12-26 16:27   ` Alexander Graf
@ 2015-12-27 18:10   ` Tom Rini
  2015-12-27 18:39     ` Leif Lindholm
  1 sibling, 1 reply; 70+ messages in thread
From: Tom Rini @ 2015-12-27 18:10 UTC (permalink / raw)
  To: u-boot

On Sat, Dec 26, 2015 at 03:31:03PM +0000, Leif Lindholm wrote:
> On Tue, Dec 22, 2015 at 02:57:47PM +0100, Alexander Graf wrote:
> > This is my Christmas present for my openSUSE friends :).
> > 
> > U-Boot is a great project for embedded devices. However, convincing
> > everyone involved that only for "a few oddball ARM devices" we need to
> > support different configuration formats from grub2 when all other platforms
> > (PPC, System Z, x86) are standardized on a single format is a nightmare.
> > 
> > So we started to explore alternatives. At first, people tried to get
> > grub2 running using the u-boot api interface. However, FWIW that one
> > doesn't support relocations, so you need to know where to link grub2 to
> > at compile time. It also seems to be broken more often than not. And on
> > top of it all, it's a one-off interface, so yet another thing to maintain.
> > 
> > That led to a nifty idea. What if we can just implement the EFI application
> > protocol on top of U-Boot? Then we could compile a single grub2 binary for
> > uEFI based systems and U-Boot based systems and as soon as that one's loaded,
> > everything looks and feels (almost) the same.
> > 
> > This patch set is the result of pursuing this endeavor.
> 
> Thanks, this is a very cool thing.
> I meant to reply sooner, but Christmas got in the way.
> 
> >   - I am successfully able to run grub2 and Linux EFI binaries with this code.
> >   - When enabled, the resulting U-Boot binary only grows by ~10kb,
> >     so it's very light weight.
> >   - It works on 32bit ARM and AArch64. 
> >   - All storage devices are directly accessible
> >   - No runtime services (all calls return unimplemented)
> 
> Yeah, this is a bit of a pain point. The time services, virtual memory
> services and reset being the key ones.
> 
> >   - No EFI variables
> 
> This would obviously (from my point of view) be desirable, but at
> least initially, we can do most things without persistent variables.
> 
> > Of course, there are still a few things one could do on top:
> > 
> >   - Implement removable media booting (search for /efi/boot/boota{a64,rm}.efi)
> 
> Yeah, that would be top of my wishlist.
> 
> >   - Improve disk media detection (don't scan, use what information we have)
> >   - Add EFI variable support using NVRAM
> >   - Add GFX support
> 
> GFX support was actually never implemented for U-Boot GRUB, so from
> this p.o.v. it is not a shortcoming over the existing impementation.
> 
> >   - Make EFI Shell work ;)
> 
>     - Network device support.
> 
> I also spotted a couple of minor things while playing around (things
> like image exit being missing), but these will be easy to flush out.
> 
> 
> I'll leave reviewing of the u-boot side of things to people who know
> the codebase better, and restrict myself to commenting on the
> UEFIness.

So, my only "big" concern here is, are we as a community able to view
and implement the relevant parts of the UEFI spec (without having to
agree to a potentially complicated enough license to have to bug a
lawyer)?  It's been a while since I tried to view a copy so I'm hoping
the answer is now yes.  Thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20151227/a8d0cf45/attachment.sig>

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

* [U-Boot] [PATCH 0/9] EFI payload / application support
  2015-12-27 18:10   ` Tom Rini
@ 2015-12-27 18:39     ` Leif Lindholm
  2015-12-27 19:48       ` Tom Rini
  2016-01-05 20:18       ` Tom Rini
  0 siblings, 2 replies; 70+ messages in thread
From: Leif Lindholm @ 2015-12-27 18:39 UTC (permalink / raw)
  To: u-boot

On Sun, Dec 27, 2015 at 01:10:39PM -0500, Tom Rini wrote:
> So, my only "big" concern here is, are we as a community able to view
> and implement the relevant parts of the UEFI spec (without having to
> agree to a potentially complicated enough license to have to bug a
> lawyer)?  It's been a while since I tried to view a copy so I'm hoping
> the answer is now yes.  Thanks!

So:
1) You can certainly read the specification without agreeing to
   anything (click-through is now gone - docs accessible straight from
   http://uefi.org/specifications/).
2) The potential complication would be with regards to implementing
   and distributing - which requires signing the Adopters Agreement:
   http://uefi.org/sites/default/files/resources/UEFI_Adopters_Agreement_100907.pdf

I actually think the implications of 2) for a project like U-Boot
would be a useful thing to bring up for discussion on the FW/OS forum
mailing list at http://uefi.org/FWOSForum.

/
    Leif

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

* [U-Boot] [PATCH 0/9] EFI payload / application support
  2015-12-27 18:39     ` Leif Lindholm
@ 2015-12-27 19:48       ` Tom Rini
  2016-01-05 20:18       ` Tom Rini
  1 sibling, 0 replies; 70+ messages in thread
From: Tom Rini @ 2015-12-27 19:48 UTC (permalink / raw)
  To: u-boot

On Sun, Dec 27, 2015 at 06:39:16PM +0000, Leif Lindholm wrote:
> On Sun, Dec 27, 2015 at 01:10:39PM -0500, Tom Rini wrote:
> > So, my only "big" concern here is, are we as a community able to view
> > and implement the relevant parts of the UEFI spec (without having to
> > agree to a potentially complicated enough license to have to bug a
> > lawyer)?  It's been a while since I tried to view a copy so I'm hoping
> > the answer is now yes.  Thanks!
> 
> So:
> 1) You can certainly read the specification without agreeing to
>    anything (click-through is now gone - docs accessible straight from
>    http://uefi.org/specifications/).

Thats good.

> 2) The potential complication would be with regards to implementing
>    and distributing - which requires signing the Adopters Agreement:
>    http://uefi.org/sites/default/files/resources/UEFI_Adopters_Agreement_100907.pdf
> 
> I actually think the implications of 2) for a project like U-Boot
> would be a useful thing to bring up for discussion on the FW/OS forum
> mailing list at http://uefi.org/FWOSForum.

OK, I'll bring it up over there, thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20151227/aba7364d/attachment.sig>

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

* [U-Boot] [PATCH 0/9] EFI payload / application support
  2015-12-26 19:34     ` Leif Lindholm
@ 2016-01-04 16:25       ` Alexander Graf
  2016-01-04 16:56         ` Tom Rini
  0 siblings, 1 reply; 70+ messages in thread
From: Alexander Graf @ 2016-01-04 16:25 UTC (permalink / raw)
  To: u-boot



On 26.12.15 20:34, Leif Lindholm wrote:
> On Sat, Dec 26, 2015 at 05:27:48PM +0100, Alexander Graf wrote:
>>>> This patch set is the result of pursuing this endeavor.
>>>
>>> Thanks, this is a very cool thing.
>>> I meant to reply sooner, but Christmas got in the way.
>>>
>>>>   - I am successfully able to run grub2 and Linux EFI binaries with this code.
>>>>   - When enabled, the resulting U-Boot binary only grows by ~10kb,
>>>>     so it's very light weight.
>>>>   - It works on 32bit ARM and AArch64. 
>>>>   - All storage devices are directly accessible
>>>>   - No runtime services (all calls return unimplemented)
>>>
>>> Yeah, this is a bit of a pain point. The time services, virtual memory
>>> services and reset being the key ones.
>>
>> I guess reset should be pretty well doable. What are virtual memory
>> services? The bits that translate RTS code to run in virtual address
>> space somewhere else?
> 
> Yup.

Can you point me to code that uses the time services?

> 
>>>
>>>>   - No EFI variables
>>>
>>> This would obviously (from my point of view) be desirable, but at
>>> least initially, we can do most things without persistent variables.
>>
>> Doing EFI variables before exiting boot services is easy - we could even
>> just map U-Boot variables to EFI variables. That could come in handy for
>> cases where you want U-Boot to tell you which board you're on so you can
>> refer to different dtb files in your grub.cfg (if you need to override
>> the dtb).
>>
>> Making them persistent is another difficult question - U-Boot usually
>> splits "modify variable" from "store variable pool to nvram".
> 
> Indeed.
> UEFI might as well, but in more convoluted ways.
> 
>> And the hardest part would obviously be to make all of this work while
>> Linux is running ;). I'd definitely prefer to defer that bit to later.
> 
> Of course.
> 
> And again - depending on ambition levels, implementing a version of
> efibootmgr that ended up simply tweaking a /boot/uEnv.txt (or similar)
> if U-Boot boot environment was detected would be entirely achievable.
> 
>>>> Of course, there are still a few things one could do on top:
>>>>
>>>>   - Implement removable media booting (search for /efi/boot/boota{a64,rm}.efi)
>>>
>>> Yeah, that would be top of my wishlist.
>>
>> That should be pretty simple to do - maybe we can even get away without
>> any C code for it.
> 
> Should be possible.
> 
>>>
>>>>   - Improve disk media detection (don't scan, use what information we have)
>>>>   - Add EFI variable support using NVRAM
>>>>   - Add GFX support
>>>
>>> GFX support was actually never implemented for U-Boot GRUB, so from
>>> this p.o.v. it is not a shortcoming over the existing impementation.
>>
>> Heh ;). My goal here really is to make U-Boot based systems be en par
>> with TianoCore based ones in terms of usability.
> 
> Sure. Just setting the nearer goal post of "where can we replace
> U-Boot API in GRUB".

I am not aware of anyone using the U-Boot API for grub these days, so
I'm not sure it's an incredibly useful goal. The main pain point distros
seem to have is to make something that "just works" on all systems out
there. Moving into that direction should be our ultimate goal.


Alex

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

* [U-Boot] [PATCH 0/9] EFI payload / application support
  2016-01-04 16:25       ` Alexander Graf
@ 2016-01-04 16:56         ` Tom Rini
  2016-01-04 18:03           ` Andreas Färber
                             ` (2 more replies)
  0 siblings, 3 replies; 70+ messages in thread
From: Tom Rini @ 2016-01-04 16:56 UTC (permalink / raw)
  To: u-boot

On Mon, Jan 04, 2016 at 05:25:44PM +0100, Alexander Graf wrote:

[snip]
> I am not aware of anyone using the U-Boot API for grub these days, so
> I'm not sure it's an incredibly useful goal. The main pain point distros
> seem to have is to make something that "just works" on all systems out
> there. Moving into that direction should be our ultimate goal.

Please note that with the generic distro framework U-Boot will grok
https://wiki.freedesktop.org/www/Specifications/BootLoaderSpec/ and
things Just Work.  I setup a bunch of SD cards with Debian and Fedora
over holiday so I can drop them in whatever board and boot up Linux as a
sanity test.

I certainly can see a usecase for kicking off an EFI binary as part of
fitting into existing work-flows.  But we do already have a something
for getting rid of that particular pain-point and it's working :)

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20160104/12fb15f5/attachment.sig>

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

* [U-Boot] [PATCH 0/9] EFI payload / application support
  2016-01-04 16:56         ` Tom Rini
@ 2016-01-04 18:03           ` Andreas Färber
  2016-01-04 18:41             ` Andreas Färber
  2016-01-15  3:40             ` Peter Robinson
  2016-01-04 20:11           ` Matwey V. Kornilov
  2016-01-15  3:32           ` Peter Robinson
  2 siblings, 2 replies; 70+ messages in thread
From: Andreas Färber @ 2016-01-04 18:03 UTC (permalink / raw)
  To: u-boot

Am 04.01.2016 um 17:56 schrieb Tom Rini:
> Please note that with the generic distro framework U-Boot will grok
> https://wiki.freedesktop.org/www/Specifications/BootLoaderSpec/ and
> things Just Work.  I setup a bunch of SD cards with Debian and Fedora
> over holiday so I can drop them in whatever board and boot up Linux as a
> sanity test.
> 
> I certainly can see a usecase for kicking off an EFI binary as part of
> fitting into existing work-flows.  But we do already have a something
> for getting rid of that particular pain-point and it's working :)

No, as I explained before, you are not addressing that particular
pain-point: extlinux is still something new to implement for us as
distro, you provide no tools to help us, while on x86, ppc, s390 and
some aarch64 we have converged on grub2 as a standard, and just recently
the YaST devs decided to only support grub2 going forward.

For extlinux (which BTW to my eye looked slightly different from the
freedesktop.org spec that you guys keep referencing?!), distro-specific
code needs to be written [1] so that on kernel installation the
/boot/extlinux/extlinux.conf file is regenerated - for grub2 such tools
simply exist as part of GRUB and this proposed EFI interface for U-Boot
will avoid having to implement any new, e.g., perl-Bootloader code.

So the open conflict is that you tell us that extlinux.conf is your
"distro" mechanism that we should be using, and our distro people are
telling us that grub2 is their preferred solution after having
accumulated bootloader code for some two decades and just got rid of it.

Standards are not created through publishing some spec, they are created
through adoption, and today I don't see anyone at SUSE moving an inch
towards adopting extlinux.conf as a generic boot mechanism for all
architectures. That leaves our ARM community at a loss, booting a single
kernel through a symlink.

No one has suggested to dump extlinux.conf or boot.scr, they can all
simply co-exist, with the difference that, from the looks of it, Alex'
EFI code could get enabled by default to allow users to choose using it,
unlike the disabled CONFIG_API code that I reported got broken by DM
migration and for many other boards was lacking defines and is in need
of a board-specific rather than generic second bootloader on the distro
side.

This patchset is a cute middle ground where for U-Boot it's mostly just
an additional command, our distro people will be content, and our ARM
users will be happy too, not having to handcraft extlinux.conf files and
benefiting from the vibrant U-Boot community as opposed to the much more
fragmented Tianocore forks out there. Thus I'm hoping we can sort out
some of the technical issues Leif pointed out and stop circling back to
this unhelpful oh-but-extlinux.conf-is-the-mechanism point.

Regards,
Andreas

[1] https://github.com/openSUSE/perl-bootloader/pull/81

-- 
SUSE Linux GmbH, Maxfeldstr. 5, 90409 N?rnberg, Germany
GF: Felix Imend?rffer, Jane Smithard, Graham Norton; HRB 21284 (AG N?rnberg)

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

* [U-Boot] [PATCH 0/9] EFI payload / application support
  2016-01-04 18:03           ` Andreas Färber
@ 2016-01-04 18:41             ` Andreas Färber
  2016-01-04 19:54               ` Tom Rini
  2016-01-15  3:40             ` Peter Robinson
  1 sibling, 1 reply; 70+ messages in thread
From: Andreas Färber @ 2016-01-04 18:41 UTC (permalink / raw)
  To: u-boot

Am 04.01.2016 um 19:03 schrieb Andreas F?rber:
> Am 04.01.2016 um 17:56 schrieb Tom Rini:
>> Please note that with the generic distro framework U-Boot will grok
>> https://wiki.freedesktop.org/www/Specifications/BootLoaderSpec/ and
>> things Just Work.  I setup a bunch of SD cards with Debian and Fedora
>> over holiday so I can drop them in whatever board and boot up Linux as a
>> sanity test.
>>
>> I certainly can see a usecase for kicking off an EFI binary as part of
>> fitting into existing work-flows.  But we do already have a something
>> for getting rid of that particular pain-point and it's working :)
> 
[snip]

Executive summary: https://xkcd.com/927/

Cheers,
Andreas

-- 
SUSE Linux GmbH, Maxfeldstr. 5, 90409 N?rnberg, Germany
GF: Felix Imend?rffer, Jane Smithard, Graham Norton; HRB 21284 (AG N?rnberg)

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

* [U-Boot] [PATCH 0/9] EFI payload / application support
  2016-01-04 18:41             ` Andreas Färber
@ 2016-01-04 19:54               ` Tom Rini
  2016-01-04 22:37                 ` Dennis Gilmore
  0 siblings, 1 reply; 70+ messages in thread
From: Tom Rini @ 2016-01-04 19:54 UTC (permalink / raw)
  To: u-boot

On Mon, Jan 04, 2016 at 07:41:42PM +0100, Andreas F?rber wrote:
> Am 04.01.2016 um 19:03 schrieb Andreas F?rber:
> > Am 04.01.2016 um 17:56 schrieb Tom Rini:
> >> Please note that with the generic distro framework U-Boot will grok
> >> https://wiki.freedesktop.org/www/Specifications/BootLoaderSpec/ and
> >> things Just Work.  I setup a bunch of SD cards with Debian and Fedora
> >> over holiday so I can drop them in whatever board and boot up Linux as a
> >> sanity test.
> >>
> >> I certainly can see a usecase for kicking off an EFI binary as part of
> >> fitting into existing work-flows.  But we do already have a something
> >> for getting rid of that particular pain-point and it's working :)
> > 
> [snip]
> 
> Executive summary: https://xkcd.com/927/

Oh pretty much.  I guess the point I am driving at here is that EFI
loading (to kick off GRUB2) needs to fit in with the framework that
other distros have already adapted to.  Or heck, maybe you can convince
them to switch over to this instead?  Hans or Dennis, what do you think?

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20160104/a381dbb6/attachment.sig>

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

* [U-Boot] [PATCH 0/9] EFI payload / application support
  2016-01-04 16:56         ` Tom Rini
  2016-01-04 18:03           ` Andreas Färber
@ 2016-01-04 20:11           ` Matwey V. Kornilov
  2016-01-15  3:32           ` Peter Robinson
  2 siblings, 0 replies; 70+ messages in thread
From: Matwey V. Kornilov @ 2016-01-04 20:11 UTC (permalink / raw)
  To: u-boot

2016-01-04 19:56 GMT+03:00 Tom Rini <trini@konsulko.com>:
> On Mon, Jan 04, 2016 at 05:25:44PM +0100, Alexander Graf wrote:
>
> [snip]
>> I am not aware of anyone using the U-Boot API for grub these days, so
>> I'm not sure it's an incredibly useful goal. The main pain point distros
>> seem to have is to make something that "just works" on all systems out
>> there. Moving into that direction should be our ultimate goal.
>
> Please note that with the generic distro framework U-Boot will grok
> https://wiki.freedesktop.org/www/Specifications/BootLoaderSpec/ and

I would say this is pretty alpha spec. How should I specify fallback
booting with it?
Not to mention that currently grub2 perfectly boots from LVM and MD
partitions in my installations and this is not supported in spec (from
what I see).

p.s. > Currently there's little cooperation between multiple
distributions in dual-boot (or triple, ... multi-boot) setups

Have you ever seen anybody really needed it?


> things Just Work.  I setup a bunch of SD cards with Debian and Fedora
> over holiday so I can drop them in whatever board and boot up Linux as a
> sanity test.
>
> I certainly can see a usecase for kicking off an EFI binary as part of
> fitting into existing work-flows.  But we do already have a something
> for getting rid of that particular pain-point and it's working :)
>
> --
> Tom



-- 
With best regards,
Matwey V. Kornilov
http://blog.matwey.name
xmpp://0x2207 at jabber.ru

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

* [U-Boot] [PATCH 0/9] EFI payload / application support
  2016-01-04 19:54               ` Tom Rini
@ 2016-01-04 22:37                 ` Dennis Gilmore
  2016-01-04 22:48                   ` Alexander Graf
  0 siblings, 1 reply; 70+ messages in thread
From: Dennis Gilmore @ 2016-01-04 22:37 UTC (permalink / raw)
  To: u-boot

On Monday, January 04, 2016 02:54:40 PM Tom Rini wrote:
> On Mon, Jan 04, 2016 at 07:41:42PM +0100, Andreas F?rber wrote:
> > Am 04.01.2016 um 19:03 schrieb Andreas F?rber:
> > > Am 04.01.2016 um 17:56 schrieb Tom Rini:
> > >> Please note that with the generic distro framework U-Boot will grok
> > >> https://wiki.freedesktop.org/www/Specifications/BootLoaderSpec/ and
> > >> things Just Work.  I setup a bunch of SD cards with Debian and Fedora
> > >> over holiday so I can drop them in whatever board and boot up Linux as
> > >> a
> > >> sanity test.
We do not fully support bootloader spec in u-boot today. but I know that we 
want to one day 

> > >> I certainly can see a usecase for kicking off an EFI binary as part of
> > >> fitting into existing work-flows.  But we do already have a something
> > >> for getting rid of that particular pain-point and it's working :)
> > 
> > [snip]
> > 
> > Executive summary: https://xkcd.com/927/
> 
> Oh pretty much.  I guess the point I am driving at here is that EFI
> loading (to kick off GRUB2) needs to fit in with the framework that
> other distros have already adapted to.  Or heck, maybe you can convince
> them to switch over to this instead?  Hans or Dennis, what do you think?

not opposed to it, but it is not something that we have evaluated, I know 
debian have done a lot of work to ensure that their systems support 
extlinux.conf also. which is the same syslinux format as used by 
extlinux/syslinux/isolinux on x86, the user experience is somewhat similiar to 
that of grub on other arches.  Long term I have planed to wire up menu support 
so you get a menu to interact with rather than a list of boot options, as well 
as the ability to edit the commandline arguments. I would not say we have 
perfect support today for extlinux. so far SuSE is the only one saying no to 
what has been proposed. It was brought up on both the u-boot and linaro cross 
distro list back in 2013[1][2] with no one saying it was not a good idea.while 
there was less feedback than I would have liked it was positive.

Anyway my main question is how dtb support would work. As that really is the 
trickiest part that I can think of.  Something that is gracefully dealt with 
in the extlinux support, regardless of distro.  Going this approach to me 
feels like trying to put a Ford engine in a GM car by adding a volkswagon 
gearbox. can we make grub a u-boot application? that is not using CONFIG_API 
or does not need to have hard coded memory locations in it?  we looked at 
grub2 support years ago as we felt that it would be the way to go as it seemed 
people were standardising on it. and decided that there were too many issues 
with the implementation for it to be viable.  so we went the route of 
proposing the extlinux.conf file option. 

Dennis 


[1] https://lists.linaro.org/pipermail/cross-distro/2013-August/000439.html
[2] http://lists.denx.de/pipermail/u-boot/2013-August/160080.html

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

* [U-Boot] [PATCH 0/9] EFI payload / application support
  2016-01-04 22:37                 ` Dennis Gilmore
@ 2016-01-04 22:48                   ` Alexander Graf
  0 siblings, 0 replies; 70+ messages in thread
From: Alexander Graf @ 2016-01-04 22:48 UTC (permalink / raw)
  To: u-boot



On 04.01.16 23:37, Dennis Gilmore wrote:
> On Monday, January 04, 2016 02:54:40 PM Tom Rini wrote:
>> On Mon, Jan 04, 2016 at 07:41:42PM +0100, Andreas F?rber wrote:
>>> Am 04.01.2016 um 19:03 schrieb Andreas F?rber:
>>>> Am 04.01.2016 um 17:56 schrieb Tom Rini:
>>>>> Please note that with the generic distro framework U-Boot will grok
>>>>> https://wiki.freedesktop.org/www/Specifications/BootLoaderSpec/ and
>>>>> things Just Work.  I setup a bunch of SD cards with Debian and Fedora
>>>>> over holiday so I can drop them in whatever board and boot up Linux as
>>>>> a
>>>>> sanity test.
> We do not fully support bootloader spec in u-boot today. but I know that we 
> want to one day 
> 
>>>>> I certainly can see a usecase for kicking off an EFI binary as part of
>>>>> fitting into existing work-flows.  But we do already have a something
>>>>> for getting rid of that particular pain-point and it's working :)
>>>
>>> [snip]
>>>
>>> Executive summary: https://xkcd.com/927/
>>
>> Oh pretty much.  I guess the point I am driving at here is that EFI
>> loading (to kick off GRUB2) needs to fit in with the framework that
>> other distros have already adapted to.  Or heck, maybe you can convince
>> them to switch over to this instead?  Hans or Dennis, what do you think?
> 
> not opposed to it, but it is not something that we have evaluated, I know 
> debian have done a lot of work to ensure that their systems support 
> extlinux.conf also. which is the same syslinux format as used by 
> extlinux/syslinux/isolinux on x86, the user experience is somewhat similiar to 
> that of grub on other arches.  Long term I have planed to wire up menu support 
> so you get a menu to interact with rather than a list of boot options, as well 
> as the ability to edit the commandline arguments. I would not say we have 
> perfect support today for extlinux. so far SuSE is the only one saying no to 
> what has been proposed. It was brought up on both the u-boot and linaro cross 
> distro list back in 2013[1][2] with no one saying it was not a good idea.while 
> there was less feedback than I would have liked it was positive.
> 
> Anyway my main question is how dtb support would work. As that really is the 

Ideally the same way as on existing uEFI based AArch64 machines:
Firmware passes it to grub, grub reformats it and passes it on to Linux.

However, as people keep pointing out, we don't live in an ideal device
tree world - especially when thinking about boards that are running
U-Boot today. Chances are pretty good that a device tree that works for
your kernel from today won't run on tomorrow's kernel - or will lack
features.

So we still need to support the devicetree option in grub2 - and it does
work today. The only convenience missing from this patch set (and I'll
look into it once I have runtime service relocation working on 32bit) is
variable export. That way you'd be able to write

  devicetree (hd0,1)/dtb-4.10.2/$fdtfile

in your grub config and u-boot would magically tell you which dtb file
to load. Then - in theory - you wouldn't need any platform specific
logic in your bootloader configuration generation anymore.

> trickiest part that I can think of.  Something that is gracefully dealt with 
> in the extlinux support, regardless of distro.  Going this approach to me 
> feels like trying to put a Ford engine in a GM car by adding a volkswagon 
> gearbox. can we make grub a u-boot application? that is not using CONFIG_API 
> or does not need to have hard coded memory locations in it?  we looked at 

That's what this patch set is about, yes. It'd be the exact same grub2
binary that runs on all other EFI enabled systems. So if you run on
HIP04D01 or AMD Seattle today, chances are pretty good you have
everything in place already.

> grub2 support years ago as we felt that it would be the way to go as it seemed 
> people were standardising on it. and decided that there were too many issues 
> with the implementation for it to be viable.  so we went the route of 
> proposing the extlinux.conf file option. 

I'm no evangelist - if the extlinux.conf solution works for people, I'm
happy if they stick with it. It just simply doesn't work well for us ;).


Alex

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

* [U-Boot] [PATCH 0/9] EFI payload / application support
  2015-12-27 18:39     ` Leif Lindholm
  2015-12-27 19:48       ` Tom Rini
@ 2016-01-05 20:18       ` Tom Rini
  1 sibling, 0 replies; 70+ messages in thread
From: Tom Rini @ 2016-01-05 20:18 UTC (permalink / raw)
  To: u-boot

On Sun, Dec 27, 2015 at 06:39:16PM +0000, Leif Lindholm wrote:
> On Sun, Dec 27, 2015 at 01:10:39PM -0500, Tom Rini wrote:
> > So, my only "big" concern here is, are we as a community able to view
> > and implement the relevant parts of the UEFI spec (without having to
> > agree to a potentially complicated enough license to have to bug a
> > lawyer)?  It's been a while since I tried to view a copy so I'm hoping
> > the answer is now yes.  Thanks!
> 
> So:
> 1) You can certainly read the specification without agreeing to
>    anything (click-through is now gone - docs accessible straight from
>    http://uefi.org/specifications/).
> 2) The potential complication would be with regards to implementing
>    and distributing - which requires signing the Adopters Agreement:
>    http://uefi.org/sites/default/files/resources/UEFI_Adopters_Agreement_100907.pdf
> 
> I actually think the implications of 2) for a project like U-Boot
> would be a useful thing to bring up for discussion on the FW/OS forum
> mailing list at http://uefi.org/FWOSForum.

The answer I got back is
http://lists.mailman.uefi.org/pipermail/fw_os_forum/20160105/000004.html
and in short, individuals are welcome to (and apparently many have) sign
and execute the agreement.  People that work for companies that have
already signed the agreement are good to go.  To me, this is reasonable
for the goals U-Boot has with respect to UEFI implementation.

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20160105/f6ccf98b/attachment.sig>

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

* [U-Boot] [PATCH 1/9] disk/part.c: Expose a list of available block drivers
  2015-12-22 13:57 ` [U-Boot] [PATCH 1/9] disk/part.c: Expose a list of available block drivers Alexander Graf
@ 2016-01-14 19:18   ` Tom Rini
  2016-01-14 23:11   ` Simon Glass
  1 sibling, 0 replies; 70+ messages in thread
From: Tom Rini @ 2016-01-14 19:18 UTC (permalink / raw)
  To: u-boot

On Tue, Dec 22, 2015 at 02:57:48PM +0100, Alexander Graf wrote:

> We have a pretty nice and generic interface to ask for a specific block
> device. However, that one is still based around the magic notion that
> we know the driver name.
> 
> In order to be able to write fully generic disk access code, expose a list
> of all available block drivers.
> 
> Signed-off-by: Alexander Graf <agraf@suse.de>

Reviewed-by: Tom Rini <trini@konsulko.com>

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20160114/cdb3b9aa/attachment.sig>

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

* [U-Boot] [PATCH 1/9] disk/part.c: Expose a list of available block drivers
  2015-12-22 13:57 ` [U-Boot] [PATCH 1/9] disk/part.c: Expose a list of available block drivers Alexander Graf
  2016-01-14 19:18   ` Tom Rini
@ 2016-01-14 23:11   ` Simon Glass
  2016-01-14 23:33     ` Alexander Graf
  1 sibling, 1 reply; 70+ messages in thread
From: Simon Glass @ 2016-01-14 23:11 UTC (permalink / raw)
  To: u-boot

Hi Alexander,

On 22 December 2015 at 06:57, Alexander Graf <agraf@suse.de> wrote:
> We have a pretty nice and generic interface to ask for a specific block
> device. However, that one is still based around the magic notion that
> we know the driver name.
>
> In order to be able to write fully generic disk access code, expose a list
> of all available block drivers.
>
> Signed-off-by: Alexander Graf <agraf@suse.de>
> ---
>  disk/part.c    | 25 +++++++++++++++++++++++++
>  include/part.h |  2 ++
>  2 files changed, 27 insertions(+)
>
> diff --git a/disk/part.c b/disk/part.c
> index 909712e..5bc64c7 100644
> --- a/disk/part.c
> +++ b/disk/part.c
> @@ -26,6 +26,31 @@ struct block_drvr {
>         int (*select_hwpart)(int dev_num, int hwpart);
>  };
>
> +const char *available_block_drvrs[] = {
> +#if defined(CONFIG_CMD_IDE)
> +       "ide",
> +#endif
> +#if defined(CONFIG_CMD_SATA)
> +       "sata",
> +#endif
> +#if defined(CONFIG_CMD_SCSI)
> +       "scsi",
> +#endif
> +#if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_STORAGE)
> +       "usb",
> +#endif
> +#if defined(CONFIG_MMC)
> +       "mmc",
> +#endif
> +#if defined(CONFIG_SYSTEMACE)
> +       "ace",
> +#endif
> +#if defined(CONFIG_SANDBOX)
> +       "host",
> +#endif
> +       NULL,
> +};

You seem to be duplicating block_drvr[]. Can we not just use that?

> +
>  static const struct block_drvr block_drvr[] = {
>  #if defined(CONFIG_CMD_IDE)
>         { .name = "ide", .get_dev = ide_get_dev, },
> diff --git a/include/part.h b/include/part.h
> index 720a867..dc2a78b 100644
> --- a/include/part.h
> +++ b/include/part.h
> @@ -122,6 +122,8 @@ int get_device(const char *ifname, const char *dev_str,
>  int get_device_and_partition(const char *ifname, const char *dev_part_str,
>                              block_dev_desc_t **dev_desc,
>                              disk_partition_t *info, int allow_whole_dev);
> +
> +extern const char *available_block_drvrs[];
>  #else
>  static inline block_dev_desc_t *get_dev(const char *ifname, int dev)
>  { return NULL; }
> --
> 2.1.4
Regards,
Simon

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

* [U-Boot] [PATCH 1/9] disk/part.c: Expose a list of available block drivers
  2016-01-14 23:11   ` Simon Glass
@ 2016-01-14 23:33     ` Alexander Graf
  2016-01-15  0:46       ` Simon Glass
  0 siblings, 1 reply; 70+ messages in thread
From: Alexander Graf @ 2016-01-14 23:33 UTC (permalink / raw)
  To: u-boot



On 15.01.16 00:11, Simon Glass wrote:
> Hi Alexander,
> 
> On 22 December 2015 at 06:57, Alexander Graf <agraf@suse.de> wrote:
>> We have a pretty nice and generic interface to ask for a specific block
>> device. However, that one is still based around the magic notion that
>> we know the driver name.
>>
>> In order to be able to write fully generic disk access code, expose a list
>> of all available block drivers.
>>
>> Signed-off-by: Alexander Graf <agraf@suse.de>
>> ---
>>  disk/part.c    | 25 +++++++++++++++++++++++++
>>  include/part.h |  2 ++
>>  2 files changed, 27 insertions(+)
>>
>> diff --git a/disk/part.c b/disk/part.c
>> index 909712e..5bc64c7 100644
>> --- a/disk/part.c
>> +++ b/disk/part.c
>> @@ -26,6 +26,31 @@ struct block_drvr {
>>         int (*select_hwpart)(int dev_num, int hwpart);
>>  };
>>
>> +const char *available_block_drvrs[] = {
>> +#if defined(CONFIG_CMD_IDE)
>> +       "ide",
>> +#endif
>> +#if defined(CONFIG_CMD_SATA)
>> +       "sata",
>> +#endif
>> +#if defined(CONFIG_CMD_SCSI)
>> +       "scsi",
>> +#endif
>> +#if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_STORAGE)
>> +       "usb",
>> +#endif
>> +#if defined(CONFIG_MMC)
>> +       "mmc",
>> +#endif
>> +#if defined(CONFIG_SYSTEMACE)
>> +       "ace",
>> +#endif
>> +#if defined(CONFIG_SANDBOX)
>> +       "host",
>> +#endif
>> +       NULL,
>> +};
> 
> You seem to be duplicating block_drvr[]. Can we not just use that?

It would mean that we'd have to make it public then - to me it looked
like people kept it static for a reason.

However if everyone's happy if I expose it (and the struct definition
behind it), I'm certainly more than happy to move to that one instead :).


Alex

> 
>> +
>>  static const struct block_drvr block_drvr[] = {
>>  #if defined(CONFIG_CMD_IDE)
>>         { .name = "ide", .get_dev = ide_get_dev, },
>> diff --git a/include/part.h b/include/part.h
>> index 720a867..dc2a78b 100644
>> --- a/include/part.h
>> +++ b/include/part.h
>> @@ -122,6 +122,8 @@ int get_device(const char *ifname, const char *dev_str,
>>  int get_device_and_partition(const char *ifname, const char *dev_part_str,
>>                              block_dev_desc_t **dev_desc,
>>                              disk_partition_t *info, int allow_whole_dev);
>> +
>> +extern const char *available_block_drvrs[];
>>  #else
>>  static inline block_dev_desc_t *get_dev(const char *ifname, int dev)
>>  { return NULL; }
>> --
>> 2.1.4
> Regards,
> Simon
> 

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

* [U-Boot] [PATCH 3/9] efi_loader: Add PE image loader
  2015-12-26 16:26   ` Leif Lindholm
@ 2016-01-14 23:45     ` Alexander Graf
  2016-01-15 12:29       ` Leif Lindholm
  0 siblings, 1 reply; 70+ messages in thread
From: Alexander Graf @ 2016-01-14 23:45 UTC (permalink / raw)
  To: u-boot



On 26.12.15 17:26, Leif Lindholm wrote:
> On Tue, Dec 22, 2015 at 02:57:50PM +0100, Alexander Graf wrote:
>> EFI uses the PE binary format for its application images. Add support to EFI PE
>> binaries as well as all necessary bits for the "EFI image loader" interfaces.
>>
>> Signed-off-by: Alexander Graf <agraf@suse.de>
>> ---
>>  include/efi_loader.h              |  37 +++++
>>  include/pe.h                      | 277 ++++++++++++++++++++++++++++++++++++++
>>  lib/efi_loader/efi_image_loader.c | 203 ++++++++++++++++++++++++++++
>>  3 files changed, 517 insertions(+)
>>  create mode 100644 include/efi_loader.h
>>  create mode 100644 include/pe.h
>>  create mode 100644 lib/efi_loader/efi_image_loader.c
>>
>> diff --git a/include/efi_loader.h b/include/efi_loader.h
>> new file mode 100644
>> index 0000000..da82354
>> --- /dev/null
>> +++ b/include/efi_loader.h
>> @@ -0,0 +1,37 @@
>> +/*
>> + *  EFI application loader
>> + *
>> + *  Copyright (c) 2015 Alexander Graf
>> + *
>> + *  This library is free software; you can redistribute it and/or
>> + *  modify it under the terms of the GNU Lesser General Public
>> + *  License as published by the Free Software Foundation; either
>> + *  version 2.1 of the License, or (at your option) any later version.
>> + *
>> + *  This library is distributed in the hope that it will be useful,
>> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> + *  Lesser General Public License for more details.
>> + *
>> + *  You should have received a copy of the GNU Lesser General Public
>> + *  License along with this library; if not, write to the Free Software
>> + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
>> + *
>> + *  SPDX-License-Identifier:     LGPL-2.1+
>> + */
>> +
>> +#include <part_efi.h>
>> +#include <efi_api.h>
>> +#include <linux/list.h>
>> +
>> +extern const efi_guid_t efi_guid_device_path;
>> +extern const efi_guid_t efi_guid_loaded_image;
>> +
>> +efi_status_t efi_return_handle(void *handle,
>> +		efi_guid_t *protocol, void **protocol_interface,
>> +		void *agent_handle, void *controller_handle,
>> +		uint32_t attributes);
>> +void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info);
>> +
>> +#define EFI_LOADER_POOL_SIZE (128 * 1024 * 1024)
>> +void *efi_loader_alloc(uint64_t len);
>> diff --git a/include/pe.h b/include/pe.h
>> new file mode 100644
>> index 0000000..009b0c5
>> --- /dev/null
>> +++ b/include/pe.h
>> @@ -0,0 +1,277 @@
>> +/*
>> + *  Portable Executable binary format structures
>> + *
>> + *  Copyright (c) 2015 Alexander Graf
>> + *
>> + *  Based on wine code
>> + *
>> + *  This library is free software; you can redistribute it and/or
>> + *  modify it under the terms of the GNU Lesser General Public
>> + *  License as published by the Free Software Foundation; either
>> + *  version 2.1 of the License, or (at your option) any later version.
>> + *
>> + *  This library is distributed in the hope that it will be useful,
>> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> + *  Lesser General Public License for more details.
>> + *
>> + *  You should have received a copy of the GNU Lesser General Public
>> + *  License along with this library; if not, write to the Free Software
>> + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
>> + *
>> + *  SPDX-License-Identifier:     LGPL-2.1+
>> + */
>> +
>> +#ifndef _PE_H
>> +#define _PE_H
>> +
>> +typedef struct _IMAGE_DOS_HEADER {
>> +	uint16_t e_magic;      /* 00: MZ Header signature */
>> +	uint16_t e_cblp;       /* 02: Bytes on last page of file */
>> +	uint16_t e_cp;         /* 04: Pages in file */
>> +	uint16_t e_crlc;       /* 06: Relocations */
>> +	uint16_t e_cparhdr;    /* 08: Size of header in paragraphs */
>> +	uint16_t e_minalloc;   /* 0a: Minimum extra paragraphs needed */
>> +	uint16_t e_maxalloc;   /* 0c: Maximum extra paragraphs needed */
>> +	uint16_t e_ss;         /* 0e: Initial (relative) SS value */
>> +	uint16_t e_sp;         /* 10: Initial SP value */
>> +	uint16_t e_csum;       /* 12: Checksum */
>> +	uint16_t e_ip;         /* 14: Initial IP value */
>> +	uint16_t e_cs;         /* 16: Initial (relative) CS value */
>> +	uint16_t e_lfarlc;     /* 18: File address of relocation table */
>> +	uint16_t e_ovno;       /* 1a: Overlay number */
>> +	uint16_t e_res[4];     /* 1c: Reserved words */
>> +	uint16_t e_oemid;      /* 24: OEM identifier (for e_oeminfo) */
>> +	uint16_t e_oeminfo;    /* 26: OEM information; e_oemid specific */
>> +	uint16_t e_res2[10];   /* 28: Reserved words */
>> +	uint32_t e_lfanew;     /* 3c: Offset to extended header */
>> +} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
>> +
>> +#define IMAGE_DOS_SIGNATURE		0x5A4D     /* MZ   */
>> +#define IMAGE_NT_SIGNATURE		0x00004550 /* PE00 */
>> +
>> +#define IMAGE_FILE_MACHINE_ARM		0x01c0
>> +#define IMAGE_FILE_MACHINE_THUMB	0x01c2
>> +#define IMAGE_FILE_MACHINE_ARMNT	0x01c4
>> +#define IMAGE_FILE_MACHINE_AMD64	0x8664
>> +#define IMAGE_FILE_MACHINE_ARM64	0xaa64
>> +#define IMAGE_NT_OPTIONAL_HDR32_MAGIC	0x10b
>> +#define IMAGE_NT_OPTIONAL_HDR64_MAGIC	0x20b
>> +#define IMAGE_SUBSYSTEM_EFI_APPLICATION	10
>> +
>> +typedef struct _IMAGE_FILE_HEADER {
>> +	uint16_t  Machine;
>> +	uint16_t  NumberOfSections;
>> +	uint32_t TimeDateStamp;
>> +	uint32_t PointerToSymbolTable;
>> +	uint32_t NumberOfSymbols;
>> +	uint16_t  SizeOfOptionalHeader;
>> +	uint16_t  Characteristics;
>> +} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
>> +
>> +typedef struct _IMAGE_DATA_DIRECTORY {
>> +	uint32_t VirtualAddress;
>> +	uint32_t Size;
>> +} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
>> +
>> +#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
>> +
>> +typedef struct _IMAGE_OPTIONAL_HEADER64 {
>> +	uint16_t  Magic; /* 0x20b */
>> +	uint8_t MajorLinkerVersion;
>> +	uint8_t MinorLinkerVersion;
>> +	uint32_t SizeOfCode;
>> +	uint32_t SizeOfInitializedData;
>> +	uint32_t SizeOfUninitializedData;
>> +	uint32_t AddressOfEntryPoint;
>> +	uint32_t BaseOfCode;
>> +	uint64_t ImageBase;
>> +	uint32_t SectionAlignment;
>> +	uint32_t FileAlignment;
>> +	uint16_t MajorOperatingSystemVersion;
>> +	uint16_t MinorOperatingSystemVersion;
>> +	uint16_t MajorImageVersion;
>> +	uint16_t MinorImageVersion;
>> +	uint16_t MajorSubsystemVersion;
>> +	uint16_t MinorSubsystemVersion;
>> +	uint32_t Win32VersionValue;
>> +	uint32_t SizeOfImage;
>> +	uint32_t SizeOfHeaders;
>> +	uint32_t CheckSum;
>> +	uint16_t Subsystem;
>> +	uint16_t DllCharacteristics;
>> +	uint64_t SizeOfStackReserve;
>> +	uint64_t SizeOfStackCommit;
>> +	uint64_t SizeOfHeapReserve;
>> +	uint64_t SizeOfHeapCommit;
>> +	uint32_t LoaderFlags;
>> +	uint32_t NumberOfRvaAndSizes;
>> +	IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
>> +} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;
>> +
>> +typedef struct _IMAGE_NT_HEADERS64 {
>> +	uint32_t Signature;
>> +	IMAGE_FILE_HEADER FileHeader;
>> +	IMAGE_OPTIONAL_HEADER64 OptionalHeader;
>> +} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;
>> +
>> +typedef struct _IMAGE_OPTIONAL_HEADER {
>> +
>> +	/* Standard fields */
>> +
>> +	uint16_t  Magic; /* 0x10b or 0x107 */     /* 0x00 */
>> +	uint8_t  MajorLinkerVersion;
>> +	uint8_t  MinorLinkerVersion;
>> +	uint32_t SizeOfCode;
>> +	uint32_t SizeOfInitializedData;
>> +	uint32_t SizeOfUninitializedData;
>> +	uint32_t AddressOfEntryPoint;            /* 0x10 */
>> +	uint32_t BaseOfCode;
>> +	uint32_t BaseOfData;
>> +
>> +	/* NT additional fields */
>> +
>> +	uint32_t ImageBase;
>> +	uint32_t SectionAlignment;               /* 0x20 */
>> +	uint32_t FileAlignment;
>> +	uint16_t  MajorOperatingSystemVersion;
>> +	uint16_t  MinorOperatingSystemVersion;
>> +	uint16_t  MajorImageVersion;
>> +	uint16_t  MinorImageVersion;
>> +	uint16_t  MajorSubsystemVersion;          /* 0x30 */
>> +	uint16_t  MinorSubsystemVersion;
>> +	uint32_t Win32VersionValue;
>> +	uint32_t SizeOfImage;
>> +	uint32_t SizeOfHeaders;
>> +	uint32_t CheckSum;                       /* 0x40 */
>> +	uint16_t  Subsystem;
>> +	uint16_t  DllCharacteristics;
>> +	uint32_t SizeOfStackReserve;
>> +	uint32_t SizeOfStackCommit;
>> +	uint32_t SizeOfHeapReserve;              /* 0x50 */
>> +	uint32_t SizeOfHeapCommit;
>> +	uint32_t LoaderFlags;
>> +	uint32_t NumberOfRvaAndSizes;
>> +	IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; /* 0x60 */
>> +	/* 0xE0 */
>> +} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
>> +
>> +typedef struct _IMAGE_NT_HEADERS {
>> +	uint32_t Signature; /* "PE"\0\0 */       /* 0x00 */
>> +	IMAGE_FILE_HEADER FileHeader;         /* 0x04 */
>> +	IMAGE_OPTIONAL_HEADER32 OptionalHeader;       /* 0x18 */
>> +} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
>> +
>> +#define IMAGE_SIZEOF_SHORT_NAME 8
>> +
>> +typedef struct _IMAGE_SECTION_HEADER {
>> +	uint8_t	Name[IMAGE_SIZEOF_SHORT_NAME];
>> +	union {
>> +		uint32_t PhysicalAddress;
>> +		uint32_t VirtualSize;
>> +	} Misc;
>> +	uint32_t VirtualAddress;
>> +	uint32_t SizeOfRawData;
>> +	uint32_t PointerToRawData;
>> +	uint32_t PointerToRelocations;
>> +	uint32_t PointerToLinenumbers;
>> +	uint16_t	NumberOfRelocations;
>> +	uint16_t	NumberOfLinenumbers;
>> +	uint32_t Characteristics;
>> +} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
>> +
>> +#define IMAGE_DIRECTORY_ENTRY_BASERELOC         5
>> +
>> +typedef struct _IMAGE_BASE_RELOCATION
>> +{
>> +        uint32_t VirtualAddress;
>> +        uint32_t SizeOfBlock;
>> +        /* WORD TypeOffset[1]; */
>> +} IMAGE_BASE_RELOCATION,*PIMAGE_BASE_RELOCATION;
>> +
>> +typedef struct _IMAGE_RELOCATION
>> +{
>> +	union {
>> +		uint32_t   VirtualAddress;
>> +		uint32_t   RelocCount;
>> +	} DUMMYUNIONNAME;
>> +	uint32_t   SymbolTableIndex;
>> +	uint16_t	Type;
>> +} IMAGE_RELOCATION, *PIMAGE_RELOCATION;
>> +
>> +#define IMAGE_SIZEOF_RELOCATION 10
>> +
>> +/* generic relocation types */
>> +#define IMAGE_REL_BASED_ABSOLUTE                0
>> +#define IMAGE_REL_BASED_HIGH                    1
>> +#define IMAGE_REL_BASED_LOW                     2
>> +#define IMAGE_REL_BASED_HIGHLOW                 3
>> +#define IMAGE_REL_BASED_HIGHADJ                 4
>> +#define IMAGE_REL_BASED_MIPS_JMPADDR            5
>> +#define IMAGE_REL_BASED_ARM_MOV32A              5 /* yes, 5 too */
>> +#define IMAGE_REL_BASED_ARM_MOV32               5 /* yes, 5 too */
>> +#define IMAGE_REL_BASED_SECTION                 6
>> +#define IMAGE_REL_BASED_REL                     7
>> +#define IMAGE_REL_BASED_ARM_MOV32T              7 /* yes, 7 too */
>> +#define IMAGE_REL_BASED_THUMB_MOV32             7 /* yes, 7 too */
>> +#define IMAGE_REL_BASED_MIPS_JMPADDR16          9
>> +#define IMAGE_REL_BASED_IA64_IMM64              9 /* yes, 9 too */
>> +#define IMAGE_REL_BASED_DIR64                   10
>> +#define IMAGE_REL_BASED_HIGH3ADJ                11
>> +
>> +/* ARM relocation types */
>> +#define IMAGE_REL_ARM_ABSOLUTE          0x0000
>> +#define IMAGE_REL_ARM_ADDR              0x0001
>> +#define IMAGE_REL_ARM_ADDR32NB          0x0002
>> +#define IMAGE_REL_ARM_BRANCH24          0x0003
>> +#define IMAGE_REL_ARM_BRANCH11          0x0004
>> +#define IMAGE_REL_ARM_TOKEN             0x0005
>> +#define IMAGE_REL_ARM_GPREL12           0x0006
>> +#define IMAGE_REL_ARM_GPREL7            0x0007
>> +#define IMAGE_REL_ARM_BLX24             0x0008
>> +#define IMAGE_REL_ARM_BLX11             0x0009
>> +#define IMAGE_REL_ARM_SECTION           0x000E
>> +#define IMAGE_REL_ARM_SECREL            0x000F
>> +#define IMAGE_REL_ARM_MOV32A            0x0010
>> +#define IMAGE_REL_ARM_MOV32T            0x0011
>> +#define IMAGE_REL_ARM_BRANCH20T 0x0012
>> +#define IMAGE_REL_ARM_BRANCH24T 0x0014
>> +#define IMAGE_REL_ARM_BLX23T            0x0015
>> +
>> +/* ARM64 relocation types */
>> +#define IMAGE_REL_ARM64_ABSOLUTE        0x0000
>> +#define IMAGE_REL_ARM64_ADDR32          0x0001
>> +#define IMAGE_REL_ARM64_ADDR32NB        0x0002
>> +#define IMAGE_REL_ARM64_BRANCH26        0x0003
>> +#define IMAGE_REL_ARM64_PAGEBASE_REL21  0x0004
>> +#define IMAGE_REL_ARM64_REL21           0x0005
>> +#define IMAGE_REL_ARM64_PAGEOFFSET_12A  0x0006
>> +#define IMAGE_REL_ARM64_PAGEOFFSET_12L  0x0007
>> +#define IMAGE_REL_ARM64_SECREL          0x0008
>> +#define IMAGE_REL_ARM64_SECREL_LOW12A   0x0009
>> +#define IMAGE_REL_ARM64_SECREL_HIGH12A  0x000A
>> +#define IMAGE_REL_ARM64_SECREL_LOW12L   0x000B
>> +#define IMAGE_REL_ARM64_TOKEN           0x000C
>> +#define IMAGE_REL_ARM64_SECTION         0x000D
>> +#define IMAGE_REL_ARM64_ADDR64          0x000E
>> +
>> +/* AMD64 relocation types */
>> +#define IMAGE_REL_AMD64_ABSOLUTE        0x0000
>> +#define IMAGE_REL_AMD64_ADDR64          0x0001
>> +#define IMAGE_REL_AMD64_ADDR32          0x0002
>> +#define IMAGE_REL_AMD64_ADDR32NB        0x0003
>> +#define IMAGE_REL_AMD64_REL32           0x0004
>> +#define IMAGE_REL_AMD64_REL32_1         0x0005
>> +#define IMAGE_REL_AMD64_REL32_2         0x0006
>> +#define IMAGE_REL_AMD64_REL32_3         0x0007
>> +#define IMAGE_REL_AMD64_REL32_4         0x0008
>> +#define IMAGE_REL_AMD64_REL32_5         0x0009
>> +#define IMAGE_REL_AMD64_SECTION         0x000A
>> +#define IMAGE_REL_AMD64_SECREL          0x000B
>> +#define IMAGE_REL_AMD64_SECREL7         0x000C
>> +#define IMAGE_REL_AMD64_TOKEN           0x000D
>> +#define IMAGE_REL_AMD64_SREL32          0x000E
>> +#define IMAGE_REL_AMD64_PAIR            0x000F
>> +#define IMAGE_REL_AMD64_SSPAN32         0x0010
>> +
>> +#endif /* _PE_H */
>> diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c
>> new file mode 100644
>> index 0000000..688e177
>> --- /dev/null
>> +++ b/lib/efi_loader/efi_image_loader.c
>> @@ -0,0 +1,203 @@
>> +/*
>> + *  EFI image loader
>> + *
>> + *  based partly on wine code
>> + *
>> + *  Copyright (c) 2015 Alexander Graf
>> + *
>> + *  This library is free software; you can redistribute it and/or
>> + *  modify it under the terms of the GNU Lesser General Public
>> + *  License as published by the Free Software Foundation; either
>> + *  version 2.1 of the License, or (at your option) any later version.
>> + *
>> + *  This library is distributed in the hope that it will be useful,
>> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> + *  Lesser General Public License for more details.
>> + *
>> + *  You should have received a copy of the GNU Lesser General Public
>> + *  License along with this library; if not, write to the Free Software
>> + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
>> + *
>> + *  SPDX-License-Identifier:     LGPL-2.1+
>> + */
>> +
>> +#include <common.h>
>> +#include <pe.h>
>> +#include <efi_loader.h>
>> +#include <asm/global_data.h>
>> +
>> +DECLARE_GLOBAL_DATA_PTR;
>> +
>> +#define ROUND_UP(val, round) ((val + (round - 1)) & ~(round - 1))
>> +#define MB (1024 * 1024)
>> +
>> +const efi_guid_t efi_guid_device_path = DEVICE_PATH_GUID;
>> +const efi_guid_t efi_guid_loaded_image = LOADED_IMAGE_GUID;
>> +
>> +efi_status_t efi_return_handle(void *handle, efi_guid_t *protocol,
>> +			void **protocol_interface, void *agent_handle,
>> +			void *controller_handle, uint32_t attributes)
>> +{
>> +	*protocol_interface = handle;
>> +	return EFI_SUCCESS;
>> +}
>> +
>> +/*
>> + * EFI payloads potentially want to load pretty big images into memory,
>> + * so our small malloc region isn't enough for them. However, they usually
>> + * don't need a smart allocator either.
>> + *
>> + * So instead give them a really dumb one. We just reserve EFI_LOADER_POOL_SIZE
>> + * bytes from 16MB below the malloc region start to give the stack some space.
> 
> Is there any chance you could break out the memory allocation and
> memory map management as a separate patch, rather than spread across
> 3,4 and 6?

Uh, sure, I can try. I'm not sure it'll end up more readable than now
though :).

> 
> Assigning a specific 128MB pool for LOADER_DATA memory can have
> unexpected side effects.

Like for example?

> 
>> + * Then every allocation gets a 4k aligned chunk from it. We never free.
> 
> Never freeing LOADER_DATA should not be an issue in and of itself. It
> all gets zapped by the OS anyway.

That's the idea, yes :).

> 
>> + */
>> +void *efi_loader_alloc(uint64_t len)
>> +{
>> +	static unsigned long loader_pool;
>> +	void *r;
>> +
>> +	if (!loader_pool) {
>> +		loader_pool = gd->relocaddr - TOTAL_MALLOC_LEN -
>> +			      EFI_LOADER_POOL_SIZE - (16 * MB);
>> +	}
>> +
>> +	len = ROUND_UP(len, 4096);
>> +	/* Out of memory */
>> +	if ((loader_pool + len) >= (gd->relocaddr - TOTAL_MALLOC_LEN))
>> +		return NULL;
>> +
>> +	r = (void *)loader_pool;
>> +	loader_pool += len;
>> +
>> +	return r;
>> +}
>> +
>> +/*
>> + * This function loads all sections from a PE binary into a newly reserved
>> + * piece of memory. On successful load it then returns the entry point for
>> + * the binary. Otherwise NULL.
>> + */
>> +void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info)
>> +{
>> +	IMAGE_NT_HEADERS32 *nt;
>> +	IMAGE_DOS_HEADER *dos;
>> +	IMAGE_SECTION_HEADER *sections;
>> +	int num_sections;
>> +	void *efi_reloc;
>> +	int i;
>> +	const uint16_t *relocs;
>> +	const IMAGE_BASE_RELOCATION *rel;
>> +	const IMAGE_BASE_RELOCATION *end;
>> +	unsigned long rel_size;
>> +	int rel_idx = IMAGE_DIRECTORY_ENTRY_BASERELOC;
>> +	void *entry;
>> +	uint64_t image_size;
>> +	unsigned long virt_size = 0;
>> +
>> +	dos = efi;
>> +	if (dos->e_magic != IMAGE_DOS_SIGNATURE) {
>> +		printf("%s: Invalid DOS Signature\n", __func__);
>> +		return NULL;
>> +	}
>> +
>> +	nt = (void *) ((char *)efi + dos->e_lfanew);
>> +	if (nt->Signature != IMAGE_NT_SIGNATURE) {
>> +		printf("%s: Invalid NT Signature\n", __func__);
>> +		return NULL;
>> +	}
>> +
>> +	/* Calculate upper virtual address boundary */
>> +	num_sections = nt->FileHeader.NumberOfSections;
>> +	sections = (void *)&nt->OptionalHeader +
>> +			    nt->FileHeader.SizeOfOptionalHeader;
>> +
>> +	for (i = num_sections - 1; i >= 0; i--) {
>> +		IMAGE_SECTION_HEADER *sec = &sections[i];
>> +		virt_size = max_t(unsigned long, virt_size,
>> +				  sec->VirtualAddress + sec->Misc.VirtualSize);
>> +	}
>> +
>> +	/* Read 32/64bit specific header bits */
> 
> I guess x86 may support 32-on-64 or 64-on-32, but ARM won't - so could
> probably be compile-time conditionalised somehow.
> (CONFIG_EFI_SUPPORTS_PE32/CONFIG_EFI_SUPPORTS_PE64)

I think I have a reasonably elegant solution now. I hope.

> 
>> +	if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
>> +		IMAGE_NT_HEADERS64 *nt64 = (void *)nt;
>> +		IMAGE_OPTIONAL_HEADER64 *opt = &nt64->OptionalHeader;
>> +		image_size = opt->SizeOfImage;
>> +		efi_reloc = efi_loader_alloc(virt_size);
>> +		if (!efi_reloc) {
>> +			printf("%s: Could not allocate %ld bytes\n",
>> +				__func__, virt_size);
>> +			return NULL;
>> +		}
>> +		entry = efi_reloc + opt->AddressOfEntryPoint;
>> +		rel_size = opt->DataDirectory[rel_idx].Size;
>> +		rel = efi_reloc + opt->DataDirectory[rel_idx].VirtualAddress;
>> +	} else {
> 
> ...and should still check the magic value for 32-bit?

True.


Alex

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

* [U-Boot] [PATCH 4/9] efi_loader: Add boot time services
  2015-12-26 18:09   ` Leif Lindholm
@ 2016-01-15  0:13     ` Alexander Graf
  2016-01-15 13:02       ` Leif Lindholm
  2016-01-15  3:40     ` Alexander Graf
  1 sibling, 1 reply; 70+ messages in thread
From: Alexander Graf @ 2016-01-15  0:13 UTC (permalink / raw)
  To: u-boot



On 26.12.15 19:09, Leif Lindholm wrote:
> On Tue, Dec 22, 2015 at 02:57:51PM +0100, Alexander Graf wrote:
>> When an EFI application runs, it has access to a few descriptor and callback
>> tables to instruct the EFI compliant firmware to do things for it. The bulk
>> of those interfaces are "boot time services". They handle all object management,
>> and memory allocation.
>>
>> This patch adds support for the boot time services and also exposes a system
>> table, which is the point of entry descriptor table for EFI payloads.
> 
> One overall observation, and I may help track these down - but not all
> for this review: this code uses EFI_UNSUPPORTED as a default
> "something went wrong" error code, but this is not actually supported
> by the specification. I'm pointing out a few of these, but it would be
> preferable if we could crowdsource this a bit since there are quire a
> few instances...
> 
>> Signed-off-by: Alexander Graf <agraf@suse.de>
>> ---
>>  include/efi_loader.h          |  41 +++
>>  lib/efi_loader/efi_boottime.c | 838 ++++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 879 insertions(+)
>>  create mode 100644 lib/efi_loader/efi_boottime.c
>>
>> diff --git a/include/efi_loader.h b/include/efi_loader.h
>> index da82354..ed7c389 100644
>> --- a/include/efi_loader.h
>> +++ b/include/efi_loader.h
>> @@ -24,14 +24,55 @@
>>  #include <efi_api.h>
>>  #include <linux/list.h>
>>  
>> +/* #define DEBUG_EFI */
>> +
>> +#ifdef DEBUG_EFI
>> +#define EFI_ENTRY(format, ...) do { \
>> +	efi_restore_gd(); \
>> +	printf("EFI: Entry %s(" format ")\n", __func__, ##__VA_ARGS__); \
>> +	} while(0)
>> +#else
>> +#define EFI_ENTRY(format, ...) do { \
>> +	efi_restore_gd(); \
>> +	} while(0)
>> +#endif
>> +
>> +#define EFI_EXIT(ret) efi_exit_func(ret);
>> +
>> +extern struct efi_system_table systab;
>> +
>>  extern const efi_guid_t efi_guid_device_path;
>>  extern const efi_guid_t efi_guid_loaded_image;
>>  
>> +struct efi_class_map {
>> +	const efi_guid_t *guid;
>> +	const void *interface;
>> +};
>> +
>> +struct efi_handler {
>> +	const efi_guid_t *guid;
>> +	efi_status_t (EFIAPI *open)(void *handle,
>> +			efi_guid_t *protocol, void **protocol_interface,
>> +			void *agent_handle, void *controller_handle,
>> +			uint32_t attributes);
>> +};
>> +
>> +struct efi_object {
>> +	struct list_head link;
>> +	struct efi_handler protocols[4];
>> +	void *handle;
>> +};
>> +extern struct list_head efi_obj_list;
>> +
>>  efi_status_t efi_return_handle(void *handle,
>>  		efi_guid_t *protocol, void **protocol_interface,
>>  		void *agent_handle, void *controller_handle,
>>  		uint32_t attributes);
>> +void efi_timer_check(void);
>>  void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info);
>> +void efi_save_gd(void);
>> +void efi_restore_gd(void);
>> +efi_status_t efi_exit_func(efi_status_t ret);
>>  
>>  #define EFI_LOADER_POOL_SIZE (128 * 1024 * 1024)
>>  void *efi_loader_alloc(uint64_t len);
>> diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
>> new file mode 100644
>> index 0000000..ed95962
>> --- /dev/null
>> +++ b/lib/efi_loader/efi_boottime.c
>> @@ -0,0 +1,838 @@
>> +/*
>> + *  EFI application boot time services
>> + *
>> + *  Copyright (c) 2015 Alexander Graf
>> + *
>> + *  This library is free software; you can redistribute it and/or
>> + *  modify it under the terms of the GNU Lesser General Public
>> + *  License as published by the Free Software Foundation; either
>> + *  version 2.1 of the License, or (at your option) any later version.
>> + *
>> + *  This library is distributed in the hope that it will be useful,
>> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> + *  Lesser General Public License for more details.
>> + *
>> + *  You should have received a copy of the GNU Lesser General Public
>> + *  License along with this library; if not, write to the Free Software
>> + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
>> + *
>> + *  SPDX-License-Identifier:     LGPL-2.1+
>> + */
>> +
>> +#define DEBUG_EFI
>> +
>> +#include <common.h>
>> +#include <efi_loader.h>
>> +#include <malloc.h>
>> +#include <asm/global_data.h>
>> +#include <libfdt_env.h>
>> +#include <u-boot/crc.h>
>> +#include <bootm.h>
>> +#include <inttypes.h>
>> +#include <watchdog.h>
>> +
>> +DECLARE_GLOBAL_DATA_PTR;
>> +
>> +/*
>> + * EFI can pass arbitrary additional "tables" containing vendor specific
>> + * information to the payload. One such table is the FDT table which contains
>> + * a pointer to a flattened device tree blob.
>> + *
>> + * In most cases we want to pass an FDT to the payload, so reserve one slot of
>> + * config table space for it. The pointer gets populated by do_bootefi_exec().
>> + */
>> +static struct efi_configuration_table efi_conf_table[] = {
>> +	{
>> +		.guid = EFI_FDT_GUID,
>> +	},
>> +};
>> +
>> +/*
>> + * The "gd" pointer lives in a register on ARM and AArch64 that we declare
>> + * fixed when compiling U-Boot. However, the payload does now know about that
>> + * restriction so we need to manually swap its and our view of that register on
>> + * EFI callback entry/exit.
>> + */
>> +static volatile void *efi_gd, *app_gd;
>> +
>> +/* Called from do_bootefi_exec() */
>> +void efi_save_gd(void)
>> +{
>> +	efi_gd = gd;
>> +}
>> +
>> +/* Called on every callback entry */
>> +void efi_restore_gd(void)
>> +{
>> +	if (gd != efi_gd)
>> +		app_gd = gd;
>> +	gd = efi_gd;
>> +}
>> +
>> +/* Called on every callback exit */
>> +efi_status_t efi_exit_func(efi_status_t ret)
>> +{
>> +	gd = app_gd;
>> +	return ret;
>> +}
>> +
>> +static efi_status_t efi_unsupported(const char *funcname)
>> +{
>> +#ifdef DEBUG_EFI
>> +	printf("EFI: App called into unimplemented function %s\n", funcname);
>> +#endif
>> +	return EFI_EXIT(EFI_UNSUPPORTED);
> 
> Not always a legal return status.
> 
>> +}
>> +
>> +static unsigned long efi_raise_tpl(unsigned long new_tpl)
>> +{
>> +	EFI_ENTRY("0x%lx", new_tpl);
>> +	return EFI_EXIT(efi_unsupported(__func__));
> 
> "Unlike other UEFI interface functions, EFI_BOOT_SERVICES.RaiseTPL()
> does not return a status code. Instead, it returns the previous task
> priority level, which is to be restored later with a matching call to
> RestoreTPL()."

Since we don't do TPLs (or IRQs for that matter), I'll just return 0 here.

> 
>> +}
>> +
>> +static void efi_restore_tpl(unsigned long old_tpl)
>> +{
>> +	EFI_ENTRY("0x%lx", old_tpl);
>> +	EFI_EXIT(efi_unsupported(__func__));
> 
> (void function, nothing to return)

Yes, hence no return. EFI_EXIT deals with the gd swapping and
efi_unsupported() gives me a nice debug message :).

> 
>> +}
>> +
>> +static void *efi_alloc(uint64_t len, int memory_type)
>> +{
>> +	switch (memory_type) {
>> +	case EFI_LOADER_DATA:
>> +		return efi_loader_alloc(len);
>> +	default:
>> +		return malloc(len);
>> +	}
>> +}
>> +
>> +static efi_status_t efi_allocate_pages(int type, int memory_type,
>> +				       unsigned long pages, uint64_t *memory)
>> +{
>> +	u64 len = pages << 12;
>> +	efi_status_t r = EFI_SUCCESS;
>> +
>> +	EFI_ENTRY("%d, %d, 0x%lx, %p", type, memory_type, pages, memory);
>> +
>> +	switch (type) {
>> +	case 0:
>> +		/* Any page means we can go to efi_alloc */
>> +		*memory = (unsigned long)efi_alloc(len, memory_type);
>> +		break;
>> +	case 1:
>> +		/* Max address */
>> +		if (gd->relocaddr < *memory) {
>> +			*memory = (unsigned long)efi_alloc(len, memory_type);
>> +			break;
>> +		}
>> +		r = EFI_UNSUPPORTED;
> 
> EFI_OUT_OF_RESOURCES/EFI_NOT_FOUND?
> 
>> +		break;
>> +	case 2:
>> +		/* Exact address, grant it. The addr is already in *memory. */
> 
> As far as I can tell, this is why GRUB works. Because it filters
> through the memory map manually, requesting to allocate its heap at an
> exact address in a region of free memory in the UEFI memory map.

Yes.

> The key is that EFI_LOADER_MEMORY will be used by applications loaded
> as well as by U-Boot to load applications into. A simple example where
> this could be problematic would be a large(ish) initrd loaded via initrd=
> on kernel (stub loader) command line rather than via GRUB.

Ah, so here the 128MB limit on the LOADER_DATA section might bite us?

> 
>> +		break;
>> +	default:
> 
> It would actually be fair here to state that the above are the only
> types supported by the UEFI specification, as opposed to not being
> implemented.
> 
>> +		r = EFI_UNSUPPORTED;
> 
> Actually, not a valid return value.
> EFI_INVALID_PARAMETER
> 
>> +		break;
>> +	}
>> +
>> +	return EFI_EXIT(r);
>> +}
>> +
>> +static efi_status_t efi_free_pages(uint64_t memory, unsigned long pages)
>> +{
>> +	/* We don't free, let's cross our fingers we have plenty RAM */
>> +	EFI_ENTRY("%"PRIx64", 0x%lx", memory, pages);
>> +	return EFI_EXIT(EFI_SUCCESS);
>> +}
>> +
>> +/*
>> + * Returns the EFI memory map. In our case, this looks pretty simple:
>> + *
>> + *  ____________________________    TOM
>> + * |                            |
>> + * |    Second half of U-Boot   |
>> + * |____________________________|   &__efi_runtime_stop
>> + * |                            |
>> + * |    EFI Runtime Services    |
>> + * |____________________________|   &__efi_runtime_start
>> + * |                            |
>> + * |    First half of U-Boot    |
>> + * |____________________________|   start of EFI loader allocation space
>> + * |                            |
>> + * |          Free RAM          |
>> + * |____________________________|   CONFIG_SYS_SDRAM_BASE
>> + *
>> + * All pointers are extended to live on a 4k boundary. After exiting the boot
>> + * services, only the EFI Runtime Services chunk of memory stays alive.
>> + */
>> +static efi_status_t efi_get_memory_map(unsigned long *memory_map_size,
>> +			       struct efi_mem_desc *memory_map,
>> +			       unsigned long *map_key,
>> +			       unsigned long *descriptor_size,
>> +			       uint32_t *descriptor_version)
>> +{
>> +	struct efi_mem_desc efi_memory_map[] = {
>> +		{
>> +			/* RAM before U-Boot */
>> +			.type = EFI_CONVENTIONAL_MEMORY,
>> +			.attribute = 1 << EFI_MEMORY_WB_SHIFT,
>> +		},
>> +		{
>> +			/* First half of U-Boot */
>> +			.type = EFI_LOADER_DATA,
>> +			.attribute = 1 << EFI_MEMORY_WB_SHIFT,
>> +		},
>> +		{
>> +			/* EFI Runtime Services */
>> +			.type = EFI_RUNTIME_SERVICES_CODE,
>> +			.attribute = 1 << EFI_MEMORY_WB_SHIFT,
>> +		},
>> +		{
>> +			/* Second half of U-Boot */
>> +			.type = EFI_LOADER_DATA,
>> +			.attribute = 1 << EFI_MEMORY_WB_SHIFT,
>> +		},
>> +	};
>> +	ulong runtime_start, runtime_end, runtime_len_pages, runtime_len;
>> +
>> +	EFI_ENTRY("%p, %p, %p, %p, %p", memory_map_size, memory_map, map_key,
>> +		  descriptor_size, descriptor_version);
>> +
>> +	runtime_start = (ulong)&__efi_runtime_start & ~0xfffULL;
>> +	runtime_end = ((ulong)&__efi_runtime_stop + 0xfff) & ~0xfffULL;
>> +	runtime_len_pages = (runtime_end - runtime_start) >> 12;
>> +	runtime_len = runtime_len_pages << 12;
>> +
>> +	/* Fill in where normal RAM is (up to U-Boot) */
>> +	efi_memory_map[0].num_pages = gd->relocaddr >> 12;
> 
> U-Boot question: is gd->relocaddr always the offset from start of RAM?
> How does this work with gaps in memory map?

U-Boot always relocates itself at TOM (or at least what we consider TOM
here). gd->relocaddr is the physical address of the start of U-Boot
which is right below TOM.

> 
>> +#ifdef CONFIG_SYS_SDRAM_BASE
>> +	efi_memory_map[0].physical_start = CONFIG_SYS_SDRAM_BASE;
>> +	efi_memory_map[0].virtual_start = CONFIG_SYS_SDRAM_BASE;
>> +	efi_memory_map[0].num_pages -= CONFIG_SYS_SDRAM_BASE >> 12;
> #else
> #error "..."
> ?

If it's not defined, it's 0 :).

>> +#endif
>> +
>> +	/* Remove U-Boot from the available RAM view */
>> +	efi_memory_map[0].num_pages -= gd->mon_len >> 12;
>> +
>> +	/* Remove the malloc area from the available RAM view */
>> +	efi_memory_map[0].num_pages -= TOTAL_MALLOC_LEN >> 12;
>> +
>> +	/* Give us some space for the stack */
>> +	efi_memory_map[0].num_pages -= (16 * 1024 * 1024) >> 12;
>> +
>> +	/* Reserve the EFI loader pool */
>> +	efi_memory_map[0].num_pages -= EFI_LOADER_POOL_SIZE >> 12;
>> +
>> +	/* Cut out the runtime services */
>> +	efi_memory_map[2].physical_start = runtime_start;
>> +	efi_memory_map[2].virtual_start = efi_memory_map[2].physical_start;
>> +	efi_memory_map[2].num_pages = runtime_len_pages;
>> +
>> +	/* Allocate the rest to U-Boot */
>> +	efi_memory_map[1].physical_start = efi_memory_map[0].physical_start +
>> +					   (efi_memory_map[0].num_pages << 12);
>> +	efi_memory_map[1].virtual_start = efi_memory_map[1].physical_start;
>> +	efi_memory_map[1].num_pages = (runtime_start -
>> +				       efi_memory_map[1].physical_start) >> 12;
>> +
>> +	efi_memory_map[3].physical_start = runtime_start + runtime_len;
>> +	efi_memory_map[3].virtual_start = efi_memory_map[3].physical_start;
>> +	efi_memory_map[3].num_pages = (gd->ram_top -
>> +				       efi_memory_map[3].physical_start) >> 12;
>> +
>> +	*memory_map_size = sizeof(efi_memory_map);
>> +
>> +	if (descriptor_size)
>> +		*descriptor_size = sizeof(struct efi_mem_desc);
>> +
>> +	if (*memory_map_size < sizeof(efi_memory_map)) {
>> +		return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
>> +	}
>> +
>> +	if (memory_map)
>> +		memcpy(memory_map, efi_memory_map, sizeof(efi_memory_map));
>> +
>> +	return EFI_EXIT(EFI_SUCCESS);
>> +}
>> +
>> +static efi_status_t efi_allocate_pool(int pool_type, unsigned long size, void **buffer)
>> +{
>> +	return efi_allocate_pages(0, pool_type, (size + 0xfff) >> 12, (void*)buffer);
>> +}
>> +
>> +static efi_status_t efi_free_pool(void *buffer)
>> +{
>> +	return efi_free_pages((ulong)buffer, 0);
>> +}
>> +
>> +/*
>> + * Our event capabilities are very limited. Only support a single
>> + * event to exist, so we don't need to maintain lists.
>> + */
>> +static struct {
>> +	enum efi_event_type type;
>> +	u32 trigger_type;
>> +	u32 trigger_time;
>> +	u64 trigger_next;
>> +	unsigned long notify_tpl;
>> +	void (*notify_function) (void *event, void *context);
>> +	void *notify_context;
>> +} efi_event;
>> +
>> +static efi_status_t efi_create_event(enum efi_event_type type, ulong notify_tpl,
>> +			     void (*notify_function) (void *event,
>> +						      void *context),
>> +			     void *notify_context, void **event)
>> +{
>> +	EFI_ENTRY("%d, 0x%lx, %p, %p", type, notify_tpl, notify_function,
>> +		  notify_context);
>> +	if (efi_event.notify_function) {
>> +		/* We only support one event at a time */
>> +		return EFI_EXIT(EFI_UNSUPPORTED);
> 
> EFI_OUT_OF_RESOURCES would be a better return value here.

Yup.

> 
>> +	}
>> +
>> +	efi_event.type = type;
>> +	efi_event.notify_tpl = notify_tpl;
>> +	efi_event.notify_function = notify_function;
>> +	efi_event.notify_context = notify_context;
>> +	*event = &efi_event;
>> +
>> +	return EFI_EXIT(EFI_SUCCESS);
>> +}
>> +
>> +/*
>> + * Our timers have to work without interrupts, so we check whenever keyboard
>> + * input or disk accesses happen if enough time elapsed for it to fire.
>> + */
>> +void efi_timer_check(void)
>> +{
>> +	u64 now = timer_get_us();
>> +
>> +	if (now >= efi_event.trigger_next) {
>> +		/* Triggering! */
>> +		if (efi_event.trigger_type == EFI_TIMER_PERIODIC)
>> +			efi_event.trigger_next += efi_event.trigger_time / 10;
>> +		efi_event.notify_function(&efi_event, efi_event.notify_context);
>> +	}
>> +
>> +	WATCHDOG_RESET();
>> +}
>> +
>> +static efi_status_t efi_set_timer(void *event, int type, uint64_t trigger_time)
>> +{
>> +	/* We don't have 64bit division available everywhere, so limit timer
>> +	 * distances to 32bit bits. */
>> +	u32 trigger32 = trigger_time;
> 
> Add a warning message if this limit is exceeded?

ok

> 
>> +
>> +	EFI_ENTRY("%p, %d, %"PRIx64, event, type, trigger_time);
>> +	if (event != &efi_event) {
>> +		/* We only support one event at a time */
>> +		return EFI_EXIT(EFI_UNSUPPORTED);
> 
> This function should only ever be called with an event successfully
> created via create_event (and stored into efi_event). If we're called
> with another event handle, EFI_INVALID_PARAMETER is the appropriate
> error code.

Sounds reasonable.

> 
>> +	}
>> +
>> +	switch (type) {
>> +	case EFI_TIMER_STOP:
>> +		efi_event.trigger_next = -1ULL;
>> +		break;
>> +	case EFI_TIMER_PERIODIC:
>> +	case EFI_TIMER_RELATIVE:
>> +		efi_event.trigger_next = timer_get_us() + (trigger32 / 10);
>> +		break;
>> +	default:
>> +		return EFI_EXIT(EFI_UNSUPPORTED);
>> +	}
>> +	efi_event.trigger_type = type;
>> +	efi_event.trigger_time = trigger_time;
>> +
>> +	return EFI_EXIT(EFI_SUCCESS);
>> +}

[...]

>> +static const struct efi_boot_services efi_boot_services = {
>> +	.hdr = {
>> +		.headersize = sizeof(struct efi_table_hdr),
>> +	},
>> +	.raise_tpl = efi_raise_tpl,
>> +	.restore_tpl = efi_restore_tpl,
>> +	.allocate_pages = efi_allocate_pages,
>> +	.free_pages = efi_free_pages,
>> +	.get_memory_map = efi_get_memory_map,
>> +	.allocate_pool = efi_allocate_pool,
>> +	.free_pool = efi_free_pool,
>> +	.create_event = efi_create_event,
>> +	.set_timer = efi_set_timer,
>> +	.wait_for_event = efi_wait_for_event,
>> +	.signal_event = efi_signal_event,
>> +	.close_event = efi_close_event,
>> +	.check_event = efi_check_event,
>> +	.install_protocol_interface = efi_install_protocol_interface,
>> +	.reinstall_protocol_interface = efi_reinstall_protocol_interface,
>> +	.uninstall_protocol_interface = efi_uninstall_protocol_interface,
>> +	.handle_protocol = efi_handle_protocol,
>> +	.reserved = NULL,
>> +	.register_protocol_notify = efi_register_protocol_notify,
>> +	.locate_handle = efi_locate_handle,
>> +	.locate_device_path = efi_locate_device_path,
>> +	.install_configuration_table = efi_install_configuration_table,
>> +	.load_image = efi_load_image,
>> +	.start_image = efi_start_image,
>> +	.exit = (void*)efi_exit,
>> +	.unload_image = efi_unload_image,
>> +	.exit_boot_services = efi_exit_boot_services,
>> +	.get_next_monotonic_count = efi_get_next_monotonic_count,
>> +	.stall = efi_stall,
>> +	.set_watchdog_timer = efi_set_watchdog_timer,
>> +	.connect_controller = efi_connect_controller,
>> +	.disconnect_controller = efi_disconnect_controller,
>> +	.open_protocol = efi_open_protocol,
>> +	.close_protocol = efi_close_protocol,
>> +	.open_protocol_information = efi_open_protocol_information,
>> +	.protocols_per_handle = efi_protocols_per_handle,
>> +	.locate_handle_buffer = efi_locate_handle_buffer,
>> +	.locate_protocol = efi_locate_protocol,
>> +	.install_multiple_protocol_interfaces = efi_install_multiple_protocol_interfaces,
>> +	.uninstall_multiple_protocol_interfaces = efi_uninstall_multiple_protocol_interfaces,
>> +	.calculate_crc32 = efi_calculate_crc32,
>> +	.copy_mem = efi_copy_mem,
>> +	.set_mem = efi_set_mem,
>> +};
>> +
>> +
>> +static uint16_t firmware_vendor[] = { 'U','-','b','o','o','t',0 };
> 
> Surely, if we're being formal, that should be 'D', 'a', 's', ' ',
> ... :)

Heh :) Sure!

> 
>> +struct efi_system_table systab = {
>> +	.hdr = {
>> +		.signature = EFI_SYSTEM_TABLE_SIGNATURE,
>> +		.revision = 0x20000, /* 2.0 */
> 
> Really, this should claim to support revision 2.5, if not 2.6 (soon
> to be released). AArch64 support was only introduced in 2.4.

Works for me :).


Alex

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

* [U-Boot] [PATCH 6/9] efi_loader: Add runtime services
  2015-12-26 18:33   ` Leif Lindholm
@ 2016-01-15  0:26     ` Alexander Graf
  2016-01-15 13:52       ` Leif Lindholm
  0 siblings, 1 reply; 70+ messages in thread
From: Alexander Graf @ 2016-01-15  0:26 UTC (permalink / raw)
  To: u-boot



On 26.12.15 19:33, Leif Lindholm wrote:
> On Tue, Dec 22, 2015 at 02:57:53PM +0100, Alexander Graf wrote:
>> After booting has finished, EFI allows firmware to still interact with the OS
>> using the "runtime services". These callbacks live in a separate address space,
>> since they are available long after U-Boot has been overwritten by the OS.
>>
>> However, since U-Boot has no notion of RTS, we just create an extremely minimal
>> RTS stub that just declares all functions as unsupported. We could in the future
>> map U-boot environment variables to EFI variables here.
>>
>> Signed-off-by: Alexander Graf <agraf@suse.de>
>> ---
>>  arch/arm/cpu/armv8/u-boot.lds |  8 ++++++
>>  arch/arm/cpu/u-boot.lds       | 13 ++++++++++
>>  arch/arm/lib/sections.c       |  2 ++
>>  include/efi_loader.h          |  3 +++
>>  lib/efi_loader/efi_runtime.c  | 59 +++++++++++++++++++++++++++++++++++++++++++
>>  5 files changed, 85 insertions(+)
>>  create mode 100644 lib/efi_loader/efi_runtime.c
>>
>> diff --git a/arch/arm/cpu/armv8/u-boot.lds b/arch/arm/cpu/armv8/u-boot.lds
>> index 4c12222..7c5b032 100644
>> --- a/arch/arm/cpu/armv8/u-boot.lds
>> +++ b/arch/arm/cpu/armv8/u-boot.lds
>> @@ -42,6 +42,14 @@ SECTIONS
>>  
>>  	. = ALIGN(8);
>>  
>> +	.efi_runtime : {
>> +                __efi_runtime_start = .;
>> +		*(efi_runtime)
>> +                __efi_runtime_stop = .;
>> +	}
>> +
>> +	. = ALIGN(8);
>> +
>>  	.image_copy_end :
>>  	{
>>  		*(.__image_copy_end)
>> diff --git a/arch/arm/cpu/u-boot.lds b/arch/arm/cpu/u-boot.lds
>> index d48a905..b5198d0 100644
>> --- a/arch/arm/cpu/u-boot.lds
>> +++ b/arch/arm/cpu/u-boot.lds
>> @@ -89,6 +89,19 @@ SECTIONS
>>  
>>  	. = ALIGN(4);
>>  
>> +	.__efi_runtime_start : {
>> +		*(.__efi_runtime_start)
>> +	}
>> +
>> +	.efi_runtime : {
>> +		*(efi_runtime)
>> +	}
>> +
>> +	.__efi_runtime_stop : {
>> +		*(.__efi_runtime_stop)
>> +	}
>> +	. = ALIGN(4);
>> +
>>  	.image_copy_end :
>>  	{
>>  		*(.__image_copy_end)
>> diff --git a/arch/arm/lib/sections.c b/arch/arm/lib/sections.c
>> index a1205c3..21b3066 100644
>> --- a/arch/arm/lib/sections.c
>> +++ b/arch/arm/lib/sections.c
>> @@ -27,4 +27,6 @@ char __rel_dyn_start[0] __attribute__((section(".__rel_dyn_start")));
>>  char __rel_dyn_end[0] __attribute__((section(".__rel_dyn_end")));
>>  char __secure_start[0] __attribute__((section(".__secure_start")));
>>  char __secure_end[0] __attribute__((section(".__secure_end")));
>> +char __efi_runtime_start[0] __attribute__((section(".__efi_runtime_start")));
>> +char __efi_runtime_stop[0] __attribute__((section(".__efi_runtime_stop")));
>>  char _end[0] __attribute__((section(".__end")));
>> diff --git a/include/efi_loader.h b/include/efi_loader.h
>> index 7fb2106..af1c88f 100644
>> --- a/include/efi_loader.h
>> +++ b/include/efi_loader.h
>> @@ -39,6 +39,7 @@
>>  
>>  #define EFI_EXIT(ret) efi_exit_func(ret);
>>  
>> +extern const struct efi_runtime_services efi_runtime_services;
>>  extern struct efi_system_table systab;
>>  
>>  extern const struct efi_simple_text_output_protocol efi_con_out;
>> @@ -49,6 +50,8 @@ extern const efi_guid_t efi_guid_console_control;
>>  extern const efi_guid_t efi_guid_device_path;
>>  extern const efi_guid_t efi_guid_loaded_image;
>>  
>> +extern unsigned int __efi_runtime_start, __efi_runtime_stop;
>> +
>>  struct efi_class_map {
>>  	const efi_guid_t *guid;
>>  	const void *interface;
>> diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c
>> new file mode 100644
>> index 0000000..214e1f5
>> --- /dev/null
>> +++ b/lib/efi_loader/efi_runtime.c
>> @@ -0,0 +1,59 @@
>> +/*
>> + *  EFI application runtime services
>> + *
>> + *  Copyright (c) 2015 Alexander Graf
>> + *
>> + *  This library is free software; you can redistribute it and/or
>> + *  modify it under the terms of the GNU Lesser General Public
>> + *  License as published by the Free Software Foundation; either
>> + *  version 2.1 of the License, or (at your option) any later version.
>> + *
>> + *  This library is distributed in the hope that it will be useful,
>> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> + *  Lesser General Public License for more details.
>> + *
>> + *  You should have received a copy of the GNU Lesser General Public
>> + *  License along with this library; if not, write to the Free Software
>> + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
>> + *
>> + *  SPDX-License-Identifier:     LGPL-2.1+
>> + */
>> +
>> +#include <common.h>
>> +#include <efi_loader.h>
>> +
>> +/*
>> + * EFI Runtime code is still alive when U-Boot is long overwritten. To isolate
>> + * this code from the rest, we put it into a special section.
>> + *
>> + *        !!WARNING!!
>> + *
>> + * This means that we can not rely on any code outside of this file at runtime.
>> + * Please keep it fully self-contained.
>> + */
>> +asm(".section efi_runtime,\"a\"");
>> +
>> +static efi_status_t efi_unimplemented(void)
>> +{
>> +	return EFI_UNSUPPORTED;
> 
> Again, EFI_UNSUPPORTED is not necessarily a valid return value for all
> runtime services.
> 
>> +}
>> +
>> +const struct efi_runtime_services efi_runtime_services = {
>> +	.hdr = {
>> +		.signature = EFI_RUNTIME_SERVICES_SIGNATURE,
>> +		.revision = EFI_RUNTIME_SERVICES_REVISION,
>> +		.headersize = sizeof(struct efi_table_hdr),
>> +	},
>> +	.get_time = (void *)&efi_unimplemented,
> 
> EFI_DEVICE_ERROR
> 
>> +	.set_time = (void *)&efi_unimplemented,
> 
> EFI_DEVICE_ERROR
> 
>> +	.get_wakeup_time = (void *)&efi_unimplemented,
>> +	.set_wakeup_time = (void *)&efi_unimplemented,
> 
> Both of these are fine, and correct, to return EFI_UNSUPPORTED.
> 
>> +	.set_virtual_address_map = (void *)&efi_unimplemented,
>> +	.convert_pointer = (void *)&efi_unimplemented,
> 
> There really isn't a way to gracefully decline these two functions.
> All valid error codes refer to invalid inputs.

Ok, changing to EFI_INVALID_PARAMETER then :).

> 
>> +	.get_variable = (void *)&efi_unimplemented,
> 
> EFI_DEVICE_ERROR would probably be the closest thing to a correct
> return code in this instance.
> 
>> +	.get_next_variable = (void *)&efi_unimplemented,
> 
> (get_next_variable_name?)

git blame says it's Simon's fault :).

867a6ac8 (Simon Glass    2015-07-31 09:31:36 -0600 170)
efi_status_t (EFIAPI *get_next_variable)(
867a6ac8 (Simon Glass    2015-07-31 09:31:36 -0600 171)
        unsigned long *variable_name_size,
867a6ac8 (Simon Glass    2015-07-31 09:31:36 -0600 172)
        s16 *variable_name, efi_guid_t *vendor);

> Again, EFI_DEVICE_ERROR, is probably the least wrong return value.
> 
>> +	.set_variable = (void *)&efi_unimplemented,
> 
> EFI_DEVICE_ERROR
> 
>> +	.get_next_high_mono_count = (void *)&efi_unimplemented,
> 
> EFI_DEVICE_ERROR
> 

Ok, fixed all of the above.

>> +	.reset_system = (void *)&efi_unimplemented,
> 
> "The ResetSystem() function does not return."

Hrm, I think returning EFI_UNSUPPORTED is still better than while(1) {
}. With the return an OS at least has the chance to fix things up itself.


Alex

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

* [U-Boot] [PATCH 1/9] disk/part.c: Expose a list of available block drivers
  2016-01-14 23:33     ` Alexander Graf
@ 2016-01-15  0:46       ` Simon Glass
  2016-01-15  1:04         ` Alexander Graf
  0 siblings, 1 reply; 70+ messages in thread
From: Simon Glass @ 2016-01-15  0:46 UTC (permalink / raw)
  To: u-boot

Hi Alex,

On 14 January 2016 at 16:33, Alexander Graf <agraf@suse.de> wrote:
>
>
> On 15.01.16 00:11, Simon Glass wrote:
>> Hi Alexander,
>>
>> On 22 December 2015 at 06:57, Alexander Graf <agraf@suse.de> wrote:
>>> We have a pretty nice and generic interface to ask for a specific block
>>> device. However, that one is still based around the magic notion that
>>> we know the driver name.
>>>
>>> In order to be able to write fully generic disk access code, expose a list
>>> of all available block drivers.
>>>
>>> Signed-off-by: Alexander Graf <agraf@suse.de>
>>> ---
>>>  disk/part.c    | 25 +++++++++++++++++++++++++
>>>  include/part.h |  2 ++
>>>  2 files changed, 27 insertions(+)
>>>
>>> diff --git a/disk/part.c b/disk/part.c
>>> index 909712e..5bc64c7 100644
>>> --- a/disk/part.c
>>> +++ b/disk/part.c
>>> @@ -26,6 +26,31 @@ struct block_drvr {
>>>         int (*select_hwpart)(int dev_num, int hwpart);
>>>  };
>>>
>>> +const char *available_block_drvrs[] = {
>>> +#if defined(CONFIG_CMD_IDE)
>>> +       "ide",
>>> +#endif
>>> +#if defined(CONFIG_CMD_SATA)
>>> +       "sata",
>>> +#endif
>>> +#if defined(CONFIG_CMD_SCSI)
>>> +       "scsi",
>>> +#endif
>>> +#if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_STORAGE)
>>> +       "usb",
>>> +#endif
>>> +#if defined(CONFIG_MMC)
>>> +       "mmc",
>>> +#endif
>>> +#if defined(CONFIG_SYSTEMACE)
>>> +       "ace",
>>> +#endif
>>> +#if defined(CONFIG_SANDBOX)
>>> +       "host",
>>> +#endif
>>> +       NULL,
>>> +};
>>
>> You seem to be duplicating block_drvr[]. Can we not just use that?
>
> It would mean that we'd have to make it public then - to me it looked
> like people kept it static for a reason.
>
> However if everyone's happy if I expose it (and the struct definition
> behind it), I'm certainly more than happy to move to that one instead :).

But you have created a public one which is a copy of part of it, so it
doesn't seem like much of a benefit :-)

How about adding a function to return the device name of a member?
Then you should be able to avoid copying it, and avoid making it
global.

I'm very interested in your series, and hope to review the rest of it
(and try it out) soon!

>
>
> Alex
>
>>
>>> +
>>>  static const struct block_drvr block_drvr[] = {
>>>  #if defined(CONFIG_CMD_IDE)
>>>         { .name = "ide", .get_dev = ide_get_dev, },
>>> diff --git a/include/part.h b/include/part.h
>>> index 720a867..dc2a78b 100644
>>> --- a/include/part.h
>>> +++ b/include/part.h
>>> @@ -122,6 +122,8 @@ int get_device(const char *ifname, const char *dev_str,
>>>  int get_device_and_partition(const char *ifname, const char *dev_part_str,
>>>                              block_dev_desc_t **dev_desc,
>>>                              disk_partition_t *info, int allow_whole_dev);
>>> +
>>> +extern const char *available_block_drvrs[];
>>>  #else
>>>  static inline block_dev_desc_t *get_dev(const char *ifname, int dev)
>>>  { return NULL; }
>>> --
>>> 2.1.4
>> Regards,
>> Simon
>>

Regards,
Simon

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

* [U-Boot] [PATCH 1/9] disk/part.c: Expose a list of available block drivers
  2016-01-15  0:46       ` Simon Glass
@ 2016-01-15  1:04         ` Alexander Graf
  0 siblings, 0 replies; 70+ messages in thread
From: Alexander Graf @ 2016-01-15  1:04 UTC (permalink / raw)
  To: u-boot



On 15.01.16 01:46, Simon Glass wrote:
> Hi Alex,
> 
> On 14 January 2016 at 16:33, Alexander Graf <agraf@suse.de> wrote:
>>
>>
>> On 15.01.16 00:11, Simon Glass wrote:
>>> Hi Alexander,
>>>
>>> On 22 December 2015 at 06:57, Alexander Graf <agraf@suse.de> wrote:
>>>> We have a pretty nice and generic interface to ask for a specific block
>>>> device. However, that one is still based around the magic notion that
>>>> we know the driver name.
>>>>
>>>> In order to be able to write fully generic disk access code, expose a list
>>>> of all available block drivers.
>>>>
>>>> Signed-off-by: Alexander Graf <agraf@suse.de>
>>>> ---
>>>>  disk/part.c    | 25 +++++++++++++++++++++++++
>>>>  include/part.h |  2 ++
>>>>  2 files changed, 27 insertions(+)
>>>>
>>>> diff --git a/disk/part.c b/disk/part.c
>>>> index 909712e..5bc64c7 100644
>>>> --- a/disk/part.c
>>>> +++ b/disk/part.c
>>>> @@ -26,6 +26,31 @@ struct block_drvr {
>>>>         int (*select_hwpart)(int dev_num, int hwpart);
>>>>  };
>>>>
>>>> +const char *available_block_drvrs[] = {
>>>> +#if defined(CONFIG_CMD_IDE)
>>>> +       "ide",
>>>> +#endif
>>>> +#if defined(CONFIG_CMD_SATA)
>>>> +       "sata",
>>>> +#endif
>>>> +#if defined(CONFIG_CMD_SCSI)
>>>> +       "scsi",
>>>> +#endif
>>>> +#if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_STORAGE)
>>>> +       "usb",
>>>> +#endif
>>>> +#if defined(CONFIG_MMC)
>>>> +       "mmc",
>>>> +#endif
>>>> +#if defined(CONFIG_SYSTEMACE)
>>>> +       "ace",
>>>> +#endif
>>>> +#if defined(CONFIG_SANDBOX)
>>>> +       "host",
>>>> +#endif
>>>> +       NULL,
>>>> +};
>>>
>>> You seem to be duplicating block_drvr[]. Can we not just use that?
>>
>> It would mean that we'd have to make it public then - to me it looked
>> like people kept it static for a reason.
>>
>> However if everyone's happy if I expose it (and the struct definition
>> behind it), I'm certainly more than happy to move to that one instead :).
> 
> But you have created a public one which is a copy of part of it, so it
> doesn't seem like much of a benefit :-)
> 
> How about adding a function to return the device name of a member?

I wouldn't know the struct size, so I couldn't walk the array, right? :)

> Then you should be able to avoid copying it, and avoid making it
> global.
> 
> I'm very interested in your series, and hope to review the rest of it
> (and try it out) soon!

Wait for v2, I'm just polishing it up :). It fixes a good number of
issues on real hardware. I have the code running well on BBB and HiKey now.


Alex

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

* [U-Boot] [PATCH 7/9] efi_loader: Add disk interfaces
  2015-12-22 13:57 ` [U-Boot] [PATCH 7/9] efi_loader: Add disk interfaces Alexander Graf
@ 2016-01-15  1:37   ` Simon Glass
  2016-01-15  2:40     ` Alexander Graf
  0 siblings, 1 reply; 70+ messages in thread
From: Simon Glass @ 2016-01-15  1:37 UTC (permalink / raw)
  To: u-boot

Hi Alexander,

On 22 December 2015 at 06:57, Alexander Graf <agraf@suse.de> wrote:
> A EFI applications usually want to access storage devices to load data from.
>
> This patch adds support for EFI disk interfaces. It loops through all block
> storage interfaces known to U-Boot and creates an EFI object for each existing
> one. EFI applications can then through these objects call U-Boot's read and
> write functions.
>
> Signed-off-by: Alexander Graf <agraf@suse.de>
> ---
>  include/efi_loader.h      |   1 +
>  lib/efi_loader/efi_disk.c | 227 ++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 228 insertions(+)
>  create mode 100644 lib/efi_loader/efi_disk.c

Reviewed-by: Simon Glass <sjg@chromium.org>

Some nits below.

>
> diff --git a/include/efi_loader.h b/include/efi_loader.h
> index af1c88f..7e821e5 100644
> --- a/include/efi_loader.h
> +++ b/include/efi_loader.h
> @@ -72,6 +72,7 @@ struct efi_object {
>  };
>  extern struct list_head efi_obj_list;
>
> +int efi_disk_register(void);
>  efi_status_t efi_return_handle(void *handle,
>                 efi_guid_t *protocol, void **protocol_interface,
>                 void *agent_handle, void *controller_handle,
> diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
> new file mode 100644
> index 0000000..1804e3e
> --- /dev/null
> +++ b/lib/efi_loader/efi_disk.c
> @@ -0,0 +1,227 @@
> +/*
> + *  EFI application disk support
> + *
> + *  Copyright (c) 2015 Alexander Graf
> + *
> + *  This library is free software; you can redistribute it and/or
> + *  modify it under the terms of the GNU Lesser General Public
> + *  License as published by the Free Software Foundation; either
> + *  version 2.1 of the License, or (at your option) any later version.
> + *
> + *  This library is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + *  Lesser General Public License for more details.
> + *
> + *  You should have received a copy of the GNU Lesser General Public
> + *  License along with this library; if not, write to the Free Software
> + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
> + *
> + *  SPDX-License-Identifier:     LGPL-2.1+

Can we have GPL 2 / 2+? Also drop the text?

> + */
> +
> +#include <common.h>
> +#include <efi_loader.h>
> +#include <part.h>
> +#include <malloc.h>
> +#include <inttypes.h>

inttypes.h should go above part.h

> +
> +static const efi_guid_t efi_block_io_guid = BLOCK_IO_GUID;
> +
> +struct efi_disk_obj {

Could use comments on these members

> +       struct efi_object parent;
> +       struct efi_block_io ops;
> +       const char *ifname;
> +       int dev_index;
> +       struct efi_block_io_media media;
> +       struct efi_device_path_file_path *dp;
> +};
> +
> +static void ascii2unicode(u16 *unicode, char *ascii)
> +{
> +       while (*ascii)
> +               *(unicode++) = *(ascii++);
> +}
> +
> +static efi_status_t efi_disk_open_block(void *handle, efi_guid_t *protocol,
> +                       void **protocol_interface, void *agent_handle,
> +                       void *controller_handle, uint32_t attributes)
> +{
> +       struct efi_disk_obj *diskobj = handle;
> +
> +       *protocol_interface = &diskobj->ops;
> +
> +       return EFI_SUCCESS;
> +}
> +
> +static efi_status_t efi_disk_open_dp(void *handle, efi_guid_t *protocol,
> +                       void **protocol_interface, void *agent_handle,
> +                       void *controller_handle, uint32_t attributes)
> +{
> +       struct efi_disk_obj *diskobj = handle;
> +
> +       *protocol_interface = diskobj->dp;
> +
> +       return EFI_SUCCESS;
> +}
> +
> +static efi_status_t efi_disk_reset(struct efi_block_io *this,
> +                       char extended_verification)
> +{
> +       EFI_ENTRY("%p, %x", this, extended_verification);
> +       return EFI_EXIT(EFI_DEVICE_ERROR);
> +}
> +
> +enum efi_disk_direction {
> +       EFI_DISK_READ,
> +       EFI_DISK_WRITE,
> +};
> +
> +static efi_status_t efi_disk_rw_blocks(struct efi_block_io *this,
> +                       u32 media_id, u64 lba, unsigned long buffer_size,
> +                       void *buffer, enum efi_disk_direction direction)
> +{
> +       struct efi_disk_obj *diskobj;
> +       struct block_dev_desc *desc;
> +       int blksz;
> +       int blocks;
> +       unsigned long n;
> +
> +       EFI_ENTRY("%p, %x, %"PRIx64", %lx, %p", this, media_id, lba,
> +                 buffer_size, buffer);
> +
> +       diskobj = container_of(this, struct efi_disk_obj, ops);
> +       if (!(desc = get_dev(diskobj->ifname, diskobj->dev_index)))
> +               return EFI_EXIT(EFI_DEVICE_ERROR);
> +       blksz = desc->blksz;
> +       blocks = buffer_size / blksz;
> +
> +#ifdef DEBUG_EFI
> +       printf("EFI: %s:%d blocks=%x lba=%"PRIx64" blksz=%x dir=%d\n", __func__,
> +              __LINE__, blocks, lba, blksz, direction);
> +#endif
> +
> +       /* We only support full block access */
> +       if (buffer_size & (blksz - 1))
> +               return EFI_EXIT(EFI_DEVICE_ERROR);
> +
> +       if (direction == EFI_DISK_READ)
> +               n = desc->block_read(desc->dev, lba, blocks, buffer);
> +       else
> +               n = desc->block_write(desc->dev, lba, blocks, buffer);
> +
> +       /* We don't do interrupts, so check for timers cooperatively */
> +       efi_timer_check();
> +
> +#ifdef DEBUG_EFI
> +       printf("EFI: %s:%d n=%lx blocks=%x\n", __func__, __LINE__, n, blocks);
> +#endif
> +       if (n != blocks)
> +               return EFI_EXIT(EFI_DEVICE_ERROR);
> +
> +       return EFI_EXIT(EFI_SUCCESS);
> +}
> +
> +static efi_status_t efi_disk_read_blocks(struct efi_block_io *this,
> +                       u32 media_id, u64 lba, unsigned long buffer_size,
> +                       void *buffer)
> +{
> +       return efi_disk_rw_blocks(this, media_id, lba, buffer_size, buffer,
> +                                 EFI_DISK_READ);
> +}
> +
> +static efi_status_t efi_disk_write_blocks(struct efi_block_io *this,
> +                       u32 media_id, u64 lba, unsigned long buffer_size,
> +                       void *buffer)
> +{
> +       return efi_disk_rw_blocks(this, media_id, lba, buffer_size, buffer,
> +                                 EFI_DISK_WRITE);
> +}
> +
> +static efi_status_t efi_disk_flush_blocks(struct efi_block_io *this)
> +{
> +       /* We always write synchronously */
> +       return EFI_SUCCESS;
> +}
> +
> +static const struct efi_block_io block_io_disk_template = {
> +       .reset = &efi_disk_reset,
> +       .read_blocks = &efi_disk_read_blocks,
> +       .write_blocks = &efi_disk_write_blocks,
> +       .flush_blocks = &efi_disk_flush_blocks,
> +};
> +
> +/*
> + * U-Boot doesn't have a list of all online disk devices. So when running our
> + * EFI payload, we scan through all of the potentially available ones and
> + * store them in our object pool.
> + *
> + * This gets called from do_bootefi_exec().
> + */
> +int efi_disk_register(void)
> +{
> +       const char **cur_drvr;
> +       int i;
> +       int disks = 0;
> +
> +       /* Search for all available disk devices */
> +       for (cur_drvr = available_block_drvrs; *cur_drvr; cur_drvr++) {
> +               printf("Scanning disks on %s...\n", *cur_drvr);
> +               for (i = 0; i < 4; i++) {

What is 4 for?

> +                       block_dev_desc_t *desc;
> +                       struct efi_disk_obj *diskobj;
> +                       struct efi_device_path_file_path *dp;
> +                       int objlen = sizeof(*diskobj) + (sizeof(*dp) * 2);
> +                       char devname[16];
> +
> +                       desc = get_dev(*cur_drvr, i);
> +                       if (!desc)
> +                               continue;
> +
> +                       diskobj = malloc(objlen);

Could use calloc() to avoid memset() if you like.

> +                       memset(diskobj, 0, objlen);
> +
> +                       /* Fill in object data */
> +
> +                       diskobj->parent.protocols[0].guid = &efi_block_io_guid;
> +                       diskobj->parent.protocols[0].open = efi_disk_open_block;
> +                       diskobj->parent.protocols[1].guid = &efi_guid_device_path;
> +                       diskobj->parent.protocols[1].open = efi_disk_open_dp;
> +                       diskobj->parent.handle = diskobj;
> +                       diskobj->ops = block_io_disk_template;
> +                       diskobj->ifname = *cur_drvr;
> +                       diskobj->dev_index = i;
> +
> +                       /* Fill in EFI IO Media info (for read/write callbacks) */
> +
> +                       diskobj->media.removable_media = desc->removable;
> +                       diskobj->media.media_present = 1;
> +                       diskobj->media.block_size = desc->blksz;
> +                       diskobj->media.io_align = desc->blksz;
> +                       diskobj->media.last_block = desc->lba;
> +                       diskobj->ops.media = &diskobj->media;
> +
> +                       /* Fill in device path */
> +
> +                       dp = (void*)&diskobj[1];
> +                       diskobj->dp = dp;
> +                       dp[0].dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
> +                       dp[0].dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH;
> +                       dp[0].dp.length = sizeof(*dp);
> +                       sprintf(devname, "%s%d", *cur_drvr, i);
> +                       ascii2unicode(dp[0].str, devname);
> +
> +                       dp[1].dp.type = DEVICE_PATH_TYPE_END;
> +                       dp[1].dp.sub_type = DEVICE_PATH_SUB_TYPE_END;
> +                       dp[1].dp.length = sizeof(*dp);
> +
> +                       /* Hook up to the device list */
> +
> +                       list_add_tail(&diskobj->parent.link, &efi_obj_list);
> +                       disks++;
> +               }
> +       }
> +       printf("Found %d disks\n", disks);
> +
> +       return 0;
> +}
> --
> 2.1.4
>

Regards,
Simon

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

* [U-Boot] [PATCH 7/9] efi_loader: Add disk interfaces
  2016-01-15  1:37   ` Simon Glass
@ 2016-01-15  2:40     ` Alexander Graf
  0 siblings, 0 replies; 70+ messages in thread
From: Alexander Graf @ 2016-01-15  2:40 UTC (permalink / raw)
  To: u-boot



On 15.01.16 02:37, Simon Glass wrote:
> Hi Alexander,
> 
> On 22 December 2015 at 06:57, Alexander Graf <agraf@suse.de> wrote:
>> A EFI applications usually want to access storage devices to load data from.
>>
>> This patch adds support for EFI disk interfaces. It loops through all block
>> storage interfaces known to U-Boot and creates an EFI object for each existing
>> one. EFI applications can then through these objects call U-Boot's read and
>> write functions.
>>
>> Signed-off-by: Alexander Graf <agraf@suse.de>
>> ---
>>  include/efi_loader.h      |   1 +
>>  lib/efi_loader/efi_disk.c | 227 ++++++++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 228 insertions(+)
>>  create mode 100644 lib/efi_loader/efi_disk.c
> 
> Reviewed-by: Simon Glass <sjg@chromium.org>
> 
> Some nits below.
> 
>>
>> diff --git a/include/efi_loader.h b/include/efi_loader.h
>> index af1c88f..7e821e5 100644
>> --- a/include/efi_loader.h
>> +++ b/include/efi_loader.h
>> @@ -72,6 +72,7 @@ struct efi_object {
>>  };
>>  extern struct list_head efi_obj_list;
>>
>> +int efi_disk_register(void);
>>  efi_status_t efi_return_handle(void *handle,
>>                 efi_guid_t *protocol, void **protocol_interface,
>>                 void *agent_handle, void *controller_handle,
>> diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
>> new file mode 100644
>> index 0000000..1804e3e
>> --- /dev/null
>> +++ b/lib/efi_loader/efi_disk.c
>> @@ -0,0 +1,227 @@
>> +/*
>> + *  EFI application disk support
>> + *
>> + *  Copyright (c) 2015 Alexander Graf
>> + *
>> + *  This library is free software; you can redistribute it and/or
>> + *  modify it under the terms of the GNU Lesser General Public
>> + *  License as published by the Free Software Foundation; either
>> + *  version 2.1 of the License, or (at your option) any later version.
>> + *
>> + *  This library is distributed in the hope that it will be useful,
>> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> + *  Lesser General Public License for more details.
>> + *
>> + *  You should have received a copy of the GNU Lesser General Public
>> + *  License along with this library; if not, write to the Free Software
>> + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
>> + *
>> + *  SPDX-License-Identifier:     LGPL-2.1+
> 
> Can we have GPL 2 / 2+? Also drop the text?
> 
>> + */
>> +
>> +#include <common.h>
>> +#include <efi_loader.h>
>> +#include <part.h>
>> +#include <malloc.h>
>> +#include <inttypes.h>
> 
> inttypes.h should go above part.h
> 
>> +
>> +static const efi_guid_t efi_block_io_guid = BLOCK_IO_GUID;
>> +
>> +struct efi_disk_obj {
> 
> Could use comments on these members
> 
>> +       struct efi_object parent;
>> +       struct efi_block_io ops;
>> +       const char *ifname;
>> +       int dev_index;
>> +       struct efi_block_io_media media;
>> +       struct efi_device_path_file_path *dp;
>> +};
>> +
>> +static void ascii2unicode(u16 *unicode, char *ascii)
>> +{
>> +       while (*ascii)
>> +               *(unicode++) = *(ascii++);
>> +}
>> +
>> +static efi_status_t efi_disk_open_block(void *handle, efi_guid_t *protocol,
>> +                       void **protocol_interface, void *agent_handle,
>> +                       void *controller_handle, uint32_t attributes)
>> +{
>> +       struct efi_disk_obj *diskobj = handle;
>> +
>> +       *protocol_interface = &diskobj->ops;
>> +
>> +       return EFI_SUCCESS;
>> +}
>> +
>> +static efi_status_t efi_disk_open_dp(void *handle, efi_guid_t *protocol,
>> +                       void **protocol_interface, void *agent_handle,
>> +                       void *controller_handle, uint32_t attributes)
>> +{
>> +       struct efi_disk_obj *diskobj = handle;
>> +
>> +       *protocol_interface = diskobj->dp;
>> +
>> +       return EFI_SUCCESS;
>> +}
>> +
>> +static efi_status_t efi_disk_reset(struct efi_block_io *this,
>> +                       char extended_verification)
>> +{
>> +       EFI_ENTRY("%p, %x", this, extended_verification);
>> +       return EFI_EXIT(EFI_DEVICE_ERROR);
>> +}
>> +
>> +enum efi_disk_direction {
>> +       EFI_DISK_READ,
>> +       EFI_DISK_WRITE,
>> +};
>> +
>> +static efi_status_t efi_disk_rw_blocks(struct efi_block_io *this,
>> +                       u32 media_id, u64 lba, unsigned long buffer_size,
>> +                       void *buffer, enum efi_disk_direction direction)
>> +{
>> +       struct efi_disk_obj *diskobj;
>> +       struct block_dev_desc *desc;
>> +       int blksz;
>> +       int blocks;
>> +       unsigned long n;
>> +
>> +       EFI_ENTRY("%p, %x, %"PRIx64", %lx, %p", this, media_id, lba,
>> +                 buffer_size, buffer);
>> +
>> +       diskobj = container_of(this, struct efi_disk_obj, ops);
>> +       if (!(desc = get_dev(diskobj->ifname, diskobj->dev_index)))
>> +               return EFI_EXIT(EFI_DEVICE_ERROR);
>> +       blksz = desc->blksz;
>> +       blocks = buffer_size / blksz;
>> +
>> +#ifdef DEBUG_EFI
>> +       printf("EFI: %s:%d blocks=%x lba=%"PRIx64" blksz=%x dir=%d\n", __func__,
>> +              __LINE__, blocks, lba, blksz, direction);
>> +#endif
>> +
>> +       /* We only support full block access */
>> +       if (buffer_size & (blksz - 1))
>> +               return EFI_EXIT(EFI_DEVICE_ERROR);
>> +
>> +       if (direction == EFI_DISK_READ)
>> +               n = desc->block_read(desc->dev, lba, blocks, buffer);
>> +       else
>> +               n = desc->block_write(desc->dev, lba, blocks, buffer);
>> +
>> +       /* We don't do interrupts, so check for timers cooperatively */
>> +       efi_timer_check();
>> +
>> +#ifdef DEBUG_EFI
>> +       printf("EFI: %s:%d n=%lx blocks=%x\n", __func__, __LINE__, n, blocks);
>> +#endif
>> +       if (n != blocks)
>> +               return EFI_EXIT(EFI_DEVICE_ERROR);
>> +
>> +       return EFI_EXIT(EFI_SUCCESS);
>> +}
>> +
>> +static efi_status_t efi_disk_read_blocks(struct efi_block_io *this,
>> +                       u32 media_id, u64 lba, unsigned long buffer_size,
>> +                       void *buffer)
>> +{
>> +       return efi_disk_rw_blocks(this, media_id, lba, buffer_size, buffer,
>> +                                 EFI_DISK_READ);
>> +}
>> +
>> +static efi_status_t efi_disk_write_blocks(struct efi_block_io *this,
>> +                       u32 media_id, u64 lba, unsigned long buffer_size,
>> +                       void *buffer)
>> +{
>> +       return efi_disk_rw_blocks(this, media_id, lba, buffer_size, buffer,
>> +                                 EFI_DISK_WRITE);
>> +}
>> +
>> +static efi_status_t efi_disk_flush_blocks(struct efi_block_io *this)
>> +{
>> +       /* We always write synchronously */
>> +       return EFI_SUCCESS;
>> +}
>> +
>> +static const struct efi_block_io block_io_disk_template = {
>> +       .reset = &efi_disk_reset,
>> +       .read_blocks = &efi_disk_read_blocks,
>> +       .write_blocks = &efi_disk_write_blocks,
>> +       .flush_blocks = &efi_disk_flush_blocks,
>> +};
>> +
>> +/*
>> + * U-Boot doesn't have a list of all online disk devices. So when running our
>> + * EFI payload, we scan through all of the potentially available ones and
>> + * store them in our object pool.
>> + *
>> + * This gets called from do_bootefi_exec().
>> + */
>> +int efi_disk_register(void)
>> +{
>> +       const char **cur_drvr;
>> +       int i;
>> +       int disks = 0;
>> +
>> +       /* Search for all available disk devices */
>> +       for (cur_drvr = available_block_drvrs; *cur_drvr; cur_drvr++) {
>> +               printf("Scanning disks on %s...\n", *cur_drvr);
>> +               for (i = 0; i < 4; i++) {
> 
> What is 4 for?

4 disks should be enough for everyone ;).

I couldn't find an easy way to limit the number of devices we have to
scan. You may have 4 MMC slots, but only slot 3 is actually populated.
How do you know how many there really are?

So we have to use some upper bound for the scan. The 4 is simply because
most devices I'm aware of that U-Boot runs on don't have much more than
4 devices per block bus attached to them. I had 128 in here first, but
then I ran into endless timeouts with MMC scans.


Thanks a bunch for the review :)

Alex

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

* [U-Boot] [PATCH 0/9] EFI payload / application support
  2015-12-25 16:50     ` Tom Rini
  2015-12-25 16:53       ` Matwey V. Kornilov
@ 2016-01-15  3:00       ` Alexander Graf
  2016-01-15  3:06         ` Tom Rini
  1 sibling, 1 reply; 70+ messages in thread
From: Alexander Graf @ 2016-01-15  3:00 UTC (permalink / raw)
  To: u-boot



On 25.12.15 17:50, Tom Rini wrote:
> On Fri, Dec 25, 2015 at 09:53:22AM +0100, Alexander Graf wrote:
>>
>>
>> On 25.12.15 04:29, Tom Rini wrote:
>>> On Tue, Dec 22, 2015 at 02:57:47PM +0100, Alexander Graf wrote:
>>>
>>>> This is my Christmas present for my openSUSE friends :).
>>>>
>>>> U-Boot is a great project for embedded devices. However, convincing
>>>> everyone involved that only for "a few oddball ARM devices" we need to
>>>> support different configuration formats from grub2 when all other platforms
>>>> (PPC, System Z, x86) are standardized on a single format is a nightmare.
>>>>
>>>> So we started to explore alternatives. At first, people tried to get
>>>> grub2 running using the u-boot api interface. However, FWIW that one
>>>> doesn't support relocations, so you need to know where to link grub2 to
>>>> at compile time. It also seems to be broken more often than not. And on
>>>> top of it all, it's a one-off interface, so yet another thing to maintain.
>>>>
>>>> That led to a nifty idea. What if we can just implement the EFI application
>>>> protocol on top of U-Boot? Then we could compile a single grub2 binary for
>>>> uEFI based systems and U-Boot based systems and as soon as that one's loaded,
>>>> everything looks and feels (almost) the same.
>>>>
>>>> This patch set is the result of pursuing this endeavor.
>>>
>>> So, I owe the whole codebase a real review.  My very quick question
>>> however is, aside from what you had to borrow from wine, can you license
>>> everything else as GPL v2 or later rather than LGPL?
>>
>> I'm personally a pretty big fan of the LGPL, since it's a very
>> reasonable compromise between closed and open source IMHO ;).
>>
>> Is there a particular reason you're asking for this? LGPL code is fully
>> compatible with GPL code and the resulting binary would be GPL anyway
>> because FWIW you can't compile U-Boot without GPL code inside.
> 
> The general rules for U-Boot code are to be GPL v2 or later.  U-Boot is
> (and always will be) a GPL v2 only project as there's simply too much
> Linux kernel code that we want to leverage.  We do make special
> exceptions at times for very good reasons (like include/android_image.h
> is the authorative BSD-2 clause copy of that information) and I've even
> told some companies that for crypto-auth-sensitive stuff they can do GPL
> v2 only in their submission (again, due to U-Boot always being a v2 only
> project).
> 
> So, I'm not gonig to reject the EFI loader code if you say no, you won't
> re-license it as GPL v2 (or v2 and later) but I'd really appreciate it.
> Thanks!

I've just read up and apparently it's completely legal and allowed to
simply remove the LGPL (2.1+) boilerplate from a file and instead put a
GPL (2.0+) one on it, even if you didn't write the code.

So even if I had insisted to stick to LGPL v2.1+, you could've just
written a patch to change it after the fact ;).

But since everyone seems to be far more happy with GPL rather than LGPL,
I've spared you that patch and changed the headers myself now.


Alex

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

* [U-Boot] [PATCH 0/9] EFI payload / application support
  2016-01-15  3:00       ` Alexander Graf
@ 2016-01-15  3:06         ` Tom Rini
  0 siblings, 0 replies; 70+ messages in thread
From: Tom Rini @ 2016-01-15  3:06 UTC (permalink / raw)
  To: u-boot

On Fri, Jan 15, 2016 at 04:00:21AM +0100, Alexander Graf wrote:
> 
> 
> On 25.12.15 17:50, Tom Rini wrote:
> > On Fri, Dec 25, 2015 at 09:53:22AM +0100, Alexander Graf wrote:
> >>
> >>
> >> On 25.12.15 04:29, Tom Rini wrote:
> >>> On Tue, Dec 22, 2015 at 02:57:47PM +0100, Alexander Graf wrote:
> >>>
> >>>> This is my Christmas present for my openSUSE friends :).
> >>>>
> >>>> U-Boot is a great project for embedded devices. However, convincing
> >>>> everyone involved that only for "a few oddball ARM devices" we need to
> >>>> support different configuration formats from grub2 when all other platforms
> >>>> (PPC, System Z, x86) are standardized on a single format is a nightmare.
> >>>>
> >>>> So we started to explore alternatives. At first, people tried to get
> >>>> grub2 running using the u-boot api interface. However, FWIW that one
> >>>> doesn't support relocations, so you need to know where to link grub2 to
> >>>> at compile time. It also seems to be broken more often than not. And on
> >>>> top of it all, it's a one-off interface, so yet another thing to maintain.
> >>>>
> >>>> That led to a nifty idea. What if we can just implement the EFI application
> >>>> protocol on top of U-Boot? Then we could compile a single grub2 binary for
> >>>> uEFI based systems and U-Boot based systems and as soon as that one's loaded,
> >>>> everything looks and feels (almost) the same.
> >>>>
> >>>> This patch set is the result of pursuing this endeavor.
> >>>
> >>> So, I owe the whole codebase a real review.  My very quick question
> >>> however is, aside from what you had to borrow from wine, can you license
> >>> everything else as GPL v2 or later rather than LGPL?
> >>
> >> I'm personally a pretty big fan of the LGPL, since it's a very
> >> reasonable compromise between closed and open source IMHO ;).
> >>
> >> Is there a particular reason you're asking for this? LGPL code is fully
> >> compatible with GPL code and the resulting binary would be GPL anyway
> >> because FWIW you can't compile U-Boot without GPL code inside.
> > 
> > The general rules for U-Boot code are to be GPL v2 or later.  U-Boot is
> > (and always will be) a GPL v2 only project as there's simply too much
> > Linux kernel code that we want to leverage.  We do make special
> > exceptions at times for very good reasons (like include/android_image.h
> > is the authorative BSD-2 clause copy of that information) and I've even
> > told some companies that for crypto-auth-sensitive stuff they can do GPL
> > v2 only in their submission (again, due to U-Boot always being a v2 only
> > project).
> > 
> > So, I'm not gonig to reject the EFI loader code if you say no, you won't
> > re-license it as GPL v2 (or v2 and later) but I'd really appreciate it.
> > Thanks!
> 
> I've just read up and apparently it's completely legal and allowed to
> simply remove the LGPL (2.1+) boilerplate from a file and instead put a
> GPL (2.0+) one on it, even if you didn't write the code.

Legal and good idea don't always match up :)

> So even if I had insisted to stick to LGPL v2.1+, you could've just
> written a patch to change it after the fact ;).
> 
> But since everyone seems to be far more happy with GPL rather than LGPL,
> I've spared you that patch and changed the headers myself now.

Thanks, I appreciate it!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20160114/1b8e2ec4/attachment.sig>

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

* [U-Boot] [PATCH 0/9] EFI payload / application support
  2016-01-04 16:56         ` Tom Rini
  2016-01-04 18:03           ` Andreas Färber
  2016-01-04 20:11           ` Matwey V. Kornilov
@ 2016-01-15  3:32           ` Peter Robinson
  2 siblings, 0 replies; 70+ messages in thread
From: Peter Robinson @ 2016-01-15  3:32 UTC (permalink / raw)
  To: u-boot

>> I am not aware of anyone using the U-Boot API for grub these days, so
>> I'm not sure it's an incredibly useful goal. The main pain point distros
>> seem to have is to make something that "just works" on all systems out
>> there. Moving into that direction should be our ultimate goal.
>
> Please note that with the generic distro framework U-Boot will grok
> https://wiki.freedesktop.org/www/Specifications/BootLoaderSpec/ and
> things Just Work.  I setup a bunch of SD cards with Debian and Fedora
> over holiday so I can drop them in whatever board and boot up Linux as a
> sanity test.

This is certtainly Fedora's preferred method for u-boot based devices

> I certainly can see a usecase for kicking off an EFI binary as part of
> fitting into existing work-flows.  But we do already have a something
> for getting rid of that particular pain-point and it's working :)

It would certainly be a useful option to have.

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

* [U-Boot] [PATCH 0/9] EFI payload / application support
  2016-01-04 18:03           ` Andreas Färber
  2016-01-04 18:41             ` Andreas Färber
@ 2016-01-15  3:40             ` Peter Robinson
  1 sibling, 0 replies; 70+ messages in thread
From: Peter Robinson @ 2016-01-15  3:40 UTC (permalink / raw)
  To: u-boot

On Mon, Jan 4, 2016 at 6:03 PM, Andreas F?rber <afaerber@suse.de> wrote:
> Am 04.01.2016 um 17:56 schrieb Tom Rini:
>> Please note that with the generic distro framework U-Boot will grok
>> https://wiki.freedesktop.org/www/Specifications/BootLoaderSpec/ and
>> things Just Work.  I setup a bunch of SD cards with Debian and Fedora
>> over holiday so I can drop them in whatever board and boot up Linux as a
>> sanity test.
>>
>> I certainly can see a usecase for kicking off an EFI binary as part of
>> fitting into existing work-flows.  But we do already have a something
>> for getting rid of that particular pain-point and it's working :)
>
> No, as I explained before, you are not addressing that particular
> pain-point: extlinux is still something new to implement for us as
> distro, you provide no tools to help us, while on x86, ppc, s390 and
> some aarch64 we have converged on grub2 as a standard, and just recently
> the YaST devs decided to only support grub2 going forward.
>
> For extlinux (which BTW to my eye looked slightly different from the
> freedesktop.org spec that you guys keep referencing?!), distro-specific
> code needs to be written [1] so that on kernel installation the
> /boot/extlinux/extlinux.conf file is regenerated - for grub2 such tools
> simply exist as part of GRUB and this proposed EFI interface for U-Boot
> will avoid having to implement any new, e.g., perl-Bootloader code.

Yes, that is true, but it only has to be done once.

> So the open conflict is that you tell us that extlinux.conf is your
> "distro" mechanism that we should be using, and our distro people are
> telling us that grub2 is their preferred solution after having
> accumulated bootloader code for some two decades and just got rid of it.
>
> Standards are not created through publishing some spec, they are created
> through adoption, and today I don't see anyone at SUSE moving an inch
> towards adopting extlinux.conf as a generic boot mechanism for all
> architectures. That leaves our ARM community at a loss, booting a single
> kernel through a symlink.

It's certainly not ideal but in Fedora (and I believe in Debian too)
we use the distro support in u-boot to boot dozens of devices with
multiple kernels and roll backs.

> No one has suggested to dump extlinux.conf or boot.scr, they can all
> simply co-exist, with the difference that, from the looks of it, Alex'
> EFI code could get enabled by default to allow users to choose using it,
> unlike the disabled CONFIG_API code that I reported got broken by DM
> migration and for many other boards was lacking defines and is in need
> of a board-specific rather than generic second bootloader on the distro
> side.
>
> This patchset is a cute middle ground where for U-Boot it's mostly just
> an additional command, our distro people will be content, and our ARM
> users will be happy too, not having to handcraft extlinux.conf files and
> benefiting from the vibrant U-Boot community as opposed to the much more
> fragmented Tianocore forks out there. Thus I'm hoping we can sort out
> some of the technical issues Leif pointed out and stop circling back to
> this unhelpful oh-but-extlinux.conf-is-the-mechanism point.

Yes, I think it's definitely good value, especially for aarch64
devices where uEFI is currently a much wider tested option due to the
current available devices.

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

* [U-Boot] [PATCH 4/9] efi_loader: Add boot time services
  2015-12-26 18:09   ` Leif Lindholm
  2016-01-15  0:13     ` Alexander Graf
@ 2016-01-15  3:40     ` Alexander Graf
  1 sibling, 0 replies; 70+ messages in thread
From: Alexander Graf @ 2016-01-15  3:40 UTC (permalink / raw)
  To: u-boot



On 26.12.15 19:09, Leif Lindholm wrote:
> On Tue, Dec 22, 2015 at 02:57:51PM +0100, Alexander Graf wrote:

[...]

>> +		break;
>> +	case 2:
>> +		/* Exact address, grant it. The addr is already in *memory. */
> 
> As far as I can tell, this is why GRUB works. Because it filters
> through the memory map manually, requesting to allocate its heap at an
> exact address in a region of free memory in the UEFI memory map.
> 
> The key is that EFI_LOADER_MEMORY will be used by applications loaded
> as well as by U-Boot to load applications into. A simple example where
> this could be problematic would be a large(ish) initrd loaded via initrd=
> on kernel (stub loader) command line rather than via GRUB.

Thinking about this once more, we don't expose any file system
interfaces to EFI applications, so initrd= won't work anyway. That means
the only viable path to go right now is via grub which means we
shouldn't get into memory contention with 128MB LOADER_DATA.


Alex

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

* [U-Boot] [PATCH 3/9] efi_loader: Add PE image loader
  2016-01-14 23:45     ` Alexander Graf
@ 2016-01-15 12:29       ` Leif Lindholm
  0 siblings, 0 replies; 70+ messages in thread
From: Leif Lindholm @ 2016-01-15 12:29 UTC (permalink / raw)
  To: u-boot

On Fri, Jan 15, 2016 at 12:45:46AM +0100, Alexander Graf wrote:
> On 26.12.15 17:26, Leif Lindholm wrote:
> >> new file mode 100644
> >> index 0000000..688e177
> >> --- /dev/null
> >> +++ b/lib/efi_loader/efi_image_loader.c
> >> @@ -0,0 +1,203 @@
> >> +/*
> >> + *  EFI image loader
> >> + *
> >> + *  based partly on wine code
> >> + *
> >> + *  Copyright (c) 2015 Alexander Graf
> >> + *
> >> + *  This library is free software; you can redistribute it and/or
> >> + *  modify it under the terms of the GNU Lesser General Public
> >> + *  License as published by the Free Software Foundation; either
> >> + *  version 2.1 of the License, or (at your option) any later version.
> >> + *
> >> + *  This library is distributed in the hope that it will be useful,
> >> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> >> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> >> + *  Lesser General Public License for more details.
> >> + *
> >> + *  You should have received a copy of the GNU Lesser General Public
> >> + *  License along with this library; if not, write to the Free Software
> >> + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
> >> + *
> >> + *  SPDX-License-Identifier:     LGPL-2.1+
> >> + */
> >> +
> >> +#include <common.h>
> >> +#include <pe.h>
> >> +#include <efi_loader.h>
> >> +#include <asm/global_data.h>
> >> +
> >> +DECLARE_GLOBAL_DATA_PTR;
> >> +
> >> +#define ROUND_UP(val, round) ((val + (round - 1)) & ~(round - 1))
> >> +#define MB (1024 * 1024)
> >> +
> >> +const efi_guid_t efi_guid_device_path = DEVICE_PATH_GUID;
> >> +const efi_guid_t efi_guid_loaded_image = LOADED_IMAGE_GUID;
> >> +
> >> +efi_status_t efi_return_handle(void *handle, efi_guid_t *protocol,
> >> +			void **protocol_interface, void *agent_handle,
> >> +			void *controller_handle, uint32_t attributes)
> >> +{
> >> +	*protocol_interface = handle;
> >> +	return EFI_SUCCESS;
> >> +}
> >> +
> >> +/*
> >> + * EFI payloads potentially want to load pretty big images into memory,
> >> + * so our small malloc region isn't enough for them. However, they usually
> >> + * don't need a smart allocator either.
> >> + *
> >> + * So instead give them a really dumb one. We just reserve EFI_LOADER_POOL_SIZE
> >> + * bytes from 16MB below the malloc region start to give the stack some space.
> > 
> > Is there any chance you could break out the memory allocation and
> > memory map management as a separate patch, rather than spread across
> > 3,4 and 6?
> 
> Uh, sure, I can try. I'm not sure it'll end up more readable than now
> though :).

Heh, ok. It was a theory.

> > Assigning a specific 128MB pool for LOADER_DATA memory can have
> > unexpected side effects.
> 
> Like for example?

Like applications running out of memory when there's plenty left in
the system. OK, so not "unexpected" unexpected, but "may cause valid
programs to break". My initial comment was because I was scratching my
head over how GRUB managed to allocate its heap at all.

/
    Leif

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

* [U-Boot] [PATCH 4/9] efi_loader: Add boot time services
  2016-01-15  0:13     ` Alexander Graf
@ 2016-01-15 13:02       ` Leif Lindholm
  2016-01-15 14:14         ` Alexander Graf
  0 siblings, 1 reply; 70+ messages in thread
From: Leif Lindholm @ 2016-01-15 13:02 UTC (permalink / raw)
  To: u-boot

On Fri, Jan 15, 2016 at 01:13:15AM +0100, Alexander Graf wrote:
> On 26.12.15 19:09, Leif Lindholm wrote:
> >> diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
> >> new file mode 100644
> >> index 0000000..ed95962
> >> --- /dev/null
> >> +++ b/lib/efi_loader/efi_boottime.c
> >> @@ -0,0 +1,838 @@
> >> +/*
> >> + *  EFI application boot time services
> >> + *
...
> >> +
> >> +static unsigned long efi_raise_tpl(unsigned long new_tpl)
> >> +{
> >> +	EFI_ENTRY("0x%lx", new_tpl);
> >> +	return EFI_EXIT(efi_unsupported(__func__));
> > 
> > "Unlike other UEFI interface functions, EFI_BOOT_SERVICES.RaiseTPL()
> > does not return a status code. Instead, it returns the previous task
> > priority level, which is to be restored later with a matching call to
> > RestoreTPL()."
> 
> Since we don't do TPLs (or IRQs for that matter), I'll just return 0 here.

Sure.

> >> +}
> >> +
> >> +static void efi_restore_tpl(unsigned long old_tpl)
> >> +{
> >> +	EFI_ENTRY("0x%lx", old_tpl);
> >> +	EFI_EXIT(efi_unsupported(__func__));
> > 
> > (void function, nothing to return)
> 
> Yes, hence no return. EFI_EXIT deals with the gd swapping and
> efi_unsupported() gives me a nice debug message :).

Ah, ok.

> >> +static efi_status_t efi_allocate_pages(int type, int memory_type,
> >> +				       unsigned long pages, uint64_t *memory)
> >> +{
> >> +	u64 len = pages << 12;
> >> +	efi_status_t r = EFI_SUCCESS;
> >> +
> >> +	EFI_ENTRY("%d, %d, 0x%lx, %p", type, memory_type, pages, memory);
> >> +
> >> +	switch (type) {
> >> +	case 0:
> >> +		/* Any page means we can go to efi_alloc */
> >> +		*memory = (unsigned long)efi_alloc(len, memory_type);
> >> +		break;
> >> +	case 1:
> >> +		/* Max address */
> >> +		if (gd->relocaddr < *memory) {
> >> +			*memory = (unsigned long)efi_alloc(len, memory_type);
> >> +			break;
> >> +		}
> >> +		r = EFI_UNSUPPORTED;
> > 
> > EFI_OUT_OF_RESOURCES/EFI_NOT_FOUND?
> > 
> >> +		break;
> >> +	case 2:
> >> +		/* Exact address, grant it. The addr is already in *memory. */
> > 
> > As far as I can tell, this is why GRUB works. Because it filters
> > through the memory map manually, requesting to allocate its heap at an
> > exact address in a region of free memory in the UEFI memory map.
> 
> Yes.
> 
> > The key is that EFI_LOADER_MEMORY will be used by applications loaded
> > as well as by U-Boot to load applications into. A simple example where
> > this could be problematic would be a large(ish) initrd loaded via initrd=
> > on kernel (stub loader) command line rather than via GRUB.
> 
> Ah, so here the 128MB limit on the LOADER_DATA section might bite us?

Yeah, I think so.

> >> +	runtime_start = (ulong)&__efi_runtime_start & ~0xfffULL;
> >> +	runtime_end = ((ulong)&__efi_runtime_stop + 0xfff) & ~0xfffULL;
> >> +	runtime_len_pages = (runtime_end - runtime_start) >> 12;
> >> +	runtime_len = runtime_len_pages << 12;
> >> +
> >> +	/* Fill in where normal RAM is (up to U-Boot) */
> >> +	efi_memory_map[0].num_pages = gd->relocaddr >> 12;
> > 
> > U-Boot question: is gd->relocaddr always the offset from start of RAM?
> > How does this work with gaps in memory map?
> 
> U-Boot always relocates itself at TOM (or at least what we consider TOM
> here). gd->relocaddr is the physical address of the start of U-Boot
> which is right below TOM.

Still ... would need additional handling if memory has holes (like,
fitted with multiple DIMMs smaller than the individual memory window
reserved for them). Or even on something like Juno, which has 2GB of
RAM at 0x00_8000_0000, and a further 6GB at 0x08_8000_0000 (I think).

> >> +#ifdef CONFIG_SYS_SDRAM_BASE
> >> +	efi_memory_map[0].physical_start = CONFIG_SYS_SDRAM_BASE;
> >> +	efi_memory_map[0].virtual_start = CONFIG_SYS_SDRAM_BASE;
> >> +	efi_memory_map[0].num_pages -= CONFIG_SYS_SDRAM_BASE >> 12;
> > #else
> > #error "..."
> > ?
> 
> If it's not defined, it's 0 :).

Make it
#if CONFIG_SYS_SDRAM_BASE != 0
for clarity?

/
    Leif

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

* [U-Boot] [PATCH 6/9] efi_loader: Add runtime services
  2016-01-15  0:26     ` Alexander Graf
@ 2016-01-15 13:52       ` Leif Lindholm
  2016-01-15 14:15         ` Alexander Graf
  0 siblings, 1 reply; 70+ messages in thread
From: Leif Lindholm @ 2016-01-15 13:52 UTC (permalink / raw)
  To: u-boot

On Fri, Jan 15, 2016 at 01:26:42AM +0100, Alexander Graf wrote:
> On 26.12.15 19:33, Leif Lindholm wrote:
> >> +	.reset_system = (void *)&efi_unimplemented,
> > 
> > "The ResetSystem() function does not return."
> 
> Hrm, I think returning EFI_UNSUPPORTED is still better than while(1) {
> }. With the return an OS at least has the chance to fix things up itself.

I'm not saying it isn't better, I'm saying it's not compliant - there
is no valid return value. I would prefer simply having the pointer set
to NULL.

/
    Leif

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

* [U-Boot] [PATCH 4/9] efi_loader: Add boot time services
  2016-01-15 13:02       ` Leif Lindholm
@ 2016-01-15 14:14         ` Alexander Graf
  2016-01-15 14:21           ` Leif Lindholm
  0 siblings, 1 reply; 70+ messages in thread
From: Alexander Graf @ 2016-01-15 14:14 UTC (permalink / raw)
  To: u-boot



On 15.01.16 14:02, Leif Lindholm wrote:
> On Fri, Jan 15, 2016 at 01:13:15AM +0100, Alexander Graf wrote:
>> On 26.12.15 19:09, Leif Lindholm wrote:
>>>> diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
>>>> new file mode 100644
>>>> index 0000000..ed95962
>>>> --- /dev/null
>>>> +++ b/lib/efi_loader/efi_boottime.c
>>>> @@ -0,0 +1,838 @@
>>>> +/*
>>>> + *  EFI application boot time services
>>>> + *
> ...
>>>> +
>>>> +static unsigned long efi_raise_tpl(unsigned long new_tpl)
>>>> +{
>>>> +	EFI_ENTRY("0x%lx", new_tpl);
>>>> +	return EFI_EXIT(efi_unsupported(__func__));
>>>
>>> "Unlike other UEFI interface functions, EFI_BOOT_SERVICES.RaiseTPL()
>>> does not return a status code. Instead, it returns the previous task
>>> priority level, which is to be restored later with a matching call to
>>> RestoreTPL()."
>>
>> Since we don't do TPLs (or IRQs for that matter), I'll just return 0 here.
> 
> Sure.
> 
>>>> +}
>>>> +
>>>> +static void efi_restore_tpl(unsigned long old_tpl)
>>>> +{
>>>> +	EFI_ENTRY("0x%lx", old_tpl);
>>>> +	EFI_EXIT(efi_unsupported(__func__));
>>>
>>> (void function, nothing to return)
>>
>> Yes, hence no return. EFI_EXIT deals with the gd swapping and
>> efi_unsupported() gives me a nice debug message :).
> 
> Ah, ok.
> 
>>>> +static efi_status_t efi_allocate_pages(int type, int memory_type,
>>>> +				       unsigned long pages, uint64_t *memory)
>>>> +{
>>>> +	u64 len = pages << 12;
>>>> +	efi_status_t r = EFI_SUCCESS;
>>>> +
>>>> +	EFI_ENTRY("%d, %d, 0x%lx, %p", type, memory_type, pages, memory);
>>>> +
>>>> +	switch (type) {
>>>> +	case 0:
>>>> +		/* Any page means we can go to efi_alloc */
>>>> +		*memory = (unsigned long)efi_alloc(len, memory_type);
>>>> +		break;
>>>> +	case 1:
>>>> +		/* Max address */
>>>> +		if (gd->relocaddr < *memory) {
>>>> +			*memory = (unsigned long)efi_alloc(len, memory_type);
>>>> +			break;
>>>> +		}
>>>> +		r = EFI_UNSUPPORTED;
>>>
>>> EFI_OUT_OF_RESOURCES/EFI_NOT_FOUND?
>>>
>>>> +		break;
>>>> +	case 2:
>>>> +		/* Exact address, grant it. The addr is already in *memory. */
>>>
>>> As far as I can tell, this is why GRUB works. Because it filters
>>> through the memory map manually, requesting to allocate its heap at an
>>> exact address in a region of free memory in the UEFI memory map.
>>
>> Yes.
>>
>>> The key is that EFI_LOADER_MEMORY will be used by applications loaded
>>> as well as by U-Boot to load applications into. A simple example where
>>> this could be problematic would be a large(ish) initrd loaded via initrd=
>>> on kernel (stub loader) command line rather than via GRUB.
>>
>> Ah, so here the 128MB limit on the LOADER_DATA section might bite us?
> 
> Yeah, I think so.
> 
>>>> +	runtime_start = (ulong)&__efi_runtime_start & ~0xfffULL;
>>>> +	runtime_end = ((ulong)&__efi_runtime_stop + 0xfff) & ~0xfffULL;
>>>> +	runtime_len_pages = (runtime_end - runtime_start) >> 12;
>>>> +	runtime_len = runtime_len_pages << 12;
>>>> +
>>>> +	/* Fill in where normal RAM is (up to U-Boot) */
>>>> +	efi_memory_map[0].num_pages = gd->relocaddr >> 12;
>>>
>>> U-Boot question: is gd->relocaddr always the offset from start of RAM?
>>> How does this work with gaps in memory map?
>>
>> U-Boot always relocates itself at TOM (or at least what we consider TOM
>> here). gd->relocaddr is the physical address of the start of U-Boot
>> which is right below TOM.
> 
> Still ... would need additional handling if memory has holes (like,
> fitted with multiple DIMMs smaller than the individual memory window
> reserved for them). Or even on something like Juno, which has 2GB of
> RAM at 0x00_8000_0000, and a further 6GB at 0x08_8000_0000 (I think).

Yes. I think we'll have to just implement that when we hit the first
board that does this (and has awareness in U-Boot for it).

With the UEFI entry path, Linux will ignore memory nodes in dt, right?

> 
>>>> +#ifdef CONFIG_SYS_SDRAM_BASE
>>>> +	efi_memory_map[0].physical_start = CONFIG_SYS_SDRAM_BASE;
>>>> +	efi_memory_map[0].virtual_start = CONFIG_SYS_SDRAM_BASE;
>>>> +	efi_memory_map[0].num_pages -= CONFIG_SYS_SDRAM_BASE >> 12;
>>> #else
>>> #error "..."
>>> ?
>>
>> If it's not defined, it's 0 :).
> 
> Make it
> #if CONFIG_SYS_SDRAM_BASE != 0
> for clarity?

I really don't think we'll make it more readable with more #iffery here :).


Alex

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

* [U-Boot] [PATCH 6/9] efi_loader: Add runtime services
  2016-01-15 13:52       ` Leif Lindholm
@ 2016-01-15 14:15         ` Alexander Graf
  2016-01-15 14:22           ` Leif Lindholm
  0 siblings, 1 reply; 70+ messages in thread
From: Alexander Graf @ 2016-01-15 14:15 UTC (permalink / raw)
  To: u-boot



On 15.01.16 14:52, Leif Lindholm wrote:
> On Fri, Jan 15, 2016 at 01:26:42AM +0100, Alexander Graf wrote:
>> On 26.12.15 19:33, Leif Lindholm wrote:
>>>> +	.reset_system = (void *)&efi_unimplemented,
>>>
>>> "The ResetSystem() function does not return."
>>
>> Hrm, I think returning EFI_UNSUPPORTED is still better than while(1) {
>> }. With the return an OS at least has the chance to fix things up itself.
> 
> I'm not saying it isn't better, I'm saying it's not compliant - there
> is no valid return value. I would prefer simply having the pointer set
> to NULL.

Is a NULL function pointer valid here?


Alex

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

* [U-Boot] [PATCH 4/9] efi_loader: Add boot time services
  2016-01-15 14:14         ` Alexander Graf
@ 2016-01-15 14:21           ` Leif Lindholm
  2016-01-15 17:04             ` Alexander Graf
  0 siblings, 1 reply; 70+ messages in thread
From: Leif Lindholm @ 2016-01-15 14:21 UTC (permalink / raw)
  To: u-boot

On Fri, Jan 15, 2016 at 03:14:54PM +0100, Alexander Graf wrote:
> On 15.01.16 14:02, Leif Lindholm wrote:
> >>> U-Boot question: is gd->relocaddr always the offset from start of RAM?
> >>> How does this work with gaps in memory map?
> >>
> >> U-Boot always relocates itself at TOM (or at least what we consider TOM
> >> here). gd->relocaddr is the physical address of the start of U-Boot
> >> which is right below TOM.
> > 
> > Still ... would need additional handling if memory has holes (like,
> > fitted with multiple DIMMs smaller than the individual memory window
> > reserved for them). Or even on something like Juno, which has 2GB of
> > RAM at 0x00_8000_0000, and a further 6GB at 0x08_8000_0000 (I think).
> 
> Yes. I think we'll have to just implement that when we hit the first
> board that does this (and has awareness in U-Boot for it).

Yeah, sure.

> With the UEFI entry path, Linux will ignore memory nodes in dt, right?

Yep.

> >>>> +#ifdef CONFIG_SYS_SDRAM_BASE
> >>>> +	efi_memory_map[0].physical_start = CONFIG_SYS_SDRAM_BASE;
> >>>> +	efi_memory_map[0].virtual_start = CONFIG_SYS_SDRAM_BASE;
> >>>> +	efi_memory_map[0].num_pages -= CONFIG_SYS_SDRAM_BASE >> 12;
> >>> #else
> >>> #error "..."
> >>> ?
> >>
> >> If it's not defined, it's 0 :).
> > 
> > Make it
> > #if CONFIG_SYS_SDRAM_BASE != 0
> > for clarity?
> 
> I really don't think we'll make it more readable with more #iffery here :).

It isn't really the kind of thing I'm here to review, but ...
Current version requires knowledge of state of certain macros, the
alternative is explicit without familiarity with the codebase.

/
    Leif

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

* [U-Boot] [PATCH 6/9] efi_loader: Add runtime services
  2016-01-15 14:15         ` Alexander Graf
@ 2016-01-15 14:22           ` Leif Lindholm
  0 siblings, 0 replies; 70+ messages in thread
From: Leif Lindholm @ 2016-01-15 14:22 UTC (permalink / raw)
  To: u-boot

On Fri, Jan 15, 2016 at 03:15:37PM +0100, Alexander Graf wrote:
> On 15.01.16 14:52, Leif Lindholm wrote:
> >>> "The ResetSystem() function does not return."
> >>
> >> Hrm, I think returning EFI_UNSUPPORTED is still better than while(1) {
> >> }. With the return an OS at least has the chance to fix things up itself.
> > 
> > I'm not saying it isn't better, I'm saying it's not compliant - there
> > is no valid return value. I would prefer simply having the pointer set
> > to NULL.
> 
> Is a NULL function pointer valid here?

More than returning is.

/
    Leif

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

* [U-Boot] [PATCH 4/9] efi_loader: Add boot time services
  2016-01-15 14:21           ` Leif Lindholm
@ 2016-01-15 17:04             ` Alexander Graf
  0 siblings, 0 replies; 70+ messages in thread
From: Alexander Graf @ 2016-01-15 17:04 UTC (permalink / raw)
  To: u-boot



On 15.01.16 15:21, Leif Lindholm wrote:
> On Fri, Jan 15, 2016 at 03:14:54PM +0100, Alexander Graf wrote:
>> On 15.01.16 14:02, Leif Lindholm wrote:
>>>>> U-Boot question: is gd->relocaddr always the offset from start of RAM?
>>>>> How does this work with gaps in memory map?
>>>>
>>>> U-Boot always relocates itself at TOM (or at least what we consider TOM
>>>> here). gd->relocaddr is the physical address of the start of U-Boot
>>>> which is right below TOM.
>>>
>>> Still ... would need additional handling if memory has holes (like,
>>> fitted with multiple DIMMs smaller than the individual memory window
>>> reserved for them). Or even on something like Juno, which has 2GB of
>>> RAM at 0x00_8000_0000, and a further 6GB at 0x08_8000_0000 (I think).
>>
>> Yes. I think we'll have to just implement that when we hit the first
>> board that does this (and has awareness in U-Boot for it).
> 
> Yeah, sure.
> 
>> With the UEFI entry path, Linux will ignore memory nodes in dt, right?
> 
> Yep.
> 
>>>>>> +#ifdef CONFIG_SYS_SDRAM_BASE
>>>>>> +	efi_memory_map[0].physical_start = CONFIG_SYS_SDRAM_BASE;
>>>>>> +	efi_memory_map[0].virtual_start = CONFIG_SYS_SDRAM_BASE;
>>>>>> +	efi_memory_map[0].num_pages -= CONFIG_SYS_SDRAM_BASE >> 12;
>>>>> #else
>>>>> #error "..."
>>>>> ?
>>>>
>>>> If it's not defined, it's 0 :).
>>>
>>> Make it
>>> #if CONFIG_SYS_SDRAM_BASE != 0
>>> for clarity?
>>
>> I really don't think we'll make it more readable with more #iffery here :).
> 
> It isn't really the kind of thing I'm here to review, but ...
> Current version requires knowledge of state of certain macros, the
> alternative is explicit without familiarity with the codebase.

Hrm. So how about a comment like this:

 /* RAM starts at an offset above 0 */

right before the #ifdef?


Alex

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

end of thread, other threads:[~2016-01-15 17:04 UTC | newest]

Thread overview: 70+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-12-22 13:57 [U-Boot] [PATCH 0/9] EFI payload / application support Alexander Graf
2015-12-22 13:57 ` [U-Boot] [PATCH 1/9] disk/part.c: Expose a list of available block drivers Alexander Graf
2016-01-14 19:18   ` Tom Rini
2016-01-14 23:11   ` Simon Glass
2016-01-14 23:33     ` Alexander Graf
2016-01-15  0:46       ` Simon Glass
2016-01-15  1:04         ` Alexander Graf
2015-12-22 13:57 ` [U-Boot] [PATCH 2/9] include/efi_api.h: Add more detailed API definitions Alexander Graf
2015-12-22 13:57 ` [U-Boot] [PATCH 3/9] efi_loader: Add PE image loader Alexander Graf
2015-12-26 16:26   ` Leif Lindholm
2016-01-14 23:45     ` Alexander Graf
2016-01-15 12:29       ` Leif Lindholm
2015-12-22 13:57 ` [U-Boot] [PATCH 4/9] efi_loader: Add boot time services Alexander Graf
2015-12-22 14:15   ` Andreas Färber
2015-12-22 14:31     ` Alexander Graf
2015-12-26 18:09   ` Leif Lindholm
2016-01-15  0:13     ` Alexander Graf
2016-01-15 13:02       ` Leif Lindholm
2016-01-15 14:14         ` Alexander Graf
2016-01-15 14:21           ` Leif Lindholm
2016-01-15 17:04             ` Alexander Graf
2016-01-15  3:40     ` Alexander Graf
2015-12-22 13:57 ` [U-Boot] [PATCH 5/9] efi_loader: Add console interface Alexander Graf
2015-12-22 13:57 ` [U-Boot] [PATCH 6/9] efi_loader: Add runtime services Alexander Graf
2015-12-26 18:33   ` Leif Lindholm
2016-01-15  0:26     ` Alexander Graf
2016-01-15 13:52       ` Leif Lindholm
2016-01-15 14:15         ` Alexander Graf
2016-01-15 14:22           ` Leif Lindholm
2015-12-22 13:57 ` [U-Boot] [PATCH 7/9] efi_loader: Add disk interfaces Alexander Graf
2016-01-15  1:37   ` Simon Glass
2016-01-15  2:40     ` Alexander Graf
2015-12-22 13:57 ` [U-Boot] [PATCH 8/9] efi_loader: Add "bootefi" command Alexander Graf
2015-12-24 11:15   ` Matwey V. Kornilov
2015-12-25  9:02     ` Alexander Graf
2015-12-25  9:25       ` Andreas Färber
2015-12-25  9:40         ` Matwey V. Kornilov
2015-12-25 17:04           ` Tom Rini
2015-12-26 18:55         ` Leif Lindholm
2015-12-27 15:33           ` Alexander Graf
2015-12-26 18:45       ` Leif Lindholm
2015-12-25 16:58     ` Tom Rini
2015-12-22 13:57 ` [U-Boot] [PATCH 9/9] efi_loader: hook up in build environment Alexander Graf
2015-12-22 18:28 ` [U-Boot] [PATCH 0/9] EFI payload / application support Matwey V. Kornilov
2015-12-22 20:32   ` Alexander Graf
2015-12-25  3:29 ` Tom Rini
2015-12-25  8:53   ` Alexander Graf
2015-12-25 16:50     ` Tom Rini
2015-12-25 16:53       ` Matwey V. Kornilov
2015-12-25 17:00         ` Tom Rini
2016-01-15  3:00       ` Alexander Graf
2016-01-15  3:06         ` Tom Rini
2015-12-25 19:34 ` Blibbet
2015-12-26 15:31 ` Leif Lindholm
2015-12-26 16:27   ` Alexander Graf
2015-12-26 19:34     ` Leif Lindholm
2016-01-04 16:25       ` Alexander Graf
2016-01-04 16:56         ` Tom Rini
2016-01-04 18:03           ` Andreas Färber
2016-01-04 18:41             ` Andreas Färber
2016-01-04 19:54               ` Tom Rini
2016-01-04 22:37                 ` Dennis Gilmore
2016-01-04 22:48                   ` Alexander Graf
2016-01-15  3:40             ` Peter Robinson
2016-01-04 20:11           ` Matwey V. Kornilov
2016-01-15  3:32           ` Peter Robinson
2015-12-27 18:10   ` Tom Rini
2015-12-27 18:39     ` Leif Lindholm
2015-12-27 19:48       ` Tom Rini
2016-01-05 20:18       ` Tom Rini

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.