From 268ec6e00e57497b96ebd4a5a5dc60b821e13fb0 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 31 Jan 2018 18:45:35 +0000 Subject: efi_loader: fix building crt0 on arm Before the patch an undefined constant EFI_SUBSYSTEM was used in the crt0 code. The current version of binutils does not swallow the error. https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=888403 The necessary constant IMAGE_SUBSYSTEM_EFI_APPLICATION is already defined in pe.h. So let's factor out asm-generic/pe.h for the image subsystem constants and use it in our assembler code. IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER does not exist in the specification let's use IMAGE_SUBSYSTEM_EFI_ROM instead. The include pe.h is only used in code maintained by Alex so let him be the maintainer here too. Reported-by: Andre Przywara Signed-off-by: Heinrich Schuchardt Tested-by: Vagrant Cascadian Signed-off-by: Alexander Graf --- include/asm-generic/pe.h | 21 +++++++++++++++++++++ include/pe.h | 8 ++------ 2 files changed, 23 insertions(+), 6 deletions(-) create mode 100644 include/asm-generic/pe.h (limited to 'include') diff --git a/include/asm-generic/pe.h b/include/asm-generic/pe.h new file mode 100644 index 00000000000..d1683f238af --- /dev/null +++ b/include/asm-generic/pe.h @@ -0,0 +1,21 @@ +/* + * Portable Executable and Common Object Constants + * + * Copyright (c) 2018 Heinrich Schuchardt + * + * based on the "Microsoft Portable Executable and Common Object File Format + * Specification", revision 11, 2017-01-23 + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _ASM_PE_H +#define _ASM_PE_H + +/* Subsystem type */ +#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 +#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 +#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 +#define IMAGE_SUBSYSTEM_EFI_ROM 13 + +#endif /* _ASM_PE_H */ diff --git a/include/pe.h b/include/pe.h index 4ef3e92efaf..c3a19cef765 100644 --- a/include/pe.h +++ b/include/pe.h @@ -11,6 +11,8 @@ #ifndef _PE_H #define _PE_H +#include + typedef struct _IMAGE_DOS_HEADER { uint16_t e_magic; /* 00: MZ Header signature */ uint16_t e_cblp; /* 02: Bytes on last page of file */ @@ -62,12 +64,6 @@ typedef struct _IMAGE_DATA_DIRECTORY { #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 -/* PE32+ Subsystem type for EFI images */ -#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 -#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 -#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 -#define IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER 13 - typedef struct _IMAGE_OPTIONAL_HEADER64 { uint16_t Magic; /* 0x20b */ uint8_t MajorLinkerVersion; -- cgit v1.3.1 From 9f0930e5d9c71a97b14f8993b3d3150a79b6a2ef Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 4 Feb 2018 23:05:13 +0100 Subject: efi_loader: create stub for CreateEventEx Currently we set the function pointer for the CreateEventEx boot service to NULL. When called this would lead to an immediate failure. A function stub is provided which handles the case that the boot service is called without an event group and returns EFI_UNSUPPORTED otherwise. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/efi_api.h | 9 ++++++++- lib/efi_loader/efi_boottime.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/efi_api.h b/include/efi_api.h index 205f8f1f700..10598a22d55 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -166,7 +166,14 @@ struct efi_boot_services { void (EFIAPI *copy_mem)(void *destination, const void *source, size_t length); void (EFIAPI *set_mem)(void *buffer, size_t size, uint8_t value); - void *create_event_ex; + efi_status_t (EFIAPI *create_event_ex)( + uint32_t type, efi_uintn_t notify_tpl, + void (EFIAPI *notify_function) ( + struct efi_event *event, + void *context), + void *notify_context, + efi_guid_t *event_group, + struct efi_event **event); }; /* Types and defines for EFI ResetSystem */ diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index da93498b36b..2cea712196e 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -525,6 +525,38 @@ efi_status_t efi_create_event(uint32_t type, efi_uintn_t notify_tpl, return EFI_OUT_OF_RESOURCES; } +/* + * Create an event in a group. + * + * This function implements the CreateEventEx service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * TODO: Support event groups + * + * @type type of the event to create + * @notify_tpl task priority level of the event + * @notify_function notification function of the event + * @notify_context pointer passed to the notification function + * @event created event + * @event_group event group + * @return status code + */ +efi_status_t EFIAPI efi_create_event_ex(uint32_t type, efi_uintn_t notify_tpl, + void (EFIAPI *notify_function) ( + struct efi_event *event, + void *context), + void *notify_context, + efi_guid_t *event_group, + struct efi_event **event) +{ + 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)); +} + /* * Create an event. * @@ -2851,6 +2883,7 @@ static const struct efi_boot_services efi_boot_services = { .calculate_crc32 = efi_calculate_crc32, .copy_mem = efi_copy_mem, .set_mem = efi_set_mem, + .create_event_ex = efi_create_event_ex, }; -- cgit v1.3.1 From 038782a27ad24260a4bc536772e10c351cf6522d Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 1 Feb 2018 12:53:32 +0100 Subject: efi_driver: return type of efi_driver_init() Change the return type of efi_driver_init() to efi_status_t. efi_driver_init() calls efi_add_driver() which returns an efi_status_t value. efi_driver_init() should not subject this value to a conversion to int losing high bits on 64bit systems. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/efi_loader.h | 2 +- lib/efi_driver/efi_uclass.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/efi_loader.h b/include/efi_loader.h index 21c03c5c28f..a2d82e1db73 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -272,7 +272,7 @@ efi_status_t efi_get_memory_map(efi_uintn_t *memory_map_size, uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type, bool overlap_only_ram); /* Called by board init to initialize the EFI drivers */ -int efi_driver_init(void); +efi_status_t efi_driver_init(void); /* Called by board init to initialize the EFI memory map */ int efi_memory_init(void); /* Adds new or overrides configuration table entry to the system table */ diff --git a/lib/efi_driver/efi_uclass.c b/lib/efi_driver/efi_uclass.c index 90797f96d8d..46b69b479cb 100644 --- a/lib/efi_driver/efi_uclass.c +++ b/lib/efi_driver/efi_uclass.c @@ -287,10 +287,10 @@ out: * * @return 0 = success, any other value will stop further execution */ -int efi_driver_init(void) +efi_status_t efi_driver_init(void) { struct driver *drv; - int ret = 0; + efi_status_t ret = EFI_SUCCESS; /* Save 'gd' pointer */ efi_save_gd(); @@ -300,7 +300,7 @@ int efi_driver_init(void) drv < ll_entry_end(struct driver, driver); ++drv) { if (drv->id == UCLASS_EFI) { ret = efi_add_driver(drv); - if (ret) { + if (ret != EFI_SUCCESS) { printf("EFI: ERROR: failed to add driver %s\n", drv->name); break; -- cgit v1.3.1 From 0c2307431e6ea3deb916ba1622046299df077ced Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 9 Feb 2018 20:41:21 +0100 Subject: efi_loader: add missing runtime services stubs Add stubs for UpdateCapsule, QueryCapsuleCapabilities, and QueryVariableInfo. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/efi_api.h | 28 +++++++++++++++++++++++++--- lib/efi_loader/efi_runtime.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/efi_api.h b/include/efi_api.h index 10598a22d55..3ba650e57e6 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -187,6 +187,17 @@ enum efi_reset_type { #define EFI_RUNTIME_SERVICES_SIGNATURE 0x5652453544e5552ULL #define EFI_RUNTIME_SERVICES_REVISION 0x00010000 +#define CAPSULE_FLAGS_PERSIST_ACROSS_RESET 0x00010000 +#define CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE 0x00020000 +#define CAPSULE_FLAGS_INITIATE_RESET 0x00040000 + +struct efi_capsule_header { + efi_guid_t *capsule_guid; + u32 header_size; + u32 flags; + u32 capsule_image_size; +}; + struct efi_runtime_services { struct efi_table_hdr hdr; efi_status_t (EFIAPI *get_time)(struct efi_time *time, @@ -216,9 +227,20 @@ struct efi_runtime_services { void (EFIAPI *reset_system)(enum efi_reset_type reset_type, efi_status_t reset_status, unsigned long data_size, void *reset_data); - void *update_capsule; - void *query_capsule_caps; - void *query_variable_info; + efi_status_t (EFIAPI *update_capsule)( + struct efi_capsule_header **capsule_header_array, + efi_uintn_t capsule_count, + u64 scatter_gather_list); + efi_status_t (EFIAPI *query_capsule_caps)( + struct efi_capsule_header **capsule_header_array, + efi_uintn_t capsule_count, + u64 maximum_capsule_size, + u32 reset_type); + efi_status_t (EFIAPI *query_variable_info)( + u32 attributes, + u64 maximum_variable_storage_size, + u64 remaining_variable_storage_size, + u64 maximum_variable_size); }; /* EFI Configuration Table and GUID definitions */ diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index 8104e08c466..ccb4fc6141b 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -381,6 +381,32 @@ static efi_status_t __efi_runtime EFIAPI efi_invalid_parameter(void) return EFI_INVALID_PARAMETER; } +efi_status_t __efi_runtime EFIAPI efi_update_capsule( + struct efi_capsule_header **capsule_header_array, + efi_uintn_t capsule_count, + u64 scatter_gather_list) +{ + return EFI_UNSUPPORTED; +} + +efi_status_t __efi_runtime EFIAPI efi_query_capsule_caps( + struct efi_capsule_header **capsule_header_array, + efi_uintn_t capsule_count, + u64 maximum_capsule_size, + u32 reset_type) +{ + return EFI_UNSUPPORTED; +} + +efi_status_t __efi_runtime EFIAPI efi_query_variable_info( + u32 attributes, + u64 maximum_variable_storage_size, + u64 remaining_variable_storage_size, + u64 maximum_variable_size) +{ + return EFI_UNSUPPORTED; +} + struct efi_runtime_services __efi_runtime_data efi_runtime_services = { .hdr = { .signature = EFI_RUNTIME_SERVICES_SIGNATURE, @@ -398,4 +424,7 @@ struct efi_runtime_services __efi_runtime_data efi_runtime_services = { .set_variable = efi_set_variable, .get_next_high_mono_count = (void *)&efi_device_error, .reset_system = &efi_reset_system_boottime, + .update_capsule = efi_update_capsule, + .query_capsule_caps = efi_query_capsule_caps, + .query_variable_info = efi_query_variable_info, }; -- cgit v1.3.1 From df9cf561b04dd3fc5a94f7a2c2500948ae8ba56b Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 9 Feb 2018 20:55:47 +0100 Subject: efi_loader: correct efi_disk_register efi_disk_register should return as status code (efi_status_t). Disks with zero blocks should be reported as 'not ready' without throwing an error. This patch solves a problem running OpenBSD on system configured with CONFIG_BLK=n (e.g. i.MX6). Reported-by: Jonathan Gray Signed-off-by: Heinrich Schuchardt Tested-by: Jonathan Gray Signed-off-by: Alexander Graf --- include/efi_loader.h | 2 +- lib/efi_loader/efi_disk.c | 71 +++++++++++++++++++++++++++++------------------ 2 files changed, 45 insertions(+), 28 deletions(-) (limited to 'include') diff --git a/include/efi_loader.h b/include/efi_loader.h index a2d82e1db73..07730c3f394 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -173,7 +173,7 @@ extern struct list_head efi_obj_list; /* Called by bootefi to make console interface available */ int efi_console_register(void); /* Called by bootefi to make all disk storage accessible as EFI objects */ -int efi_disk_register(void); +efi_status_t efi_disk_register(void); /* Create handles and protocols for the partitions of a block device */ int efi_disk_create_partitions(efi_handle_t parent, struct blk_desc *desc, const char *if_typename, int diskid, diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index ac39a65ee89..825a6d86de8 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -226,25 +226,26 @@ efi_fs_from_path(struct efi_device_path *full_path) * @offset offset into disk for simple partitions * @return disk object */ -static struct efi_disk_obj *efi_disk_add_dev( +static efi_status_t efi_disk_add_dev( efi_handle_t parent, struct efi_device_path *dp_parent, const char *if_typename, struct blk_desc *desc, int dev_index, lbaint_t offset, - unsigned int part) + unsigned int part, + struct efi_disk_obj **disk) { struct efi_disk_obj *diskobj; efi_status_t ret; /* Don't add empty devices */ if (!desc->lba) - return NULL; + return EFI_NOT_READY; diskobj = calloc(1, sizeof(*diskobj)); if (!diskobj) - goto out_of_memory; + return EFI_OUT_OF_RESOURCES; /* Hook up to the device list */ efi_add_handle(&diskobj->parent); @@ -262,11 +263,11 @@ static struct efi_disk_obj *efi_disk_add_dev( ret = efi_add_protocol(diskobj->parent.handle, &efi_block_io_guid, &diskobj->ops); if (ret != EFI_SUCCESS) - goto out_of_memory; + return ret; ret = efi_add_protocol(diskobj->parent.handle, &efi_guid_device_path, diskobj->dp); if (ret != EFI_SUCCESS) - goto out_of_memory; + return ret; if (part >= 1) { diskobj->volume = efi_simple_file_system(desc, part, diskobj->dp); @@ -274,7 +275,7 @@ static struct efi_disk_obj *efi_disk_add_dev( &efi_simple_file_system_protocol_guid, diskobj->volume); if (ret != EFI_SUCCESS) - goto out_of_memory; + return ret; } diskobj->ops = block_io_disk_template; diskobj->ifname = if_typename; @@ -291,10 +292,9 @@ static struct efi_disk_obj *efi_disk_add_dev( if (part != 0) diskobj->media.logical_partition = 1; diskobj->ops.media = &diskobj->media; - return diskobj; -out_of_memory: - printf("ERROR: Out of memory\n"); - return NULL; + if (disk) + *disk = diskobj; + return EFI_SUCCESS; } /* @@ -330,8 +330,12 @@ int efi_disk_create_partitions(efi_handle_t parent, struct blk_desc *desc, continue; snprintf(devname, sizeof(devname), "%s:%d", pdevname, part); - efi_disk_add_dev(parent, dp, if_typename, desc, diskid, - info.start, part); + ret = efi_disk_add_dev(parent, dp, if_typename, desc, diskid, + info.start, part, NULL); + if (ret != EFI_SUCCESS) { + printf("Adding partition %s failed\n", pdevname); + continue; + } disks++; } @@ -349,26 +353,32 @@ int efi_disk_create_partitions(efi_handle_t parent, struct blk_desc *desc, * * This gets called from do_bootefi_exec(). */ -int efi_disk_register(void) +efi_status_t efi_disk_register(void) { struct efi_disk_obj *disk; int disks = 0; + efi_status_t ret; #ifdef CONFIG_BLK struct udevice *dev; - for (uclass_first_device_check(UCLASS_BLK, &dev); - dev; + for (uclass_first_device_check(UCLASS_BLK, &dev); dev; uclass_next_device_check(&dev)) { struct blk_desc *desc = dev_get_uclass_platdata(dev); const char *if_typename = blk_get_if_type_name(desc->if_type); - printf("Scanning disk %s...\n", dev->name); - /* Add block device for the full device */ - disk = efi_disk_add_dev(NULL, NULL, if_typename, - desc, desc->devnum, 0, 0); - if (!disk) - return -ENOMEM; + printf("Scanning disk %s...\n", dev->name); + ret = efi_disk_add_dev(NULL, NULL, if_typename, + desc, desc->devnum, 0, 0, &disk); + if (ret == EFI_NOT_READY) { + printf("Disk %s not ready\n", dev->name); + continue; + } + if (ret) { + printf("ERROR: failure to add disk device %s, r = %lu\n", + dev->name, ret & ~EFI_ERROR_MASK); + return ret; + } disks++; /* Partitions show up as block devices in EFI */ @@ -404,10 +414,17 @@ int efi_disk_register(void) if_typename, i); /* Add block device for the full device */ - disk = efi_disk_add_dev(NULL, NULL, if_typename, desc, - i, 0, 0); - if (!disk) - return -ENOMEM; + ret = efi_disk_add_dev(NULL, NULL, if_typename, desc, + i, 0, 0, &disk); + if (ret == EFI_NOT_READY) { + printf("Disk %s not ready\n", devname); + continue; + } + if (ret) { + printf("ERROR: failure to add disk device %s, r = %lu\n", + devname, ret & ~EFI_ERROR_MASK); + return ret; + } disks++; /* Partitions show up as block devices in EFI */ @@ -419,5 +436,5 @@ int efi_disk_register(void) #endif printf("Found %d disks\n", disks); - return 0; + return EFI_SUCCESS; } -- cgit v1.3.1