diff options
Diffstat (limited to 'lib/efi_loader')
-rw-r--r-- | lib/efi_loader/Kconfig | 1 | ||||
-rw-r--r-- | lib/efi_loader/efi_bootmgr.c | 7 | ||||
-rw-r--r-- | lib/efi_loader/efi_boottime.c | 56 | ||||
-rw-r--r-- | lib/efi_loader/efi_console.c | 70 | ||||
-rw-r--r-- | lib/efi_loader/efi_disk.c | 60 | ||||
-rw-r--r-- | lib/efi_loader/efi_file.c | 75 | ||||
-rw-r--r-- | lib/efi_loader/efi_var_file.c | 4 |
7 files changed, 216 insertions, 57 deletions
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index b8fb2701a7..41756ea539 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -20,7 +20,6 @@ config EFI_LOADER select EVENT_DYNAMIC select LIB_UUID imply PARTITION_UUIDS - select HAVE_BLOCK_DEVICE select REGEX imply FAT imply FAT_WRITE diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c index 234073ecb7..4b24b41047 100644 --- a/lib/efi_loader/efi_bootmgr.c +++ b/lib/efi_loader/efi_bootmgr.c @@ -19,6 +19,9 @@ static const struct efi_boot_services *bs; static const struct efi_runtime_services *rs; +const efi_guid_t efi_guid_bootmenu_auto_generated = + EFICONFIG_AUTO_GENERATED_ENTRY_GUID; + /* * bootmgr implements the logic of trying to find a payload to boot * based on the BootOrder + BootXXXX variables, and then loading it. @@ -243,6 +246,10 @@ static efi_status_t try_load_entry(u16 n, efi_handle_t *handle, } /* Set load options */ + if (size >= sizeof(efi_guid_t) && + !guidcmp(lo.optional_data, &efi_guid_bootmenu_auto_generated)) + size = 0; + if (size) { *load_options = malloc(size); if (!*load_options) { diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 6f7333638a..1bfd094e89 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -833,7 +833,7 @@ void efi_timer_check(void) efi_signal_event(evt); } efi_process_event_queue(); - WATCHDOG_RESET(); + schedule(); } /** @@ -2198,7 +2198,7 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle, /* Give the payload some time to boot */ efi_set_watchdog(0); - WATCHDOG_RESET(); + schedule(); out: if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) { if (ret != EFI_SUCCESS) @@ -2458,6 +2458,35 @@ static efi_status_t EFIAPI efi_protocols_per_handle( return EFI_EXIT(EFI_SUCCESS); } +efi_status_t efi_locate_handle_buffer_int(enum efi_locate_search_type search_type, + const efi_guid_t *protocol, void *search_key, + efi_uintn_t *no_handles, efi_handle_t **buffer) +{ + efi_status_t r; + efi_uintn_t buffer_size = 0; + + if (!no_handles || !buffer) { + r = EFI_INVALID_PARAMETER; + goto out; + } + *no_handles = 0; + *buffer = NULL; + r = efi_locate_handle(search_type, protocol, search_key, &buffer_size, + *buffer); + if (r != EFI_BUFFER_TOO_SMALL) + goto out; + r = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, buffer_size, + (void **)buffer); + if (r != EFI_SUCCESS) + goto out; + r = efi_locate_handle(search_type, protocol, search_key, &buffer_size, + *buffer); + if (r == EFI_SUCCESS) + *no_handles = buffer_size / sizeof(efi_handle_t); +out: + return r; +} + /** * efi_locate_handle_buffer() - locate handles implementing a protocol * @search_type: selection criterion @@ -2479,30 +2508,13 @@ efi_status_t EFIAPI efi_locate_handle_buffer( efi_uintn_t *no_handles, efi_handle_t **buffer) { efi_status_t r; - efi_uintn_t buffer_size = 0; EFI_ENTRY("%d, %pUs, %p, %p, %p", search_type, protocol, search_key, no_handles, buffer); - if (!no_handles || !buffer) { - r = EFI_INVALID_PARAMETER; - goto out; - } - *no_handles = 0; - *buffer = NULL; - r = efi_locate_handle(search_type, protocol, search_key, &buffer_size, - *buffer); - if (r != EFI_BUFFER_TOO_SMALL) - goto out; - r = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, buffer_size, - (void **)buffer); - if (r != EFI_SUCCESS) - goto out; - r = efi_locate_handle(search_type, protocol, search_key, &buffer_size, - *buffer); - if (r == EFI_SUCCESS) - *no_handles = buffer_size / sizeof(efi_handle_t); -out: + r = efi_locate_handle_buffer_int(search_type, protocol, search_key, + no_handles, buffer); + return EFI_EXIT(r); } diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c index ee9dc6bbd8..cf9fbd9cb5 100644 --- a/lib/efi_loader/efi_console.c +++ b/lib/efi_loader/efi_console.c @@ -7,6 +7,7 @@ #define LOG_CATEGORY LOGC_EFI +#include <ansi.h> #include <common.h> #include <charset.h> #include <malloc.h> @@ -1323,3 +1324,72 @@ out_of_memory: printf("ERROR: Out of memory\n"); return r; } + +/** + * efi_console_get_u16_string() - get user input string + * + * @cin: protocol interface to EFI_SIMPLE_TEXT_INPUT_PROTOCOL + * @buf: buffer to store user input string in UTF16 + * @count: number of u16 string including NULL terminator that buf has + * @filter_func: callback to filter user input + * @row: row number to locate user input form + * @col: column number to locate user input form + * Return: status code + */ +efi_status_t efi_console_get_u16_string(struct efi_simple_text_input_protocol *cin, + u16 *buf, efi_uintn_t count, + efi_console_filter_func filter_func, + int row, int col) +{ + efi_status_t ret; + efi_uintn_t len = 0; + struct efi_input_key key; + + printf(ANSI_CURSOR_POSITION + ANSI_CLEAR_LINE_TO_END + ANSI_CURSOR_SHOW, row, col); + + ret = EFI_CALL(cin->reset(cin, false)); + if (ret != EFI_SUCCESS) + return ret; + + for (;;) { + do { + ret = EFI_CALL(cin->read_key_stroke(cin, &key)); + mdelay(10); + } while (ret == EFI_NOT_READY); + + if (key.unicode_char == u'\b') { + if (len > 0) + buf[--len] = u'\0'; + + printf(ANSI_CURSOR_POSITION + "%ls" + ANSI_CLEAR_LINE_TO_END, row, col, buf); + continue; + } else if (key.unicode_char == u'\r') { + buf[len] = u'\0'; + return EFI_SUCCESS; + } else if (key.unicode_char == 0x3 || key.scan_code == 23) { + return EFI_ABORTED; + } else if (key.unicode_char < 0x20) { + /* ignore control codes other than Ctrl+C, '\r' and '\b' */ + continue; + } else if (key.scan_code != 0) { + /* only accept single ESC press for cancel */ + continue; + } + + if (filter_func) { + if (filter_func(&key) != EFI_SUCCESS) + continue; + } + + if (len >= (count - 1)) + continue; + + buf[len] = key.unicode_char; + len++; + printf(ANSI_CURSOR_POSITION "%ls", row, col, buf); + } +} diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index 5feeb52ccb..39ea1a68a6 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -498,13 +498,13 @@ static efi_status_t efi_disk_add_dev( diskobj->media.last_block); /* Store first EFI system partition */ - if (part && !efi_system_partition.if_type) { + if (part && !efi_system_partition.uclass_id) { if (part_info->bootable & PART_EFI_SYSTEM_PARTITION) { - efi_system_partition.if_type = desc->if_type; + efi_system_partition.uclass_id = desc->uclass_id; efi_system_partition.devnum = desc->devnum; efi_system_partition.part = part; EFI_PRINT("EFI system partition: %s %x:%x\n", - blk_get_if_type_name(desc->if_type), + blk_get_uclass_name(desc->uclass_id), desc->devnum, part); } } @@ -640,7 +640,7 @@ static int efi_disk_probe(void *ctx, struct event *event) * has already created an efi_disk at this moment. */ desc = dev_get_uclass_plat(dev); - if (desc->if_type != IF_TYPE_EFI_LOADER) { + if (desc->uclass_id != UCLASS_EFI_LOADER) { ret = efi_disk_create_raw(dev); if (ret) return -1; @@ -675,7 +675,7 @@ static int efi_disk_delete_raw(struct udevice *dev) return -1; desc = dev_get_uclass_plat(dev); - if (desc->if_type != IF_TYPE_EFI_LOADER) { + if (desc->uclass_id != UCLASS_EFI_LOADER) { diskobj = container_of(handle, struct efi_disk_obj, header); efi_free_pool(diskobj->dp); } @@ -762,6 +762,56 @@ efi_status_t efi_disk_init(void) } /** + * efi_disk_get_device_name() - get U-Boot device name associated with EFI handle + * + * @handle: pointer to the EFI handle + * @buf: pointer to the buffer to store the string + * @size: size of buffer + * Return: status code + */ +efi_status_t efi_disk_get_device_name(const efi_handle_t handle, char *buf, int size) +{ + int count; + int diskid; + enum uclass_id id; + unsigned int part; + struct udevice *dev; + struct blk_desc *desc; + const char *if_typename; + bool is_partition = false; + struct disk_part *part_data; + + if (!handle || !buf || !size) + return EFI_INVALID_PARAMETER; + + dev = handle->dev; + id = device_get_uclass_id(dev); + if (id == UCLASS_BLK) { + desc = dev_get_uclass_plat(dev); + } else if (id == UCLASS_PARTITION) { + desc = dev_get_uclass_plat(dev_get_parent(dev)); + is_partition = true; + } else { + return EFI_INVALID_PARAMETER; + } + if_typename = blk_get_uclass_name(desc->uclass_id); + diskid = desc->devnum; + + if (is_partition) { + part_data = dev_get_uclass_plat(dev); + part = part_data->partnum; + count = snprintf(buf, size, "%s %d:%d", if_typename, diskid, part); + } else { + count = snprintf(buf, size, "%s %d", if_typename, diskid); + } + + if (count < 0 || (count + 1) > size) + return EFI_INVALID_PARAMETER; + + return EFI_SUCCESS; +} + +/** * efi_disks_register() - ensure all block devices are available in UEFI * * The function probes all block devices. As we store UEFI variables on the diff --git a/lib/efi_loader/efi_file.c b/lib/efi_loader/efi_file.c index 7a7077e6d0..c96a7f7ca3 100644 --- a/lib/efi_loader/efi_file.c +++ b/lib/efi_loader/efi_file.c @@ -246,10 +246,10 @@ error: return NULL; } -static efi_status_t efi_file_open_int(struct efi_file_handle *this, - struct efi_file_handle **new_handle, - u16 *file_name, u64 open_mode, - u64 attributes) +efi_status_t efi_file_open_int(struct efi_file_handle *this, + struct efi_file_handle **new_handle, + u16 *file_name, u64 open_mode, + u64 attributes) { struct file_handle *fh = to_fh(this); efi_status_t ret; @@ -369,11 +369,17 @@ static efi_status_t file_close(struct file_handle *fh) return EFI_SUCCESS; } -static efi_status_t EFIAPI efi_file_close(struct efi_file_handle *file) +efi_status_t efi_file_close_int(struct efi_file_handle *file) { struct file_handle *fh = to_fh(file); + + return file_close(fh); +} + +static efi_status_t EFIAPI efi_file_close(struct efi_file_handle *file) +{ EFI_ENTRY("%p", file); - return EFI_EXIT(file_close(fh)); + return EFI_EXIT(efi_file_close_int(file)); } static efi_status_t EFIAPI efi_file_delete(struct efi_file_handle *file) @@ -562,8 +568,8 @@ static efi_status_t dir_read(struct file_handle *fh, u64 *buffer_size, return EFI_SUCCESS; } -static efi_status_t efi_file_read_int(struct efi_file_handle *this, - efi_uintn_t *buffer_size, void *buffer) +efi_status_t efi_file_read_int(struct efi_file_handle *this, + efi_uintn_t *buffer_size, void *buffer) { struct file_handle *fh = to_fh(this); efi_status_t ret = EFI_SUCCESS; @@ -773,24 +779,11 @@ out: return EFI_EXIT(ret); } -/** - * efi_file_setpos() - set current position in file - * - * This function implements the SetPosition service of the EFI file protocol. - * See the UEFI spec for details. - * - * @file: file handle - * @pos: new file position - * Return: status code - */ -static efi_status_t EFIAPI efi_file_setpos(struct efi_file_handle *file, - u64 pos) +efi_status_t efi_file_setpos_int(struct efi_file_handle *file, u64 pos) { struct file_handle *fh = to_fh(file); efi_status_t ret = EFI_SUCCESS; - EFI_ENTRY("%p, %llu", file, pos); - if (fh->isdir) { if (pos != 0) { ret = EFI_UNSUPPORTED; @@ -812,6 +805,28 @@ static efi_status_t EFIAPI efi_file_setpos(struct efi_file_handle *file, fh->offset = pos; error: + return ret; +} + +/** + * efi_file_setpos() - set current position in file + * + * This function implements the SetPosition service of the EFI file protocol. + * See the UEFI spec for details. + * + * @file: file handle + * @pos: new file position + * Return: status code + */ +static efi_status_t EFIAPI efi_file_setpos(struct efi_file_handle *file, + u64 pos) +{ + efi_status_t ret = EFI_SUCCESS; + + EFI_ENTRY("%p, %llu", file, pos); + + ret = efi_file_setpos_int(file, pos); + return EFI_EXIT(ret); } @@ -1138,17 +1153,23 @@ struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp) return f; } +efi_status_t efi_open_volume_int(struct efi_simple_file_system_protocol *this, + struct efi_file_handle **root) +{ + struct file_system *fs = to_fs(this); + + *root = file_open(fs, NULL, NULL, 0, 0); + + return EFI_SUCCESS; +} + static efi_status_t EFIAPI efi_open_volume(struct efi_simple_file_system_protocol *this, struct efi_file_handle **root) { - struct file_system *fs = to_fs(this); - EFI_ENTRY("%p, %p", this, root); - *root = file_open(fs, NULL, NULL, 0, 0); - - return EFI_EXIT(EFI_SUCCESS); + return EFI_EXIT(efi_open_volume_int(this, root)); } struct efi_simple_file_system_protocol * diff --git a/lib/efi_loader/efi_var_file.c b/lib/efi_loader/efi_var_file.c index 76a2ff9e41..3d58caa13d 100644 --- a/lib/efi_loader/efi_var_file.c +++ b/lib/efi_loader/efi_var_file.c @@ -38,13 +38,13 @@ static efi_status_t __maybe_unused efi_set_blk_dev_to_system_partition(void) char part_str[PART_STR_LEN]; int r; - if (!efi_system_partition.if_type) { + if (efi_system_partition.uclass_id == UCLASS_INVALID) { log_err("No EFI system partition\n"); return EFI_DEVICE_ERROR; } snprintf(part_str, PART_STR_LEN, "%x:%x", efi_system_partition.devnum, efi_system_partition.part); - r = fs_set_blk_dev(blk_get_if_type_name(efi_system_partition.if_type), + r = fs_set_blk_dev(blk_get_uclass_name(efi_system_partition.uclass_id), part_str, FS_TYPE_ANY); if (r) { log_err("Cannot read EFI system partition\n"); |