summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/lib/elf_arm_efi.lds11
-rw-r--r--include/efi_loader.h10
-rw-r--r--lib/efi_loader/efi_boottime.c228
-rw-r--r--lib/efi_loader/efi_device_path.c56
-rw-r--r--lib/efi_loader/efi_device_path_to_text.c43
-rw-r--r--lib/efi_loader/helloworld.c3
6 files changed, 214 insertions, 137 deletions
diff --git a/arch/arm/lib/elf_arm_efi.lds b/arch/arm/lib/elf_arm_efi.lds
index 59f66a1d4ab..15c9c5c6722 100644
--- a/arch/arm/lib/elf_arm_efi.lds
+++ b/arch/arm/lib/elf_arm_efi.lds
@@ -55,16 +55,13 @@ SECTIONS
.rel.data : { *(.rel.data) *(.rel.data*) }
_data_size = . - _etext;
- . = ALIGN(4096);
- .dynsym : { *(.dynsym) }
- . = ALIGN(4096);
- .dynstr : { *(.dynstr) }
- . = ALIGN(4096);
- .note.gnu.build-id : { *(.note.gnu.build-id) }
/DISCARD/ : {
*(.rel.reloc)
*(.eh_frame)
*(.note.GNU-stack)
+ *(.dynsym)
+ *(.dynstr)
+ *(.note.gnu.build-id)
+ *(.comment)
}
- .comment 0 : { *(.comment) }
}
diff --git a/include/efi_loader.h b/include/efi_loader.h
index c0caabddb12..6185055e78e 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -190,6 +190,8 @@ void efi_set_bootdev(const char *dev, const char *devnr, const char *path);
void efi_add_handle(struct efi_object *obj);
/* Create handle */
efi_status_t efi_create_handle(void **handle);
+/* Delete handle */
+void efi_delete_handle(struct efi_object *obj);
/* Call this to validate a handle and find the EFI object for it */
struct efi_object *efi_search_obj(const void *handle);
/* Find a protocol on a handle */
@@ -249,9 +251,11 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
int efi_memory_init(void);
/* Adds new or overrides configuration table entry to the system table */
efi_status_t efi_install_configuration_table(const efi_guid_t *guid, void *table);
-void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *obj,
- struct efi_device_path *device_path,
- struct efi_device_path *file_path);
+/* Sets up a loaded image */
+efi_status_t efi_setup_loaded_image(
+ struct efi_loaded_image *info, struct efi_object *obj,
+ struct efi_device_path *device_path,
+ struct efi_device_path *file_path);
efi_status_t efi_load_image_from_path(struct efi_device_path *file_path,
void **buffer);
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index a37fb25638c..b90bd0b426f 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -360,6 +360,106 @@ efi_status_t efi_create_handle(void **handle)
}
/*
+ * Find a protocol on a handle.
+ *
+ * @handle handle
+ * @protocol_guid GUID of the protocol
+ * @handler reference to the protocol
+ * @return status code
+ */
+efi_status_t efi_search_protocol(const void *handle,
+ const efi_guid_t *protocol_guid,
+ struct efi_handler **handler)
+{
+ struct efi_object *efiobj;
+ struct list_head *lhandle;
+
+ if (!handle || !protocol_guid)
+ return EFI_INVALID_PARAMETER;
+ efiobj = efi_search_obj(handle);
+ if (!efiobj)
+ return EFI_INVALID_PARAMETER;
+ list_for_each(lhandle, &efiobj->protocols) {
+ struct efi_handler *protocol;
+
+ protocol = list_entry(lhandle, struct efi_handler, link);
+ if (!guidcmp(protocol->guid, protocol_guid)) {
+ if (handler)
+ *handler = protocol;
+ return EFI_SUCCESS;
+ }
+ }
+ return EFI_NOT_FOUND;
+}
+
+/*
+ * Delete protocol from a handle.
+ *
+ * @handle handle from which the protocol shall be deleted
+ * @protocol GUID of the protocol to be deleted
+ * @protocol_interface interface of the protocol implementation
+ * @return status code
+ */
+efi_status_t efi_remove_protocol(const void *handle, const efi_guid_t *protocol,
+ void *protocol_interface)
+{
+ struct efi_handler *handler;
+ efi_status_t ret;
+
+ ret = efi_search_protocol(handle, protocol, &handler);
+ if (ret != EFI_SUCCESS)
+ return ret;
+ if (guidcmp(handler->guid, protocol))
+ return EFI_INVALID_PARAMETER;
+ list_del(&handler->link);
+ free(handler);
+ return EFI_SUCCESS;
+}
+
+/*
+ * Delete all protocols from a handle.
+ *
+ * @handle handle from which the protocols shall be deleted
+ * @return status code
+ */
+efi_status_t efi_remove_all_protocols(const void *handle)
+{
+ struct efi_object *efiobj;
+ struct list_head *lhandle;
+ struct list_head *pos;
+
+ efiobj = efi_search_obj(handle);
+ if (!efiobj)
+ return EFI_INVALID_PARAMETER;
+ list_for_each_safe(lhandle, pos, &efiobj->protocols) {
+ struct efi_handler *protocol;
+ efi_status_t ret;
+
+ protocol = list_entry(lhandle, struct efi_handler, link);
+
+ ret = efi_remove_protocol(handle, protocol->guid,
+ protocol->protocol_interface);
+ if (ret != EFI_SUCCESS)
+ return ret;
+ }
+ return EFI_SUCCESS;
+}
+
+/*
+ * Delete handle.
+ *
+ * @handle handle to delete
+ */
+void efi_delete_handle(struct efi_object *obj)
+{
+ if (!obj)
+ return;
+ efi_remove_all_protocols(obj->handle);
+ list_del(&obj->link);
+ free(obj);
+}
+
+/*
* Our event capabilities are very limited. Only a small limited
* number of events is allowed to coexist.
*/
@@ -718,39 +818,6 @@ struct efi_object *efi_search_obj(const void *handle)
}
/*
- * Find a protocol on a handle.
- *
- * @handle handle
- * @protocol_guid GUID of the protocol
- * @handler reference to the protocol
- * @return status code
- */
-efi_status_t efi_search_protocol(const void *handle,
- const efi_guid_t *protocol_guid,
- struct efi_handler **handler)
-{
- struct efi_object *efiobj;
- struct list_head *lhandle;
-
- if (!handle || !protocol_guid)
- return EFI_INVALID_PARAMETER;
- efiobj = efi_search_obj(handle);
- if (!efiobj)
- return EFI_INVALID_PARAMETER;
- list_for_each(lhandle, &efiobj->protocols) {
- struct efi_handler *protocol;
-
- protocol = list_entry(lhandle, struct efi_handler, link);
- if (!guidcmp(protocol->guid, protocol_guid)) {
- if (handler)
- *handler = protocol;
- return EFI_SUCCESS;
- }
- }
- return EFI_NOT_FOUND;
-}
-
-/*
* Install new protocol on a handle.
*
* @handle handle on which the protocol shall be installed
@@ -781,59 +848,6 @@ efi_status_t efi_add_protocol(const void *handle, const efi_guid_t *protocol,
}
/*
- * Delete protocol from a handle.
- *
- * @handle handle from which the protocol shall be deleted
- * @protocol GUID of the protocol to be deleted
- * @protocol_interface interface of the protocol implementation
- * @return status code
- */
-efi_status_t efi_remove_protocol(const void *handle, const efi_guid_t *protocol,
- void *protocol_interface)
-{
- struct efi_handler *handler;
- efi_status_t ret;
-
- ret = efi_search_protocol(handle, protocol, &handler);
- if (ret != EFI_SUCCESS)
- return ret;
- if (guidcmp(handler->guid, protocol))
- return EFI_INVALID_PARAMETER;
- list_del(&handler->link);
- free(handler);
- return EFI_SUCCESS;
-}
-
-/*
- * Delete all protocols from a handle.
- *
- * @handle handle from which the protocols shall be deleted
- * @return status code
- */
-efi_status_t efi_remove_all_protocols(const void *handle)
-{
- struct efi_object *efiobj;
- struct list_head *lhandle;
- struct list_head *pos;
-
- efiobj = efi_search_obj(handle);
- if (!efiobj)
- return EFI_INVALID_PARAMETER;
- list_for_each_safe(lhandle, pos, &efiobj->protocols) {
- struct efi_handler *protocol;
- efi_status_t ret;
-
- protocol = list_entry(lhandle, struct efi_handler, link);
-
- ret = efi_remove_protocol(handle, protocol->guid,
- protocol->protocol_interface);
- if (ret != EFI_SUCCESS)
- return ret;
- }
- return EFI_SUCCESS;
-}
-
-/*
* Install protocol interface.
*
* This function implements the InstallProtocolInterface service.
@@ -1170,10 +1184,12 @@ static efi_status_t EFIAPI efi_install_configuration_table_ext(efi_guid_t *guid,
* @obj internal object associated with the loaded image
* @device_path device path of the loaded image
* @file_path file path of the loaded image
+ * @return status code
*/
-void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *obj,
- struct efi_device_path *device_path,
- struct efi_device_path *file_path)
+efi_status_t efi_setup_loaded_image(
+ struct efi_loaded_image *info, struct efi_object *obj,
+ struct efi_device_path *device_path,
+ struct efi_device_path *file_path)
{
efi_status_t ret;
@@ -1213,9 +1229,10 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob
if (ret != EFI_SUCCESS)
goto failure;
- return;
+ return ret;
failure:
printf("ERROR: Failure to install protocols for loaded image\n");
+ return ret;
}
/*
@@ -1291,6 +1308,7 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy,
{
struct efi_loaded_image *info;
struct efi_object *obj;
+ efi_status_t ret;
EFI_ENTRY("%d, %p, %p, %p, %ld, %p", boot_policy, parent_image,
file_path, source_buffer, source_size, image_handle);
@@ -1300,41 +1318,39 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy,
if (!source_buffer) {
struct efi_device_path *dp, *fp;
- efi_status_t ret;
ret = efi_load_image_from_path(file_path, &source_buffer);
- if (ret != EFI_SUCCESS) {
- free(info);
- free(obj);
- return EFI_EXIT(ret);
- }
-
+ if (ret != EFI_SUCCESS)
+ goto failure;
/*
* split file_path which contains both the device and
* file parts:
*/
efi_dp_split_file_path(file_path, &dp, &fp);
-
- efi_setup_loaded_image(info, obj, dp, fp);
+ ret = efi_setup_loaded_image(info, obj, dp, fp);
+ if (ret != EFI_SUCCESS)
+ goto failure;
} else {
/* In this case, file_path is the "device" path, ie.
* something like a HARDWARE_DEVICE:MEMORY_MAPPED
*/
- efi_setup_loaded_image(info, obj, file_path, NULL);
+ ret = efi_setup_loaded_image(info, obj, file_path, NULL);
+ if (ret != EFI_SUCCESS)
+ goto failure;
}
-
info->reserved = efi_load_pe(source_buffer, info);
if (!info->reserved) {
- free(info);
- free(obj);
- return EFI_EXIT(EFI_UNSUPPORTED);
+ ret = EFI_UNSUPPORTED;
+ goto failure;
}
-
info->system_table = &systab;
info->parent_handle = parent_image;
*image_handle = obj->handle;
-
return EFI_EXIT(EFI_SUCCESS);
+failure:
+ free(info);
+ efi_delete_handle(obj);
+ return EFI_EXIT(ret);
}
/*
diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
index b4e2f933cb6..ccb59337f18 100644
--- a/lib/efi_loader/efi_device_path.c
+++ b/lib/efi_loader/efi_device_path.c
@@ -36,6 +36,24 @@ static const struct efi_device_path_vendor ROOT = {
.guid = U_BOOT_GUID,
};
+#if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC)
+/*
+ * Determine if an MMC device is an SD card.
+ *
+ * @desc block device descriptor
+ * @return true if the device is an SD card
+ */
+static bool is_sd(struct blk_desc *desc)
+{
+ struct mmc *mmc = find_mmc_device(desc->devnum);
+
+ if (!mmc)
+ return false;
+
+ return IS_SD(mmc) != 0U;
+}
+#endif
+
static void *dp_alloc(size_t sz)
{
void *buf;
@@ -126,6 +144,7 @@ static struct efi_object *find_obj(struct efi_device_path *dp, bool short_path,
struct efi_device_path **rem)
{
struct efi_object *efiobj;
+ unsigned int dp_size = efi_dp_size(dp);
list_for_each_entry(efiobj, &efi_obj_list, link) {
struct efi_handler *handler;
@@ -141,10 +160,18 @@ static struct efi_object *find_obj(struct efi_device_path *dp, bool short_path,
do {
if (efi_dp_match(dp, obj_dp) == 0) {
if (rem) {
+ /*
+ * Allow partial matches, but inform
+ * the caller.
+ */
*rem = ((void *)dp) +
efi_dp_size(obj_dp);
+ return efiobj;
+ } else {
+ /* Only return on exact matches */
+ if (efi_dp_size(obj_dp) == dp_size)
+ return efiobj;
}
- return efiobj;
}
obj_dp = shorten_path(efi_dp_next(obj_dp));
@@ -164,8 +191,14 @@ struct efi_object *efi_dp_find_obj(struct efi_device_path *dp,
{
struct efi_object *efiobj;
- efiobj = find_obj(dp, false, rem);
+ /* Search for an exact match first */
+ efiobj = find_obj(dp, false, NULL);
+
+ /* Then for a fuzzy match */
+ if (!efiobj)
+ efiobj = find_obj(dp, false, rem);
+ /* And now for a fuzzy short match */
if (!efiobj)
efiobj = find_obj(dp, true, rem);
@@ -298,9 +331,9 @@ static void *dp_fill(void *buf, struct udevice *dev)
struct blk_desc *desc = mmc_get_blk_desc(mmc);
sddp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
- sddp->dp.sub_type = (desc->if_type == IF_TYPE_MMC) ?
- DEVICE_PATH_SUB_TYPE_MSG_MMC :
- DEVICE_PATH_SUB_TYPE_MSG_SD;
+ sddp->dp.sub_type = is_sd(desc) ?
+ DEVICE_PATH_SUB_TYPE_MSG_SD :
+ DEVICE_PATH_SUB_TYPE_MSG_MMC;
sddp->dp.length = sizeof(*sddp);
sddp->slot_number = dev->seq;
@@ -366,6 +399,13 @@ static unsigned dp_part_size(struct blk_desc *desc, int part)
return dpsize;
}
+/*
+ * Create a device path for a block device or one of its partitions.
+ *
+ * @buf buffer to which the device path is wirtten
+ * @desc block device descriptor
+ * @part partition number, 0 identifies a block device
+ */
static void *dp_part_fill(void *buf, struct blk_desc *desc, int part)
{
disk_partition_t info;
@@ -378,7 +418,7 @@ static void *dp_part_fill(void *buf, struct blk_desc *desc, int part)
* and handling all the different cases like we do for non-
* legacy (ie CONFIG_BLK=y) case. But most important thing
* is just to have a unique device-path for if_type+devnum.
- * So map things to a fictional USB device:
+ * So map things to a fictitious USB device.
*/
struct efi_device_path_usb *udp;
@@ -402,7 +442,7 @@ static void *dp_part_fill(void *buf, struct blk_desc *desc, int part)
if (desc->part_type == PART_TYPE_ISO) {
struct efi_device_path_cdrom_path *cddp = buf;
- cddp->boot_entry = part - 1;
+ cddp->boot_entry = part;
cddp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
cddp->dp.sub_type = DEVICE_PATH_SUB_TYPE_CDROM_PATH;
cddp->dp.length = sizeof(*cddp);
@@ -416,7 +456,7 @@ static void *dp_part_fill(void *buf, struct blk_desc *desc, int part)
hddp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
hddp->dp.sub_type = DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH;
hddp->dp.length = sizeof(*hddp);
- hddp->partition_number = part - 1;
+ hddp->partition_number = part;
hddp->partition_start = info.start;
hddp->partition_end = info.size;
if (desc->part_type == PART_TYPE_EFI)
diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c
index 7159c974d4d..50d9e911c0b 100644
--- a/lib/efi_loader/efi_device_path_to_text.c
+++ b/lib/efi_loader/efi_device_path_to_text.c
@@ -90,7 +90,7 @@ static char *dp_msging(char *s, struct efi_device_path *dp)
case DEVICE_PATH_SUB_TYPE_MSG_USB: {
struct efi_device_path_usb *udp =
(struct efi_device_path_usb *)dp;
- s += sprintf(s, "Usb(0x%x,0x%x)", udp->parent_port_number,
+ s += sprintf(s, "USB(0x%x,0x%x)", udp->parent_port_number,
udp->usb_interface);
break;
}
@@ -124,10 +124,10 @@ static char *dp_msging(char *s, struct efi_device_path *dp)
case DEVICE_PATH_SUB_TYPE_MSG_MMC: {
const char *typename =
(dp->sub_type == DEVICE_PATH_SUB_TYPE_MSG_SD) ?
- "SDCard" : "MMC";
+ "SD" : "eMMC";
struct efi_device_path_sd_mmc_path *sddp =
(struct efi_device_path_sd_mmc_path *)dp;
- s += sprintf(s, "%s(Slot%u)", typename, sddp->slot_number);
+ s += sprintf(s, "%s(%u)", typename, sddp->slot_number);
break;
}
default:
@@ -137,6 +137,13 @@ static char *dp_msging(char *s, struct efi_device_path *dp)
return s;
}
+/*
+ * Convert a media device path node to text.
+ *
+ * @s output buffer
+ * @dp device path node
+ * @return next unused buffer address
+ */
static char *dp_media(char *s, struct efi_device_path *dp)
{
switch (dp->sub_type) {
@@ -144,21 +151,33 @@ static char *dp_media(char *s, struct efi_device_path *dp)
struct efi_device_path_hard_drive_path *hddp =
(struct efi_device_path_hard_drive_path *)dp;
void *sig = hddp->partition_signature;
+ u64 start;
+ u64 end;
+
+ /* Copy from packed structure to aligned memory */
+ memcpy(&start, &hddp->partition_start, sizeof(start));
+ memcpy(&end, &hddp->partition_end, sizeof(end));
switch (hddp->signature_type) {
- case SIG_TYPE_MBR:
- s += sprintf(s, "HD(Part%d,Sig%08x)",
- hddp->partition_number,
- *(uint32_t *)sig);
+ case SIG_TYPE_MBR: {
+ u32 signature;
+
+ memcpy(&signature, sig, sizeof(signature));
+ s += sprintf(
+ s, "HD(%d,MBR,0x%08x,0x%llx,0x%llx)",
+ hddp->partition_number, signature, start, end);
break;
+ }
case SIG_TYPE_GUID:
- s += sprintf(s, "HD(Part%d,Sig%pUl)",
- hddp->partition_number, sig);
+ s += sprintf(
+ s, "HD(%d,GPT,%pUl,0x%llx,0x%llx)",
+ hddp->partition_number, sig, start, end);
break;
default:
- s += sprintf(s, "HD(Part%d,MBRType=%02x,SigType=%02x)",
- hddp->partition_number, hddp->partmap_type,
- hddp->signature_type);
+ s += sprintf(
+ s, "HD(%d,0x%02x,0,0x%llx,0x%llx)",
+ hddp->partition_number, hddp->partmap_type,
+ start, end);
break;
}
diff --git a/lib/efi_loader/helloworld.c b/lib/efi_loader/helloworld.c
index e59c24c7881..b8c147d7f2a 100644
--- a/lib/efi_loader/helloworld.c
+++ b/lib/efi_loader/helloworld.c
@@ -13,6 +13,8 @@
#include <common.h>
#include <efi_api.h>
+static const efi_guid_t loaded_image_guid = LOADED_IMAGE_GUID;
+
/*
* Entry point of the EFI application.
*
@@ -26,7 +28,6 @@ efi_status_t EFIAPI efi_main(efi_handle_t handle,
struct efi_simple_text_output_protocol *con_out = systable->con_out;
struct efi_boot_services *boottime = systable->boottime;
struct efi_loaded_image *loaded_image;
- const efi_guid_t loaded_image_guid = LOADED_IMAGE_GUID;
efi_status_t ret;
con_out->output_string(con_out, L"Hello, world!\n");