From 8396e3fd63e8c8e17d60a6d1992ca3df10bc8d66 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 3 Mar 2018 15:41:37 +0100 Subject: efi_loader: remove deprecated ConsoleControlProtocol The console control protocol is not defined in the UEFI standard. It exists in EDK2's EdkCompatiblityPkg package. But this package is deprecated according to https://github.com/tianocore/tianocore.github.io/wiki/Differences-between-EDK-and-EDK-II Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/efi_api.h | 18 ------------------ 1 file changed, 18 deletions(-) (limited to 'include') diff --git a/include/efi_api.h b/include/efi_api.h index 3ba650e57e6..8559656bad9 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -571,24 +571,6 @@ struct efi_simple_input_interface { struct efi_event *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); -}; - #define EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID \ EFI_GUID(0x8b843e20, 0x8132, 0x4852, \ 0x90, 0xcc, 0x55, 0x1a, 0x4e, 0x4a, 0x7f, 0x1c) -- cgit v1.3.1 From e70f8dfa2ce2f47a6eed891016a4c6f289da1cb6 Mon Sep 17 00:00:00 2001 From: Leif Lindholm Date: Fri, 9 Mar 2018 17:43:21 +0100 Subject: efi_loader: Initial EFI_DEVICE_PATH_UTILITIES_PROTOCOL Not complete, but enough for Shell.efi and SCT.efi. We'll implement the rest as needed or once we have SCT running properly so there is a way to validate the interface against the conformance test suite. Initial skeleton written by Leif, and then implementation by Rob. Signed-off-by: Leif Lindholm [Fill initial skeleton] Signed-off-by: Rob Clark [Rebase on v2018.03-rc1] Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/efi_api.h | 29 ++++++++++ include/efi_loader.h | 4 ++ lib/efi_loader/Makefile | 3 +- lib/efi_loader/efi_boottime.c | 6 ++ lib/efi_loader/efi_device_path_utilities.c | 89 ++++++++++++++++++++++++++++++ 5 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 lib/efi_loader/efi_device_path_utilities.c (limited to 'include') diff --git a/include/efi_api.h b/include/efi_api.h index 8559656bad9..827a192620b 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -587,6 +587,35 @@ struct efi_device_path_to_text_protocol bool allow_shortcuts); }; +#define EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID \ + EFI_GUID(0x0379be4e, 0xd706, 0x437d, \ + 0xb0, 0x37, 0xed, 0xb8, 0x2f, 0xb7, 0x72, 0xa4) + +struct efi_device_path_utilities_protocol { + efi_uintn_t (EFIAPI *get_device_path_size)( + const struct efi_device_path *device_path); + struct efi_device_path *(EFIAPI *duplicate_device_path)( + const struct efi_device_path *device_path); + struct efi_device_path *(EFIAPI *append_device_path)( + const struct efi_device_path *src1, + const struct efi_device_path *src2); + struct efi_device_path *(EFIAPI *append_device_node)( + const struct efi_device_path *device_path, + const struct efi_device_path *device_node); + struct efi_device_path *(EFIAPI *append_device_path_instance)( + const struct efi_device_path *device_path, + const struct efi_device_path *device_path_instance); + struct efi_device_path *(EFIAPI *get_next_device_path_instance)( + struct efi_device_path **device_path_instance, + efi_uintn_t *device_path_instance_size); + bool (EFIAPI *is_device_path_multi_instance)( + const struct efi_device_path *device_path); + struct efi_device_path *(EFIAPI *create_device_node)( + uint8_t node_type, + uint8_t node_sub_type, + uint16_t node_length); +}; + #define EFI_GOP_GUID \ EFI_GUID(0x9042a9de, 0x23dc, 0x4a38, \ 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a) diff --git a/include/efi_loader.h b/include/efi_loader.h index 07730c3f394..39d02669524 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -83,6 +83,9 @@ extern struct efi_simple_text_output_protocol efi_con_out; extern struct efi_simple_input_interface efi_con_in; extern struct efi_console_control_protocol efi_console_control; extern const struct efi_device_path_to_text_protocol efi_device_path_to_text; +/* implementation of the EFI_DEVICE_PATH_UTILITIES_PROTOCOL */ +extern const struct efi_device_path_utilities_protocol + efi_device_path_utilities; uint16_t *efi_dp_str(struct efi_device_path *dp); @@ -97,6 +100,7 @@ extern const efi_guid_t efi_guid_loaded_image; extern const efi_guid_t efi_guid_device_path_to_text_protocol; extern const efi_guid_t efi_simple_file_system_protocol_guid; extern const efi_guid_t efi_file_info_guid; +extern const efi_guid_t efi_guid_device_path_utilities_protocol; extern unsigned int __efi_runtime_start, __efi_runtime_stop; extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop; diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 2a87d9ed776..d2ce89713ec 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -17,7 +17,8 @@ endif obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o -obj-y += efi_file.o efi_variable.o efi_bootmgr.o efi_watchdog.o +obj-y += efi_device_path_utilities.o efi_file.o efi_variable.o efi_bootmgr.o +obj-y += efi_watchdog.o obj-$(CONFIG_LCD) += efi_gop.o obj-$(CONFIG_DM_VIDEO) += efi_gop.o obj-$(CONFIG_PARTITIONS) += efi_disk.o diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 71c244ea805..4e133e9b47d 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1426,6 +1426,12 @@ efi_status_t efi_setup_loaded_image( if (ret != EFI_SUCCESS) goto failure; + ret = efi_add_protocol(obj->handle, + &efi_guid_device_path_utilities_protocol, + (void *)&efi_device_path_utilities); + if (ret != EFI_SUCCESS) + goto failure; + return ret; failure: printf("ERROR: Failure to install protocols for loaded image\n"); diff --git a/lib/efi_loader/efi_device_path_utilities.c b/lib/efi_loader/efi_device_path_utilities.c new file mode 100644 index 00000000000..bc97eeee31b --- /dev/null +++ b/lib/efi_loader/efi_device_path_utilities.c @@ -0,0 +1,89 @@ +/* + * EFI device path interface + * + * Copyright (c) 2017 Leif Lindholm + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include + +const efi_guid_t efi_guid_device_path_utilities_protocol = + EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID; + +static efi_uintn_t EFIAPI get_device_path_size( + const struct efi_device_path *device_path) +{ + efi_uintn_t sz = 0; + + EFI_ENTRY("%p", device_path); + /* size includes the END node: */ + if (device_path) + sz = efi_dp_size(device_path) + sizeof(struct efi_device_path); + return EFI_EXIT(sz); +} + +static struct efi_device_path * EFIAPI duplicate_device_path( + const struct efi_device_path *device_path) +{ + EFI_ENTRY("%p", device_path); + return EFI_EXIT(efi_dp_dup(device_path)); +} + +static struct efi_device_path * EFIAPI append_device_path( + const struct efi_device_path *src1, + const struct efi_device_path *src2) +{ + EFI_ENTRY("%p, %p", src1, src2); + return EFI_EXIT(efi_dp_append(src1, src2)); +} + +static struct efi_device_path * EFIAPI append_device_node( + const struct efi_device_path *device_path, + const struct efi_device_path *device_node) +{ + EFI_ENTRY("%p, %p", device_path, device_node); + return EFI_EXIT(efi_dp_append_node(device_path, device_node)); +} + +static struct efi_device_path * EFIAPI append_device_path_instance( + const struct efi_device_path *device_path, + const struct efi_device_path *device_path_instance) +{ + EFI_ENTRY("%p, %p", device_path, device_path_instance); + return EFI_EXIT(NULL); +} + +static struct efi_device_path * EFIAPI get_next_device_path_instance( + struct efi_device_path **device_path_instance, + efi_uintn_t *device_path_instance_size) +{ + EFI_ENTRY("%p, %p", device_path_instance, device_path_instance_size); + return EFI_EXIT(NULL); +} + +static bool EFIAPI is_device_path_multi_instance( + const struct efi_device_path *device_path) +{ + EFI_ENTRY("%p", device_path); + return EFI_EXIT(false); +} + +static struct efi_device_path * EFIAPI create_device_node( + uint8_t node_type, uint8_t node_sub_type, uint16_t node_length) +{ + EFI_ENTRY("%u, %u, %u", node_type, node_sub_type, node_length); + return EFI_EXIT(NULL); +} + +const struct efi_device_path_utilities_protocol efi_device_path_utilities = { + .get_device_path_size = get_device_path_size, + .duplicate_device_path = duplicate_device_path, + .append_device_path = append_device_path, + .append_device_node = append_device_node, + .append_device_path_instance = append_device_path_instance, + .get_next_device_path_instance = get_next_device_path_instance, + .is_device_path_multi_instance = is_device_path_multi_instance, + .create_device_node = create_device_node, +}; -- cgit v1.3.1 From 7657152bddd131e47390c2b2d6f63d58149d79f1 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 3 Mar 2018 15:28:54 +0100 Subject: efi_loader: efi_smbios_register should have a return value Errors may occur inside efi_smbios_register(). - Return a status code. - Remove unused variables. - Use constants where applicable. Suggested-by: Simon Glass Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/efi_loader.h | 2 +- lib/efi_loader/efi_smbios.c | 23 +++++++++++++++-------- 2 files changed, 16 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/include/efi_loader.h b/include/efi_loader.h index 39d02669524..c686cd3b02b 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -189,7 +189,7 @@ int efi_net_register(void); /* Called by bootefi to make the watchdog available */ int efi_watchdog_register(void); /* Called by bootefi to make SMBIOS tables available */ -void efi_smbios_register(void); +efi_status_t efi_smbios_register(void); struct efi_simple_file_system_protocol * efi_fs_from_path(struct efi_device_path *fp); diff --git a/lib/efi_loader/efi_smbios.c b/lib/efi_loader/efi_smbios.c index ac412e7362a..62e96979021 100644 --- a/lib/efi_loader/efi_smbios.c +++ b/lib/efi_loader/efi_smbios.c @@ -13,20 +13,27 @@ static const efi_guid_t smbios_guid = SMBIOS_TABLE_GUID; -void efi_smbios_register(void) +/* + * Install the SMBIOS table as a configuration table. + * + * @return status code + */ +efi_status_t efi_smbios_register(void) { /* Map within the low 32 bits, to allow for 32bit SMBIOS tables */ - uint64_t dmi = 0xffffffff; - /* Reserve 4kb for SMBIOS */ - uint64_t pages = 1; - int memtype = EFI_RUNTIME_SERVICES_DATA; + u64 dmi = U32_MAX; + efi_status_t ret; - if (efi_allocate_pages(1, memtype, pages, &dmi) != EFI_SUCCESS) - return; + /* Reserve 4kiB page for SMBIOS */ + ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, + EFI_RUNTIME_SERVICES_DATA, 1, &dmi); + if (ret != EFI_SUCCESS) + return ret; /* Generate SMBIOS tables */ write_smbios_table(dmi); /* And expose them to our EFI payload */ - efi_install_configuration_table(&smbios_guid, (void*)(uintptr_t)dmi); + return efi_install_configuration_table(&smbios_guid, + (void *)(uintptr_t)dmi); } -- cgit v1.3.1 From 80ea9b09900bc35a21468f5422bd36a345ae7eda Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 3 Mar 2018 15:28:55 +0100 Subject: efi_loader: return efi_status_t from efi_gop_register All initialization routines should return a status code instead of a boolean. Signed-off-by: Heinrich Schuchardt [agraf: Convert warnings to debug() prints] Signed-off-by: Alexander Graf --- include/efi_loader.h | 2 +- lib/efi_loader/efi_gop.c | 34 ++++++++++++++++++++++------------ 2 files changed, 23 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/include/efi_loader.h b/include/efi_loader.h index c686cd3b02b..a28a7a1764d 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -183,7 +183,7 @@ int efi_disk_create_partitions(efi_handle_t parent, struct blk_desc *desc, const char *if_typename, int diskid, const char *pdevname); /* Called by bootefi to make GOP (graphical) interface available */ -int efi_gop_register(void); +efi_status_t efi_gop_register(void); /* Called by bootefi to make the network interface available */ int efi_net_register(void); /* Called by bootefi to make the watchdog available */ diff --git a/lib/efi_loader/efi_gop.c b/lib/efi_loader/efi_gop.c index 3caddd5f844..28818eb781a 100644 --- a/lib/efi_loader/efi_gop.c +++ b/lib/efi_loader/efi_gop.c @@ -125,8 +125,13 @@ efi_status_t EFIAPI gop_blt(struct efi_gop *this, void *buffer, return EFI_EXIT(EFI_SUCCESS); } -/* This gets called from do_bootefi_exec(). */ -int efi_gop_register(void) +/* + * Install graphical output protocol. + * + * If no supported video device exists this is not considered as an + * error. + */ +efi_status_t efi_gop_register(void) { struct efi_gop_obj *gopobj; u32 bpix, col, row; @@ -136,12 +141,15 @@ int efi_gop_register(void) #ifdef CONFIG_DM_VIDEO struct udevice *vdev; + struct video_priv *priv; /* We only support a single video output device for now */ - if (uclass_first_device(UCLASS_VIDEO, &vdev) || !vdev) - return -1; + if (uclass_first_device(UCLASS_VIDEO, &vdev) || !vdev) { + debug("WARNING: No video device\n"); + return EFI_SUCCESS; + } - struct video_priv *priv = dev_get_uclass_priv(vdev); + priv = dev_get_uclass_priv(vdev); bpix = priv->bpix; col = video_get_xsize(vdev); row = video_get_ysize(vdev); @@ -170,13 +178,14 @@ int efi_gop_register(void) break; default: /* So far, we only work in 16 or 32 bit mode */ - return -1; + debug("WARNING: Unsupported video mode\n"); + return EFI_SUCCESS; } gopobj = calloc(1, sizeof(*gopobj)); if (!gopobj) { printf("ERROR: Out of memory\n"); - return 1; + return EFI_OUT_OF_RESOURCES; } /* Hook up to the device list */ @@ -186,8 +195,8 @@ int efi_gop_register(void) ret = efi_add_protocol(gopobj->parent.handle, &efi_gop_guid, &gopobj->ops); if (ret != EFI_SUCCESS) { - printf("ERROR: Out of memory\n"); - return 1; + printf("ERROR: Failure adding gop protocol\n"); + return ret; } gopobj->ops.query_mode = gop_query_mode; gopobj->ops.set_mode = gop_set_mode; @@ -199,10 +208,11 @@ int efi_gop_register(void) gopobj->mode.info_size = sizeof(gopobj->info); #ifdef CONFIG_DM_VIDEO - if (bpix == VIDEO_BPP32) { + if (bpix == VIDEO_BPP32) #else - if (bpix == LCD_COLOR32) { + if (bpix == LCD_COLOR32) #endif + { /* With 32bit color space we can directly expose the fb */ gopobj->mode.fb_base = fb_base; gopobj->mode.fb_size = fb_size; @@ -217,5 +227,5 @@ int efi_gop_register(void) gopobj->bpix = bpix; gopobj->fb = fb; - return 0; + return EFI_SUCCESS; } -- cgit v1.3.1 From 075d425d652038e67136db61ace4606fcec89475 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 3 Mar 2018 15:28:56 +0100 Subject: efi_loader: return efi_status_t from efi_net_register Consistently return status codes form efi_net_register(). Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/efi_loader.h | 2 +- lib/efi_loader/efi_net.c | 24 +++++++++++++----------- 2 files changed, 14 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/include/efi_loader.h b/include/efi_loader.h index a28a7a1764d..d2fadc5c731 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -185,7 +185,7 @@ int efi_disk_create_partitions(efi_handle_t parent, struct blk_desc *desc, /* Called by bootefi to make GOP (graphical) interface available */ efi_status_t efi_gop_register(void); /* Called by bootefi to make the network interface available */ -int efi_net_register(void); +efi_status_t efi_net_register(void); /* Called by bootefi to make the watchdog available */ int efi_watchdog_register(void); /* Called by bootefi to make SMBIOS tables available */ diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c index 8c5d5b492ca..e7fed794502 100644 --- a/lib/efi_loader/efi_net.c +++ b/lib/efi_loader/efi_net.c @@ -280,20 +280,22 @@ static void EFIAPI efi_network_timer_notify(struct efi_event *event, } /* This gets called from do_bootefi_exec(). */ -int efi_net_register(void) +efi_status_t efi_net_register(void) { struct efi_net_obj *netobj; efi_status_t r; if (!eth_get_dev()) { /* No eth device active, don't expose any */ - return 0; + return EFI_SUCCESS; } /* We only expose the "active" eth device, so one is enough */ netobj = calloc(1, sizeof(*netobj)); - if (!netobj) - goto out_of_memory; + if (!netobj) { + printf("ERROR: Out of memory\n"); + return EFI_OUT_OF_RESOURCES; + } /* Hook net up to the device list */ efi_add_handle(&netobj->parent); @@ -302,15 +304,15 @@ int efi_net_register(void) r = efi_add_protocol(netobj->parent.handle, &efi_net_guid, &netobj->net); if (r != EFI_SUCCESS) - goto out_of_memory; + goto failure_to_add_protocol; r = efi_add_protocol(netobj->parent.handle, &efi_guid_device_path, efi_dp_from_eth()); if (r != EFI_SUCCESS) - goto out_of_memory; + goto failure_to_add_protocol; r = efi_add_protocol(netobj->parent.handle, &efi_pxe_guid, &netobj->pxe); if (r != EFI_SUCCESS) - goto out_of_memory; + goto failure_to_add_protocol; netobj->net.revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION; netobj->net.start = efi_net_start; netobj->net.stop = efi_net_stop; @@ -366,8 +368,8 @@ int efi_net_register(void) return r; } - return 0; -out_of_memory: - printf("ERROR: Out of memory\n"); - return 1; + return EFI_SUCCESS; +failure_to_add_protocol: + printf("ERROR: Failure to add protocol\n"); + return r; } -- cgit v1.3.1 From d7b181d57d0c7080facce755c4b9ff7a22436a48 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 3 Mar 2018 15:28:57 +0100 Subject: efi_loader: consistently return efi_status_t efi_watchdog_register efi_watchdog_register() should always return a status code and not a boolean value. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/efi_loader.h | 2 +- lib/efi_loader/efi_watchdog.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/efi_loader.h b/include/efi_loader.h index d2fadc5c731..48fbe7a214f 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -187,7 +187,7 @@ efi_status_t efi_gop_register(void); /* Called by bootefi to make the network interface available */ efi_status_t efi_net_register(void); /* Called by bootefi to make the watchdog available */ -int efi_watchdog_register(void); +efi_status_t efi_watchdog_register(void); /* Called by bootefi to make SMBIOS tables available */ efi_status_t efi_smbios_register(void); diff --git a/lib/efi_loader/efi_watchdog.c b/lib/efi_loader/efi_watchdog.c index 35a45dedf84..b1c35a8e29d 100644 --- a/lib/efi_loader/efi_watchdog.c +++ b/lib/efi_loader/efi_watchdog.c @@ -59,7 +59,7 @@ efi_status_t efi_set_watchdog(unsigned long timeout) * * This function is called by efi_init_obj_list() */ -int efi_watchdog_register(void) +efi_status_t efi_watchdog_register(void) { efi_status_t r; @@ -85,5 +85,5 @@ int efi_watchdog_register(void) printf("ERROR: Failed to set watchdog timer\n"); return r; } - return 0; + return EFI_SUCCESS; } -- cgit v1.3.1 From 22c793e6a26505fdf80cb5b099142dd6f8f0fff9 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 3 Mar 2018 15:28:59 +0100 Subject: efi_loader: exit status for efi_reset_system_init efi_reset_system_init provides the architecture or board specific initialization of the EFI subsystem. Errors should be caught and signalled by a return code. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- arch/arm/cpu/armv8/fsl-layerscape/cpu.c | 4 ++-- arch/arm/mach-bcm283x/reset.c | 4 ++-- include/efi_loader.h | 11 ++++++++--- lib/efi_loader/efi_runtime.c | 15 ++++++++++++--- 4 files changed, 24 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/arch/arm/cpu/armv8/fsl-layerscape/cpu.c b/arch/arm/cpu/armv8/fsl-layerscape/cpu.c index 70a60709357..0e90302d3fb 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/cpu.c +++ b/arch/arm/cpu/armv8/fsl-layerscape/cpu.c @@ -654,9 +654,9 @@ void __efi_runtime EFIAPI efi_reset_system( while (1) { } } -void efi_reset_system_init(void) +efi_status_t efi_reset_system_init(void) { - efi_add_runtime_mmio(&rstcr, sizeof(*rstcr)); + return efi_add_runtime_mmio(&rstcr, sizeof(*rstcr)); } #endif diff --git a/arch/arm/mach-bcm283x/reset.c b/arch/arm/mach-bcm283x/reset.c index b62cb8a51ee..5b83fdf43d6 100644 --- a/arch/arm/mach-bcm283x/reset.c +++ b/arch/arm/mach-bcm283x/reset.c @@ -82,9 +82,9 @@ void __efi_runtime EFIAPI efi_reset_system( while (1) { } } -void efi_reset_system_init(void) +efi_status_t efi_reset_system_init(void) { - efi_add_runtime_mmio(&wdog_regs, sizeof(*wdog_regs)); + return efi_add_runtime_mmio(&wdog_regs, sizeof(*wdog_regs)); } #endif diff --git a/include/efi_loader.h b/include/efi_loader.h index 48fbe7a214f..3d369436a19 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -350,7 +350,7 @@ static inline int guidcmp(const efi_guid_t *g1, const efi_guid_t *g2) /* Call this with mmio_ptr as the _pointer_ to a pointer to an MMIO region * to make it available at runtime */ -void efi_add_runtime_mmio(void *mmio_ptr, u64 len); +efi_status_t efi_add_runtime_mmio(void *mmio_ptr, u64 len); /* Boards may provide the functions below to implement RTS functionality */ @@ -358,7 +358,9 @@ void __efi_runtime EFIAPI efi_reset_system( enum efi_reset_type reset_type, efi_status_t reset_status, unsigned long data_size, void *reset_data); -void efi_reset_system_init(void); + +/* Architecture specific initialization of the EFI subsystem */ +efi_status_t efi_reset_system_init(void); efi_status_t __efi_runtime EFIAPI efi_get_time( struct efi_time *time, @@ -392,7 +394,10 @@ void *efi_bootmgr_load(struct efi_device_path **device_path, /* Without CONFIG_EFI_LOADER we don't have a runtime section, stub it out */ #define __efi_runtime_data #define __efi_runtime -static inline void efi_add_runtime_mmio(void *mmio_ptr, u64 len) { } +static inline efi_status_t efi_add_runtime_mmio(void *mmio_ptr, u64 len) +{ + return EFI_SUCCESS; +} /* No loader configured, stub out EFI_ENTRY */ static inline void efi_restore_gd(void) { } diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index ccb4fc6141b..85f85711ddc 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -134,8 +134,9 @@ void __weak __efi_runtime EFIAPI efi_reset_system( while (1) { } } -void __weak efi_reset_system_init(void) +efi_status_t __weak efi_reset_system_init(void) { + return EFI_SUCCESS; } efi_status_t __weak __efi_runtime EFIAPI efi_get_time( @@ -332,18 +333,26 @@ static efi_status_t EFIAPI efi_set_virtual_address_map( return EFI_EXIT(EFI_INVALID_PARAMETER); } -void efi_add_runtime_mmio(void *mmio_ptr, u64 len) +efi_status_t efi_add_runtime_mmio(void *mmio_ptr, u64 len) { struct efi_runtime_mmio_list *newmmio; + efi_status_t ret; u64 pages = (len + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT; - efi_add_memory_map(*(uintptr_t *)mmio_ptr, pages, EFI_MMAP_IO, false); + ret = efi_add_memory_map(*(uintptr_t *)mmio_ptr, pages, EFI_MMAP_IO, + false); + if (ret != EFI_SUCCESS) + return ret; newmmio = calloc(1, sizeof(*newmmio)); + if (!newmmio) + return EFI_OUT_OF_RESOURCES; newmmio->ptr = mmio_ptr; newmmio->paddr = *(uintptr_t *)mmio_ptr; newmmio->len = len; list_add_tail(&newmmio->link, &efi_runtime_mmio); + + return ret; } /* -- cgit v1.3.1 From 14ad49d100a0ba4abafedf8ca6459b699c9d0fa1 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 3 Mar 2018 15:29:00 +0100 Subject: efi_loader: efi_get_time_init should return status code All EFI initialization functions should return a status code. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/efi_loader.h | 2 +- lib/efi_loader/efi_runtime.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/efi_loader.h b/include/efi_loader.h index 3d369436a19..b6335182eda 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -365,7 +365,7 @@ efi_status_t efi_reset_system_init(void); efi_status_t __efi_runtime EFIAPI efi_get_time( struct efi_time *time, struct efi_time_cap *capabilities); -void efi_get_time_init(void); +efi_status_t efi_get_time_init(void); #ifdef CONFIG_CMD_BOOTEFI_SELFTEST /* diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index 85f85711ddc..c59d161c8fe 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -147,8 +147,9 @@ efi_status_t __weak __efi_runtime EFIAPI efi_get_time( return EFI_DEVICE_ERROR; } -void __weak efi_get_time_init(void) +efi_status_t __weak efi_get_time_init(void) { + return EFI_SUCCESS; } struct efi_runtime_detach_list_struct { -- cgit v1.3.1 From bc4f9133edb4baf5f68689a03137bb2c336e2026 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 3 Mar 2018 15:29:03 +0100 Subject: efi_loader: support device tree for bootefi selftest The second argument of the bootefi command should always be usable to specify a device tree. This was missing for bootefi selftest and bootefi hello. Proper error handling is added. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- cmd/bootefi.c | 111 ++++++++++++++++++++++++------------------ include/efi_loader.h | 2 + lib/efi_loader/efi_boottime.c | 2 + 3 files changed, 68 insertions(+), 47 deletions(-) (limited to 'include') diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 025a3dd1718..6afece10bc1 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -178,11 +178,49 @@ static efi_status_t efi_run_in_el2(EFIAPI efi_status_t (*entry)( } #endif +static efi_status_t efi_install_fdt(void *fdt) +{ + bootm_headers_t img = { 0 }; + ulong fdt_pages, fdt_size, fdt_start, fdt_end; + efi_status_t ret; + + if (fdt_check_header(fdt)) { + printf("ERROR: invalid device tree\n"); + return EFI_INVALID_PARAMETER; + } + + /* Prepare fdt for payload */ + fdt = copy_fdt(fdt); + if (!fdt) + return EFI_OUT_OF_RESOURCES; + + if (image_setup_libfdt(&img, fdt, 0, NULL)) { + printf("ERROR: failed to process device tree\n"); + return EFI_LOAD_ERROR; + } + + /* Link to it in the efi tables */ + ret = efi_install_configuration_table(&efi_guid_fdt, fdt); + if (ret != EFI_SUCCESS) + return EFI_OUT_OF_RESOURCES; + + /* And reserve the space in the memory map */ + fdt_start = ((ulong)fdt) & ~EFI_PAGE_MASK; + fdt_end = ((ulong)fdt) + fdt_totalsize(fdt); + fdt_size = (fdt_end - fdt_start) + EFI_PAGE_MASK; + fdt_pages = fdt_size >> EFI_PAGE_SHIFT; + /* Give a bootloader the chance to modify the device tree */ + fdt_pages += 2; + ret = efi_add_memory_map(fdt_start, fdt_pages, + EFI_BOOT_SERVICES_DATA, true); + return ret; +} + /* * 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 efi_status_t do_bootefi_exec(void *efi, void *fdt, +static efi_status_t do_bootefi_exec(void *efi, struct efi_device_path *device_path, struct efi_device_path *image_path) { @@ -193,9 +231,6 @@ static efi_status_t do_bootefi_exec(void *efi, void *fdt, EFIAPI efi_status_t (*entry)(efi_handle_t image_handle, struct efi_system_table *st); - ulong fdt_pages, fdt_size, fdt_start, fdt_end; - const efi_guid_t fdt_guid = EFI_FDT_GUID; - bootm_headers_t img = { 0 }; /* * Special case for efi payload not loaded from disk, such as @@ -220,32 +255,6 @@ static efi_status_t do_bootefi_exec(void *efi, void *fdt, */ efi_save_gd(); - if (fdt && !fdt_check_header(fdt)) { - /* Prepare fdt for payload */ - fdt = copy_fdt(fdt); - - if (image_setup_libfdt(&img, fdt, 0, NULL)) { - printf("ERROR: Failed to process device tree\n"); - return -EINVAL; - } - - /* Link to it in the efi tables */ - efi_install_configuration_table(&fdt_guid, fdt); - - /* And reserve the space in the memory map */ - fdt_start = ((ulong)fdt) & ~EFI_PAGE_MASK; - fdt_end = ((ulong)fdt) + fdt_totalsize(fdt); - fdt_size = (fdt_end - fdt_start) + EFI_PAGE_MASK; - fdt_pages = fdt_size >> EFI_PAGE_SHIFT; - /* Give a bootloader the chance to modify the device tree */ - fdt_pages += 2; - efi_add_memory_map(fdt_start, fdt_pages, - EFI_BOOT_SERVICES_DATA, true); - } else { - printf("WARNING: Invalid device tree, expect boot to fail\n"); - efi_install_configuration_table(&fdt_guid, NULL); - } - /* Transfer environment variable bootargs as load options */ set_load_options(&loaded_image_info, "bootargs"); /* Load the EFI payload */ @@ -301,7 +310,7 @@ exit: return ret; } -static int do_bootefi_bootmgr_exec(unsigned long fdt_addr) +static int do_bootefi_bootmgr_exec(void) { struct efi_device_path *device_path, *file_path; void *addr; @@ -318,7 +327,7 @@ static int do_bootefi_bootmgr_exec(unsigned long fdt_addr) return 1; printf("## Starting EFI application at %p ...\n", addr); - r = do_bootefi_exec(addr, (void *)fdt_addr, device_path, file_path); + r = do_bootefi_exec(addr, device_path, file_path); printf("## Application terminated, r = %lu\n", r & ~EFI_ERROR_MASK); @@ -331,9 +340,10 @@ static int do_bootefi_bootmgr_exec(unsigned long fdt_addr) /* 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, *sfdt; - unsigned long addr, fdt_addr = 0; + unsigned long addr; + char *saddr; efi_status_t r; + void *fdt_addr; /* Initialize EFI drivers */ r = efi_init_obj_list(); @@ -345,6 +355,22 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) if (argc < 2) return CMD_RET_USAGE; + + if (argc > 2) { + fdt_addr = (void *)simple_strtoul(argv[2], NULL, 16); + if (!fdt_addr && *argv[2] != '0') + return CMD_RET_USAGE; + /* Install device tree */ + r = efi_install_fdt(fdt_addr); + if (r != EFI_SUCCESS) { + printf("ERROR: failed to install device tree\n"); + return CMD_RET_FAILURE; + } + } else { + /* Remove device tree. EFI_NOT_FOUND can be ignored here */ + efi_install_configuration_table(&efi_guid_fdt, NULL); + printf("WARNING: booting without device tree\n"); + } #ifdef CONFIG_CMD_BOOTEFI_HELLO if (!strcmp(argv[1], "hello")) { ulong size = __efi_helloworld_end - __efi_helloworld_begin; @@ -390,12 +416,7 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) } else #endif if (!strcmp(argv[1], "bootmgr")) { - unsigned long fdt_addr = 0; - - if (argc > 2) - fdt_addr = simple_strtoul(argv[2], NULL, 16); - - return do_bootefi_bootmgr_exec(fdt_addr); + return do_bootefi_bootmgr_exec(); } else { saddr = argv[1]; @@ -404,15 +425,11 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) if (!addr && *saddr != '0') return CMD_RET_USAGE; - if (argc > 2) { - sfdt = argv[2]; - fdt_addr = simple_strtoul(sfdt, NULL, 16); - } } printf("## Starting EFI application at %08lx ...\n", addr); - r = do_bootefi_exec((void *)addr, (void *)fdt_addr, - bootefi_device_path, bootefi_image_path); + r = do_bootefi_exec((void *)addr, bootefi_device_path, + bootefi_image_path); printf("## Application terminated, r = %lu\n", r & ~EFI_ERROR_MASK); @@ -433,7 +450,7 @@ static char bootefi_help_text[] = " - boot a sample Hello World application stored within U-Boot\n" #endif #ifdef CONFIG_CMD_BOOTEFI_SELFTEST - "bootefi selftest\n" + "bootefi selftest [fdt address]\n" " - boot an EFI selftest application stored within U-Boot\n" " Use environment variable efi_selftest to select a single test.\n" " Use 'setenv efi_selftest list' to enumerate all tests.\n" diff --git a/include/efi_loader.h b/include/efi_loader.h index b6335182eda..60f84dcf24b 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -96,6 +96,8 @@ extern const efi_guid_t efi_guid_console_control; extern const efi_guid_t efi_guid_device_path; /* GUID of the EFI_DRIVER_BINDING_PROTOCOL */ extern const efi_guid_t efi_guid_driver_binding_protocol; +/* GUID of the device tree table */ +extern const efi_guid_t efi_guid_fdt; extern const efi_guid_t efi_guid_loaded_image; extern const efi_guid_t efi_guid_device_path_to_text_protocol; extern const efi_guid_t efi_simple_file_system_protocol_guid; diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 4e133e9b47d..3cee8d607c8 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -56,6 +56,8 @@ static volatile void *efi_gd, *app_gd; static int entry_count; static int nesting_level; +/* GUID of the device tree table */ +const efi_guid_t efi_guid_fdt = EFI_FDT_GUID; /* GUID of the EFI_DRIVER_BINDING_PROTOCOL */ const efi_guid_t efi_guid_driver_binding_protocol = EFI_DRIVER_BINDING_PROTOCOL_GUID; -- cgit v1.3.1 From 43bce44262ca7cbb04bb236c50571ca84eb6fdd9 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 18 Feb 2018 15:17:50 +0100 Subject: efi_loader: manage events in a linked list Lift the limit on the number of events by using a linked list. This also allows to have events with type == 0. This patch is based on Rob's patch efi_loader: fix events https://lists.denx.de/pipermail/u-boot/2017-October/309348.html Suggested-by: Rob Clark Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/efi_loader.h | 11 +-- lib/efi_loader/efi_boottime.c | 192 +++++++++++++++++++----------------------- 2 files changed, 93 insertions(+), 110 deletions(-) (limited to 'include') diff --git a/include/efi_loader.h b/include/efi_loader.h index 60f84dcf24b..1a670586b92 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -150,17 +150,19 @@ struct efi_object { /** * struct efi_event * + * @link: Link to list of all events * @type: Type of event, see efi_create_event * @notify_tpl: Task priority level of notifications - * @trigger_time: Period of the timer - * @trigger_next: Next time to trigger the timer * @nofify_function: Function to call when the event is triggered * @notify_context: Data to be passed to the notify function + * @trigger_time: Period of the timer + * @trigger_next: Next time to trigger the timer * @trigger_type: Type of timer, see efi_set_timer - * @queued: The notification function is queued - * @signaled: The event occurred. The event is in the signaled state. + * @is_queued: The notification function is queued + * @is_signaled: The event occurred. The event is in the signaled state. */ struct efi_event { + struct list_head link; uint32_t type; efi_uintn_t notify_tpl; void (EFIAPI *notify_function)(struct efi_event *event, void *context); @@ -172,7 +174,6 @@ struct efi_event { bool is_signaled; }; - /* This list contains all UEFI objects we know of */ extern struct list_head efi_obj_list; diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 1a2154591cb..ca43925be44 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -26,6 +26,9 @@ static efi_uintn_t efi_tpl = TPL_APPLICATION; /* This list contains all the EFI objects our payload has access to */ LIST_HEAD(efi_obj_list); +/* List of all events */ +static LIST_HEAD(efi_events); + /* * If we're running on nasty systems (32bit ARM booting into non-EFI Linux) * we need to do trickery with caches. Since we don't want to break the EFI @@ -473,10 +476,23 @@ void efi_delete_handle(struct efi_object *obj) } /* - * Our event capabilities are very limited. Only a small limited - * number of events is allowed to coexist. + * Check if a pointer is a valid event. + * + * @event pointer to check + * @return status code */ -static struct efi_event efi_events[16]; +static efi_status_t efi_is_event(const struct efi_event *event) +{ + const struct efi_event *evt; + + if (!event) + return EFI_INVALID_PARAMETER; + list_for_each_entry(evt, &efi_events, link) { + if (evt == event) + return EFI_SUCCESS; + } + return EFI_INVALID_PARAMETER; +} /* * Create an event. @@ -499,7 +515,7 @@ efi_status_t efi_create_event(uint32_t type, efi_uintn_t notify_tpl, void *context), void *notify_context, struct efi_event **event) { - int i; + struct efi_event *evt; if (event == NULL) return EFI_INVALID_PARAMETER; @@ -507,25 +523,24 @@ efi_status_t efi_create_event(uint32_t type, efi_uintn_t notify_tpl, if ((type & EVT_NOTIFY_SIGNAL) && (type & EVT_NOTIFY_WAIT)) return EFI_INVALID_PARAMETER; - if ((type & (EVT_NOTIFY_SIGNAL|EVT_NOTIFY_WAIT)) && + if ((type & (EVT_NOTIFY_SIGNAL | EVT_NOTIFY_WAIT)) && notify_function == NULL) return EFI_INVALID_PARAMETER; - for (i = 0; i < ARRAY_SIZE(efi_events); ++i) { - if (efi_events[i].type) - continue; - efi_events[i].type = type; - efi_events[i].notify_tpl = notify_tpl; - efi_events[i].notify_function = notify_function; - efi_events[i].notify_context = notify_context; - /* Disable timers on bootup */ - efi_events[i].trigger_next = -1ULL; - efi_events[i].is_queued = false; - efi_events[i].is_signaled = false; - *event = &efi_events[i]; - return EFI_SUCCESS; - } - return EFI_OUT_OF_RESOURCES; + evt = calloc(1, sizeof(struct efi_event)); + if (!evt) + return EFI_OUT_OF_RESOURCES; + evt->type = type; + evt->notify_tpl = notify_tpl; + evt->notify_function = notify_function; + evt->notify_context = notify_context; + /* Disable timers on bootup */ + evt->trigger_next = -1ULL; + evt->is_queued = false; + evt->is_signaled = false; + list_add_tail(&evt->link, &efi_events); + *event = evt; + return EFI_SUCCESS; } /* @@ -596,30 +611,26 @@ static efi_status_t EFIAPI efi_create_event_ext( */ void efi_timer_check(void) { - int i; + struct efi_event *evt; u64 now = timer_get_us(); - for (i = 0; i < ARRAY_SIZE(efi_events); ++i) { - if (!efi_events[i].type) + list_for_each_entry(evt, &efi_events, link) { + if (evt->is_queued) + efi_signal_event(evt, true); + if (!(evt->type & EVT_TIMER) || now < evt->trigger_next) continue; - if (efi_events[i].is_queued) - efi_signal_event(&efi_events[i], true); - if (!(efi_events[i].type & EVT_TIMER) || - now < efi_events[i].trigger_next) - continue; - switch (efi_events[i].trigger_type) { + switch (evt->trigger_type) { case EFI_TIMER_RELATIVE: - efi_events[i].trigger_type = EFI_TIMER_STOP; + evt->trigger_type = EFI_TIMER_STOP; break; case EFI_TIMER_PERIODIC: - efi_events[i].trigger_next += - efi_events[i].trigger_time; + evt->trigger_next += evt->trigger_time; break; default: continue; } - efi_events[i].is_signaled = true; - efi_signal_event(&efi_events[i], true); + evt->is_signaled = true; + efi_signal_event(evt, true); } WATCHDOG_RESET(); } @@ -638,7 +649,9 @@ void efi_timer_check(void) efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type, uint64_t trigger_time) { - int i; + /* Check that the event is valid */ + if (efi_is_event(event) != EFI_SUCCESS || !(event->type & EVT_TIMER)) + return EFI_INVALID_PARAMETER; /* * The parameter defines a multiple of 100ns. @@ -646,30 +659,21 @@ efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type, */ do_div(trigger_time, 10); - for (i = 0; i < ARRAY_SIZE(efi_events); ++i) { - if (event != &efi_events[i]) - continue; - - if (!(event->type & EVT_TIMER)) - break; - switch (type) { - case EFI_TIMER_STOP: - event->trigger_next = -1ULL; - break; - case EFI_TIMER_PERIODIC: - case EFI_TIMER_RELATIVE: - event->trigger_next = - timer_get_us() + trigger_time; - break; - default: - return EFI_INVALID_PARAMETER; - } - event->trigger_type = type; - event->trigger_time = trigger_time; - event->is_signaled = false; - return EFI_SUCCESS; + switch (type) { + case EFI_TIMER_STOP: + event->trigger_next = -1ULL; + break; + case EFI_TIMER_PERIODIC: + case EFI_TIMER_RELATIVE: + event->trigger_next = timer_get_us() + trigger_time; + break; + default: + return EFI_INVALID_PARAMETER; } - return EFI_INVALID_PARAMETER; + event->trigger_type = type; + event->trigger_time = trigger_time; + event->is_signaled = false; + return EFI_SUCCESS; } /* @@ -708,7 +712,7 @@ static efi_status_t EFIAPI efi_wait_for_event(efi_uintn_t num_events, struct efi_event **event, efi_uintn_t *index) { - int i, j; + int i; EFI_ENTRY("%zd, %p, %p", num_events, event, index); @@ -719,12 +723,8 @@ static efi_status_t EFIAPI efi_wait_for_event(efi_uintn_t num_events, if (efi_tpl != TPL_APPLICATION) return EFI_EXIT(EFI_UNSUPPORTED); for (i = 0; i < num_events; ++i) { - for (j = 0; j < ARRAY_SIZE(efi_events); ++j) { - if (event[i] == &efi_events[j]) - goto known_event; - } - return EFI_EXIT(EFI_INVALID_PARAMETER); -known_event: + if (efi_is_event(event[i]) != EFI_SUCCESS) + return EFI_EXIT(EFI_INVALID_PARAMETER); if (!event[i]->type || event[i]->type & EVT_NOTIFY_SIGNAL) return EFI_EXIT(EFI_INVALID_PARAMETER); if (!event[i]->is_signaled) @@ -768,18 +768,13 @@ out: */ static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event) { - int i; - EFI_ENTRY("%p", event); - for (i = 0; i < ARRAY_SIZE(efi_events); ++i) { - if (event != &efi_events[i]) - continue; - if (event->is_signaled) - break; + if (efi_is_event(event) != EFI_SUCCESS) + return EFI_EXIT(EFI_INVALID_PARAMETER); + if (!event->is_signaled) { event->is_signaled = true; if (event->type & EVT_NOTIFY_SIGNAL) efi_signal_event(event, true); - break; } return EFI_EXIT(EFI_SUCCESS); } @@ -796,19 +791,12 @@ static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event) */ static efi_status_t EFIAPI efi_close_event(struct efi_event *event) { - int i; - EFI_ENTRY("%p", event); - for (i = 0; i < ARRAY_SIZE(efi_events); ++i) { - if (event == &efi_events[i]) { - event->type = 0; - event->trigger_next = -1ULL; - event->is_queued = false; - event->is_signaled = false; - return EFI_EXIT(EFI_SUCCESS); - } - } - return EFI_EXIT(EFI_INVALID_PARAMETER); + if (efi_is_event(event) != EFI_SUCCESS) + return EFI_EXIT(EFI_INVALID_PARAMETER); + list_del(&event->link); + free(event); + return EFI_EXIT(EFI_SUCCESS); } /* @@ -826,24 +814,18 @@ static efi_status_t EFIAPI efi_close_event(struct efi_event *event) */ static efi_status_t EFIAPI efi_check_event(struct efi_event *event) { - int i; - EFI_ENTRY("%p", event); efi_timer_check(); - for (i = 0; i < ARRAY_SIZE(efi_events); ++i) { - if (event != &efi_events[i]) - continue; - if (!event->type || event->type & EVT_NOTIFY_SIGNAL) - break; - if (!event->is_signaled) - efi_signal_event(event, true); - if (event->is_signaled) { - event->is_signaled = false; - return EFI_EXIT(EFI_SUCCESS); - } - return EFI_EXIT(EFI_NOT_READY); + if (efi_is_event(event) != EFI_SUCCESS || + event->type & EVT_NOTIFY_SIGNAL) + return EFI_EXIT(EFI_INVALID_PARAMETER); + if (!event->is_signaled) + efi_signal_event(event, true); + if (event->is_signaled) { + event->is_signaled = false; + return EFI_EXIT(EFI_SUCCESS); } - return EFI_EXIT(EFI_INVALID_PARAMETER); + return EFI_EXIT(EFI_NOT_READY); } /* @@ -1755,7 +1737,7 @@ static void efi_exit_caches(void) static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle, unsigned long map_key) { - int i; + struct efi_event *evt; EFI_ENTRY("%p, %ld", image_handle, map_key); @@ -1767,11 +1749,11 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle, return EFI_EXIT(EFI_SUCCESS); /* Notify that ExitBootServices is invoked. */ - for (i = 0; i < ARRAY_SIZE(efi_events); ++i) { - if (efi_events[i].type != EVT_SIGNAL_EXIT_BOOT_SERVICES) + list_for_each_entry(evt, &efi_events, link) { + if (evt->type != EVT_SIGNAL_EXIT_BOOT_SERVICES) continue; - efi_events[i].is_signaled = true; - efi_signal_event(&efi_events[i], false); + evt->is_signaled = true; + efi_signal_event(evt, false); } /* TODO Should persist EFI variables here */ -- cgit v1.3.1 From a3a28f5f0c39d94733d23e2bbbb53e6e4ddb46c6 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 18 Feb 2018 15:17:51 +0100 Subject: efi_loader: define GUIDS for event groups Event groups are used to signal multiple events at the same time. They are identified by GUIDs. This patch provided the predefined GUIDs of UEFI specification 2.7. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/efi_api.h | 21 +++++++++++++++++++++ include/efi_loader.h | 10 ++++++++++ lib/efi_loader/efi_boottime.c | 16 ++++++++++++++++ 3 files changed, 47 insertions(+) (limited to 'include') diff --git a/include/efi_api.h b/include/efi_api.h index 827a192620b..433594f339c 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -243,6 +243,27 @@ struct efi_runtime_services { u64 maximum_variable_size); }; +/* EFI event group GUID definitions */ +#define EFI_EVENT_GROUP_EXIT_BOOT_SERVICES \ + EFI_GUID(0x27abf055, 0xb1b8, 0x4c26, 0x80, 0x48, \ + 0x74, 0x8f, 0x37, 0xba, 0xa2, 0xdf) + +#define EFI_EVENT_GROUP_VIRTUAL_ADDRESS_CHANGE \ + EFI_GUID(0x13fa7698, 0xc831, 0x49c7, 0x87, 0xea, \ + 0x8f, 0x43, 0xfc, 0xc2, 0x51, 0x96) + +#define EFI_EVENT_GROUP_MEMORY_MAP_CHANGE \ + EFI_GUID(0x78bee926, 0x692f, 0x48fd, 0x9e, 0xdb, \ + 0x01, 0x42, 0x2e, 0xf0, 0xd7, 0xab) + +#define EFI_EVENT_GROUP_READY_TO_BOOT \ + EFI_GUID(0x7ce88fb3, 0x4bd7, 0x4679, 0x87, 0xa8, \ + 0xa8, 0xd8, 0xde, 0xe5, 0x0d, 0x2b) + +#define EFI_EVENT_GROUP_RESET_SYSTEM \ + EFI_GUID(0x62da6a56, 0x13fb, 0x485a, 0xa8, 0xda, \ + 0xa3, 0xdd, 0x79, 0x12, 0xcb, 0x6b) + /* EFI Configuration Table and GUID definitions */ #define NULL_GUID \ EFI_GUID(0x00000000, 0x0000, 0x0000, 0x00, 0x00, \ diff --git a/include/efi_loader.h b/include/efi_loader.h index 1a670586b92..8596c0e7291 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -96,6 +96,16 @@ extern const efi_guid_t efi_guid_console_control; extern const efi_guid_t efi_guid_device_path; /* GUID of the EFI_DRIVER_BINDING_PROTOCOL */ extern const efi_guid_t efi_guid_driver_binding_protocol; +/* event group ExitBootServices() invoked */ +extern const efi_guid_t efi_guid_event_group_exit_boot_services; +/* event group SetVirtualAddressMap() invoked */ +extern const efi_guid_t efi_guid_event_group_virtual_address_change; +/* event group memory map changed */ +extern const efi_guid_t efi_guid_event_group_memory_map_change; +/* event group boot manager about to boot */ +extern const efi_guid_t efi_guid_event_group_ready_to_boot; +/* event group ResetSystem() invoked (before ExitBootServices) */ +extern const efi_guid_t efi_guid_event_group_reset_system; /* GUID of the device tree table */ extern const efi_guid_t efi_guid_fdt; extern const efi_guid_t efi_guid_loaded_image; diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index ca43925be44..d9abb3ccedd 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -65,6 +65,22 @@ const efi_guid_t efi_guid_fdt = EFI_FDT_GUID; const efi_guid_t efi_guid_driver_binding_protocol = EFI_DRIVER_BINDING_PROTOCOL_GUID; +/* event group ExitBootServices() invoked */ +const efi_guid_t efi_guid_event_group_exit_boot_services = + EFI_EVENT_GROUP_EXIT_BOOT_SERVICES; +/* event group SetVirtualAddressMap() invoked */ +const efi_guid_t efi_guid_event_group_virtual_address_change = + EFI_EVENT_GROUP_VIRTUAL_ADDRESS_CHANGE; +/* event group memory map changed */ +const efi_guid_t efi_guid_event_group_memory_map_change = + EFI_EVENT_GROUP_MEMORY_MAP_CHANGE; +/* event group boot manager about to boot */ +const efi_guid_t efi_guid_event_group_ready_to_boot = + EFI_EVENT_GROUP_READY_TO_BOOT; +/* event group ResetSystem() invoked (before ExitBootServices) */ +const efi_guid_t efi_guid_event_group_reset_system = + EFI_EVENT_GROUP_RESET_SYSTEM; + static efi_status_t EFIAPI efi_disconnect_controller( efi_handle_t controller_handle, efi_handle_t driver_image_handle, -- cgit v1.3.1 From b095f3c85fe08744d6081b98db65768f3421295e Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 18 Feb 2018 15:17:52 +0100 Subject: efi_loader: implement event groups If an event of a group event is signaled all other events of the same group are signaled too. Function efi_signal_event is renamed to efi_queue_event. A new function efi_signal_event is introduced that checks if an event belongs to a group and than signals all events of the group. Event group notifciation is implemented for ExitBootServices, InstallConfigurationTable, and ResetSystem. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/efi_loader.h | 7 ++- lib/efi_loader/efi_boottime.c | 99 ++++++++++++++++++++++++++++++++++--------- lib/efi_loader/efi_console.c | 6 +-- lib/efi_loader/efi_net.c | 4 +- lib/efi_loader/efi_runtime.c | 11 +++++ lib/efi_loader/efi_watchdog.c | 2 +- 6 files changed, 101 insertions(+), 28 deletions(-) (limited to 'include') diff --git a/include/efi_loader.h b/include/efi_loader.h index 8596c0e7291..0df482ee217 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -165,6 +165,7 @@ struct efi_object { * @notify_tpl: Task priority level of notifications * @nofify_function: Function to call when the event is triggered * @notify_context: Data to be passed to the notify function + * @group: Event group * @trigger_time: Period of the timer * @trigger_next: Next time to trigger the timer * @trigger_type: Type of timer, see efi_set_timer @@ -177,6 +178,7 @@ struct efi_event { efi_uintn_t notify_tpl; void (EFIAPI *notify_function)(struct efi_event *event, void *context); void *notify_context; + const efi_guid_t *group; u64 trigger_next; u64 trigger_time; enum efi_timer_delay trigger_type; @@ -186,6 +188,8 @@ struct efi_event { /* This list contains all UEFI objects we know of */ extern struct list_head efi_obj_list; +/* List of all events */ +extern struct list_head efi_events; /* Called by bootefi to make console interface available */ int efi_console_register(void); @@ -252,7 +256,8 @@ efi_status_t efi_create_event(uint32_t type, efi_uintn_t notify_tpl, void (EFIAPI *notify_function) ( struct efi_event *event, void *context), - void *notify_context, struct efi_event **event); + void *notify_context, efi_guid_t *group, + struct efi_event **event); /* Call this to set a timer */ efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type, uint64_t trigger_time); diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index d9abb3ccedd..1ff0568d474 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -27,7 +27,7 @@ static efi_uintn_t efi_tpl = TPL_APPLICATION; LIST_HEAD(efi_obj_list); /* List of all events */ -static LIST_HEAD(efi_events); +LIST_HEAD(efi_events); /* * If we're running on nasty systems (32bit ARM booting into non-EFI Linux) @@ -176,7 +176,7 @@ const char *__efi_nesting_dec(void) * @event event to signal * @check_tpl check the TPL level */ -void efi_signal_event(struct efi_event *event, bool check_tpl) +static void efi_queue_event(struct efi_event *event, bool check_tpl) { if (event->notify_function) { event->is_queued = true; @@ -189,6 +189,50 @@ void efi_signal_event(struct efi_event *event, bool check_tpl) event->is_queued = false; } +/* + * Signal an EFI event. + * + * This function signals an event. If the event belongs to an event group + * all events of the group are signaled. If they are of type EVT_NOTIFY_SIGNAL + * their notification function is queued. + * + * For the SignalEvent service see efi_signal_event_ext. + * + * @event event to signal + * @check_tpl check the TPL level + */ +void efi_signal_event(struct efi_event *event, bool check_tpl) +{ + if (event->group) { + struct efi_event *evt; + + /* + * The signaled state has to set before executing any + * notification function + */ + list_for_each_entry(evt, &efi_events, link) { + if (!evt->group || guidcmp(evt->group, event->group)) + continue; + if (evt->is_signaled) + continue; + evt->is_signaled = true; + if (evt->type & EVT_NOTIFY_SIGNAL && + evt->notify_function) + evt->is_queued = true; + } + list_for_each_entry(evt, &efi_events, link) { + if (!evt->group || guidcmp(evt->group, event->group)) + continue; + if (evt->is_queued) + efi_queue_event(evt, check_tpl); + } + } else if (!event->is_signaled) { + event->is_signaled = true; + if (event->type & EVT_NOTIFY_SIGNAL) + efi_queue_event(event, check_tpl); + } +} + /* * Raise the task priority level. * @@ -529,7 +573,8 @@ efi_status_t efi_create_event(uint32_t type, efi_uintn_t notify_tpl, void (EFIAPI *notify_function) ( struct efi_event *event, void *context), - void *notify_context, struct efi_event **event) + void *notify_context, efi_guid_t *group, + struct efi_event **event) { struct efi_event *evt; @@ -550,6 +595,7 @@ efi_status_t efi_create_event(uint32_t type, efi_uintn_t notify_tpl, evt->notify_tpl = notify_tpl; evt->notify_function = notify_function; evt->notify_context = notify_context; + evt->group = group; /* Disable timers on bootup */ evt->trigger_next = -1ULL; evt->is_queued = false; @@ -585,10 +631,8 @@ efi_status_t EFIAPI efi_create_event_ex(uint32_t type, efi_uintn_t notify_tpl, { EFI_ENTRY("%d, 0x%zx, %p, %p, %pUl", type, notify_tpl, notify_function, notify_context, event_group); - if (event_group) - return EFI_EXIT(EFI_UNSUPPORTED); return EFI_EXIT(efi_create_event(type, notify_tpl, notify_function, - notify_context, event)); + notify_context, event_group, event)); } /* @@ -615,7 +659,7 @@ static efi_status_t EFIAPI efi_create_event_ext( EFI_ENTRY("%d, 0x%zx, %p, %p", type, notify_tpl, notify_function, notify_context); return EFI_EXIT(efi_create_event(type, notify_tpl, notify_function, - notify_context, event)); + notify_context, NULL, event)); } /* @@ -632,7 +676,7 @@ void efi_timer_check(void) list_for_each_entry(evt, &efi_events, link) { if (evt->is_queued) - efi_signal_event(evt, true); + efi_queue_event(evt, true); if (!(evt->type & EVT_TIMER) || now < evt->trigger_next) continue; switch (evt->trigger_type) { @@ -645,7 +689,7 @@ void efi_timer_check(void) default: continue; } - evt->is_signaled = true; + evt->is_signaled = false; efi_signal_event(evt, true); } WATCHDOG_RESET(); @@ -744,7 +788,7 @@ static efi_status_t EFIAPI efi_wait_for_event(efi_uintn_t num_events, if (!event[i]->type || event[i]->type & EVT_NOTIFY_SIGNAL) return EFI_EXIT(EFI_INVALID_PARAMETER); if (!event[i]->is_signaled) - efi_signal_event(event[i], true); + efi_queue_event(event[i], true); } /* Wait for signal */ @@ -787,11 +831,7 @@ static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event) EFI_ENTRY("%p", event); if (efi_is_event(event) != EFI_SUCCESS) return EFI_EXIT(EFI_INVALID_PARAMETER); - if (!event->is_signaled) { - event->is_signaled = true; - if (event->type & EVT_NOTIFY_SIGNAL) - efi_signal_event(event, true); - } + efi_signal_event(event, true); return EFI_EXIT(EFI_SUCCESS); } @@ -836,7 +876,7 @@ static efi_status_t EFIAPI efi_check_event(struct efi_event *event) event->type & EVT_NOTIFY_SIGNAL) return EFI_EXIT(EFI_INVALID_PARAMETER); if (!event->is_signaled) - efi_signal_event(event, true); + efi_queue_event(event, true); if (event->is_signaled) { event->is_signaled = false; return EFI_EXIT(EFI_SUCCESS); @@ -1333,6 +1373,7 @@ static void efi_remove_configuration_table(int i) efi_status_t efi_install_configuration_table(const efi_guid_t *guid, void *table) { + struct efi_event *evt; int i; if (!guid) @@ -1345,7 +1386,7 @@ efi_status_t efi_install_configuration_table(const efi_guid_t *guid, efi_conf_table[i].table = table; else efi_remove_configuration_table(i); - return EFI_SUCCESS; + goto out; } } @@ -1361,6 +1402,15 @@ efi_status_t efi_install_configuration_table(const efi_guid_t *guid, efi_conf_table[i].table = table; systab.nr_tables = i + 1; +out: + /* Notify that the configuration table was changed */ + list_for_each_entry(evt, &efi_events, link) { + if (evt->group && !guidcmp(evt->group, guid)) { + efi_signal_event(evt, false); + break; + } + } + return EFI_SUCCESS; } @@ -1764,12 +1814,19 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle, if (!systab.boottime) return EFI_EXIT(EFI_SUCCESS); + /* Add related events to the event group */ + list_for_each_entry(evt, &efi_events, link) { + if (evt->type == EVT_SIGNAL_EXIT_BOOT_SERVICES) + evt->group = &efi_guid_event_group_exit_boot_services; + } /* Notify that ExitBootServices is invoked. */ list_for_each_entry(evt, &efi_events, link) { - if (evt->type != EVT_SIGNAL_EXIT_BOOT_SERVICES) - continue; - evt->is_signaled = true; - efi_signal_event(evt, false); + if (evt->group && + !guidcmp(evt->group, + &efi_guid_event_group_exit_boot_services)) { + efi_signal_event(evt, false); + break; + } } /* TODO Should persist EFI variables here */ diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c index d0e8617d0d3..5d1a9a8081e 100644 --- a/lib/efi_loader/efi_console.c +++ b/lib/efi_loader/efi_console.c @@ -572,14 +572,14 @@ int efi_console_register(void) goto out_of_memory; /* Create console events */ - r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK, - efi_key_notify, NULL, &efi_con_in.wait_for_key); + r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK, efi_key_notify, + NULL, NULL, &efi_con_in.wait_for_key); if (r != EFI_SUCCESS) { printf("ERROR: Failed to register WaitForKey event\n"); return r; } r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, - efi_console_timer_notify, NULL, + efi_console_timer_notify, NULL, NULL, &console_timer_event); if (r != EFI_SUCCESS) { printf("ERROR: Failed to register console event\n"); diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c index e7fed794502..b88dc91f58c 100644 --- a/lib/efi_loader/efi_net.c +++ b/lib/efi_loader/efi_net.c @@ -341,7 +341,7 @@ efi_status_t efi_net_register(void) * Create WaitForPacket event. */ r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK, - efi_network_timer_notify, NULL, + efi_network_timer_notify, NULL, NULL, &wait_for_packet); if (r != EFI_SUCCESS) { printf("ERROR: Failed to register network event\n"); @@ -355,7 +355,7 @@ efi_status_t efi_net_register(void) * has been received. */ r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, - efi_network_timer_notify, NULL, + efi_network_timer_notify, NULL, NULL, &network_timer_event); if (r != EFI_SUCCESS) { printf("ERROR: Failed to register network event\n"); diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index c59d161c8fe..9e281728f9f 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -74,9 +74,20 @@ static void EFIAPI efi_reset_system_boottime( efi_status_t reset_status, unsigned long data_size, void *reset_data) { + struct efi_event *evt; + EFI_ENTRY("%d %lx %lx %p", reset_type, reset_status, data_size, reset_data); + /* Notify reset */ + list_for_each_entry(evt, &efi_events, link) { + if (evt->group && + !guidcmp(evt->group, + &efi_guid_event_group_reset_system)) { + efi_signal_event(evt, false); + break; + } + } switch (reset_type) { case EFI_RESET_COLD: case EFI_RESET_WARM: diff --git a/lib/efi_loader/efi_watchdog.c b/lib/efi_loader/efi_watchdog.c index b1c35a8e29d..d12e51da0a2 100644 --- a/lib/efi_loader/efi_watchdog.c +++ b/lib/efi_loader/efi_watchdog.c @@ -67,7 +67,7 @@ efi_status_t efi_watchdog_register(void) * Create a timer event. */ r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, - efi_watchdog_timer_notify, NULL, + efi_watchdog_timer_notify, NULL, NULL, &watchdog_timer_event); if (r != EFI_SUCCESS) { printf("ERROR: Failed to register watchdog event\n"); -- cgit v1.3.1 From 0e0a3ceb509b19af55c5064607d9057ec7d8c1c4 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 7 Feb 2018 22:14:22 +0100 Subject: efi_loader: implement missing bit blit operations in gop With the patch all block image transfer operations of the EFI_GRAPHICS_OUTPUT_PROTOCOL are supported. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/efi_api.h | 10 ++- lib/efi_loader/efi_gop.c | 158 ++++++++++++++++++++++++++++++++++++----------- 2 files changed, 131 insertions(+), 37 deletions(-) (limited to 'include') diff --git a/include/efi_api.h b/include/efi_api.h index 433594f339c..167c44e3a44 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -665,6 +665,13 @@ struct efi_gop_mode unsigned long fb_size; }; +struct efi_gop_pixel { + u8 blue; + u8 green; + u8 red; + u8 reserved; +}; + #define EFI_BLT_VIDEO_FILL 0 #define EFI_BLT_VIDEO_TO_BLT_BUFFER 1 #define EFI_BLT_BUFFER_TO_VIDEO 2 @@ -676,7 +683,8 @@ struct efi_gop efi_uintn_t *size_of_info, struct efi_gop_mode_info **info); efi_status_t (EFIAPI *set_mode)(struct efi_gop *this, u32 mode_number); - efi_status_t (EFIAPI *blt)(struct efi_gop *this, void *buffer, + efi_status_t (EFIAPI *blt)(struct efi_gop *this, + struct efi_gop_pixel *buffer, u32 operation, efi_uintn_t sx, efi_uintn_t sy, efi_uintn_t dx, efi_uintn_t dy, efi_uintn_t width, diff --git a/lib/efi_loader/efi_gop.c b/lib/efi_loader/efi_gop.c index 28818eb781a..154f3065406 100644 --- a/lib/efi_loader/efi_gop.c +++ b/lib/efi_loader/efi_gop.c @@ -56,64 +56,150 @@ static efi_status_t EFIAPI gop_set_mode(struct efi_gop *this, u32 mode_number) return EFI_EXIT(EFI_SUCCESS); } -efi_status_t EFIAPI gop_blt(struct efi_gop *this, void *buffer, +static inline struct efi_gop_pixel efi_vid16_to_blt_col(u16 vid) +{ + struct efi_gop_pixel blt = { + .reserved = 0, + }; + + blt.blue = (vid & 0x1f) << 3; + vid >>= 5; + blt.green = (vid & 0x3f) << 2; + vid >>= 6; + blt.red = (vid & 0x1f) << 3; + return blt; +} + +static inline u16 efi_blt_col_to_vid16(struct efi_gop_pixel *blt) +{ + return (u16)(blt->red >> 3) << 11 | + (u16)(blt->green >> 2) << 5 | + (u16)(blt->blue >> 3); +} + +efi_status_t EFIAPI gop_blt(struct efi_gop *this, struct efi_gop_pixel *buffer, u32 operation, efi_uintn_t sx, efi_uintn_t sy, efi_uintn_t dx, efi_uintn_t dy, efi_uintn_t width, efi_uintn_t height, efi_uintn_t delta) { struct efi_gop_obj *gopobj = container_of(this, struct efi_gop_obj, ops); - int i, j, line_len16, line_len32; - void *fb; + efi_uintn_t i, j, linelen; + u32 *fb32 = gopobj->fb; + u16 *fb16 = gopobj->fb; + + if (delta) + linelen = delta; + else + linelen = width; EFI_ENTRY("%p, %p, %u, %zu, %zu, %zu, %zu, %zu, %zu, %zu", this, buffer, operation, sx, sy, dx, dy, width, height, delta); - if (operation != EFI_BLT_BUFFER_TO_VIDEO) + /* Check source rectangle */ + switch (operation) { + case EFI_BLT_VIDEO_FILL: + break; + case EFI_BLT_BUFFER_TO_VIDEO: + if (sx + width > linelen) + return EFI_EXIT(EFI_INVALID_PARAMETER); + break; + case EFI_BLT_VIDEO_TO_BLT_BUFFER: + case EFI_BLT_VIDEO_TO_VIDEO: + if (sx + width > gopobj->info.width || + sy + height > gopobj->info.height) + return EFI_EXIT(EFI_INVALID_PARAMETER); + break; + default: return EFI_EXIT(EFI_INVALID_PARAMETER); + } - fb = gopobj->fb; - line_len16 = gopobj->info.width * sizeof(u16); - line_len32 = gopobj->info.width * sizeof(u32); + /* Check destination rectangle */ + switch (operation) { + case EFI_BLT_VIDEO_FILL: + case EFI_BLT_BUFFER_TO_VIDEO: + case EFI_BLT_VIDEO_TO_VIDEO: + if (dx + width > gopobj->info.width || + dy + height > gopobj->info.height) + return EFI_EXIT(EFI_INVALID_PARAMETER); + break; + case EFI_BLT_VIDEO_TO_BLT_BUFFER: + if (dx + width > linelen) + return EFI_EXIT(EFI_INVALID_PARAMETER); + break; + } - /* Copy the contents line by line */ + for (i = 0; i < height; i++) { + for (j = 0; j < width; j++) { + struct efi_gop_pixel pix; + + /* Read source pixel */ + switch (operation) { + case EFI_BLT_VIDEO_FILL: + pix = *buffer; + break; + case EFI_BLT_BUFFER_TO_VIDEO: + pix = buffer[linelen * (i + sy) + j + sx]; + break; + case EFI_BLT_VIDEO_TO_BLT_BUFFER: + case EFI_BLT_VIDEO_TO_VIDEO: + switch (gopobj->bpix) { +#ifdef CONFIG_DM_VIDEO + case VIDEO_BPP32: +#else + case LCD_COLOR32: +#endif + pix = *(struct efi_gop_pixel *)&fb32[ + gopobj->info.width * + (i + sy) + j + sx]; + break; +#ifdef CONFIG_DM_VIDEO + case VIDEO_BPP16: +#else + case LCD_COLOR16: +#endif + pix = efi_vid16_to_blt_col(fb16[ + gopobj->info.width * + (i + sy) + j + sx]); + break; + default: + return EFI_EXIT(EFI_UNSUPPORTED); + } + break; + } - switch (gopobj->bpix) { + /* Write destination pixel */ + switch (operation) { + case EFI_BLT_VIDEO_TO_BLT_BUFFER: + buffer[linelen * (i + dy) + j + dx] = pix; + break; + case EFI_BLT_BUFFER_TO_VIDEO: + case EFI_BLT_VIDEO_FILL: + case EFI_BLT_VIDEO_TO_VIDEO: + switch (gopobj->bpix) { #ifdef CONFIG_DM_VIDEO - case VIDEO_BPP32: + case VIDEO_BPP32: #else - case LCD_COLOR32: + case LCD_COLOR32: #endif - for (i = 0; i < height; i++) { - u32 *dest = fb + ((i + dy) * line_len32) + - (dx * sizeof(u32)); - u32 *src = buffer + ((i + sy) * line_len32) + - (sx * sizeof(u32)); - - /* Same color format, just memcpy */ - memcpy(dest, src, width * sizeof(u32)); - } - break; + fb32[gopobj->info.width * + (i + dy) + j + dx] = *(u32 *)&pix; + break; #ifdef CONFIG_DM_VIDEO - case VIDEO_BPP16: + case VIDEO_BPP16: #else - case LCD_COLOR16: + case LCD_COLOR16: #endif - for (i = 0; i < height; i++) { - u16 *dest = fb + ((i + dy) * line_len16) + - (dx * sizeof(u16)); - u32 *src = buffer + ((i + sy) * line_len32) + - (sx * sizeof(u32)); - - /* Convert from rgb888 to rgb565 */ - for (j = 0; j < width; j++) { - u32 rgb888 = src[j]; - dest[j] = ((((rgb888 >> (16 + 3)) & 0x1f) << 11) | - (((rgb888 >> (8 + 2)) & 0x3f) << 5) | - (((rgb888 >> (0 + 3)) & 0x1f) << 0)); + fb16[gopobj->info.width * + (i + dy) + j + dx] = + efi_blt_col_to_vid16(&pix); + break; + default: + return EFI_EXIT(EFI_UNSUPPORTED); + } + break; } } - break; } #ifdef CONFIG_DM_VIDEO -- cgit v1.3.1 From 482fc90c0a93bdab8473bbd4c8d63732ce888bba Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 6 Feb 2018 22:00:22 +0100 Subject: efi_loader: add missing EFI_RESET_PLATFORM_SPECIFIC EFI_RESET_PLATFORM_SPECIFIC is one of the values that can be used for the EFI service ResetSystem. The missing definition is added. The value has to handled in efi_reset_system(). Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- arch/arm/cpu/armv8/fsl-layerscape/cpu.c | 1 + arch/arm/cpu/armv8/fwcall.c | 1 + arch/arm/mach-bcm283x/reset.c | 1 + include/efi_api.h | 3 ++- lib/efi_loader/efi_runtime.c | 1 + 5 files changed, 6 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/arch/arm/cpu/armv8/fsl-layerscape/cpu.c b/arch/arm/cpu/armv8/fsl-layerscape/cpu.c index 0e90302d3fb..45cbd91d97c 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/cpu.c +++ b/arch/arm/cpu/armv8/fsl-layerscape/cpu.c @@ -644,6 +644,7 @@ void __efi_runtime EFIAPI efi_reset_system( switch (reset_type) { case EFI_RESET_COLD: case EFI_RESET_WARM: + case EFI_RESET_PLATFORM_SPECIFIC: reset_cpu(0); break; case EFI_RESET_SHUTDOWN: diff --git a/arch/arm/cpu/armv8/fwcall.c b/arch/arm/cpu/armv8/fwcall.c index c2202675366..ff0712bf650 100644 --- a/arch/arm/cpu/armv8/fwcall.c +++ b/arch/arm/cpu/armv8/fwcall.c @@ -146,6 +146,7 @@ void __efi_runtime EFIAPI efi_reset_system( switch (reset_type) { case EFI_RESET_COLD: case EFI_RESET_WARM: + case EFI_RESET_PLATFORM_SPECIFIC: psci_system_reset(); break; case EFI_RESET_SHUTDOWN: diff --git a/arch/arm/mach-bcm283x/reset.c b/arch/arm/mach-bcm283x/reset.c index 5b83fdf43d6..aa02d3f9f6a 100644 --- a/arch/arm/mach-bcm283x/reset.c +++ b/arch/arm/mach-bcm283x/reset.c @@ -63,6 +63,7 @@ void __efi_runtime EFIAPI efi_reset_system( switch (reset_type) { case EFI_RESET_COLD: case EFI_RESET_WARM: + case EFI_RESET_PLATFORM_SPECIFIC: reset_cpu(0); break; case EFI_RESET_SHUTDOWN: diff --git a/include/efi_api.h b/include/efi_api.h index 167c44e3a44..28de93a1324 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -180,7 +180,8 @@ struct efi_boot_services { enum efi_reset_type { EFI_RESET_COLD = 0, EFI_RESET_WARM = 1, - EFI_RESET_SHUTDOWN = 2 + EFI_RESET_SHUTDOWN = 2, + EFI_RESET_PLATFORM_SPECIFIC = 3, }; /* EFI Runtime Services table */ diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index 9e281728f9f..08883161407 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -91,6 +91,7 @@ static void EFIAPI efi_reset_system_boottime( switch (reset_type) { case EFI_RESET_COLD: case EFI_RESET_WARM: + case EFI_RESET_PLATFORM_SPECIFIC: do_reset(NULL, 0, 0, NULL); break; case EFI_RESET_SHUTDOWN: -- cgit v1.3.1 From e2742358661137b60eccd2e80b6835b58d8c5763 Mon Sep 17 00:00:00 2001 From: Patrick Wildt Date: Tue, 27 Mar 2018 14:23:20 +0200 Subject: efi_loader: complete efi_pxe_mode struct definition The efi_pxe_mode struct which represents the PXE_BASE_CODE_PROTOCOL Replace the placeholder paddings in the efi_pxe_mode struct with the actual fields as defined in UEFI's PXE Base Code Protocol. Since our efi_ip_address is a simple char array set a specific alignment to the efi_ip_address fields, as expected by the UEFI spec. Signed-off-by: Patrick Wildt [agraf: s/pxe_discovervalid/pxe_discover_valid] Signed-off-by: Alexander Graf --- include/efi_api.h | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/efi_api.h b/include/efi_api.h index 28de93a1324..d956aee560b 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -703,7 +703,7 @@ struct efi_mac_address { struct efi_ip_address { u8 ip_addr[16]; -}; +} __attribute__((aligned(4))); enum efi_simple_network_state { EFI_NETWORK_STOPPED, @@ -797,7 +797,28 @@ struct efi_pxe_packet { struct efi_pxe_mode { - u8 unused[52]; + u8 started; + u8 ipv6_available; + u8 ipv6_supported; + u8 using_ipv6; + u8 bis_supported; + u8 bis_detected; + u8 auto_arp; + u8 send_guid; + u8 dhcp_discover_valid; + u8 dhcp_ack_received; + u8 proxy_offer_received; + u8 pxe_discover_valid; + u8 pxe_reply_received; + u8 pxe_bis_reply_received; + u8 icmp_error_received; + u8 tftp_error_received; + u8 make_callbacks; + u8 ttl; + u8 tos; + u8 pad; + struct efi_ip_address station_ip; + struct efi_ip_address subnet_mask; struct efi_pxe_packet dhcp_discover; struct efi_pxe_packet dhcp_ack; struct efi_pxe_packet proxy_offer; -- cgit v1.3.1 From 7fb96a10b31953cde698326a61e963ba9df1dc1f Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 3 Apr 2018 22:29:30 +0200 Subject: efi_loader: use efi_uintn_t for LoadImage We generally use efi_uintn_t where the UEFI spec uses UINTN. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/efi_api.h | 2 +- lib/efi_loader/efi_boottime.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/efi_api.h b/include/efi_api.h index d956aee560b..d9a69dbc005 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -107,7 +107,7 @@ struct efi_boot_services { efi_status_t (EFIAPI *load_image)(bool boot_policiy, efi_handle_t parent_image, struct efi_device_path *file_path, void *source_buffer, - unsigned long source_size, efi_handle_t *image); + efi_uintn_t source_size, efi_handle_t *image); efi_status_t (EFIAPI *start_image)(efi_handle_t handle, unsigned long *exitdata_size, s16 **exitdata); diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index fd35ffa359b..d15a131e743 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1568,14 +1568,14 @@ static efi_status_t EFIAPI 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_uintn_t source_size, efi_handle_t *image_handle) { struct efi_loaded_image *info; struct efi_object *obj; efi_status_t ret; - EFI_ENTRY("%d, %p, %pD, %p, %ld, %p", boot_policy, parent_image, + EFI_ENTRY("%d, %p, %pD, %p, %zd, %p", boot_policy, parent_image, file_path, source_buffer, source_size, image_handle); if (!image_handle || !parent_image) { -- cgit v1.3.1 From 84b40b40ad9b95b4680766597c866b604147144c Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 3 Apr 2018 22:29:31 +0200 Subject: efi_loader: save image relocation address and size For analyzing crash output the relocation address and size are needed. Save them in the loaded image info. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/efi_api.h | 2 ++ lib/efi_loader/efi_image_loader.c | 2 ++ 2 files changed, 4 insertions(+) (limited to 'include') diff --git a/include/efi_api.h b/include/efi_api.h index d9a69dbc005..2be470b2378 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -331,6 +331,8 @@ struct efi_loaded_image { /* Below are efi loader private fields */ #ifdef CONFIG_EFI_LOADER + void *reloc_base; + aligned_u64 reloc_size; efi_status_t exit_status; struct jmp_buf_data exit_jmp; #endif diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c index cac64ba9fec..701387b95f2 100644 --- a/lib/efi_loader/efi_image_loader.c +++ b/lib/efi_loader/efi_image_loader.c @@ -221,6 +221,8 @@ void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info) /* Populate the loaded image interface bits */ loaded_image_info->image_base = efi; loaded_image_info->image_size = image_size; + loaded_image_info->reloc_base = efi_reloc; + loaded_image_info->reloc_size = virt_size; return entry; } -- cgit v1.3.1 From 43dace5d897ef1ac5eadaf906d77f671e018116f Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 3 Apr 2018 22:29:33 +0200 Subject: efi_loader: correct types for EFI_LOADED_IMAGE_PROTOCOL We should not use void * but specific types for * device_handle * file_path Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/efi_api.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/efi_api.h b/include/efi_api.h index 2be470b2378..f5bb6ec1719 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -318,8 +318,8 @@ struct efi_loaded_image { u32 revision; void *parent_handle; struct efi_system_table *system_table; - void *device_handle; - void *file_path; + efi_handle_t device_handle; + struct efi_device_path *file_path; void *reserved; u32 load_options_size; void *load_options; -- cgit v1.3.1 From b6dd57773719bfcea6a295973c349b7842870337 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 3 Apr 2018 22:37:11 +0200 Subject: efi_loader: use correct types in EFI_FILE_PROTOCOL In the EFI_FILE_PROTOCOL buffer sizes and positions are passed as UINTN and not as u64. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/efi_api.h | 14 +++++---- lib/efi_loader/efi_boottime.c | 5 +-- lib/efi_loader/efi_file.c | 47 +++++++++++++++++++++------- lib/efi_selftest/efi_selftest_block_device.c | 2 +- 4 files changed, 47 insertions(+), 21 deletions(-) (limited to 'include') diff --git a/include/efi_api.h b/include/efi_api.h index f5bb6ec1719..396f45eaa8f 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -858,17 +858,19 @@ struct efi_file_handle { efi_status_t (EFIAPI *close)(struct efi_file_handle *file); efi_status_t (EFIAPI *delete)(struct efi_file_handle *file); efi_status_t (EFIAPI *read)(struct efi_file_handle *file, - u64 *buffer_size, void *buffer); + efi_uintn_t *buffer_size, void *buffer); efi_status_t (EFIAPI *write)(struct efi_file_handle *file, - u64 *buffer_size, void *buffer); + efi_uintn_t *buffer_size, void *buffer); efi_status_t (EFIAPI *getpos)(struct efi_file_handle *file, - u64 *pos); + efi_uintn_t *pos); efi_status_t (EFIAPI *setpos)(struct efi_file_handle *file, - u64 pos); + efi_uintn_t pos); efi_status_t (EFIAPI *getinfo)(struct efi_file_handle *file, - efi_guid_t *info_type, u64 *buffer_size, void *buffer); + efi_guid_t *info_type, efi_uintn_t *buffer_size, + void *buffer); efi_status_t (EFIAPI *setinfo)(struct efi_file_handle *file, - efi_guid_t *info_type, u64 buffer_size, void *buffer); + efi_guid_t *info_type, efi_uintn_t buffer_size, + void *buffer); efi_status_t (EFIAPI *flush)(struct efi_file_handle *file); }; diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index d15a131e743..7a9449f59c3 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1513,7 +1513,7 @@ efi_status_t efi_load_image_from_path(struct efi_device_path *file_path, struct efi_file_info *info = NULL; struct efi_file_handle *f; static efi_status_t ret; - uint64_t bs; + efi_uintn_t bs; f = efi_file_from_path(file_path); if (!f) @@ -1534,7 +1534,8 @@ efi_status_t efi_load_image_from_path(struct efi_device_path *file_path, if (ret) goto error; - EFI_CALL(ret = f->read(f, &info->file_size, *buffer)); + bs = info->file_size; + EFI_CALL(ret = f->read(f, &bs, *buffer)); error: free(info); diff --git a/lib/efi_loader/efi_file.c b/lib/efi_loader/efi_file.c index 52a4e7438e3..0be0f8b807e 100644 --- a/lib/efi_loader/efi_file.c +++ b/lib/efi_loader/efi_file.c @@ -314,29 +314,41 @@ static efi_status_t dir_read(struct file_handle *fh, u64 *buffer_size, } static efi_status_t EFIAPI efi_file_read(struct efi_file_handle *file, - u64 *buffer_size, void *buffer) + efi_uintn_t *buffer_size, void *buffer) { struct file_handle *fh = to_fh(file); efi_status_t ret = EFI_SUCCESS; + u64 bs; EFI_ENTRY("%p, %p, %p", file, buffer_size, buffer); + if (!buffer_size || !buffer) { + ret = EFI_INVALID_PARAMETER; + goto error; + } + if (set_blk_dev(fh)) { ret = EFI_DEVICE_ERROR; goto error; } + bs = *buffer_size; if (fh->isdir) - ret = dir_read(fh, buffer_size, buffer); + ret = dir_read(fh, &bs, buffer); else - ret = file_read(fh, buffer_size, buffer); + ret = file_read(fh, &bs, buffer); + if (bs <= SIZE_MAX) + *buffer_size = bs; + else + *buffer_size = SIZE_MAX; error: return EFI_EXIT(ret); } static efi_status_t EFIAPI efi_file_write(struct efi_file_handle *file, - u64 *buffer_size, void *buffer) + efi_uintn_t *buffer_size, + void *buffer) { struct file_handle *fh = to_fh(file); efi_status_t ret = EFI_SUCCESS; @@ -363,21 +375,27 @@ error: } static efi_status_t EFIAPI efi_file_getpos(struct efi_file_handle *file, - u64 *pos) + efi_uintn_t *pos) { struct file_handle *fh = to_fh(file); + EFI_ENTRY("%p, %p", file, pos); - *pos = fh->offset; - return EFI_EXIT(EFI_SUCCESS); + + if (fh->offset <= SIZE_MAX) { + *pos = fh->offset; + return EFI_EXIT(EFI_SUCCESS); + } else { + return EFI_EXIT(EFI_DEVICE_ERROR); + } } static efi_status_t EFIAPI efi_file_setpos(struct efi_file_handle *file, - u64 pos) + efi_uintn_t pos) { struct file_handle *fh = to_fh(file); efi_status_t ret = EFI_SUCCESS; - EFI_ENTRY("%p, %llu", file, pos); + EFI_ENTRY("%p, %zu", file, pos); if (fh->isdir) { if (pos != 0) { @@ -411,7 +429,9 @@ error: } static efi_status_t EFIAPI efi_file_getinfo(struct efi_file_handle *file, - efi_guid_t *info_type, u64 *buffer_size, void *buffer) + efi_guid_t *info_type, + efi_uintn_t *buffer_size, + void *buffer) { struct file_handle *fh = to_fh(file); efi_status_t ret = EFI_SUCCESS; @@ -461,9 +481,12 @@ error: } static efi_status_t EFIAPI efi_file_setinfo(struct efi_file_handle *file, - efi_guid_t *info_type, u64 buffer_size, void *buffer) + efi_guid_t *info_type, + efi_uintn_t buffer_size, + void *buffer) { - EFI_ENTRY("%p, %p, %llu, %p", file, info_type, buffer_size, buffer); + EFI_ENTRY("%p, %p, %zu, %p", file, info_type, buffer_size, buffer); + return EFI_EXIT(EFI_UNSUPPORTED); } diff --git a/lib/efi_selftest/efi_selftest_block_device.c b/lib/efi_selftest/efi_selftest_block_device.c index 9e4b93d9a61..b07b22465f4 100644 --- a/lib/efi_selftest/efi_selftest_block_device.c +++ b/lib/efi_selftest/efi_selftest_block_device.c @@ -302,7 +302,7 @@ static int execute(void) struct efi_device_path *dp_partition; struct efi_simple_file_system_protocol *file_system; struct efi_file_handle *root, *file; - u64 buf_size; + efi_uintn_t buf_size; char buf[16] __aligned(ARCH_DMA_MINALIGN); ret = boottime->connect_controller(disk_handle, NULL, NULL, 1); -- cgit v1.3.1 From 9c9021e24571505d76969d8fd37b3b5e06ad2590 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 4 Apr 2018 15:42:09 +0200 Subject: efi_loader: use const for GUIDs in the EFI_FILE_PROTOCOL Use const efi_guid_t* when passing GUIDs. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/efi_api.h | 4 ++-- lib/efi_loader/efi_file.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/efi_api.h b/include/efi_api.h index 396f45eaa8f..8af466a6dc7 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -866,10 +866,10 @@ struct efi_file_handle { efi_status_t (EFIAPI *setpos)(struct efi_file_handle *file, efi_uintn_t pos); efi_status_t (EFIAPI *getinfo)(struct efi_file_handle *file, - efi_guid_t *info_type, efi_uintn_t *buffer_size, + const efi_guid_t *info_type, efi_uintn_t *buffer_size, void *buffer); efi_status_t (EFIAPI *setinfo)(struct efi_file_handle *file, - efi_guid_t *info_type, efi_uintn_t buffer_size, + const efi_guid_t *info_type, efi_uintn_t buffer_size, void *buffer); efi_status_t (EFIAPI *flush)(struct efi_file_handle *file); }; diff --git a/lib/efi_loader/efi_file.c b/lib/efi_loader/efi_file.c index 0be0f8b807e..2fc77cfb874 100644 --- a/lib/efi_loader/efi_file.c +++ b/lib/efi_loader/efi_file.c @@ -429,7 +429,7 @@ error: } static efi_status_t EFIAPI efi_file_getinfo(struct efi_file_handle *file, - efi_guid_t *info_type, + const efi_guid_t *info_type, efi_uintn_t *buffer_size, void *buffer) { @@ -481,7 +481,7 @@ error: } static efi_status_t EFIAPI efi_file_setinfo(struct efi_file_handle *file, - efi_guid_t *info_type, + const efi_guid_t *info_type, efi_uintn_t buffer_size, void *buffer) { -- cgit v1.3.1 From c412166de28e7f7722b42a4c4c5e637da2d570ee Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 4 Apr 2018 15:42:10 +0200 Subject: efi_loader: ascii2unicode(): add trailing \0 When converting an ASCII string to UTF-16 don't forget to copy the trailing \0. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/efi_loader.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/efi_loader.h b/include/efi_loader.h index 0df482ee217..21e6692e92d 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -352,6 +352,7 @@ static inline void ascii2unicode(u16 *unicode, const char *ascii) { while (*ascii) *(unicode++) = *(ascii++); + *unicode = 0; } static inline int guidcmp(const efi_guid_t *g1, const efi_guid_t *g2) -- cgit v1.3.1 From 9e6835e6baab3d56e1bb2d4b96ee80f98e2196e7 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 4 Apr 2018 15:42:11 +0200 Subject: efi_loader: implement EFI_FILE_SYSTEM_INFO Implement the information type EFI_FILE_SYSTEM_INFO in the service GetInfo() of the EFI_FILE_PROTOCOL. The volume label is not available in U-Boot. As a work-around use the partition name instead. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/efi_api.h | 13 +++++++++++++ include/efi_loader.h | 2 ++ lib/efi_loader/efi_file.c | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+) (limited to 'include') diff --git a/include/efi_api.h b/include/efi_api.h index 8af466a6dc7..ae930611606 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -889,6 +889,10 @@ struct efi_simple_file_system_protocol { EFI_GUID(0x9576e92, 0x6d3f, 0x11d2, \ 0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b) +#define EFI_FILE_SYSTEM_INFO_GUID \ + EFI_GUID(0x09576e93, 0x6d3f, 0x11d2, \ + 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) + #define EFI_FILE_MODE_READ 0x0000000000000001 #define EFI_FILE_MODE_WRITE 0x0000000000000002 #define EFI_FILE_MODE_CREATE 0x8000000000000000 @@ -912,6 +916,15 @@ struct efi_file_info { s16 file_name[0]; }; +struct efi_file_system_info { + u64 size; + u8 read_only; + u64 volume_size; + u64 free_space; + u32 block_size; + u16 volume_label[0]; +}; + #define EFI_DRIVER_BINDING_PROTOCOL_GUID \ EFI_GUID(0x18a031ab, 0xb443, 0x4d1a,\ 0xa5, 0xc0, 0x0c, 0x09, 0x26, 0x1e, 0x9f, 0x71) diff --git a/include/efi_loader.h b/include/efi_loader.h index 21e6692e92d..f2942fbb2b6 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -112,6 +112,8 @@ extern const efi_guid_t efi_guid_loaded_image; extern const efi_guid_t efi_guid_device_path_to_text_protocol; extern const efi_guid_t efi_simple_file_system_protocol_guid; extern const efi_guid_t efi_file_info_guid; +/* GUID for file system information */ +extern const efi_guid_t efi_file_system_info_guid; extern const efi_guid_t efi_guid_device_path_utilities_protocol; extern unsigned int __efi_runtime_start, __efi_runtime_stop; diff --git a/lib/efi_loader/efi_file.c b/lib/efi_loader/efi_file.c index 2fc77cfb874..cec8347f558 100644 --- a/lib/efi_loader/efi_file.c +++ b/lib/efi_loader/efi_file.c @@ -12,6 +12,9 @@ #include #include +/* GUID for file system information */ +const efi_guid_t efi_file_system_info_guid = EFI_FILE_SYSTEM_INFO_GUID; + struct file_system { struct efi_simple_file_system_protocol base; struct efi_device_path *dp; @@ -472,6 +475,41 @@ static efi_status_t EFIAPI efi_file_getinfo(struct efi_file_handle *file, info->attribute |= EFI_FILE_DIRECTORY; ascii2unicode((u16 *)info->file_name, filename); + } else if (!guidcmp(info_type, &efi_file_system_info_guid)) { + struct efi_file_system_info *info = buffer; + disk_partition_t part; + efi_uintn_t required_size; + int r; + + if (fh->fs->part >= 1) + r = part_get_info(fh->fs->desc, fh->fs->part, &part); + else + r = part_get_info_whole_disk(fh->fs->desc, &part); + if (r < 0) { + ret = EFI_DEVICE_ERROR; + goto error; + } + required_size = sizeof(info) + 2 * + (strlen((const char *)part.name) + 1); + if (*buffer_size < required_size) { + *buffer_size = required_size; + ret = EFI_BUFFER_TOO_SMALL; + goto error; + } + + memset(info, 0, required_size); + + info->size = required_size; + info->read_only = true; + info->volume_size = part.size * part.blksz; + info->free_space = 0; + info->block_size = part.blksz; + /* + * TODO: The volume label is not available in U-Boot. + * Use the partition name as substitute. + */ + ascii2unicode((u16 *)info->volume_label, + (const char *)part.name); } else { ret = EFI_UNSUPPORTED; } -- cgit v1.3.1 From c9a63f44b526696a60e275087d79fe709f65f48b Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 5 Apr 2018 11:56:21 +0200 Subject: efi_loader: new functions to print loaded image information Introduce functions to print information about loaded images. If we want to analyze an exception in an EFI image we need the offset between the PC and the start of the loaded image. With efi_print_image_info() we can print the necessary information for a single image, e.g. UEFI image [0xbffe6000:0xbffe631f] pc=0x138 '/\snp.efi' efi_print_image_infos() provides output for all loaded images. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/efi_loader.h | 5 +++++ lib/efi_loader/efi_image_loader.c | 46 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) (limited to 'include') diff --git a/include/efi_loader.h b/include/efi_loader.h index f2942fbb2b6..17f9d3d1ef2 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -308,6 +308,10 @@ efi_status_t efi_setup_loaded_image( struct efi_device_path *file_path); efi_status_t efi_load_image_from_path(struct efi_device_path *file_path, void **buffer); +/* Print information about a loaded image */ +efi_status_t efi_print_image_info(struct efi_loaded_image *image, void *pc); +/* Print information about all loaded images */ +void efi_print_image_infos(void *pc); #ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER extern void *efi_bounce_buffer; @@ -425,6 +429,7 @@ static inline void efi_restore_gd(void) { } static inline void efi_set_bootdev(const char *dev, const char *devnr, const char *path) { } static inline void efi_net_set_dhcp_ack(void *pkt, int len) { } +static inline void efi_print_image_infos(void *pc) { } #endif /* CONFIG_EFI_LOADER && !CONFIG_SPL_BUILD */ diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c index 74c6a9f9213..f5885760d41 100644 --- a/lib/efi_loader/efi_image_loader.c +++ b/lib/efi_loader/efi_image_loader.c @@ -22,6 +22,52 @@ const efi_guid_t efi_simple_file_system_protocol_guid = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID; const efi_guid_t efi_file_info_guid = EFI_FILE_INFO_GUID; +/* + * Print information about a loaded image. + * + * If the program counter is located within the image the offset to the base + * address is shown. + * + * @image: loaded image + * @pc: program counter (use NULL to suppress offset output) + * @return: status code + */ +efi_status_t efi_print_image_info(struct efi_loaded_image *image, void *pc) +{ + if (!image) + return EFI_INVALID_PARAMETER; + printf("UEFI image"); + printf(" [0x%p:0x%p]", + image->reloc_base, image->reloc_base + image->reloc_size - 1); + if (pc && pc >= image->reloc_base && + pc < image->reloc_base + image->reloc_size) + printf(" pc=0x%zx", pc - image->reloc_base); + if (image->file_path) + printf(" '%pD'", image->file_path); + printf("\n"); + return EFI_SUCCESS; +} + +/* + * Print information about all loaded images. + * + * @pc: program counter (use NULL to suppress offset output) + */ +void efi_print_image_infos(void *pc) +{ + struct efi_object *efiobj; + struct efi_handler *handler; + + list_for_each_entry(efiobj, &efi_obj_list, link) { + list_for_each_entry(handler, &efiobj->protocols, link) { + if (!guidcmp(handler->guid, &efi_guid_loaded_image)) { + efi_print_image_info( + handler->protocol_interface, pc); + } + } + } +} + static efi_status_t efi_loader_relocate(const IMAGE_BASE_RELOCATION *rel, unsigned long rel_size, void *efi_reloc) { -- cgit v1.3.1 From 61a5ced6ad9376a0755ea2a920667e3a9072990c Mon Sep 17 00:00:00 2001 From: Ivan Gorinov Date: Thu, 5 Apr 2018 18:32:06 -0700 Subject: efi_loader: Check machine type in the image header Check FileHeader.Machine to make sure the EFI executable image is built for the same architecture. For example, 32-bit U-Boot on x86 will print an error message instead of loading an x86_64 image and crashing. Signed-off-by: Ivan Gorinov Signed-off-by: Alexander Graf --- include/pe.h | 4 +++ lib/efi_loader/efi_image_loader.c | 51 ++++++++++++++++++++++++++++++--------- 2 files changed, 43 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/include/pe.h b/include/pe.h index c3a19cef765..e7845bb7d2c 100644 --- a/include/pe.h +++ b/include/pe.h @@ -38,11 +38,15 @@ typedef struct _IMAGE_DOS_HEADER { #define IMAGE_DOS_SIGNATURE 0x5A4D /* MZ */ #define IMAGE_NT_SIGNATURE 0x00004550 /* PE00 */ +#define IMAGE_FILE_MACHINE_I386 0x014c #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_FILE_MACHINE_RISCV32 0x5032 +#define IMAGE_FILE_MACHINE_RISCV64 0x5064 + #define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b #define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b #define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c index f5885760d41..d5fbba31383 100644 --- a/lib/efi_loader/efi_image_loader.c +++ b/lib/efi_loader/efi_image_loader.c @@ -22,6 +22,30 @@ const efi_guid_t efi_simple_file_system_protocol_guid = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID; const efi_guid_t efi_file_info_guid = EFI_FILE_INFO_GUID; +static int machines[] = { +#if defined(CONFIG_ARM64) + IMAGE_FILE_MACHINE_ARM64, +#elif defined(CONFIG_ARM) + IMAGE_FILE_MACHINE_ARM, + IMAGE_FILE_MACHINE_THUMB, + IMAGE_FILE_MACHINE_ARMNT, +#endif + +#if defined(CONFIG_X86_64) + IMAGE_FILE_MACHINE_AMD64, +#elif defined(CONFIG_X86) + IMAGE_FILE_MACHINE_I386, +#endif + +#if defined(CONFIG_CPU_RISCV_32) + IMAGE_FILE_MACHINE_RISCV32, +#endif + +#if defined(CONFIG_CPU_RISCV_64) + IMAGE_FILE_MACHINE_RISCV64, +#endif + 0 }; + /* * Print information about a loaded image. * @@ -172,14 +196,7 @@ void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info) void *entry; uint64_t image_size; unsigned long virt_size = 0; - bool can_run_nt64 = true; - bool can_run_nt32 = true; - -#if defined(CONFIG_ARM64) - can_run_nt32 = false; -#elif defined(CONFIG_ARM) - can_run_nt64 = false; -#endif + int supported = 0; dos = efi; if (dos->e_magic != IMAGE_DOS_SIGNATURE) { @@ -193,6 +210,18 @@ void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info) return NULL; } + for (i = 0; machines[i]; i++) + if (machines[i] == nt->FileHeader.Machine) { + supported = 1; + break; + } + + if (!supported) { + printf("%s: Machine type 0x%04x is not supported\n", + __func__, nt->FileHeader.Machine); + return NULL; + } + /* Calculate upper virtual address boundary */ num_sections = nt->FileHeader.NumberOfSections; sections = (void *)&nt->OptionalHeader + @@ -205,8 +234,7 @@ void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info) } /* Read 32/64bit specific header bits */ - if (can_run_nt64 && - (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)) { + 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; @@ -222,8 +250,7 @@ void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info) rel_size = opt->DataDirectory[rel_idx].Size; rel = efi_reloc + opt->DataDirectory[rel_idx].VirtualAddress; virt_size = ALIGN(virt_size, opt->SectionAlignment); - } else if (can_run_nt32 && - (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)) { + } else if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { IMAGE_OPTIONAL_HEADER32 *opt = &nt->OptionalHeader; image_size = opt->SizeOfImage; efi_set_code_and_data_type(loaded_image_info, opt->Subsystem); -- cgit v1.3.1