diff options
-rw-r--r-- | cmd/bootefi.c | 135 | ||||
-rw-r--r-- | include/efi.h | 50 | ||||
-rw-r--r-- | include/efi_api.h | 86 | ||||
-rw-r--r-- | include/efi_loader.h | 125 | ||||
-rw-r--r-- | lib/efi_loader/Makefile | 3 | ||||
-rw-r--r-- | lib/efi_loader/efi_boottime.c | 706 | ||||
-rw-r--r-- | lib/efi_loader/efi_console.c | 55 | ||||
-rw-r--r-- | lib/efi_loader/efi_device_path_to_text.c | 130 | ||||
-rw-r--r-- | lib/efi_loader/efi_disk.c | 39 | ||||
-rw-r--r-- | lib/efi_loader/efi_gop.c | 9 | ||||
-rw-r--r-- | lib/efi_loader/efi_image_loader.c | 8 | ||||
-rw-r--r-- | lib/efi_loader/efi_memory.c | 11 | ||||
-rw-r--r-- | lib/efi_loader/efi_net.c | 30 |
13 files changed, 1057 insertions, 330 deletions
diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 771300ee94b..d20775eccd9 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -20,6 +20,8 @@ DECLARE_GLOBAL_DATA_PTR; +static uint8_t efi_obj_list_initalized; + /* * When booting using the "bootefi" command, we don't know which * physical device the file came from. So we create a pseudo-device @@ -54,14 +56,6 @@ static struct efi_device_path_file_path bootefi_device_path[] = { } }; -static efi_status_t EFIAPI bootefi_open_dp(void *handle, efi_guid_t *protocol, - void **protocol_interface, void *agent_handle, - void *controller_handle, uint32_t attributes) -{ - *protocol_interface = bootefi_device_path; - return EFI_SUCCESS; -} - /* The EFI loaded_image interface for the image executed via "bootefi" */ static struct efi_loaded_image loaded_image_info = { .device_handle = bootefi_device_path, @@ -78,7 +72,7 @@ static struct efi_object loaded_image_info_obj = { * return handle which points to loaded_image_info */ .guid = &efi_guid_loaded_image, - .open = &efi_return_handle, + .protocol_interface = &loaded_image_info, }, { /* @@ -86,7 +80,15 @@ static struct efi_object loaded_image_info_obj = { * bootefi_device_path */ .guid = &efi_guid_device_path, - .open = &bootefi_open_dp, + .protocol_interface = bootefi_device_path, + }, + { + .guid = &efi_guid_console_control, + .protocol_interface = (void *) &efi_console_control + }, + { + .guid = &efi_guid_device_path_to_text_protocol, + .protocol_interface = (void *) &efi_device_path_to_text }, }, }; @@ -99,11 +101,43 @@ static struct efi_object bootefi_device_obj = { /* When asking for the device path interface, return * bootefi_device_path */ .guid = &efi_guid_device_path, - .open = &bootefi_open_dp, + .protocol_interface = bootefi_device_path } }, }; +/* Initialize and populate EFI object list */ +static void efi_init_obj_list(void) +{ + efi_obj_list_initalized = 1; + + list_add_tail(&loaded_image_info_obj.link, &efi_obj_list); + list_add_tail(&bootefi_device_obj.link, &efi_obj_list); + efi_console_register(); +#ifdef CONFIG_PARTITIONS + efi_disk_register(); +#endif +#if defined(CONFIG_LCD) || defined(CONFIG_DM_VIDEO) + efi_gop_register(); +#endif +#ifdef CONFIG_NET + void *nethandle = loaded_image_info.device_handle; + efi_net_register(&nethandle); + + if (!memcmp(bootefi_device_path[0].str, "N\0e\0t", 6)) + loaded_image_info.device_handle = nethandle; + else + loaded_image_info.device_handle = bootefi_device_path; +#endif +#ifdef CONFIG_GENERATE_SMBIOS_TABLE + efi_smbios_register(); +#endif + + /* Initialize EFI runtime services */ + efi_reset_system_init(); + efi_get_time_init(); +} + static void *copy_fdt(void *fdt) { u64 fdt_size = fdt_totalsize(fdt); @@ -147,15 +181,28 @@ static void *copy_fdt(void *fdt) return new_fdt; } +static ulong efi_do_enter(void *image_handle, + struct efi_system_table *st, + asmlinkage ulong (*entry)(void *image_handle, + struct efi_system_table *st)) +{ + efi_status_t ret = EFI_LOAD_ERROR; + + if (entry) + ret = entry(image_handle, st); + st->boottime->exit(image_handle, ret, 0, NULL); + return ret; +} + #ifdef CONFIG_ARM64 -static unsigned long efi_run_in_el2(ulong (*entry)(void *image_handle, - struct efi_system_table *st), void *image_handle, - struct efi_system_table *st) +static unsigned long efi_run_in_el2(asmlinkage ulong (*entry)( + void *image_handle, struct efi_system_table *st), + void *image_handle, struct efi_system_table *st) { /* Enable caches again */ dcache_enable(); - return entry(image_handle, st); + return efi_do_enter(image_handle, st, entry); } #endif @@ -168,6 +215,7 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt) ulong (*entry)(void *image_handle, struct efi_system_table *st) asmlinkage; ulong fdt_pages, fdt_size, fdt_start, fdt_end; + const efi_guid_t fdt_guid = EFI_FDT_GUID; bootm_headers_t img = { 0 }; /* @@ -186,9 +234,7 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt) } /* Link to it in the efi tables */ - systab.tables[0].guid = EFI_FDT_GUID; - systab.tables[0].table = fdt; - systab.nr_tables = 1; + efi_install_configuration_table(&fdt_guid, fdt); /* And reserve the space in the memory map */ fdt_start = ((ulong)fdt) & ~EFI_PAGE_MASK; @@ -201,7 +247,7 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt) EFI_BOOT_SERVICES_DATA, true); } else { printf("WARNING: Invalid device tree, expect boot to fail\n"); - systab.nr_tables = 0; + efi_install_configuration_table(&fdt_guid, NULL); } /* Load the EFI payload */ @@ -210,38 +256,14 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt) return -ENOENT; /* Initialize and populate EFI object list */ - INIT_LIST_HEAD(&efi_obj_list); - list_add_tail(&loaded_image_info_obj.link, &efi_obj_list); - list_add_tail(&bootefi_device_obj.link, &efi_obj_list); -#ifdef CONFIG_PARTITIONS - efi_disk_register(); -#endif -#ifdef CONFIG_LCD - efi_gop_register(); -#endif -#ifdef CONFIG_NET - void *nethandle = loaded_image_info.device_handle; - efi_net_register(&nethandle); - - if (!memcmp(bootefi_device_path[0].str, "N\0e\0t", 6)) - loaded_image_info.device_handle = nethandle; - else - loaded_image_info.device_handle = bootefi_device_path; -#endif -#ifdef CONFIG_GENERATE_SMBIOS_TABLE - efi_smbios_register(); -#endif - - /* Initialize EFI runtime services */ - efi_reset_system_init(); - efi_get_time_init(); + if (!efi_obj_list_initalized) + efi_init_obj_list(); /* Call our payload! */ debug("%s:%d Jumping to 0x%lx\n", __func__, __LINE__, (long)entry); if (setjmp(&loaded_image_info.exit_jmp)) { - efi_status_t status = loaded_image_info.exit_status; - return status == EFI_SUCCESS ? 0 : -EINVAL; + return loaded_image_info.exit_status; } #ifdef CONFIG_ARM64 @@ -260,7 +282,7 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt) } #endif - return entry(&loaded_image_info, &systab); + return efi_do_enter(&loaded_image_info, &systab, entry); } @@ -269,7 +291,7 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { char *saddr, *sfdt; unsigned long addr, fdt_addr = 0; - int r = 0; + unsigned long r; if (argc < 2) return CMD_RET_USAGE; @@ -294,12 +316,13 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) printf("## Starting EFI application at %08lx ...\n", addr); r = do_bootefi_exec((void *)addr, (void*)fdt_addr); - printf("## Application terminated, r = %d\n", r); + printf("## Application terminated, r = %lu\n", + r & ~EFI_ERROR_MASK); - if (r != 0) - r = 1; - - return r; + if (r != EFI_SUCCESS) + return 1; + else + return 0; } #ifdef CONFIG_SYS_LONGHELP @@ -325,7 +348,7 @@ void efi_set_bootdev(const char *dev, const char *devnr, const char *path) { __maybe_unused struct blk_desc *desc; char devname[32] = { 0 }; /* dp->str is u16[32] long */ - char *colon; + char *colon, *s; #if defined(CONFIG_BLK) || CONFIG_IS_ENABLED(ISO_PARTITION) desc = blk_get_dev(dev, simple_strtol(devnr, NULL, 10)); @@ -370,5 +393,9 @@ void efi_set_bootdev(const char *dev, const char *devnr, const char *path) } else { snprintf(devname, sizeof(devname), "%s", path); } + /* DOS style file path: */ + s = devname; + while ((s = strchr(s, '/'))) + *s++ = '\\'; ascii2unicode(bootefi_image_path[0].str, devname); } diff --git a/include/efi.h b/include/efi.h index 3d587807e8c..02b78b31b12 100644 --- a/include/efi.h +++ b/include/efi.h @@ -39,19 +39,43 @@ struct efi_device_path; #define EFI_BITS_PER_LONG 64 #endif -#define EFI_SUCCESS 0 -#define EFI_LOAD_ERROR (1 | (1UL << (EFI_BITS_PER_LONG - 1))) -#define EFI_INVALID_PARAMETER (2 | (1UL << (EFI_BITS_PER_LONG - 1))) -#define EFI_UNSUPPORTED (3 | (1UL << (EFI_BITS_PER_LONG - 1))) -#define EFI_BAD_BUFFER_SIZE (4 | (1UL << (EFI_BITS_PER_LONG - 1))) -#define EFI_BUFFER_TOO_SMALL (5 | (1UL << (EFI_BITS_PER_LONG - 1))) -#define EFI_NOT_READY (6 | (1UL << (EFI_BITS_PER_LONG - 1))) -#define EFI_DEVICE_ERROR (7 | (1UL << (EFI_BITS_PER_LONG - 1))) -#define EFI_WRITE_PROTECTED (8 | (1UL << (EFI_BITS_PER_LONG - 1))) -#define EFI_OUT_OF_RESOURCES (9 | (1UL << (EFI_BITS_PER_LONG - 1))) -#define EFI_NOT_FOUND (14 | (1UL << (EFI_BITS_PER_LONG - 1))) -#define EFI_ACCESS_DENIED (15 | (1UL << (EFI_BITS_PER_LONG - 1))) -#define EFI_SECURITY_VIOLATION (26 | (1UL << (EFI_BITS_PER_LONG - 1))) +/* Bit mask for EFI status code with error */ +#define EFI_ERROR_MASK (1UL << (EFI_BITS_PER_LONG - 1)) +/* Status codes returned by EFI protocols */ +#define EFI_SUCCESS 0 +#define EFI_LOAD_ERROR (EFI_ERROR_MASK | 1) +#define EFI_INVALID_PARAMETER (EFI_ERROR_MASK | 2) +#define EFI_UNSUPPORTED (EFI_ERROR_MASK | 3) +#define EFI_BAD_BUFFER_SIZE (EFI_ERROR_MASK | 4) +#define EFI_BUFFER_TOO_SMALL (EFI_ERROR_MASK | 5) +#define EFI_NOT_READY (EFI_ERROR_MASK | 6) +#define EFI_DEVICE_ERROR (EFI_ERROR_MASK | 7) +#define EFI_WRITE_PROTECTED (EFI_ERROR_MASK | 8) +#define EFI_OUT_OF_RESOURCES (EFI_ERROR_MASK | 9) +#define EFI_VOLUME_CORRUPTED (EFI_ERROR_MASK | 10) +#define EFI_VOLUME_FULL (EFI_ERROR_MASK | 11) +#define EFI_NO_MEDIA (EFI_ERROR_MASK | 12) +#define EFI_MEDIA_CHANGED (EFI_ERROR_MASK | 13) +#define EFI_NOT_FOUND (EFI_ERROR_MASK | 14) +#define EFI_ACCESS_DENIED (EFI_ERROR_MASK | 15) +#define EFI_NO_RESPONSE (EFI_ERROR_MASK | 16) +#define EFI_NO_MAPPING (EFI_ERROR_MASK | 17) +#define EFI_TIMEOUT (EFI_ERROR_MASK | 18) +#define EFI_NOT_STARTED (EFI_ERROR_MASK | 19) +#define EFI_ALREADY_STARTED (EFI_ERROR_MASK | 20) +#define EFI_ABORTED (EFI_ERROR_MASK | 21) +#define EFI_ICMP_ERROR (EFI_ERROR_MASK | 22) +#define EFI_TFTP_ERROR (EFI_ERROR_MASK | 23) +#define EFI_PROTOCOL_ERROR (EFI_ERROR_MASK | 24) +#define EFI_INCOMPATIBLE_VERSION (EFI_ERROR_MASK | 25) +#define EFI_SECURITY_VIOLATION (EFI_ERROR_MASK | 26) +#define EFI_CRC_ERROR (EFI_ERROR_MASK | 27) +#define EFI_END_OF_MEDIA (EFI_ERROR_MASK | 28) +#define EFI_END_OF_FILE (EFI_ERROR_MASK | 31) +#define EFI_INVALID_LANGUAGE (EFI_ERROR_MASK | 32) +#define EFI_COMPROMISED_DATA (EFI_ERROR_MASK | 33) +#define EFI_IP_ADDRESS_CONFLICT (EFI_ERROR_MASK | 34) +#define EFI_HTTP_ERROR (EFI_ERROR_MASK | 35) typedef unsigned long efi_status_t; typedef u64 efi_physical_addr_t; diff --git a/include/efi_api.h b/include/efi_api.h index f071b36b536..ec1b321e8e7 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -22,20 +22,33 @@ #endif /* Types and defines for EFI CreateEvent */ -enum efi_event_type { +enum efi_timer_delay { EFI_TIMER_STOP = 0, EFI_TIMER_PERIODIC = 1, EFI_TIMER_RELATIVE = 2 }; -#define EVT_NOTIFY_WAIT 0x00000100 -#define EVT_NOTIFY_SIGNAL 0x00000200 +#define UINTN size_t + +#define EVT_TIMER 0x80000000 +#define EVT_RUNTIME 0x40000000 +#define EVT_NOTIFY_WAIT 0x00000100 +#define EVT_NOTIFY_SIGNAL 0x00000200 +#define EVT_SIGNAL_EXIT_BOOT_SERVICES 0x00000201 +#define EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE 0x60000202 + +#define TPL_APPLICATION 0x04 +#define TPL_CALLBACK 0x08 +#define TPL_NOTIFY 0x10 +#define TPL_HIGH_LEVEL 0x1F + +struct efi_event; /* EFI Boot Services table */ struct efi_boot_services { struct efi_table_hdr hdr; - efi_status_t (EFIAPI *raise_tpl)(unsigned long new_tpl); - void (EFIAPI *restore_tpl)(unsigned long old_tpl); + efi_status_t (EFIAPI *raise_tpl)(UINTN new_tpl); + void (EFIAPI *restore_tpl)(UINTN old_tpl); efi_status_t (EFIAPI *allocate_pages)(int, int, unsigned long, efi_physical_addr_t *); @@ -46,19 +59,21 @@ struct efi_boot_services { efi_status_t (EFIAPI *allocate_pool)(int, unsigned long, void **); efi_status_t (EFIAPI *free_pool)(void *); - efi_status_t (EFIAPI *create_event)(enum efi_event_type type, - unsigned long notify_tpl, - void (EFIAPI *notify_function) (void *event, - void *context), - void *notify_context, void **event); - efi_status_t (EFIAPI *set_timer)(void *event, int type, - uint64_t trigger_time); + efi_status_t (EFIAPI *create_event)(uint32_t type, + UINTN notify_tpl, + void (EFIAPI *notify_function) ( + struct efi_event *event, + void *context), + void *notify_context, struct efi_event **event); + efi_status_t (EFIAPI *set_timer)(struct efi_event *event, + enum efi_timer_delay type, + uint64_t trigger_time); efi_status_t (EFIAPI *wait_for_event)(unsigned long number_of_events, - void *event, unsigned long *index); - efi_status_t (EFIAPI *signal_event)(void *event); - efi_status_t (EFIAPI *close_event)(void *event); - efi_status_t (EFIAPI *check_event)(void *event); - + struct efi_event **event, unsigned long *index); + efi_status_t (EFIAPI *signal_event)(struct efi_event *event); + efi_status_t (EFIAPI *close_event)(struct efi_event *event); + efi_status_t (EFIAPI *check_event)(struct efi_event *event); +#define EFI_NATIVE_INTERFACE 0x00000000 efi_status_t (EFIAPI *install_protocol_interface)( void **handle, efi_guid_t *protocol, int protocol_interface_type, void *protocol_interface); @@ -71,7 +86,7 @@ struct efi_boot_services { void **); void *reserved; efi_status_t (EFIAPI *register_protocol_notify)( - efi_guid_t *protocol, void *event, + efi_guid_t *protocol, struct efi_event *event, void **registration); efi_status_t (EFIAPI *locate_handle)( enum efi_locate_search_type search_type, @@ -334,6 +349,11 @@ struct simple_text_output_mode { bool cursor_visible; }; + +#define EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID \ + EFI_GUID(0x387477c2, 0x69c7, 0x11d2, \ + 0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b) + struct efi_simple_text_output_protocol { void *reset; efi_status_t (EFIAPI *output_string)( @@ -368,13 +388,17 @@ struct efi_input_key { s16 unicode_char; }; +#define EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID \ + EFI_GUID(0x387477c1, 0x69c7, 0x11d2, \ + 0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b) + struct efi_simple_input_interface { efi_status_t(EFIAPI *reset)(struct efi_simple_input_interface *this, bool ExtendedVerification); efi_status_t(EFIAPI *read_key_stroke)( struct efi_simple_input_interface *this, struct efi_input_key *key); - void *wait_for_key; + struct efi_event *wait_for_key; }; #define CONSOLE_CONTROL_GUID \ @@ -395,6 +419,30 @@ struct efi_console_control_protocol uint16_t *password); }; +#define EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID \ + EFI_GUID(0x8b843e20, 0x8132, 0x4852, \ + 0x90, 0xcc, 0x55, 0x1a, 0x4e, 0x4a, 0x7f, 0x1c) + +struct efi_device_path_protocol +{ + uint8_t type; + uint8_t sub_type; + uint16_t length; + uint8_t data[]; +}; + +struct efi_device_path_to_text_protocol +{ + uint16_t *(EFIAPI *convert_device_node_to_text)( + struct efi_device_path_protocol *device_node, + bool display_only, + bool allow_shortcuts); + uint16_t *(EFIAPI *convert_device_path_to_text)( + struct efi_device_path_protocol *device_path, + bool display_only, + bool allow_shortcuts); +}; + #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 99619f53a94..037cc7c5434 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -15,49 +15,65 @@ #include <linux/list.h> +int __efi_entry_check(void); +int __efi_exit_check(void); +const char *__efi_nesting_inc(void); +const char *__efi_nesting_dec(void); + +/* + * Enter the u-boot world from UEFI: + */ #define EFI_ENTRY(format, ...) do { \ - efi_restore_gd(); \ - debug("EFI: Entry %s(" format ")\n", __func__, ##__VA_ARGS__); \ + assert(__efi_entry_check()); \ + debug("%sEFI: Entry %s(" format ")\n", __efi_nesting_inc(), \ + __func__, ##__VA_ARGS__); \ } while(0) -#define EFI_EXIT(ret) efi_exit_func(ret); +/* + * Exit the u-boot world back to UEFI: + */ +#define EFI_EXIT(ret) ({ \ + efi_status_t _r = ret; \ + debug("%sEFI: Exit: %s: %u\n", __efi_nesting_dec(), \ + __func__, (u32)(_r & ~EFI_ERROR_MASK)); \ + assert(__efi_exit_check()); \ + _r; \ + }) + +/* + * Callback into UEFI world from u-boot: + */ +#define EFI_CALL(exp) do { \ + debug("%sEFI: Call: %s\n", __efi_nesting_inc(), #exp); \ + assert(__efi_exit_check()); \ + exp; \ + assert(__efi_entry_check()); \ + debug("%sEFI: Return From: %s\n", __efi_nesting_dec(), #exp); \ + } while(0) extern struct efi_runtime_services efi_runtime_services; extern struct efi_system_table systab; extern const struct efi_simple_text_output_protocol efi_con_out; -extern const struct efi_simple_input_interface efi_con_in; +extern struct efi_simple_input_interface efi_con_in; extern const struct efi_console_control_protocol efi_console_control; +extern const struct efi_device_path_to_text_protocol efi_device_path_to_text; extern const efi_guid_t efi_guid_console_control; extern const efi_guid_t efi_guid_device_path; extern const efi_guid_t efi_guid_loaded_image; +extern const efi_guid_t efi_guid_device_path_to_text_protocol; extern unsigned int __efi_runtime_start, __efi_runtime_stop; extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop; /* - * While UEFI objects can have callbacks, you can also call functions on - * protocols (classes) themselves. This struct maps a protocol GUID to its - * interface (usually a struct with callback functions). - */ -struct efi_class_map { - const efi_guid_t *guid; - const void *interface; -}; - -/* * When the UEFI payload wants to open a protocol on an object to get its * interface (usually a struct with callback functions), this struct maps the - * protocol GUID to the respective protocol handler open function for that - * object protocol combination. - */ + * protocol GUID to the respective protocol interface */ struct efi_handler { const efi_guid_t *guid; - efi_status_t (EFIAPI *open)(void *handle, - efi_guid_t *protocol, void **protocol_interface, - void *agent_handle, void *controller_handle, - uint32_t attributes); + void *protocol_interface; }; /* @@ -70,15 +86,49 @@ struct efi_handler { struct efi_object { /* Every UEFI object is part of a global object list */ struct list_head link; - /* We support up to 4 "protocols" an object can be accessed through */ - struct efi_handler protocols[4]; + /* We support up to 8 "protocols" an object can be accessed through */ + struct efi_handler protocols[8]; /* The object spawner can either use this for data or as identifier */ void *handle; }; +#define EFI_PROTOCOL_OBJECT(_guid, _protocol) (struct efi_object){ \ + .protocols = {{ \ + .guid = &(_guid), \ + .protocol_interface = (void *)(_protocol), \ + }}, \ + .handle = (void *)(_protocol), \ +} + +/** + * struct efi_event + * + * @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_type: Type of timer, see efi_set_timer + * @signaled: The notify function was already called + */ +struct efi_event { + uint32_t type; + UINTN notify_tpl; + void (EFIAPI *notify_function)(struct efi_event *event, void *context); + void *notify_context; + u64 trigger_next; + u64 trigger_time; + enum efi_timer_delay trigger_type; + int signaled; +}; + + /* This list contains all UEFI objects we know of */ 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); /* Called by bootefi to make GOP (graphical) interface available */ @@ -91,28 +141,30 @@ void efi_smbios_register(void); /* Called by networking code to memorize the dhcp ack package */ void efi_net_set_dhcp_ack(void *pkt, int len); -/* - * Stub implementation for a protocol opener that just returns the handle as - * interface - */ -efi_status_t EFIAPI efi_return_handle(void *handle, - efi_guid_t *protocol, void **protocol_interface, - void *agent_handle, void *controller_handle, - uint32_t attributes); /* Called from places to check whether a timer expired */ void efi_timer_check(void); /* PE loader implementation */ void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info); /* Called once to store the pristine gd pointer */ void efi_save_gd(void); -/* Called from EFI_ENTRY on callback entry to put gd into the gd register */ +/* Special case handler for error/abort that just tries to dtrt to get + * back to u-boot world */ void efi_restore_gd(void); -/* Called from EFI_EXIT on callback exit to restore the gd register */ -efi_status_t efi_exit_func(efi_status_t ret); /* Call this to relocate the runtime section to an address space */ void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map); /* Call this to set the current device name */ void efi_set_bootdev(const char *dev, const char *devnr, const char *path); +/* Call this to create an event */ +efi_status_t efi_create_event(uint32_t type, UINTN notify_tpl, + void (EFIAPI *notify_function) ( + struct efi_event *event, + void *context), + void *notify_context, 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); +/* Call this to signal an event */ +void efi_signal_event(struct efi_event *event); /* Generic EFI memory allocator, call this to get memory */ void *efi_alloc(uint64_t len, int memory_type); @@ -152,6 +204,11 @@ static inline void ascii2unicode(u16 *unicode, const char *ascii) *(unicode++) = *(ascii++); } +static inline int guidcmp(const efi_guid_t *g1, const efi_guid_t *g2) +{ + return memcmp(g1, g2, sizeof(efi_guid_t)); +} + /* * Use these to indicate that your code / data should go into the EFI runtime * section and thus still be available when the OS is running diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index fa8b91a5269..30bf343a365 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -15,8 +15,9 @@ always := $(efiprogs-y) 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 +obj-y += efi_memory.o efi_device_path_to_text.o obj-$(CONFIG_LCD) += efi_gop.o +obj-$(CONFIG_DM_VIDEO) += efi_gop.o obj-$(CONFIG_PARTITIONS) += efi_disk.o obj-$(CONFIG_NET) += efi_net.o obj-$(CONFIG_GENERATE_SMBIOS_TABLE) += efi_smbios.o diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 27e51a253fc..59479eddb9d 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -49,6 +49,31 @@ static struct efi_configuration_table __efi_runtime_data efi_conf_table[2]; static volatile void *efi_gd, *app_gd; #endif +static int entry_count; +static int nesting_level; + +/* Called on every callback entry */ +int __efi_entry_check(void) +{ + int ret = entry_count++ == 0; +#ifdef CONFIG_ARM + assert(efi_gd); + app_gd = gd; + gd = efi_gd; +#endif + return ret; +} + +/* Called on every callback exit */ +int __efi_exit_check(void) +{ + int ret = --entry_count == 0; +#ifdef CONFIG_ARM + gd = app_gd; +#endif + return ret; +} + /* Called from do_bootefi_exec() */ void efi_save_gd(void) { @@ -57,51 +82,102 @@ void efi_save_gd(void) #endif } -/* Called on every callback entry */ +/* + * Special case handler for error/abort that just forces things back + * to u-boot world so we can dump out an abort msg, without any care + * about returning back to UEFI world. + */ void efi_restore_gd(void) { #ifdef CONFIG_ARM /* Only restore if we're already in EFI context */ if (!efi_gd) return; - - if (gd != efi_gd) - app_gd = gd; gd = efi_gd; #endif } -/* Called on every callback exit */ -efi_status_t efi_exit_func(efi_status_t ret) +/* + * Two spaces per indent level, maxing out at 10.. which ought to be + * enough for anyone ;-) + */ +static const char *indent_string(int level) { -#ifdef CONFIG_ARM - gd = app_gd; -#endif + const char *indent = " "; + const int max = strlen(indent); + level = min(max, level * 2); + return &indent[max - level]; +} + +const char *__efi_nesting_inc(void) +{ + return indent_string(nesting_level++); +} +const char *__efi_nesting_dec(void) +{ + return indent_string(--nesting_level); +} + +/* Low 32 bit */ +#define EFI_LOW32(a) (a & 0xFFFFFFFFULL) +/* High 32 bit */ +#define EFI_HIGH32(a) (a >> 32) + +/* + * 64bit division by 10 implemented as multiplication by 1 / 10 + * + * Decimals of one tenth: 0x1 / 0xA = 0x0.19999... + */ +#define EFI_TENTH 0x199999999999999A +static u64 efi_div10(u64 a) +{ + u64 prod; + u64 rem; + u64 ret; + + ret = EFI_HIGH32(a) * EFI_HIGH32(EFI_TENTH); + prod = EFI_HIGH32(a) * EFI_LOW32(EFI_TENTH); + rem = EFI_LOW32(prod); + ret += EFI_HIGH32(prod); + prod = EFI_LOW32(a) * EFI_HIGH32(EFI_TENTH); + rem += EFI_LOW32(prod); + ret += EFI_HIGH32(prod); + prod = EFI_LOW32(a) * EFI_LOW32(EFI_TENTH); + rem += EFI_HIGH32(prod); + ret += EFI_HIGH32(rem); + /* Round to nearest integer */ + if (rem >= (1 << 31)) + ++ret; return ret; } -static efi_status_t efi_unsupported(const char *funcname) +void efi_signal_event(struct efi_event *event) { - debug("EFI: App called into unimplemented function %s\n", funcname); - return EFI_EXIT(EFI_UNSUPPORTED); + if (event->signaled) + return; + event->signaled = 1; + if (event->type & EVT_NOTIFY_SIGNAL) { + EFI_CALL(event->notify_function(event, event->notify_context)); + } } -static int guidcmp(const efi_guid_t *g1, const efi_guid_t *g2) +static efi_status_t efi_unsupported(const char *funcname) { - return memcmp(g1, g2, sizeof(efi_guid_t)); + debug("EFI: App called into unimplemented function %s\n", funcname); + return EFI_EXIT(EFI_UNSUPPORTED); } -static unsigned long EFIAPI efi_raise_tpl(unsigned long new_tpl) +static unsigned long EFIAPI efi_raise_tpl(UINTN new_tpl) { - EFI_ENTRY("0x%lx", new_tpl); + EFI_ENTRY("0x%zx", new_tpl); return EFI_EXIT(0); } -static void EFIAPI efi_restore_tpl(unsigned long old_tpl) +static void EFIAPI efi_restore_tpl(UINTN old_tpl) { - EFI_ENTRY("0x%lx", old_tpl); - EFI_EXIT(efi_unsupported(__func__)); + EFI_ENTRY("0x%zx", old_tpl); + efi_unsupported(__func__); } static efi_status_t EFIAPI efi_allocate_pages_ext(int type, int memory_type, @@ -162,151 +238,289 @@ static efi_status_t EFIAPI efi_free_pool_ext(void *buffer) } /* - * Our event capabilities are very limited. Only support a single - * event to exist, so we don't need to maintain lists. + * Our event capabilities are very limited. Only a small limited + * number of events is allowed to coexist. */ -static struct { - enum efi_event_type type; - u32 trigger_type; - u32 trigger_time; - u64 trigger_next; - unsigned long notify_tpl; - void (EFIAPI *notify_function) (void *event, void *context); - void *notify_context; -} efi_event = { - /* Disable timers on bootup */ - .trigger_next = -1ULL, -}; +static struct efi_event efi_events[16]; -static efi_status_t EFIAPI efi_create_event( - enum efi_event_type type, ulong notify_tpl, - void (EFIAPI *notify_function) (void *event, - void *context), - void *notify_context, void **event) +efi_status_t efi_create_event(uint32_t type, UINTN notify_tpl, + void (EFIAPI *notify_function) ( + struct efi_event *event, + void *context), + void *notify_context, struct efi_event **event) { - EFI_ENTRY("%d, 0x%lx, %p, %p", type, notify_tpl, notify_function, - notify_context); - if (efi_event.notify_function) { - /* We only support one event at a time */ - return EFI_EXIT(EFI_OUT_OF_RESOURCES); - } + int i; if (event == NULL) - return EFI_EXIT(EFI_INVALID_PARAMETER); + return EFI_INVALID_PARAMETER; if ((type & EVT_NOTIFY_SIGNAL) && (type & EVT_NOTIFY_WAIT)) - return EFI_EXIT(EFI_INVALID_PARAMETER); + return EFI_INVALID_PARAMETER; if ((type & (EVT_NOTIFY_SIGNAL|EVT_NOTIFY_WAIT)) && notify_function == NULL) - return EFI_EXIT(EFI_INVALID_PARAMETER); + return EFI_INVALID_PARAMETER; - efi_event.type = type; - efi_event.notify_tpl = notify_tpl; - efi_event.notify_function = notify_function; - efi_event.notify_context = notify_context; - *event = &efi_event; + 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].signaled = 0; + *event = &efi_events[i]; + return EFI_SUCCESS; + } + return EFI_OUT_OF_RESOURCES; +} - return EFI_EXIT(EFI_SUCCESS); +static efi_status_t EFIAPI efi_create_event_ext( + uint32_t type, UINTN notify_tpl, + void (EFIAPI *notify_function) ( + struct efi_event *event, + void *context), + void *notify_context, struct efi_event **event) +{ + 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)); } + /* * Our timers have to work without interrupts, so we check whenever keyboard * input or disk accesses happen if enough time elapsed for it to fire. */ void efi_timer_check(void) { + int i; u64 now = timer_get_us(); - if (now >= efi_event.trigger_next) { - /* Triggering! */ - if (efi_event.trigger_type == EFI_TIMER_PERIODIC) - efi_event.trigger_next += efi_event.trigger_time / 10; - if (efi_event.type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) - efi_event.notify_function(&efi_event, - efi_event.notify_context); + for (i = 0; i < ARRAY_SIZE(efi_events); ++i) { + if (!efi_events[i].type || + !(efi_events[i].type & EVT_TIMER) || + efi_events[i].trigger_type == EFI_TIMER_STOP || + now < efi_events[i].trigger_next) + continue; + if (efi_events[i].trigger_type == EFI_TIMER_PERIODIC) { + efi_events[i].trigger_next += + efi_events[i].trigger_time; + efi_events[i].signaled = 0; + } + efi_signal_event(&efi_events[i]); } - WATCHDOG_RESET(); } -static efi_status_t EFIAPI efi_set_timer(void *event, int type, - uint64_t trigger_time) +efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type, + uint64_t trigger_time) { - /* We don't have 64bit division available everywhere, so limit timer - * distances to 32bit bits. */ - u32 trigger32 = trigger_time; - - EFI_ENTRY("%p, %d, %"PRIx64, event, type, trigger_time); + int i; - if (trigger32 < trigger_time) { - printf("WARNING: Truncating timer from %"PRIx64" to %x\n", - trigger_time, trigger32); - } + /* + * The parameter defines a multiple of 100ns. + * We use multiples of 1000ns. So divide by 10. + */ + trigger_time = efi_div10(trigger_time); - if (event != &efi_event) { - /* We only support one event at a time */ - return EFI_EXIT(EFI_INVALID_PARAMETER); - } + for (i = 0; i < ARRAY_SIZE(efi_events); ++i) { + if (event != &efi_events[i]) + continue; - switch (type) { - case EFI_TIMER_STOP: - efi_event.trigger_next = -1ULL; - break; - case EFI_TIMER_PERIODIC: - case EFI_TIMER_RELATIVE: - efi_event.trigger_next = timer_get_us() + (trigger32 / 10); - break; - default: - return EFI_EXIT(EFI_INVALID_PARAMETER); + 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; + return EFI_SUCCESS; } - efi_event.trigger_type = type; - efi_event.trigger_time = trigger_time; + return EFI_INVALID_PARAMETER; +} - return EFI_EXIT(EFI_SUCCESS); +static efi_status_t EFIAPI efi_set_timer_ext(struct efi_event *event, + enum efi_timer_delay type, + uint64_t trigger_time) +{ + EFI_ENTRY("%p, %d, %"PRIx64, event, type, trigger_time); + return EFI_EXIT(efi_set_timer(event, type, trigger_time)); } static efi_status_t EFIAPI efi_wait_for_event(unsigned long num_events, - void *event, unsigned long *index) + struct efi_event **event, + unsigned long *index) { - u64 now; + int i, j; EFI_ENTRY("%ld, %p, %p", num_events, event, index); - now = timer_get_us(); - while (now < efi_event.trigger_next) { } - efi_timer_check(); + /* Check parameters */ + if (!num_events || !event) + return EFI_EXIT(EFI_INVALID_PARAMETER); + 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 (!event[i]->type || event[i]->type & EVT_NOTIFY_SIGNAL) + return EFI_EXIT(EFI_INVALID_PARAMETER); + } + + /* Wait for signal */ + for (;;) { + for (i = 0; i < num_events; ++i) { + if (event[i]->signaled) + goto out; + } + /* Allow events to occur. */ + efi_timer_check(); + } + +out: + /* + * Reset the signal which is passed to the caller to allow periodic + * events to occur. + */ + event[i]->signaled = 0; + if (index) + *index = i; return EFI_EXIT(EFI_SUCCESS); } -static efi_status_t EFIAPI efi_signal_event(void *event) +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; + efi_signal_event(event); + break; + } return EFI_EXIT(EFI_SUCCESS); } -static efi_status_t EFIAPI efi_close_event(void *event) +static efi_status_t EFIAPI efi_close_event(struct efi_event *event) { + int i; + EFI_ENTRY("%p", event); - efi_event.trigger_next = -1ULL; - return EFI_EXIT(EFI_SUCCESS); + for (i = 0; i < ARRAY_SIZE(efi_events); ++i) { + if (event == &efi_events[i]) { + event->type = 0; + event->trigger_next = -1ULL; + event->signaled = 0; + return EFI_EXIT(EFI_SUCCESS); + } + } + return EFI_EXIT(EFI_INVALID_PARAMETER); } -static efi_status_t EFIAPI efi_check_event(void *event) +static efi_status_t EFIAPI efi_check_event(struct efi_event *event) { + int i; + EFI_ENTRY("%p", event); - return EFI_EXIT(EFI_NOT_READY); + 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->signaled) + return EFI_EXIT(EFI_SUCCESS); + return EFI_EXIT(EFI_NOT_READY); + } + return EFI_EXIT(EFI_INVALID_PARAMETER); } static efi_status_t EFIAPI efi_install_protocol_interface(void **handle, efi_guid_t *protocol, int protocol_interface_type, void *protocol_interface) { + struct list_head *lhandle; + int i; + efi_status_t r; + + if (!handle || !protocol || + protocol_interface_type != EFI_NATIVE_INTERFACE) { + r = EFI_INVALID_PARAMETER; + goto out; + } + + /* Create new handle if requested. */ + if (!*handle) { + r = EFI_OUT_OF_RESOURCES; + goto out; + } + /* Find object. */ + list_for_each(lhandle, &efi_obj_list) { + struct efi_object *efiobj; + efiobj = list_entry(lhandle, struct efi_object, link); + + if (efiobj->handle != *handle) + continue; + /* Check if protocol is already installed on the handle. */ + for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) { + struct efi_handler *handler = &efiobj->protocols[i]; + + if (!handler->guid) + continue; + if (!guidcmp(handler->guid, protocol)) { + r = EFI_INVALID_PARAMETER; + goto out; + } + } + /* Install protocol in first empty slot. */ + for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) { + struct efi_handler *handler = &efiobj->protocols[i]; + + if (handler->guid) + continue; + + handler->guid = protocol; + handler->protocol_interface = protocol_interface; + r = EFI_SUCCESS; + goto out; + } + r = EFI_OUT_OF_RESOURCES; + goto out; + } + r = EFI_INVALID_PARAMETER; +out: + return r; +} + +static efi_status_t EFIAPI efi_install_protocol_interface_ext(void **handle, + efi_guid_t *protocol, int protocol_interface_type, + void *protocol_interface) +{ EFI_ENTRY("%p, %p, %d, %p", handle, protocol, protocol_interface_type, protocol_interface); - return EFI_EXIT(EFI_OUT_OF_RESOURCES); + + return EFI_EXIT(efi_install_protocol_interface(handle, protocol, + protocol_interface_type, + protocol_interface)); } + static efi_status_t EFIAPI efi_reinstall_protocol_interface(void *handle, efi_guid_t *protocol, void *old_interface, void *new_interface) @@ -319,12 +533,55 @@ static efi_status_t EFIAPI efi_reinstall_protocol_interface(void *handle, static efi_status_t EFIAPI efi_uninstall_protocol_interface(void *handle, efi_guid_t *protocol, void *protocol_interface) { + struct list_head *lhandle; + int i; + efi_status_t r = EFI_NOT_FOUND; + + if (!handle || !protocol) { + r = EFI_INVALID_PARAMETER; + goto out; + } + + list_for_each(lhandle, &efi_obj_list) { + struct efi_object *efiobj; + efiobj = list_entry(lhandle, struct efi_object, link); + + if (efiobj->handle != handle) + continue; + + for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) { + struct efi_handler *handler = &efiobj->protocols[i]; + const efi_guid_t *hprotocol = handler->guid; + + if (!hprotocol) + continue; + if (!guidcmp(hprotocol, protocol)) { + if (handler->protocol_interface) { + r = EFI_ACCESS_DENIED; + } else { + handler->guid = 0; + r = EFI_SUCCESS; + } + goto out; + } + } + } + +out: + return r; +} + +static efi_status_t EFIAPI efi_uninstall_protocol_interface_ext(void *handle, + efi_guid_t *protocol, void *protocol_interface) +{ EFI_ENTRY("%p, %p, %p", handle, protocol, protocol_interface); - return EFI_EXIT(EFI_NOT_FOUND); + + return EFI_EXIT(efi_uninstall_protocol_interface(handle, protocol, + protocol_interface)); } static efi_status_t EFIAPI efi_register_protocol_notify(efi_guid_t *protocol, - void *event, + struct efi_event *event, void **registration) { EFI_ENTRY("%p, %p, %p", protocol, event, registration); @@ -362,9 +619,6 @@ static efi_status_t EFIAPI efi_locate_handle( struct list_head *lhandle; unsigned long size = 0; - EFI_ENTRY("%d, %p, %p, %p, %p", search_type, protocol, search_key, - buffer_size, buffer); - /* Count how much space we need */ list_for_each(lhandle, &efi_obj_list) { struct efi_object *efiobj; @@ -376,7 +630,7 @@ static efi_status_t EFIAPI efi_locate_handle( if (*buffer_size < size) { *buffer_size = size; - return EFI_EXIT(EFI_BUFFER_TOO_SMALL); + return EFI_BUFFER_TOO_SMALL; } /* Then fill the array */ @@ -389,7 +643,19 @@ static efi_status_t EFIAPI efi_locate_handle( } *buffer_size = size; - return EFI_EXIT(EFI_SUCCESS); + return EFI_SUCCESS; +} + +static efi_status_t EFIAPI efi_locate_handle_ext( + enum efi_locate_search_type search_type, + efi_guid_t *protocol, void *search_key, + unsigned long *buffer_size, efi_handle_t *buffer) +{ + EFI_ENTRY("%d, %p, %p, %p, %p", search_type, protocol, search_key, + buffer_size, buffer); + + return EFI_EXIT(efi_locate_handle(search_type, protocol, search_key, + buffer_size, buffer)); } static efi_status_t EFIAPI efi_locate_device_path(efi_guid_t *protocol, @@ -400,6 +666,17 @@ static efi_status_t EFIAPI efi_locate_device_path(efi_guid_t *protocol, return EFI_EXIT(EFI_NOT_FOUND); } +/* Collapses configuration table entries, removing index i */ +static void efi_remove_configuration_table(int i) +{ + struct efi_configuration_table *this = &efi_conf_table[i]; + struct efi_configuration_table *next = &efi_conf_table[i+1]; + struct efi_configuration_table *end = &efi_conf_table[systab.nr_tables]; + + memmove(this, next, (ulong)end - (ulong)next); + systab.nr_tables--; +} + efi_status_t efi_install_configuration_table(const efi_guid_t *guid, void *table) { int i; @@ -407,11 +684,17 @@ efi_status_t efi_install_configuration_table(const efi_guid_t *guid, void *table /* Check for guid override */ for (i = 0; i < systab.nr_tables; i++) { if (!guidcmp(guid, &efi_conf_table[i].guid)) { - efi_conf_table[i].table = table; + if (table) + efi_conf_table[i].table = table; + else + efi_remove_configuration_table(i); return EFI_SUCCESS; } } + if (!table) + return EFI_NOT_FOUND; + /* No override, check for overflow */ if (i >= ARRAY_SIZE(efi_conf_table)) return EFI_OUT_OF_RESOURCES; @@ -442,7 +725,6 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy, .protocols = { { .guid = &efi_guid_loaded_image, - .open = &efi_return_handle, }, }, }; @@ -452,6 +734,7 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy, EFI_ENTRY("%d, %p, %p, %p, %ld, %p", boot_policy, parent_image, file_path, source_buffer, source_size, image_handle); info = malloc(sizeof(*info)); + loaded_image_info_obj.protocols[0].protocol_interface = info; obj = malloc(sizeof(loaded_image_info_obj)); memset(info, 0, sizeof(*info)); memcpy(obj, &loaded_image_info_obj, sizeof(loaded_image_info_obj)); @@ -488,7 +771,11 @@ static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, return EFI_EXIT(info->exit_status); } + __efi_nesting_dec(); + __efi_exit_check(); entry(image_handle, &systab); + __efi_entry_check(); + __efi_nesting_inc(); /* Should usually never get here */ return EFI_EXIT(EFI_SUCCESS); @@ -588,7 +875,7 @@ static efi_status_t EFIAPI efi_set_watchdog_timer(unsigned long timeout, { EFI_ENTRY("%ld, 0x%"PRIx64", %ld, %p", timeout, watchdog_code, data_size, watchdog_data); - return EFI_EXIT(efi_unsupported(__func__)); + return efi_unsupported(__func__); } static efi_status_t EFIAPI efi_connect_controller( @@ -635,9 +922,53 @@ static efi_status_t EFIAPI efi_protocols_per_handle(void *handle, efi_guid_t ***protocol_buffer, unsigned long *protocol_buffer_count) { + unsigned long buffer_size; + struct efi_object *efiobj; + unsigned long i, j; + struct list_head *lhandle; + efi_status_t r; + EFI_ENTRY("%p, %p, %p", handle, protocol_buffer, protocol_buffer_count); - return EFI_EXIT(EFI_OUT_OF_RESOURCES); + + if (!handle || !protocol_buffer || !protocol_buffer_count) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + *protocol_buffer = NULL; + *protocol_buffer_count = 0; + list_for_each(lhandle, &efi_obj_list) { + efiobj = list_entry(lhandle, struct efi_object, link); + + if (efiobj->handle != handle) + continue; + + /* Count protocols */ + for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) { + if (efiobj->protocols[i].guid) + ++*protocol_buffer_count; + } + /* Copy guids */ + if (*protocol_buffer_count) { + buffer_size = sizeof(efi_guid_t *) * + *protocol_buffer_count; + r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, + buffer_size, + (void **)protocol_buffer); + if (r != EFI_SUCCESS) + return EFI_EXIT(r); + j = 0; + for (i = 0; i < ARRAY_SIZE(efiobj->protocols); ++i) { + if (efiobj->protocols[i].guid) { + (*protocol_buffer)[j] = (void *) + efiobj->protocols[i].guid; + ++j; + } + } + } + break; + } + + return EFI_EXIT(EFI_SUCCESS); } static efi_status_t EFIAPI efi_locate_handle_buffer( @@ -645,32 +976,63 @@ static efi_status_t EFIAPI efi_locate_handle_buffer( efi_guid_t *protocol, void *search_key, unsigned long *no_handles, efi_handle_t **buffer) { + efi_status_t r; + unsigned long buffer_size = 0; + EFI_ENTRY("%d, %p, %p, %p, %p", search_type, protocol, search_key, no_handles, buffer); - return EFI_EXIT(EFI_NOT_FOUND); -} -static struct efi_class_map efi_class_maps[] = { - { - .guid = &efi_guid_console_control, - .interface = &efi_console_control - }, -}; + 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_ALLOCATE_ANY_PAGES, 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(void *); +out: + return EFI_EXIT(r); +} static efi_status_t EFIAPI efi_locate_protocol(efi_guid_t *protocol, void *registration, void **protocol_interface) { + struct list_head *lhandle; int i; EFI_ENTRY("%p, %p, %p", protocol, registration, protocol_interface); - for (i = 0; i < ARRAY_SIZE(efi_class_maps); i++) { - struct efi_class_map *curmap = &efi_class_maps[i]; - if (!guidcmp(protocol, curmap->guid)) { - *protocol_interface = (void*)curmap->interface; - return EFI_EXIT(EFI_SUCCESS); + + if (!protocol || !protocol_interface) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + list_for_each(lhandle, &efi_obj_list) { + struct efi_object *efiobj; + + efiobj = list_entry(lhandle, struct efi_object, link); + for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) { + struct efi_handler *handler = &efiobj->protocols[i]; + + if (!handler->guid) + continue; + if (!guidcmp(handler->guid, protocol)) { + *protocol_interface = + handler->protocol_interface; + return EFI_EXIT(EFI_SUCCESS); + } } } + *protocol_interface = NULL; return EFI_EXIT(EFI_NOT_FOUND); } @@ -679,7 +1041,44 @@ static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces( void **handle, ...) { EFI_ENTRY("%p", handle); - return EFI_EXIT(EFI_OUT_OF_RESOURCES); + + va_list argptr; + efi_guid_t *protocol; + void *protocol_interface; + efi_status_t r = EFI_SUCCESS; + int i = 0; + + if (!handle) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + va_start(argptr, handle); + for (;;) { + protocol = va_arg(argptr, efi_guid_t*); + if (!protocol) + break; + protocol_interface = va_arg(argptr, void*); + r = efi_install_protocol_interface(handle, protocol, + EFI_NATIVE_INTERFACE, + protocol_interface); + if (r != EFI_SUCCESS) + break; + i++; + } + va_end(argptr); + if (r == EFI_SUCCESS) + return EFI_EXIT(r); + + /* If an error occured undo all changes. */ + va_start(argptr, handle); + for (; i; --i) { + protocol = va_arg(argptr, efi_guid_t*); + protocol_interface = va_arg(argptr, void*); + efi_uninstall_protocol_interface(handle, protocol, + protocol_interface); + } + va_end(argptr); + + return EFI_EXIT(r); } static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces( @@ -718,11 +1117,38 @@ static efi_status_t EFIAPI efi_open_protocol( { struct list_head *lhandle; int i; - efi_status_t r = EFI_UNSUPPORTED; + efi_status_t r = EFI_INVALID_PARAMETER; EFI_ENTRY("%p, %p, %p, %p, %p, 0x%x", handle, protocol, protocol_interface, agent_handle, controller_handle, attributes); + + if (!handle || !protocol || + (!protocol_interface && attributes != + EFI_OPEN_PROTOCOL_TEST_PROTOCOL)) { + goto out; + } + + switch (attributes) { + case EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL: + case EFI_OPEN_PROTOCOL_GET_PROTOCOL: + case EFI_OPEN_PROTOCOL_TEST_PROTOCOL: + break; + case EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER: + if (controller_handle == handle) + goto out; + case EFI_OPEN_PROTOCOL_BY_DRIVER: + case EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE: + if (controller_handle == NULL) + goto out; + case EFI_OPEN_PROTOCOL_EXCLUSIVE: + if (agent_handle == NULL) + goto out; + break; + default: + goto out; + } + list_for_each(lhandle, &efi_obj_list) { struct efi_object *efiobj; efiobj = list_entry(lhandle, struct efi_object, link); @@ -734,16 +1160,22 @@ static efi_status_t EFIAPI efi_open_protocol( struct efi_handler *handler = &efiobj->protocols[i]; const efi_guid_t *hprotocol = handler->guid; if (!hprotocol) - break; + continue; if (!guidcmp(hprotocol, protocol)) { - r = handler->open(handle, protocol, - protocol_interface, agent_handle, - controller_handle, attributes); + if (attributes != + EFI_OPEN_PROTOCOL_TEST_PROTOCOL) { + *protocol_interface = + handler->protocol_interface; + } + r = EFI_SUCCESS; goto out; } } + goto unsupported; } +unsupported: + r = EFI_UNSUPPORTED; out: return EFI_EXIT(r); } @@ -767,19 +1199,19 @@ static const struct efi_boot_services efi_boot_services = { .get_memory_map = efi_get_memory_map_ext, .allocate_pool = efi_allocate_pool_ext, .free_pool = efi_free_pool_ext, - .create_event = efi_create_event, - .set_timer = efi_set_timer, + .create_event = efi_create_event_ext, + .set_timer = efi_set_timer_ext, .wait_for_event = efi_wait_for_event, - .signal_event = efi_signal_event, + .signal_event = efi_signal_event_ext, .close_event = efi_close_event, .check_event = efi_check_event, - .install_protocol_interface = efi_install_protocol_interface, + .install_protocol_interface = efi_install_protocol_interface_ext, .reinstall_protocol_interface = efi_reinstall_protocol_interface, - .uninstall_protocol_interface = efi_uninstall_protocol_interface, + .uninstall_protocol_interface = efi_uninstall_protocol_interface_ext, .handle_protocol = efi_handle_protocol, .reserved = NULL, .register_protocol_notify = efi_register_protocol_notify, - .locate_handle = efi_locate_handle, + .locate_handle = efi_locate_handle_ext, .locate_device_path = efi_locate_device_path, .install_configuration_table = efi_install_configuration_table_ext, .load_image = efi_load_image, diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c index 8ef7326fef2..5ebce4b544d 100644 --- a/lib/efi_loader/efi_console.c +++ b/lib/efi_loader/efi_console.c @@ -421,8 +421,61 @@ static efi_status_t EFIAPI efi_cin_read_key_stroke( return EFI_EXIT(EFI_SUCCESS); } -const struct efi_simple_input_interface efi_con_in = { +struct efi_simple_input_interface efi_con_in = { .reset = efi_cin_reset, .read_key_stroke = efi_cin_read_key_stroke, .wait_for_key = NULL, }; + +static struct efi_event *console_timer_event; + +static void EFIAPI efi_key_notify(struct efi_event *event, void *context) +{ +} + +static void EFIAPI efi_console_timer_notify(struct efi_event *event, + void *context) +{ + EFI_ENTRY("%p, %p", event, context); + if (tstc()) + efi_signal_event(efi_con_in.wait_for_key); + EFI_EXIT(EFI_SUCCESS); +} + + +static struct efi_object efi_console_control_obj = + EFI_PROTOCOL_OBJECT(efi_guid_console_control, &efi_console_control); +static struct efi_object efi_console_output_obj = + EFI_PROTOCOL_OBJECT(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID, &efi_con_out); +static struct efi_object efi_console_input_obj = + EFI_PROTOCOL_OBJECT(EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID, &efi_con_in); + +/* This gets called from do_bootefi_exec(). */ +int efi_console_register(void) +{ + efi_status_t r; + + /* Hook up to the device list */ + list_add_tail(&efi_console_control_obj.link, &efi_obj_list); + list_add_tail(&efi_console_output_obj.link, &efi_obj_list); + list_add_tail(&efi_console_input_obj.link, &efi_obj_list); + + r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK, + efi_key_notify, 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, + &console_timer_event); + if (r != EFI_SUCCESS) { + printf("ERROR: Failed to register console event\n"); + return r; + } + /* 5000 ns cycle is sufficient for 2 MBaud */ + r = efi_set_timer(console_timer_event, EFI_TIMER_PERIODIC, 50); + if (r != EFI_SUCCESS) + printf("ERROR: Failed to set console timer\n"); + return r; +} diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c new file mode 100644 index 00000000000..4b2f43f0c8a --- /dev/null +++ b/lib/efi_loader/efi_device_path_to_text.c @@ -0,0 +1,130 @@ +/* + * EFI device path interface + * + * Copyright (c) 2017 Heinrich Schuchardt + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <efi_loader.h> + +#define MAC_OUTPUT_LEN 22 +#define UNKNOWN_OUTPUT_LEN 23 + +const efi_guid_t efi_guid_device_path_to_text_protocol = + EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID; + +static uint16_t *efi_convert_device_node_to_text( + struct efi_device_path_protocol *device_node, + bool display_only, + bool allow_shortcuts) +{ + unsigned long buffer_size; + efi_status_t r; + uint16_t *buffer = NULL; + int i; + + switch (device_node->type) { + case DEVICE_PATH_TYPE_END: + return NULL; + case DEVICE_PATH_TYPE_MESSAGING_DEVICE: + switch (device_node->sub_type) { + case DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR: { + struct efi_device_path_mac_addr *dp = + (struct efi_device_path_mac_addr *)device_node; + + if (dp->if_type != 0 && dp->if_type != 1) + break; + r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, + 2 * MAC_OUTPUT_LEN, + (void **)&buffer); + if (r != EFI_SUCCESS) + return NULL; + sprintf((char *)buffer, + "MAC(%02x%02x%02x%02x%02x%02x,0x%1x)", + dp->mac.addr[0], dp->mac.addr[1], + dp->mac.addr[2], dp->mac.addr[3], + dp->mac.addr[4], dp->mac.addr[5], + dp->if_type); + for (i = MAC_OUTPUT_LEN - 1; i >= 0; --i) + buffer[i] = ((uint8_t *)buffer)[i]; + break; + } + } + break; + case DEVICE_PATH_TYPE_MEDIA_DEVICE: + switch (device_node->sub_type) { + case DEVICE_PATH_SUB_TYPE_FILE_PATH: + buffer_size = device_node->length - 4; + r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, + buffer_size, (void **) &buffer); + if (r != EFI_SUCCESS) + return NULL; + memcpy(buffer, device_node->data, buffer_size); + break; + } + break; + } + + /* + * For all node types that we do not yet support return + * 'UNKNOWN(type,subtype)'. + */ + if (!buffer) { + r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, + 2 * UNKNOWN_OUTPUT_LEN, + (void **)&buffer); + if (r != EFI_SUCCESS) + return NULL; + sprintf((char *)buffer, + "UNKNOWN(%04x,%04x)", + device_node->type, + device_node->sub_type); + for (i = UNKNOWN_OUTPUT_LEN - 1; i >= 0; --i) + buffer[i] = ((uint8_t *)buffer)[i]; + } + + return buffer; +} + +static uint16_t EFIAPI *efi_convert_device_node_to_text_ext( + struct efi_device_path_protocol *device_node, + bool display_only, + bool allow_shortcuts) +{ + uint16_t *buffer; + + EFI_ENTRY("%p, %d, %d", device_node, display_only, allow_shortcuts); + + buffer = efi_convert_device_node_to_text(device_node, display_only, + allow_shortcuts); + + EFI_EXIT(EFI_SUCCESS); + return buffer; +} + +static uint16_t EFIAPI *efi_convert_device_path_to_text( + struct efi_device_path_protocol *device_path, + bool display_only, + bool allow_shortcuts) +{ + uint16_t *buffer; + + EFI_ENTRY("%p, %d, %d", device_path, display_only, allow_shortcuts); + + /* + * Our device paths are all of depth one. So its is sufficient to + * to convert the first node. + */ + buffer = efi_convert_device_node_to_text(device_path, display_only, + allow_shortcuts); + + EFI_EXIT(EFI_SUCCESS); + return buffer; +} + +const struct efi_device_path_to_text_protocol efi_device_path_to_text = { + .convert_device_node_to_text = efi_convert_device_node_to_text_ext, + .convert_device_path_to_text = efi_convert_device_path_to_text, +}; diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index 39e602a8689..ed06485e334 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -35,29 +35,6 @@ struct efi_disk_obj { const struct blk_desc *desc; }; -static efi_status_t EFIAPI efi_disk_open_block(void *handle, - efi_guid_t *protocol, void **protocol_interface, - void *agent_handle, void *controller_handle, - uint32_t attributes) -{ - struct efi_disk_obj *diskobj = handle; - - *protocol_interface = &diskobj->ops; - - return EFI_SUCCESS; -} - -static efi_status_t EFIAPI efi_disk_open_dp(void *handle, efi_guid_t *protocol, - void **protocol_interface, void *agent_handle, - void *controller_handle, uint32_t attributes) -{ - struct efi_disk_obj *diskobj = handle; - - *protocol_interface = diskobj->dp; - - return EFI_SUCCESS; -} - static efi_status_t EFIAPI efi_disk_reset(struct efi_block_io *this, char extended_verification) { @@ -91,7 +68,7 @@ static efi_status_t EFIAPI efi_disk_rw_blocks(struct efi_block_io *this, /* We only support full block access */ if (buffer_size & (blksz - 1)) - return EFI_EXIT(EFI_DEVICE_ERROR); + return EFI_DEVICE_ERROR; if (direction == EFI_DISK_READ) n = blk_dread(desc, lba, blocks, buffer); @@ -104,9 +81,9 @@ static efi_status_t EFIAPI efi_disk_rw_blocks(struct efi_block_io *this, debug("EFI: %s:%d n=%lx blocks=%x\n", __func__, __LINE__, n, blocks); if (n != blocks) - return EFI_EXIT(EFI_DEVICE_ERROR); + return EFI_DEVICE_ERROR; - return EFI_EXIT(EFI_SUCCESS); + return EFI_SUCCESS; } static efi_status_t EFIAPI efi_disk_read_blocks(struct efi_block_io *this, @@ -210,10 +187,11 @@ static void efi_disk_add_dev(const char *name, diskobj = calloc(1, objlen); /* Fill in object data */ + dp = (void *)&diskobj[1]; diskobj->parent.protocols[0].guid = &efi_block_io_guid; - diskobj->parent.protocols[0].open = efi_disk_open_block; + diskobj->parent.protocols[0].protocol_interface = &diskobj->ops; diskobj->parent.protocols[1].guid = &efi_guid_device_path; - diskobj->parent.protocols[1].open = efi_disk_open_dp; + diskobj->parent.protocols[1].protocol_interface = dp; diskobj->parent.handle = diskobj; diskobj->ops = block_io_disk_template; diskobj->ifname = if_typename; @@ -230,7 +208,6 @@ static void efi_disk_add_dev(const char *name, diskobj->ops.media = &diskobj->media; /* Fill in device path */ - dp = (void*)&diskobj[1]; diskobj->dp = dp; dp[0].dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE; dp[0].dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH; @@ -289,9 +266,9 @@ int efi_disk_register(void) #ifdef CONFIG_BLK struct udevice *dev; - for (uclass_first_device(UCLASS_BLK, &dev); + for (uclass_first_device_check(UCLASS_BLK, &dev); dev; - uclass_next_device(&dev)) { + uclass_next_device_check(&dev)) { struct blk_desc *desc = dev_get_uclass_platdata(dev); const char *if_typename = dev->driver->name; diff --git a/lib/efi_loader/efi_gop.c b/lib/efi_loader/efi_gop.c index 286ad830976..806cfaeea18 100644 --- a/lib/efi_loader/efi_gop.c +++ b/lib/efi_loader/efi_gop.c @@ -28,6 +28,7 @@ struct efi_gop_obj { struct efi_gop_mode mode; /* Fields we only have acces to during init */ u32 bpix; + void *fb; }; static efi_status_t EFIAPI gop_query_mode(struct efi_gop *this, u32 mode_number, @@ -71,7 +72,7 @@ static efi_status_t EFIAPI gop_blt(struct efi_gop *this, void *buffer, if (operation != EFI_BLT_BUFFER_TO_VIDEO) return EFI_EXIT(EFI_INVALID_PARAMETER); - fb = (void*)gd->fb_base; + fb = gopobj->fb; line_len16 = gopobj->info.width * sizeof(u16); line_len32 = gopobj->info.width * sizeof(u32); @@ -130,6 +131,7 @@ int efi_gop_register(void) struct efi_gop_obj *gopobj; u32 bpix, col, row; u64 fb_base, fb_size; + void *fb; #ifdef CONFIG_DM_VIDEO struct udevice *vdev; @@ -144,6 +146,7 @@ int efi_gop_register(void) row = video_get_ysize(vdev); fb_base = (uintptr_t)priv->fb; fb_size = priv->fb_size; + fb = priv->fb; #else int line_len; @@ -152,6 +155,7 @@ int efi_gop_register(void) row = panel_info.vl_row; fb_base = gd->fb_base; fb_size = lcd_get_size(&line_len); + fb = gd->fb_base; #endif switch (bpix) { @@ -172,7 +176,7 @@ int efi_gop_register(void) /* Fill in object data */ gopobj->parent.protocols[0].guid = &efi_gop_guid; - gopobj->parent.protocols[0].open = efi_return_handle; + gopobj->parent.protocols[0].protocol_interface = &gopobj->ops; gopobj->parent.handle = &gopobj->ops; gopobj->ops.query_mode = gop_query_mode; gopobj->ops.set_mode = gop_set_mode; @@ -200,6 +204,7 @@ int efi_gop_register(void) gopobj->info.pixels_per_scanline = col; gopobj->bpix = bpix; + gopobj->fb = fb; /* Hook up to the device list */ list_add_tail(&gopobj->parent.link, &efi_obj_list); diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c index d4c62e677c6..f961407f50a 100644 --- a/lib/efi_loader/efi_image_loader.c +++ b/lib/efi_loader/efi_image_loader.c @@ -18,14 +18,6 @@ DECLARE_GLOBAL_DATA_PTR; const efi_guid_t efi_guid_device_path = DEVICE_PATH_GUID; const efi_guid_t efi_guid_loaded_image = LOADED_IMAGE_GUID; -efi_status_t EFIAPI efi_return_handle(void *handle, efi_guid_t *protocol, - void **protocol_interface, void *agent_handle, - void *controller_handle, uint32_t attributes) -{ - *protocol_interface = handle; - return EFI_SUCCESS; -} - static efi_status_t efi_loader_relocate(const IMAGE_BASE_RELOCATION *rel, unsigned long rel_size, void *efi_reloc) { diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index db2ae19f590..9e079f1fa3a 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -379,6 +379,9 @@ efi_status_t efi_free_pool(void *buffer) efi_status_t r; struct efi_pool_allocation *alloc; + if (buffer == NULL) + return EFI_INVALID_PARAMETER; + alloc = container_of(buffer, struct efi_pool_allocation, data); /* Sanity check, was the supplied address returned by allocate_pool */ assert(((uintptr_t)alloc & EFI_PAGE_MASK) == 0); @@ -406,15 +409,15 @@ efi_status_t efi_get_memory_map(unsigned long *memory_map_size, *memory_map_size = map_size; + if (provided_map_size < map_size) + return EFI_BUFFER_TOO_SMALL; + if (descriptor_size) *descriptor_size = sizeof(struct efi_mem_desc); if (descriptor_version) *descriptor_version = EFI_MEMORY_DESCRIPTOR_VERSION; - if (provided_map_size < map_size) - return EFI_BUFFER_TOO_SMALL; - /* Copy list into array */ if (memory_map) { /* Return the list in ascending order */ @@ -428,6 +431,8 @@ efi_status_t efi_get_memory_map(unsigned long *memory_map_size, } } + *map_key = 0; + return EFI_SUCCESS; } diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c index 604ac6e0408..0b949d86e8d 100644 --- a/lib/efi_loader/efi_net.c +++ b/lib/efi_loader/efi_net.c @@ -199,30 +199,6 @@ static efi_status_t EFIAPI efi_net_receive(struct efi_simple_network *this, return EFI_EXIT(EFI_SUCCESS); } -static efi_status_t EFIAPI efi_net_open_dp(void *handle, efi_guid_t *protocol, - void **protocol_interface, void *agent_handle, - void *controller_handle, uint32_t attributes) -{ - struct efi_simple_network *net = handle; - struct efi_net_obj *netobj = container_of(net, struct efi_net_obj, net); - - *protocol_interface = &netobj->dp_mac; - - return EFI_SUCCESS; -} - -static efi_status_t EFIAPI efi_net_open_pxe(void *handle, efi_guid_t *protocol, - void **protocol_interface, void *agent_handle, - void *controller_handle, uint32_t attributes) -{ - struct efi_simple_network *net = handle; - struct efi_net_obj *netobj = container_of(net, struct efi_net_obj, net); - - *protocol_interface = &netobj->pxe; - - return EFI_SUCCESS; -} - void efi_net_set_dhcp_ack(void *pkt, int len) { int maxsize = sizeof(*dhcp_ack); @@ -258,11 +234,11 @@ int efi_net_register(void **handle) /* Fill in object data */ netobj->parent.protocols[0].guid = &efi_net_guid; - netobj->parent.protocols[0].open = efi_return_handle; + netobj->parent.protocols[0].protocol_interface = &netobj->net; netobj->parent.protocols[1].guid = &efi_guid_device_path; - netobj->parent.protocols[1].open = efi_net_open_dp; + netobj->parent.protocols[1].protocol_interface = &netobj->dp_mac; netobj->parent.protocols[2].guid = &efi_pxe_guid; - netobj->parent.protocols[2].open = efi_net_open_pxe; + netobj->parent.protocols[2].protocol_interface = &netobj->pxe; netobj->parent.handle = &netobj->net; netobj->net.start = efi_net_start; netobj->net.stop = efi_net_stop; |