diff options
-rw-r--r-- | arch/arm/lib/elf_arm_efi.lds | 11 | ||||
-rw-r--r-- | include/efi_loader.h | 10 | ||||
-rw-r--r-- | lib/efi_loader/efi_boottime.c | 228 | ||||
-rw-r--r-- | lib/efi_loader/efi_device_path.c | 56 | ||||
-rw-r--r-- | lib/efi_loader/efi_device_path_to_text.c | 43 | ||||
-rw-r--r-- | lib/efi_loader/helloworld.c | 3 |
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"); |