[PATCH] efi: Use LocateHandleBuffer instead of LocateHandle

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Use LocateHandleBuffer instead of the LocateHandle + AllocatePool +
LocateHandle combo to save a bit on code.

Usage of LocateHandle for UGA and GOP has been present in the efistub
since its introduction with commit 291f36325f9f ("x86, efi: EFI boot
stub support"). It was subsequently inherited by the PCI ROM retrieval
with commit dd5fc854de5f ("EFI: Stash ROMs if they're not in the PCI
BAR").

One valid reason to not use LocateHandleBuffer would be if a specific
memory type is required for the buffer, and particularly if the buffer
needs to persist across ExitBootServices. The spec does not mandate
which type is used, edk2 seems to default to EfiBootServicesData.
In the three use cases modified by this commit (UGA, GOP, PCI), the
buffer is freed before ExitBootServices is called. Hence the memory
type is irrelevant.

No functional change intended.

Cc: Ard Biesheuvel <ard.biesheuvel@xxxxxxxxxx>
Signed-off-by: Lukas Wunner <lukas@xxxxxxxxx>
---

The patch can be reviewed somewhat more comfortably with green/red
highlighting on GitHub:
https://github.com/l1k/linux/commit/2ff1fc10c84f

It depends on two patches which are already queued in Matt's tree for 4.9:

"x86/efi: Optimize away setup_gop32/64 if unused"
https://patchwork.kernel.org/patch/9315763/

"x86/efi: Allow invocation of arbitrary boot services"
https://patchwork.kernel.org/patch/9293371/

 arch/x86/boot/compressed/eboot.c        | 90 ++++++++++-----------------------
 drivers/firmware/efi/libstub/arm-stub.c | 17 ++++---
 drivers/firmware/efi/libstub/gop.c      | 29 +++--------
 include/linux/efi.h                     |  5 +-
 4 files changed, 47 insertions(+), 94 deletions(-)

diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index 447a6a2..87c8d31 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -340,13 +340,12 @@ free_struct:
 
 static void
 setup_efi_pci32(struct boot_params *params, void **pci_handle,
-		unsigned long size)
+		unsigned long nr_pci)
 {
 	efi_pci_io_protocol_32 *pci = NULL;
 	efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
 	u32 *handles = (u32 *)(unsigned long)pci_handle;
 	efi_status_t status;
-	unsigned long nr_pci;
 	struct setup_data *data;
 	int i;
 
@@ -355,7 +354,6 @@ setup_efi_pci32(struct boot_params *params, void **pci_handle,
 	while (data && data->next)
 		data = (struct setup_data *)(unsigned long)data->next;
 
-	nr_pci = size / sizeof(u32);
 	for (i = 0; i < nr_pci; i++) {
 		struct pci_setup_rom *rom = NULL;
 		u32 h = handles[i];
@@ -447,13 +445,12 @@ free_struct:
 
 static void
 setup_efi_pci64(struct boot_params *params, void **pci_handle,
-		unsigned long size)
+		unsigned long nr_pci)
 {
 	efi_pci_io_protocol_64 *pci = NULL;
 	efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
 	u64 *handles = (u64 *)(unsigned long)pci_handle;
 	efi_status_t status;
-	unsigned long nr_pci;
 	struct setup_data *data;
 	int i;
 
@@ -462,7 +459,6 @@ setup_efi_pci64(struct boot_params *params, void **pci_handle,
 	while (data && data->next)
 		data = (struct setup_data *)(unsigned long)data->next;
 
-	nr_pci = size / sizeof(u64);
 	for (i = 0; i < nr_pci; i++) {
 		struct pci_setup_rom *rom = NULL;
 		u64 h = handles[i];
@@ -502,53 +498,38 @@ setup_efi_pci64(struct boot_params *params, void **pci_handle,
 static void setup_efi_pci(struct boot_params *params)
 {
 	efi_status_t status;
-	void **pci_handle = NULL;
+	void **pci_handle;
 	efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
-	unsigned long size = 0;
+	unsigned long nr_pci;
 
-	status = efi_call_early(locate_handle,
+	status = efi_call_early(locate_handle_buffer,
 				EFI_LOCATE_BY_PROTOCOL,
-				&pci_proto, NULL, &size, pci_handle);
+				&pci_proto, NULL, &nr_pci, &pci_handle);
 
-	if (status == EFI_BUFFER_TOO_SMALL) {
-		status = efi_call_early(allocate_pool,
-					EFI_LOADER_DATA,
-					size, (void **)&pci_handle);
-
-		if (status != EFI_SUCCESS) {
-			efi_printk(sys_table, "Failed to alloc mem for pci_handle\n");
-			return;
-		}
-
-		status = efi_call_early(locate_handle,
-					EFI_LOCATE_BY_PROTOCOL, &pci_proto,
-					NULL, &size, pci_handle);
-	}
+	if (status == EFI_OUT_OF_RESOURCES)
+		efi_printk(sys_table, "Failed to alloc mem for pci_handle\n");
 
 	if (status != EFI_SUCCESS)
-		goto free_handle;
+		return;
 
 	if (efi_early->is64)
-		setup_efi_pci64(params, pci_handle, size);
+		setup_efi_pci64(params, pci_handle, nr_pci);
 	else
-		setup_efi_pci32(params, pci_handle, size);
+		setup_efi_pci32(params, pci_handle, nr_pci);
 
-free_handle:
 	efi_call_early(free_pool, pci_handle);
 }
 
 static efi_status_t
-setup_uga32(void **uga_handle, unsigned long size, u32 *width, u32 *height)
+setup_uga32(void **uga_handle, unsigned long nr_ugas, u32 *width, u32 *height)
 {
 	struct efi_uga_draw_protocol *uga = NULL, *first_uga;
 	efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID;
-	unsigned long nr_ugas;
 	u32 *handles = (u32 *)uga_handle;;
 	efi_status_t status = EFI_INVALID_PARAMETER;
 	int i;
 
 	first_uga = NULL;
-	nr_ugas = size / sizeof(u32);
 	for (i = 0; i < nr_ugas; i++) {
 		efi_guid_t pciio_proto = EFI_PCI_IO_PROTOCOL_GUID;
 		u32 w, h, depth, refresh;
@@ -583,17 +564,15 @@ setup_uga32(void **uga_handle, unsigned long size, u32 *width, u32 *height)
 }
 
 static efi_status_t
-setup_uga64(void **uga_handle, unsigned long size, u32 *width, u32 *height)
+setup_uga64(void **uga_handle, unsigned long nr_ugas, u32 *width, u32 *height)
 {
 	struct efi_uga_draw_protocol *uga = NULL, *first_uga;
 	efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID;
-	unsigned long nr_ugas;
 	u64 *handles = (u64 *)uga_handle;;
 	efi_status_t status = EFI_INVALID_PARAMETER;
 	int i;
 
 	first_uga = NULL;
-	nr_ugas = size / sizeof(u64);
 	for (i = 0; i < nr_ugas; i++) {
 		efi_guid_t pciio_proto = EFI_PCI_IO_PROTOCOL_GUID;
 		u32 w, h, depth, refresh;
@@ -631,30 +610,18 @@ setup_uga64(void **uga_handle, unsigned long size, u32 *width, u32 *height)
  * See if we have Universal Graphics Adapter (UGA) protocol
  */
 static efi_status_t setup_uga(struct screen_info *si, efi_guid_t *uga_proto,
-			      unsigned long size)
+			      unsigned long nr_ugas, void **uga_handle)
 {
 	efi_status_t status;
 	u32 width, height;
-	void **uga_handle = NULL;
-
-	status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
-				size, (void **)&uga_handle);
-	if (status != EFI_SUCCESS)
-		return status;
-
-	status = efi_call_early(locate_handle,
-				EFI_LOCATE_BY_PROTOCOL,
-				uga_proto, NULL, &size, uga_handle);
-	if (status != EFI_SUCCESS)
-		goto free_handle;
 
 	height = 0;
 	width = 0;
 
 	if (efi_early->is64)
-		status = setup_uga64(uga_handle, size, &width, &height);
+		status = setup_uga64(uga_handle, nr_ugas, &width, &height);
 	else
-		status = setup_uga32(uga_handle, size, &width, &height);
+		status = setup_uga32(uga_handle, nr_ugas, &width, &height);
 
 	if (!width && !height)
 		goto free_handle;
@@ -686,27 +653,26 @@ void setup_graphics(struct boot_params *boot_params)
 	struct screen_info *si;
 	efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID;
 	efi_status_t status;
-	unsigned long size;
-	void **gop_handle = NULL;
-	void **uga_handle = NULL;
+	unsigned long nr;
+	void **gop_handle;
+	void **uga_handle;
 
 	si = &boot_params->screen_info;
 	memset(si, 0, sizeof(*si));
 
-	size = 0;
-	status = efi_call_early(locate_handle,
+	status = efi_call_early(locate_handle_buffer,
 				EFI_LOCATE_BY_PROTOCOL,
-				&graphics_proto, NULL, &size, gop_handle);
-	if (status == EFI_BUFFER_TOO_SMALL)
-		status = efi_setup_gop(NULL, si, &graphics_proto, size);
+				&graphics_proto, NULL, &nr, &gop_handle);
+	if (status == EFI_SUCCESS)
+		status = efi_setup_gop(NULL, si, &graphics_proto, nr,
+				       gop_handle);
 
 	if (status != EFI_SUCCESS) {
-		size = 0;
-		status = efi_call_early(locate_handle,
+		status = efi_call_early(locate_handle_buffer,
 					EFI_LOCATE_BY_PROTOCOL,
-					&uga_proto, NULL, &size, uga_handle);
-		if (status == EFI_BUFFER_TOO_SMALL)
-			setup_uga(si, &uga_proto, size);
+					&uga_proto, NULL, &nr, &uga_handle);
+		if (status == EFI_SUCCESS)
+			setup_uga(si, &uga_proto, nr, uga_handle);
 	}
 }
 
diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c
index 993aa56..27fd62d 100644
--- a/drivers/firmware/efi/libstub/arm-stub.c
+++ b/drivers/firmware/efi/libstub/arm-stub.c
@@ -173,18 +173,19 @@ static struct screen_info *setup_graphics(efi_system_table_t *sys_table_arg)
 {
 	efi_guid_t gop_proto = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
 	efi_status_t status;
-	unsigned long size;
-	void **gop_handle = NULL;
+	unsigned long nr;
+	void **gop_handle;
 	struct screen_info *si = NULL;
 
-	size = 0;
-	status = efi_call_early(locate_handle, EFI_LOCATE_BY_PROTOCOL,
-				&gop_proto, NULL, &size, gop_handle);
-	if (status == EFI_BUFFER_TOO_SMALL) {
+	status = efi_call_early(locate_handle_buffer, EFI_LOCATE_BY_PROTOCOL,
+				&gop_proto, NULL, &nr, &gop_handle);
+	if (status == EFI_SUCCESS) {
 		si = alloc_screen_info(sys_table_arg);
-		if (!si)
+		if (!si) {
+			efi_call_early(free_pool, gop_handle);
 			return NULL;
-		efi_setup_gop(sys_table_arg, si, &gop_proto, size);
+		}
+		efi_setup_gop(sys_table_arg, si, &gop_proto, nr, gop_handle);
 	}
 	return si;
 }
diff --git a/drivers/firmware/efi/libstub/gop.c b/drivers/firmware/efi/libstub/gop.c
index 932742e..a2dca32 100644
--- a/drivers/firmware/efi/libstub/gop.c
+++ b/drivers/firmware/efi/libstub/gop.c
@@ -111,10 +111,9 @@ __gop_query32(efi_system_table_t *sys_table_arg,
 
 static efi_status_t
 setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si,
-            efi_guid_t *proto, unsigned long size, void **gop_handle)
+	    efi_guid_t *proto, unsigned long nr_gops, void **gop_handle)
 {
 	struct efi_graphics_output_protocol_32 *gop32, *first_gop;
-	unsigned long nr_gops;
 	u16 width, height;
 	u32 pixels_per_scan_line;
 	u32 ext_lfb_base;
@@ -128,7 +127,6 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si,
 	first_gop = NULL;
 	gop32 = NULL;
 
-	nr_gops = size / sizeof(u32);
 	for (i = 0; i < nr_gops; i++) {
 		struct efi_graphics_output_mode_info *info = NULL;
 		efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID;
@@ -136,6 +134,7 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si,
 		void *dummy = NULL;
 		efi_handle_t h = (efi_handle_t)(unsigned long)handles[i];
 		u64 current_fb_base;
+		unsigned long size;
 
 		status = efi_call_early(handle_protocol, h,
 					proto, (void **)&gop32);
@@ -228,10 +227,9 @@ __gop_query64(efi_system_table_t *sys_table_arg,
 
 static efi_status_t
 setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si,
-	    efi_guid_t *proto, unsigned long size, void **gop_handle)
+	    efi_guid_t *proto, unsigned long nr_gops, void **gop_handle)
 {
 	struct efi_graphics_output_protocol_64 *gop64, *first_gop;
-	unsigned long nr_gops;
 	u16 width, height;
 	u32 pixels_per_scan_line;
 	u32 ext_lfb_base;
@@ -245,7 +243,6 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si,
 	first_gop = NULL;
 	gop64 = NULL;
 
-	nr_gops = size / sizeof(u64);
 	for (i = 0; i < nr_gops; i++) {
 		struct efi_graphics_output_mode_info *info = NULL;
 		efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID;
@@ -253,6 +250,7 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si,
 		void *dummy = NULL;
 		efi_handle_t h = (efi_handle_t)(unsigned long)handles[i];
 		u64 current_fb_base;
+		unsigned long size;
 
 		status = efi_call_early(handle_protocol, h,
 					proto, (void **)&gop64);
@@ -324,31 +322,18 @@ out:
  */
 efi_status_t efi_setup_gop(efi_system_table_t *sys_table_arg,
 			   struct screen_info *si, efi_guid_t *proto,
-			   unsigned long size)
+			   unsigned long nr_gops, void **gop_handle)
 {
 	efi_status_t status;
-	void **gop_handle = NULL;
-
-	status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
-				size, (void **)&gop_handle);
-	if (status != EFI_SUCCESS)
-		return status;
-
-	status = efi_call_early(locate_handle,
-				EFI_LOCATE_BY_PROTOCOL,
-				proto, NULL, &size, gop_handle);
-	if (status != EFI_SUCCESS)
-		goto free_handle;
 
 	if (efi_is_64bit()) {
-		status = setup_gop64(sys_table_arg, si, proto, size,
+		status = setup_gop64(sys_table_arg, si, proto, nr_gops,
 				     gop_handle);
 	} else {
-		status = setup_gop32(sys_table_arg, si, proto, size,
+		status = setup_gop32(sys_table_arg, si, proto, nr_gops,
 				     gop_handle);
 	}
 
-free_handle:
 	efi_call_early(free_pool, gop_handle);
 	return status;
 }
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 4ae1a1a..52fe49d 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -304,7 +304,8 @@ typedef struct {
 	void *close_protocol;
 	void *open_protocol_information;
 	void *protocols_per_handle;
-	void *locate_handle_buffer;
+	efi_status_t (*locate_handle_buffer)(int, efi_guid_t *, void *,
+					     unsigned long *, efi_handle_t **);
 	efi_status_t (*locate_protocol)(efi_guid_t *, void *, void **);
 	void *install_multiple_protocol_interfaces;
 	void *uninstall_multiple_protocol_interfaces;
@@ -1424,7 +1425,7 @@ efi_status_t efi_parse_options(char *cmdline);
 
 efi_status_t efi_setup_gop(efi_system_table_t *sys_table_arg,
 			   struct screen_info *si, efi_guid_t *proto,
-			   unsigned long size);
+			   unsigned long nr_gops, void **gop_handle);
 
 bool efi_runtime_disabled(void);
 extern void efi_call_virt_check_flags(unsigned long flags, const char *call);
-- 
2.9.3

--
To unsubscribe from this list: send the line "unsubscribe linux-efi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux