EFI payload / application support
Subsystems (2)
cover EFI payload / application support
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
Signature · 1 line
2.1.4
PATCH 1/9 disk/part.c: Expose a list of available block drivers
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.
--- disk/part.c | 25 +++++++++++++++++++++++++ include/part.h | 2 ++ 2 files changed, 27 insertions(+)
disk/part.c +25 -0
@@ -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, },
include/part.h +2 -0
@@ -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 ; }
Signature · 1 line
2.1.4
PATCH 1/9 disk/part.c: Expose a list of available block drivers
Quoted 8 lines · Alexander Graf
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 <[email protected]>
Signature · 8 lines
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>
PATCH 1/9 disk/part.c: Expose a list of available block drivers
In reply to Alexander GrafHi Alexander,
Quoted 35 lines · Alexander Graf
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 <[email protected]>--- disk/part.c | 25 +++++++++++++++++++++++++ include/part.h | 2 ++ 2 files changed, 27 insertions(+)disk/part.c +14
-0@@ -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 )
disk/part.c struct block_drvr { · line 52
Quoted 10 lines
disk/part.c +10
-0+ "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?
Quoted 18 lines
disk/part.c +1
-0+static const struct block_drvr block_drvr[] = { #if defined(CONFIG_CMD_IDE) { .name = "ide", .get_dev = ide_get_dev, },include/part.h +2
-1@@ -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 ; } --
Quoted 1 line
2.1.4
Regards,
Simon
PATCH 1/9 disk/part.c: Expose a list of available block drivers
Quoted 42 lines · Simon Glass
Hi Alexander,
Quoted 39 lines · Alexander Graf
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 <[email protected]>--- disk/part.c | 25 +++++++++++++++++++++++++ include/part.h | 2 ++ 2 files changed, 27 insertions(+)disk/part.c +18
-0@@ -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",
Quoted 8 lines
disk/part.c struct block_drvr { · line 52
Quoted 6 lines
disk/part.c +6
-0+#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
Quoted 23 lines
Quoted 19 lines
disk/part.c +1
-0+static const struct block_drvr block_drvr[] = { #if defined(CONFIG_CMD_IDE) { .name = "ide", .get_dev = ide_get_dev, },include/part.h +2
-1@@ -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 ; } --Quoted 1 line
2.1.4
Regards,
Simon
PATCH 1/9 disk/part.c: Expose a list of available block drivers
Hi Alex,
Quoted 54 lines · Alexander Graf
Quoted 42 lines · Simon Glass
Hi Alexander,
Quoted 39 lines · Alexander Graf
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 <[email protected]>--- disk/part.c | 25 +++++++++++++++++++++++++ include/part.h | 2 ++ 2 files changed, 27 insertions(+)disk/part.c +18
-0@@ -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",Quoted 8 lines
disk/part.c struct block_drvr { · line 52
Quoted 6 lines
disk/part.c +6
-0+#endif +#if defined(CONFIG_SANDBOX ) +"host" , +#endif + NULL, +};You seem to be duplicating block_drvr[]. Can we not just use that?
Quoted 5 lines
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!
Quoted 27 lines
Alex
Quoted 23 lines
Quoted 19 lines
disk/part.c +1
-0+static const struct block_drvr block_drvr[] = { #if defined(CONFIG_CMD_IDE) { .name = "ide", .get_dev = ide_get_dev, },include/part.h +2
-1@@ -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 ; } --Quoted 1 line
2.1.4
Regards,
Simon
Regards,
Simon
PATCH 1/9 disk/part.c: Expose a list of available block drivers
Quoted 60 lines · Simon Glass
Hi Alex,
Quoted 57 lines · Alexander Graf
Quoted 42 lines · Simon Glass
Hi Alexander,
Quoted 39 lines · Alexander Graf
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 <[email protected]>--- disk/part.c | 25 +++++++++++++++++++++++++ include/part.h | 2 ++ 2 files changed, 27 insertions(+)disk/part.c +18
-0@@ -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",Quoted 8 lines
disk/part.c struct block_drvr { · line 52
Quoted 6 lines
disk/part.c +6
-0+#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.
Quoted 7 lines
Quoted 2 lines
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? :)
Quoted 5 lines
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
PATCH 2/9 include/efi_api.h: Add more detailed API definitions
In reply to Alexander GrafThe 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.
--- include/efi_api.h | 197 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 160 insertions(+), 37 deletions(-)
include/efi_api.h +160 -37
@@ -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
Signature · 1 line
2.1.4
PATCH 3/9 efi_loader: Add PE image loader
In reply to Alexander GrafEFI 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.
--- 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
include/efi_loader.h new file +37 -0
@@ -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);
include/pe.h new file +277 -0
277 lines not on this page · raw message
lib/efi_loader/efi_image_loader.c new file +203 -0
203 lines not on this page · raw message
Signature · 1 line
2.1.4
PATCH 3/9 efi_loader: Add PE image loader
Quoted 387 lines · Alexander Graf
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 <[email protected]>--- 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.cinclude/efi_loader.h new file +37
-0@@ -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);include/pe.h new file +277
-0@@ -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 */ lib/efi_loader/efi_image_loader.c new file +42
-0@@ -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;
lib/efi_loader/efi_image_loader.c line 52
Quoted 10 lines
lib/efi_loader/efi_image_loader.c new file +10
-0+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.
lib/efi_loader/efi_image_loader.c line 53
Quoted 1 line
lib/efi_loader/efi_image_loader.c new file +1
-0+* 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.
Quoted 58 lines
lib/efi_loader/efi_image_loader.c new file +58
-0+*/ +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;
lib/efi_loader/efi_image_loader.c line 121
Quoted 10 lines
lib/efi_loader/efi_image_loader.c new file +10
-0+ sections = (void *)&nt->OptionalHeader + + nt->FileHeader.SizeOfOptionalHeader; + +for (i = num_sections -1 ; i >=0 ; i--) { +IMAGE_SECTION_HEADER *sec = §ions[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)
Quoted 4 lines
lib/efi_loader/efi_image_loader.c new file +4
-0+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;
lib/efi_loader/efi_image_loader.c line 135
Quoted 10 lines
lib/efi_loader/efi_image_loader.c new file +10
-0+ 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?
Quoted 71 lines
lib/efi_loader/efi_image_loader.c new file +68
-0+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 = §ions[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; +}Signature · 1 line
2.1.4
PATCH 3/9 efi_loader: Add PE image loader
Quoted 394 lines · Leif Lindholm
Quoted 393 lines · Alexander Graf
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 <[email protected]>--- 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.cinclude/efi_loader.h new file +37
-0@@ -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);include/pe.h new file +277
-0@@ -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 */ lib/efi_loader/efi_image_loader.c new file +48
-0@@ -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
Quoted 8 lines
lib/efi_loader/efi_image_loader.c line 52
Quoted 4 lines
lib/efi_loader/efi_image_loader.c new file +4
-0+* 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 :).
Quoted 3 lines
Assigning a specific 128MB pool for
LOADER_DATAmemory can have unexpected side effects.
Like for example?
Quoted 5 lines
lib/efi_loader/efi_image_loader.c line 53
Quoted 2 lines
lib/efi_loader/efi_image_loader.c new file +1
-0+* Then every allocation gets a 4k aligned chunk from it. We never free. Never freeing
LOADER_DATAshould not be an issue in and of itself. It all gets zapped by the OS anyway.
That's the idea, yes :).
Quoted 65 lines
Quoted 65 lines
lib/efi_loader/efi_image_loader.c new file +64
-0+*/ +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 = §ions[i]; + virt_size = max_t(unsigned long, virt_size,
Quoted 8 lines
lib/efi_loader/efi_image_loader.c line 121
Quoted 4 lines
lib/efi_loader/efi_image_loader.c new file +4
-0+ 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.
Quoted 17 lines
Quoted 5 lines
lib/efi_loader/efi_image_loader.c new file +4
-0+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;lib/efi_loader/efi_image_loader.c line 135
Quoted 10 lines
lib/efi_loader/efi_image_loader.c new file +10
-0+ 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
PATCH 3/9 efi_loader: Add PE image loader
Quoted 63 lines · Alexander Graf
Quoted 53 lines · Leif Lindholm
Quoted 53 lines
new file mode 100644
index 0000000..688e177lib/efi_loader/efi_image_loader.c new file +48
-0@@ -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 Quoted 8 lines
lib/efi_loader/efi_image_loader.c line 52
Quoted 4 lines
lib/efi_loader/efi_image_loader.c new file +4
-0+* 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?
Quoted 2 lines
Uh, sure, I can try. I'm not sure it'll end up more readable than now though :).
Heh, ok. It was a theory.
Quoted 4 lines
Quoted 2 lines
Assigning a specific 128MB pool for
LOADER_DATAmemory 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
PATCH 4/9 efi_loader: Add boot time services
In reply to Alexander GrafWhen 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.
--- 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
include/efi_loader.h +41 -0
@@ -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);
lib/efi_loader/efi_boottime.c new file +838 -0
838 lines not on this page · raw message
Signature · 1 line
2.1.4
PATCH 4/9 efi_loader: Add boot time services
Am 22.12.2015 um 14:57 schrieb Alexander Graf:
Quoted 5 lines
lib/efi_loader/efi_boottime.c new file +0
-0
[...]
Quoted 3 lines
+/*
+ * 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"?
Quoted 4 lines
+ * 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
Signature · 2 lines
SUSE Linux GmbH, Maxfeldstr. 5, 90409 N?rnberg, Germany GF: Felix Imend?rffer, Jane Smithard, Graham Norton; HRB 21284 (AG N?rnberg)
PATCH 4/9 efi_loader: Add boot time services
Quoted 7 lines · Andreas F?rber
Am 22.12.2015 um 14:57 schrieb Alexander Graf:
Quoted 5 lines
lib/efi_loader/efi_boottime.c new file +0
-0[...]
Quoted 5 lines
Quoted 3 lines
+/*
+ * 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
PATCH 4/9 efi_loader: Add boot time services
In reply to Alexander GrafQuoted 7 lines · Alexander Graf
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...
Quoted 148 lines
Signed-off-by Alexander Graf <[email protected]>--- 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.cinclude/efi_loader.h +41
-0@@ -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);lib/efi_loader/efi_boottime.c new file +75
-0@@ -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) +{
lib/efi_loader/efi_boottime.c line 85
Quoted 10 lines
lib/efi_loader/efi_boottime.c new file +10
-0+ 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.
lib/efi_loader/efi_boottime.c line 91
Quoted 6 lines
lib/efi_loader/efi_boottime.c new file +6
-0+} + +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()."
lib/efi_loader/efi_boottime.c line 97
Quoted 6 lines
lib/efi_loader/efi_boottime.c new file +6
-0+} + +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)
Quoted 22 lines
lib/efi_loader/efi_boottime.c new file +22
-0+} + +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 :
lib/efi_loader/efi_boottime.c line 129
Quoted 10 lines
lib/efi_loader/efi_boottime.c new file +10
-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?
lib/efi_loader/efi_boottime.c line 132
Quoted 3 lines
lib/efi_loader/efi_boottime.c new file +3
-0+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.
lib/efi_loader/efi_boottime.c line 134
Quoted 2 lines
lib/efi_loader/efi_boottime.c new file +2
-0+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.
lib/efi_loader/efi_boottime.c line 135
Quoted 1 line
lib/efi_loader/efi_boottime.c new file +1
-0+ r =EFI_UNSUPPORTED ;
Actually, not a valid return value.EFI_INVALID_PARAMETER
Quoted 63 lines
lib/efi_loader/efi_boottime.c new file +63
-0+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; +
lib/efi_loader/efi_boottime.c line 208
Quoted 10 lines
lib/efi_loader/efi_boottime.c new file +10
-0+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?
lib/efi_loader/efi_boottime.c line 212
Quoted 4 lines
lib/efi_loader/efi_boottime.c new file +4
-0+#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 "..."
?
Quoted 70 lines
lib/efi_loader/efi_boottime.c new file +70
-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; +
lib/efi_loader/efi_boottime.c line 292
Quoted 10 lines
lib/efi_loader/efi_boottime.c new file +10
-0+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.
Quoted 24 lines
lib/efi_loader/efi_boottime.c new file +24
-0+ } + + 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);
lib/efi_loader/efi_boottime.c line 326
Quoted 10 lines
lib/efi_loader/efi_boottime.c new file +10
-0+ } + +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?
lib/efi_loader/efi_boottime.c line 331
Quoted 5 lines
lib/efi_loader/efi_boottime.c new file +5
-0+ +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.
Quoted 341 lines
lib/efi_loader/efi_boottime.c new file +341
-0+ } + +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[] = {
lib/efi_loader/efi_boottime.c line 682
Quoted 10 lines
lib/efi_loader/efi_boottime.c new file +10
-0+ { + .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
Quoted 43 lines
lib/efi_loader/efi_boottime.c new file +43
-0+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);
lib/efi_loader/efi_boottime.c line 735
Quoted 10 lines
lib/efi_loader/efi_boottime.c new file +10
-0+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.)
Quoted 78 lines
lib/efi_loader/efi_boottime.c new file +78
-0+ +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,
lib/efi_loader/efi_boottime.c line 823
Quoted 10 lines
lib/efi_loader/efi_boottime.c new file +10
-0+ .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', ' ', ... :)
lib/efi_loader/efi_boottime.c line 827
Quoted 4 lines
lib/efi_loader/efi_boottime.c new file +4
-0+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.
Quoted 13 lines
lib/efi_loader/efi_boottime.c new file +11
-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, +};Signature · 1 line
2.1.4
PATCH 4/9 efi_loader: Add boot time services
Quoted 177 lines · Leif Lindholm
Quoted 7 lines · Alexander Graf
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_UNSUPPORTEDas 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...Quoted 148 lines
Signed-off-by Alexander Graf <[email protected]>--- 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.cinclude/efi_loader.h +41
-0@@ -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);lib/efi_loader/efi_boottime.c new file +75
-0@@ -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) +{lib/efi_loader/efi_boottime.c line 85
Quoted 10 lines
lib/efi_loader/efi_boottime.c new file +10
-0+ 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.
Quoted 11 lines
lib/efi_loader/efi_boottime.c line 91
Quoted 6 lines
lib/efi_loader/efi_boottime.c new file +6
-0+} + +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 toRestoreTPL()."
Since we don't do TPLs (or IRQs for that matter), I'll just return 0 here.
Quoted 9 lines
lib/efi_loader/efi_boottime.c line 97
Quoted 7 lines
lib/efi_loader/efi_boottime.c new file +6
-0+} + +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 :).
Quoted 36 lines
Quoted 23 lines
lib/efi_loader/efi_boottime.c new file +22
-0+} + +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 :lib/efi_loader/efi_boottime.c line 129
Quoted 10 lines
lib/efi_loader/efi_boottime.c new file +10
-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?
Quoted 7 lines
lib/efi_loader/efi_boottime.c line 132
Quoted 3 lines
lib/efi_loader/efi_boottime.c new file +3
-0+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.
Quoted 4 lines
The key is that
EFI_LOADER_MEMORYwill 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?
Quoted 81 lines
lib/efi_loader/efi_boottime.c line 134
Quoted 3 lines
lib/efi_loader/efi_boottime.c new file +2
-0+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.
lib/efi_loader/efi_boottime.c line 135
Quoted 1 line
lib/efi_loader/efi_boottime.c new file +1
-0+ r =EFI_UNSUPPORTED ;Actually, not a valid return value.
EFI_INVALID_PARAMETERQuoted 68 lines
lib/efi_loader/efi_boottime.c new file +68
-0+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 ;
Quoted 8 lines
lib/efi_loader/efi_boottime.c line 208
Quoted 5 lines
lib/efi_loader/efi_boottime.c new file +5
-0+ 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->relocaddralways 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.
Quoted 8 lines
lib/efi_loader/efi_boottime.c line 212
Quoted 5 lines
lib/efi_loader/efi_boottime.c new file +4
-0+#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 :).
Quoted 74 lines
Quoted 74 lines
lib/efi_loader/efi_boottime.c new file +74
-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)
Quoted 8 lines
lib/efi_loader/efi_boottime.c line 292
Quoted 6 lines
lib/efi_loader/efi_boottime.c new file +6
-0+{ +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_RESOURCESwould be a better return value here.
Yup.
Quoted 29 lines
Quoted 29 lines
lib/efi_loader/efi_boottime.c new file +28
-0+ } + + 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 (); +}
Quoted 8 lines
lib/efi_loader/efi_boottime.c line 326
Quoted 6 lines
lib/efi_loader/efi_boottime.c new file +6
-0+ +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
Quoted 11 lines
lib/efi_loader/efi_boottime.c line 331
Quoted 6 lines
lib/efi_loader/efi_boottime.c new file +5
-0+ +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 intoefi_event). If we're called with another event handle,EFI_INVALID_PARAMETERis the appropriate error code.
Sounds reasonable.
Quoted 19 lines
Quoted 19 lines
lib/efi_loader/efi_boottime.c new file +18
-0+ } + +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 ); +}
[...]
Quoted 46 lines
Quoted 46 lines
lib/efi_loader/efi_boottime.c new file +46
-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,
Quoted 8 lines
lib/efi_loader/efi_boottime.c line 823
Quoted 5 lines
lib/efi_loader/efi_boottime.c new file +5
-0+ .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!
Quoted 8 lines
lib/efi_loader/efi_boottime.c line 827
Quoted 5 lines
lib/efi_loader/efi_boottime.c new file +4
-0+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
PATCH 4/9 efi_loader: Add boot time services
Quoted 10 lines · Alexander Graf
Quoted 9 lines · Leif Lindholm
Quoted 9 lines
lib/efi_loader/efi_boottime.c new file +3
-0@@ -0,0 +1,838 @@ +/* +* EFI application boot time services +*
...
Quoted 11 lines
Quoted 10 lines
lib/efi_loader/efi_boottime.c line 91
Quoted 5 lines
lib/efi_loader/efi_boottime.c new file +5
-0+ +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 toRestoreTPL()."
Quoted 1 line
Since we don't do TPLs (or IRQs for that matter), I'll just return 0 here.
Sure.
Quoted 11 lines
Quoted 8 lines
lib/efi_loader/efi_boottime.c line 97
Quoted 6 lines
lib/efi_loader/efi_boottime.c new file +6
-0+} + +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_EXITdeals with the gd swapping andefi_unsupported()gives me a nice debug message :).
Ah, ok.
Quoted 31 lines
Quoted 23 lines
Quoted 10 lines
lib/efi_loader/efi_boottime.c new file +10
-0+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 :lib/efi_loader/efi_boottime.c line 129
Quoted 10 lines
lib/efi_loader/efi_boottime.c new file +10
-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?
Quoted 7 lines
lib/efi_loader/efi_boottime.c line 132
Quoted 3 lines
lib/efi_loader/efi_boottime.c new file +3
-0+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.
Quoted 8 lines
Yes.
Quoted 4 lines
The key is that
EFI_LOADER_MEMORYwill 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_DATAsection might bite us?
Yeah, I think so.
Quoted 11 lines
Quoted 10 lines
lib/efi_loader/efi_boottime.c line 208
Quoted 7 lines
lib/efi_loader/efi_boottime.c new file +7
-0+ 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->relocaddralways the offset from start of RAM? How does this work with gaps in memory map?
Quoted 3 lines
U-Boot always relocates itself at TOM (or at least what we consider TOM here).
gd->relocaddris 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).
Quoted 9 lines
Quoted 7 lines
lib/efi_loader/efi_boottime.c line 212
Quoted 4 lines
lib/efi_loader/efi_boottime.c new file +4
-0+#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
PATCH 4/9 efi_loader: Add boot time services
Quoted 94 lines · Leif Lindholm
Quoted 10 lines · Alexander Graf
Quoted 9 lines · Leif Lindholm
Quoted 9 lines
lib/efi_loader/efi_boottime.c new file +3
-0@@ -0,0 +1,838 @@ +/* +* EFI application boot time services +* ...
Quoted 11 lines
Quoted 10 lines
lib/efi_loader/efi_boottime.c line 91
Quoted 5 lines
lib/efi_loader/efi_boottime.c new file +5
-0+ +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 toRestoreTPL()."Quoted 1 line
Since we don't do TPLs (or IRQs for that matter), I'll just return 0 here.
Sure.
Quoted 11 lines
Quoted 8 lines
lib/efi_loader/efi_boottime.c line 97
Quoted 6 lines
lib/efi_loader/efi_boottime.c new file +6
-0+} + +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_EXITdeals with the gd swapping andefi_unsupported()gives me a nice debug message :).Ah, ok.
Quoted 31 lines
Quoted 23 lines
Quoted 10 lines
lib/efi_loader/efi_boottime.c new file +10
-0+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 :lib/efi_loader/efi_boottime.c line 129
Quoted 10 lines
lib/efi_loader/efi_boottime.c new file +10
-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?
Quoted 7 lines
lib/efi_loader/efi_boottime.c line 132
Quoted 3 lines
lib/efi_loader/efi_boottime.c new file +3
-0+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.
Quoted 8 lines
Yes.
Quoted 4 lines
The key is that
EFI_LOADER_MEMORYwill 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_DATAsection might bite us?Yeah, I think so.
Quoted 11 lines
Quoted 10 lines
lib/efi_loader/efi_boottime.c line 208
Quoted 7 lines
lib/efi_loader/efi_boottime.c new file +7
-0+ 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->relocaddralways the offset from start of RAM? How does this work with gaps in memory map?
Quoted 8 lines
Quoted 3 lines
U-Boot always relocates itself at TOM (or at least what we consider TOM here).
gd->relocaddris 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?
Quoted 9 lines
Quoted 9 lines
Quoted 8 lines
lib/efi_loader/efi_boottime.c line 212
Quoted 5 lines
lib/efi_loader/efi_boottime.c new file +4
-0+#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 "..."
?
Quoted 5 lines
Quoted 1 line
If it's not defined, it's 0 :).
Make it
#ifCONFIG_SYS_SDRAM_BASE!= 0
for clarity?
I really don't think we'll make it more readable with more #iffery here :).
Alex
PATCH 4/9 efi_loader: Add boot time services
Quoted 8 lines · Alexander Graf
Quoted 7 lines · Leif Lindholm
Quoted 6 lines
Quoted 2 lines
U-Boot question: is
gd->relocaddralways 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->relocaddris the physical address of the start of U-Boot which is right below TOM.
Quoted 7 lines
Quoted 4 lines
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.
Quoted 1 line
With the UEFI entry path, Linux will ignore memory nodes in dt, right?
Yep.
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 7 lines
lib/efi_loader/efi_boottime.c line 212
Quoted 4 lines
lib/efi_loader/efi_boottime.c new file +4
-0+#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 "..."
?
Quoted 7 lines
Quoted 5 lines
Quoted 1 line
If it's not defined, it's 0 :).
Make it
#ifCONFIG_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
PATCH 4/9 efi_loader: Add boot time services
Quoted 37 lines · Leif Lindholm
Quoted 8 lines · Alexander Graf
Quoted 7 lines · Leif Lindholm
Quoted 6 lines
Quoted 2 lines
U-Boot question: is
gd->relocaddralways 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->relocaddris the physical address of the start of U-Boot which is right below TOM.Quoted 7 lines
Quoted 4 lines
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.
Quoted 1 line
With the UEFI entry path, Linux will ignore memory nodes in dt, right?
Yep.
Quoted 14 lines
Quoted 13 lines
Quoted 9 lines
Quoted 7 lines
lib/efi_loader/efi_boottime.c line 212
Quoted 4 lines
lib/efi_loader/efi_boottime.c new file +4
-0+#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
#ifCONFIG_SYS_SDRAM_BASE!= 0
for clarity?
Quoted 5 lines
Quoted 1 line
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
PATCH 4/9 efi_loader: Add boot time services
In reply to Leif LindholmQuoted 1 line · Leif Lindholm
On Tue, Dec 22, 2015 at 02:57:51PM +0100, Alexander Graf wrote:
[...]
Quoted 8 lines
lib/efi_loader/efi_boottime.c line 132
Quoted 3 lines
lib/efi_loader/efi_boottime.c new file +3
-0+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.
Quoted 4 lines
The key is that
EFI_LOADER_MEMORYwill 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
PATCH 5/9 efi_loader: Add console interface
In reply to Alexander GrafOne 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.
--- 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
include/efi_loader.h +5 -0
@@ -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;
lib/efi_loader/efi_console.c new file +371 -0
371 lines not on this page · raw message
Signature · 1 line
2.1.4
PATCH 6/9 efi_loader: Add runtime services
In reply to Alexander GrafAfter 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.
--- 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
arch/arm/cpu/armv8/u-boot.lds +8 -0
@@ -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)
arch/arm/cpu/u-boot.lds +13 -0
@@ -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)
arch/arm/lib/sections.c +2 -0
@@ -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")));
include/efi_loader.h +3 -0
@@ -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;
lib/efi_loader/efi_runtime.c new file +59 -0
59 lines not on this page · raw message
Signature · 1 line
2.1.4
PATCH 6/9 efi_loader: Add runtime services
Quoted 128 lines · Alexander Graf
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 <[email protected]>--- 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.carch/arm/cpu/armv8/u-boot.lds +8
-0@@ -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)arch/arm/cpu/u-boot.lds +13
-0@@ -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)arch/arm/lib/sections.c +2
-0@@ -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")));include/efi_loader.h +3
-0@@ -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;lib/efi_loader/efi_runtime.c new file +29
-0@@ -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. +*
lib/efi_loader/efi_runtime.c line 39
Quoted 10 lines
lib/efi_loader/efi_runtime.c new file +10
-0+* !!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.
lib/efi_loader/efi_runtime.c line 48
Quoted 9 lines
lib/efi_loader/efi_runtime.c new file +9
-0+} + +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
lib/efi_loader/efi_runtime.c line 49
Quoted 1 line
lib/efi_loader/efi_runtime.c new file +1
-0+ .set_time = (void *)&efi_unimplemented,
EFI_DEVICE_ERROR
lib/efi_loader/efi_runtime.c line 51
Quoted 2 lines
lib/efi_loader/efi_runtime.c new file +2
-0+ .get_wakeup_time = (void *)&efi_unimplemented, + .set_wakeup_time = (void *)&efi_unimplemented,
Both of these are fine, and correct, to return EFI_UNSUPPORTED.
lib/efi_loader/efi_runtime.c line 53
Quoted 2 lines
lib/efi_loader/efi_runtime.c new file +2
-0+ .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.
lib/efi_loader/efi_runtime.c line 54
Quoted 1 line
lib/efi_loader/efi_runtime.c new file +1
-0+ .get_variable = (void *)&efi_unimplemented,
EFI_DEVICE_ERROR would probably be the closest thing to a correct return code in this instance.
lib/efi_loader/efi_runtime.c line 55
Quoted 1 line
lib/efi_loader/efi_runtime.c new file +1
-0+ .get_next_variable = (void *)&efi_unimplemented,
(get_next_variable_name?)
Again, EFI_DEVICE_ERROR, is probably the least wrong return value.
lib/efi_loader/efi_runtime.c line 56
Quoted 1 line
lib/efi_loader/efi_runtime.c new file +1
-0+ .set_variable = (void *)&efi_unimplemented,
EFI_DEVICE_ERROR
lib/efi_loader/efi_runtime.c line 57
Quoted 1 line
lib/efi_loader/efi_runtime.c new file +1
-0+ .get_next_high_mono_count = (void *)&efi_unimplemented,
EFI_DEVICE_ERROR
lib/efi_loader/efi_runtime.c line 58
Quoted 1 line
lib/efi_loader/efi_runtime.c new file +1
-0+ .reset_system = (void *)&efi_unimplemented,
"The ResetSystem() function does not return."
Quoted 3 lines
lib/efi_loader/efi_runtime.c new file +1
-0+};Signature · 1 line
2.1.4
PATCH 6/9 efi_loader: Add runtime services
Quoted 164 lines · Leif Lindholm
Quoted 128 lines · Alexander Graf
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 <[email protected]>--- 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.carch/arm/cpu/armv8/u-boot.lds +8
-0@@ -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)arch/arm/cpu/u-boot.lds +13
-0@@ -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)arch/arm/lib/sections.c +2
-0@@ -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")));include/efi_loader.h +3
-0@@ -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;lib/efi_loader/efi_runtime.c new file +29
-0@@ -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. +* lib/efi_loader/efi_runtime.c line 39
Quoted 10 lines
lib/efi_loader/efi_runtime.c new file +10
-0+* !!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_UNSUPPORTEDis not necessarily a valid return value for all runtime services.lib/efi_loader/efi_runtime.c line 48
Quoted 9 lines
lib/efi_loader/efi_runtime.c new file +9
-0+} + +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_ERRORlib/efi_loader/efi_runtime.c line 49
Quoted 1 line
lib/efi_loader/efi_runtime.c new file +1
-0+ .set_time = (void *)&efi_unimplemented,
EFI_DEVICE_ERRORlib/efi_loader/efi_runtime.c line 51
Quoted 2 lines
lib/efi_loader/efi_runtime.c new file +2
-0+ .get_wakeup_time = (void *)&efi_unimplemented, + .set_wakeup_time = (void *)&efi_unimplemented,Both of these are fine, and correct, to return
EFI_UNSUPPORTED.
Quoted 5 lines
lib/efi_loader/efi_runtime.c line 53
Quoted 2 lines
lib/efi_loader/efi_runtime.c new file +2
-0+ .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 :).
Quoted 9 lines
lib/efi_loader/efi_runtime.c line 54
Quoted 2 lines
lib/efi_loader/efi_runtime.c new file +1
-0+ .get_variable = (void *)&efi_unimplemented,
EFI_DEVICE_ERRORwould probably be the closest thing to a correct return code in this instance.lib/efi_loader/efi_runtime.c line 55
Quoted 1 line
lib/efi_loader/efi_runtime.c new file +1
-0+ .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);
Quoted 10 lines
Again,
EFI_DEVICE_ERROR, is probably the least wrong return value.lib/efi_loader/efi_runtime.c line 56
Quoted 1 line
lib/efi_loader/efi_runtime.c new file +1
-0+ .set_variable = (void *)&efi_unimplemented,
EFI_DEVICE_ERRORlib/efi_loader/efi_runtime.c line 57
Quoted 1 line
lib/efi_loader/efi_runtime.c new file +1
-0+ .get_next_high_mono_count = (void *)&efi_unimplemented,
EFI_DEVICE_ERROR
Ok, fixed all of the above.
Quoted 3 lines
lib/efi_loader/efi_runtime.c line 58
Quoted 1 line
lib/efi_loader/efi_runtime.c new file +1
-0+ .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
PATCH 6/9 efi_loader: Add runtime services
Quoted 7 lines · Alexander Graf
Quoted 3 lines · Leif Lindholm
lib/efi_loader/efi_runtime.c line 58
Quoted 1 line
lib/efi_loader/efi_runtime.c new file +1
-0+ .reset_system = (void *)&efi_unimplemented,"The
ResetSystem()function does not return."Hrm, I think returning
EFI_UNSUPPORTEDis 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
PATCH 6/9 efi_loader: Add runtime services
Quoted 6 lines · Leif Lindholm
Quoted 5 lines · Alexander Graf
Quoted 3 lines · Leif Lindholm
lib/efi_loader/efi_runtime.c line 58
Quoted 1 line
lib/efi_loader/efi_runtime.c new file +1
-0+ .reset_system = (void *)&efi_unimplemented,"The
ResetSystem()function does not return."
Quoted 6 lines
Quoted 2 lines
Hrm, I think returning
EFI_UNSUPPORTEDis 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
PATCH 6/9 efi_loader: Add runtime services
Quoted 11 lines · Alexander Graf
Quoted 8 lines · Leif Lindholm
Quoted 4 lines
Quoted 1 line
"The
ResetSystem()function does not return."Hrm, I think returning
EFI_UNSUPPORTEDis 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
PATCH 7/9 efi_loader: Add disk interfaces
In reply to Alexander GrafA 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.
--- 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
include/efi_loader.h +1 -0
@@ -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,
lib/efi_loader/efi_disk.c new file +227 -0
227 lines not on this page · raw message
Signature · 1 line
2.1.4
PATCH 7/9 efi_loader: Add disk interfaces
Hi Alexander,
Quoted 7 lines · Alexander Graf
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.
Quoted 6 lines
Signed-off-by Alexander Graf <[email protected]>--- 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
Some nits below.
Quoted 29 lines
include/efi_loader.h +1
-0@@ -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,lib/efi_loader/efi_disk.c new file +10
-0@@ -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. +*
lib/efi_loader/efi_disk.c line 20
Quoted 10 lines
lib/efi_loader/efi_disk.c new file +10
-0+* 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?
lib/efi_loader/efi_disk.c line 27
Quoted 7 lines
lib/efi_loader/efi_disk.c new file +7
-0+*/ + +#include <common.h> +#include <efi_loader.h> +#include <part.h> +#include <malloc.h> +#include <inttypes.h>
inttypes.h should go above part.h
lib/efi_loader/efi_disk.c line 31
Quoted 4 lines
lib/efi_loader/efi_disk.c new file +4
-0+ +static const efi_guid_t efi_block_io_guid =BLOCK_IO_GUID ; + +struct efi_disk_obj {
Could use comments on these members
Quoted 129 lines
lib/efi_loader/efi_disk.c new file +129
-0+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(). +*/
lib/efi_loader/efi_disk.c line 170
Quoted 10 lines
lib/efi_loader/efi_disk.c new file +10
-0+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?
lib/efi_loader/efi_disk.c line 181
Quoted 11 lines
lib/efi_loader/efi_disk.c new file +11
-0+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.
Quoted 47 lines
lib/efi_loader/efi_disk.c new file +46
-1+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 ; +} --
Quoted 2 lines
2.1.4
Regards,
Simon
PATCH 7/9 efi_loader: Add disk interfaces
Quoted 213 lines · Simon Glass
Hi Alexander,
Quoted 7 lines · Alexander Graf
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.
Quoted 6 lines
Signed-off-by Alexander Graf <[email protected]>--- 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.cReviewed-by Simon Glass <[email protected]>Some nits below.
Quoted 29 lines
include/efi_loader.h +1
-0@@ -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,lib/efi_loader/efi_disk.c new file +10
-0@@ -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. +* lib/efi_loader/efi_disk.c line 20
Quoted 10 lines
lib/efi_loader/efi_disk.c new file +10
-0+* 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?
lib/efi_loader/efi_disk.c line 27
Quoted 7 lines
lib/efi_loader/efi_disk.c new file +7
-0+*/ + +#include <common.h> +#include <efi_loader.h> +#include <part.h> +#include <malloc.h> +#include <inttypes.h>
inttypes.hshould go abovepart.hlib/efi_loader/efi_disk.c line 31
Quoted 4 lines
lib/efi_loader/efi_disk.c new file +4
-0+ +static const efi_guid_t efi_block_io_guid =BLOCK_IO_GUID ; + +struct efi_disk_obj {Could use comments on these members
Quoted 133 lines
lib/efi_loader/efi_disk.c new file +133
-0+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;
Quoted 8 lines
lib/efi_loader/efi_disk.c line 170
Quoted 6 lines
lib/efi_loader/efi_disk.c new file +6
-0+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
PATCH 8/9 efi_loader: Add "bootefi" command
In reply to Alexander GrafIn 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.
--- common/Makefile | 1 + common/cmd_bootefi.c | 168 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 169 insertions(+) create mode 100644 common/cmd_bootefi.c
common/Makefile +1 -0
@@ -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
common/cmd_bootefi.c new file +168 -0
168 lines not on this page · raw message
Signature · 1 line
2.1.4
PATCH 8/9 efi_loader: Add "bootefi" command
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 <[email protected]>:
Quoted 210 lines
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 $loadaddrwhich 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 <[email protected]>--- common/Makefile | 1 + common/cmd_bootefi.c | 168 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 169 insertions(+) create mode 100644 common/cmd_bootefi.ccommon/Makefile +1
-0@@ -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.ocommon/cmd_bootefi.c new file +168
-1@@ -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
Signature · 4 lines
With best regards, Matwey V. Kornilov http://blog.matwey.name xmpp://0x2207 at jabber.ru
PATCH 8/9 efi_loader: Add "bootefi" command
Quoted 2 lines · Matwey V. Kornilov
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.
Quoted 8 lines
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
PATCH 8/9 efi_loader: Add "bootefi" command
Am 25.12.2015 um 10:02 schrieb Alexander Graf:
[snip]
Quoted 3 lines
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
Signature · 2 lines
SUSE Linux GmbH, Maxfeldstr. 5, 90409 N?rnberg, Germany GF: Felix Imend?rffer, Jane Smithard, Graham Norton; HRB 21284 (AG N?rnberg)
PATCH 8/9 efi_loader: Add "bootefi" command
2015-12-25 12:25 GMT+03:00 Andreas F?rber <[email protected]>:
Quoted 10 lines
Am 25.12.2015 um 10:02 schrieb Alexander Graf:
[snip]Quoted 3 lines
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.
Quoted 11 lines
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
Quoted 6 lines
Cheers,
Andreas--
SUSE Linux GmbH, Maxfeldstr. 5, 90409 N?rnberg, Germany
GF: Felix Imend?rffer, Jane Smithard, Graham Norton; HRB 21284 (AG N?rnberg)
Signature · 4 lines
With best regards, Matwey V. Kornilov http://blog.matwey.name xmpp://0x2207 at jabber.ru
PATCH 8/9 efi_loader: Add "bootefi" command
Quoted 28 lines · Matwey V. Kornilov
2015-12-25 12:25 GMT+03:00 Andreas F?rber <[email protected]>:
Quoted 10 lines
Am 25.12.2015 um 10:02 schrieb Alexander Graf:
[snip]Quoted 3 lines
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.Quoted 11 lines
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.
Quoted 3 lines
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.
Signature · 8 lines
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>
PATCH 8/9 efi_loader: Add "bootefi" command
In reply to Andreas FärberQuoted 11 lines · Andreas F?rber
Am 25.12.2015 um 10:02 schrieb Alexander Graf:
[snip]Quoted 3 lines
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.
Quoted 4 lines
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.
Quoted 4 lines
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
PATCH 8/9 efi_loader: Add "bootefi" command
Quoted 17 lines · Leif Lindholm
Quoted 11 lines · Andreas F?rber
Am 25.12.2015 um 10:02 schrieb Alexander Graf:
[snip]Quoted 3 lines
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.
Quoted 4 lines
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".
Quoted 7 lines
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
PATCH 8/9 efi_loader: Add "bootefi" command
In reply to Alexander GrafQuoted 23 lines · Alexander Graf
Quoted 2 lines · Matwey V. Kornilov
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.
Quoted 7 lines
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.
Quoted 4 lines
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.
Quoted 4 lines
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.
Quoted 18 lines
Quoted 8 lines
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
PATCH 8/9 efi_loader: Add "bootefi" command
In reply to Matwey V. KornilovQuoted 11 lines · Matwey V. Kornilov
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.
Signature · 8 lines
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>
PATCH 9/9 efi_loader: hook up in build environment
In reply to Alexander GrafNow 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.
--- 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
lib/Kconfig +1 -0
@@ -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
lib/Makefile +1 -0
@@ -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/
lib/efi_loader/Kconfig new file +8 -0
@@ -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.
lib/efi_loader/Makefile new file +11 -0
@@ -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
Signature · 1 line
2.1.4
cover EFI payload / application support
In reply to Alexander Graf2015-12-22 16:57 GMT+03:00 Alexander Graf <[email protected]>:
Quoted 2 lines
This is my Christmas present for my openSUSE friends :).
Santa, do you have u-boot rpm packed with the patches to test?
Signature · 4 lines
With best regards, Matwey V. Kornilov http://blog.matwey.name xmpp://0x2207 at jabber.ru
cover EFI payload / application support
Quoted 5 lines · Matwey V. Kornilov
2015-12-22 16:57 GMT+03:00 Alexander Graf <[email protected]>:
Quoted 2 lines
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
cover EFI payload / application support
In reply to Alexander GrafQuoted 13 lines · Alexander Graf
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.
Quoted 6 lines
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?
Signature · 8 lines
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>
cover EFI payload / application support
Quoted 20 lines · Tom Rini
Quoted 18 lines · Alexander Graf
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.
Quoted 5 lines
Quoted 1 line
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
cover EFI payload / application support
Quoted 29 lines · Alexander Graf
Quoted 20 lines · Tom Rini
Quoted 18 lines · Alexander Graf
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.
Quoted 5 lines
Quoted 1 line
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?
Quoted 6 lines
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!
Signature · 8 lines
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>
cover EFI payload / application support
2015-12-25 19:50 GMT+03:00 Tom Rini <[email protected]>:
Quoted 46 lines · Alexander Graf
Quoted 29 lines · Tom Rini
Quoted 20 lines · Alexander Graf
Quoted 19 lines
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.
Quoted 5 lines
Quoted 1 line
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?
Quoted 6 lines
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.his 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).
Quoted 3 lines
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?
Signature · 4 lines
With best regards, Matwey V. Kornilov http://blog.matwey.name xmpp://0x2207 at jabber.ru
cover EFI payload / application support
Quoted 47 lines · Matwey V. Kornilov
2015-12-25 19:50 GMT+03:00 Tom Rini <[email protected]>:
Quoted 46 lines · Alexander Graf
Quoted 29 lines · Tom Rini
Quoted 20 lines · Alexander Graf
Quoted 19 lines
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.
Quoted 5 lines
Quoted 1 line
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?
Quoted 6 lines
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.his 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).
Quoted 6 lines
Quoted 3 lines
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.
Signature · 8 lines
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>
cover EFI payload / application support
In reply to Tom RiniQuoted 46 lines · Tom Rini
Quoted 29 lines · Alexander Graf
Quoted 20 lines · Tom Rini
Quoted 18 lines · Alexander Graf
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.
Quoted 5 lines
Quoted 1 line
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?
Quoted 6 lines
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.his 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).
Quoted 3 lines
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
cover EFI payload / application support
Quoted 49 lines · Alexander Graf
Quoted 46 lines · Tom Rini
Quoted 29 lines · Alexander Graf
Quoted 20 lines · Tom Rini
Quoted 18 lines · Alexander Graf
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.
Quoted 5 lines
Quoted 1 line
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?
Quoted 6 lines
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.his 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).
Quoted 7 lines
Quoted 3 lines
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 :)
Quoted 5 lines
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!
Signature · 8 lines
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>
cover EFI payload / application support
In reply to Alexander GrafQuoted 5 lines · Alexander Graf
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
Quoted 1 line
(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
cover EFI payload / application support
In reply to Alexander GrafQuoted 13 lines · Alexander Graf
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.
Quoted 6 lines
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.
Quoted 6 lines
- 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.
Quoted 1 line
- 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.
Quoted 3 lines
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.
Quoted 3 lines
- 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.
Quoted 1 line
- 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
Quoted 52 lines
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 driversinclude/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 environmentarch/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.cSignature · 1 line
2.1.4
cover EFI payload / application support
Quoted 31 lines · Leif Lindholm
Quoted 13 lines · Alexander Graf
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.
Quoted 6 lines
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.Quoted 6 lines
- 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)
Quoted 2 lines
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?
Quoted 5 lines
Quoted 2 lines
- 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.
Quoted 6 lines
Quoted 4 lines
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.
Quoted 7 lines
Quoted 4 lines
- Improve disk media detection (don't scan, use what information we have)
- Add EFI variable support using NVRAM
- Add GFX supportGFX 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.
Quoted 4 lines
Quoted 2 lines
- Make EFI Shell work ;)
- Network device support.
Oh, good point. I forgot about that one.
Quoted 2 lines
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
cover EFI payload / application support
Quoted 12 lines · Alexander Graf
Quoted 12 lines
Quoted 1 line
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.Quoted 6 lines
- 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)
Quoted 6 lines
Quoted 2 lines
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.
Quoted 6 lines
Quoted 5 lines
Quoted 2 lines
- 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.
Quoted 8 lines
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.
Quoted 2 lines
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.
Quoted 8 lines
Quoted 5 lines
Quoted 3 lines
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.
Quoted 10 lines
Quoted 7 lines
Quoted 4 lines
- Improve disk media detection (don't scan, use what information we have)
- Add EFI variable support using NVRAM
- Add GFX supportGFX 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".
Quoted 5 lines
Quoted 4 lines
Quoted 2 lines
- Make EFI Shell work ;)
- Network device support.
Quoted 8 lines
Oh, good point. I forgot about that one.
Quoted 2 lines
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
cover EFI payload / application support
Quoted 13 lines · Leif Lindholm
Quoted 12 lines · Alexander Graf
Quoted 12 lines
Quoted 1 line
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.Quoted 6 lines
- 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)
Quoted 8 lines
Quoted 6 lines
Quoted 2 lines
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?
Quoted 44 lines
Quoted 7 lines
Quoted 6 lines
Quoted 3 lines
- 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.
Quoted 8 lines
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.Quoted 2 lines
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.Quoted 8 lines
Quoted 5 lines
Quoted 3 lines
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.
Quoted 5 lines
Quoted 5 lines
Quoted 4 lines
- Improve disk media detection (don't scan, use what information we have)
- Add EFI variable support using NVRAM
- Add GFX support
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
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
cover EFI payload / application support
On Mon, Jan 04, 2016 at 05:25:44PM +0100, Alexander Graf wrote:
[snip]
Quoted 4 lines
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 :)
Signature · 8 lines
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>
cover EFI payload / application support
Am 04.01.2016 um 17:56 schrieb Tom Rini:
Quoted 9 lines
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
Signature · 2 lines
SUSE Linux GmbH, Maxfeldstr. 5, 90409 N?rnberg, Germany GF: Felix Imend?rffer, Jane Smithard, Graham Norton; HRB 21284 (AG N?rnberg)
cover EFI payload / application support
Am 04.01.2016 um 19:03 schrieb Andreas F?rber:
Quoted 11 lines
Am 04.01.2016 um 17:56 schrieb Tom Rini:
Quoted 9 lines
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
Signature · 2 lines
SUSE Linux GmbH, Maxfeldstr. 5, 90409 N?rnberg, Germany GF: Felix Imend?rffer, Jane Smithard, Graham Norton; HRB 21284 (AG N?rnberg)
cover EFI payload / application support
Quoted 8 lines · Andreas F?rber
Am 04.01.2016 um 19:03 schrieb Andreas F?rber:
Quoted 7 lines
Am 04.01.2016 um 17:56 schrieb Tom Rini:
Quoted 6 lines
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.
Quoted 7 lines
Quoted 4 lines
Quoted 3 lines
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?
Signature · 8 lines
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>
cover EFI payload / application support
Quoted 9 lines · Tom Rini
Quoted 8 lines · Andreas F?rber
Am 04.01.2016 um 19:03 schrieb Andreas F?rber:
Quoted 7 lines
Am 04.01.2016 um 17:56 schrieb Tom Rini:
Quoted 6 lines
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
Quoted 4 lines
Quoted 4 lines
Quoted 3 lines
Quoted 3 lines
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 :)
Quoted 8 lines
Quoted 3 lines
[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
cover EFI payload / application support
Quoted 38 lines · Dennis Gilmore
Quoted 9 lines · Tom Rini
Quoted 8 lines · Andreas F?rber
Am 04.01.2016 um 19:03 schrieb Andreas F?rber:
Quoted 7 lines
Am 04.01.2016 um 17:56 schrieb Tom Rini:
Quoted 6 lines
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
Quoted 4 lines
Quoted 4 lines
Quoted 3 lines
Quoted 3 lines
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 :)
Quoted 8 lines
Quoted 3 lines
[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.
Quoted 1 line
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.
Quoted 5 lines
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_APIor 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.
Quoted 4 lines
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
cover EFI payload / application support
In reply to Andreas FärberQuoted 17 lines · Andreas F?rber
Am 04.01.2016 um 17:56 schrieb Tom Rini:
Quoted 9 lines
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.
Quoted 6 lines
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.conffile 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.
Quoted 10 lines
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.
Quoted 8 lines
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_APIcode 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.
Quoted 7 lines
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.
cover EFI payload / application support
In reply to Tom Rini2016-01-04 19:56 GMT+03:00 Tom Rini <[email protected]>:
Quoted 10 lines · Alexander Graf
[snip]
Quoted 4 lines
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?
Quoted 10 lines
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
Signature · 4 lines
With best regards, Matwey V. Kornilov http://blog.matwey.name xmpp://0x2207 at jabber.ru
cover EFI payload / application support
In reply to Tom RiniQuoted 10 lines
Quoted 4 lines
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
Quoted 3 lines
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.
cover EFI payload / application support
In reply to Leif LindholmQuoted 56 lines · Leif Lindholm
Quoted 13 lines · Alexander Graf
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.
Quoted 6 lines
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.Quoted 6 lines
- 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.
Quoted 1 line
- 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.
Quoted 3 lines
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.
Quoted 3 lines
- Improve disk media detection (don't scan, use what information we have)
- Add EFI variable support using NVRAM
- Add GFX supportGFX support was actually never implemented for U-Boot GRUB, so from this p.o.v. it is not a shortcoming over the existing impementation.
Quoted 1 line
- Make EFI Shell work ;)
- Network device support.
Quoted 7 lines
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!
Signature · 8 lines
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>
cover EFI payload / application support
Quoted 5 lines · Tom Rini
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
cover EFI payload / application support
Quoted 11 lines · Leif Lindholm
Quoted 5 lines · Tom Rini
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.
Quoted 7 lines
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.pdfI 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!
Signature · 8 lines
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>
cover EFI payload / application support
In reply to Leif LindholmQuoted 15 lines · Leif Lindholm
Quoted 5 lines · Tom Rini
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
Quoted 3 lines
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.
Signature · 8 lines
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>