Skip to contentSkip to conversation

EFI framebuffer support for ARM and arm64

PATCH New Ard Biesheuvel 6 participants 31 messages Mar 10, 2016 – Mar 21, 2016

Subsystems (6)
lore
Share & tools
lore
#0 lore raw

cover EFI framebuffer support for ARM and arm64

This series adds support to ARM and arm64 for using the kernel's EFI framebuffer driver to drive EFI Graphics Output Protocol (GOP) based framebuffers.

This involves refactoring some of the existing x86 code so it can be reused by ARM and arm64, and wiring it up both in the UEFI stub and in the core kernel into the existing UEFI infrastructure for ARM and arm64.

Ard Biesheuvel (8):
efi: make install_configuration_table() boot service usable
efi: libstub: move Graphics Output Protocol handling to generic code efi/x86: libstub: move to generic GOP code
efi/x86: efifb: move DMI based quirks handling out of generic code
efi: efifb: use builtin_platform_driver and drop unused includes efi/arm*: libstub: wire up GOP handling into the ARM UEFI stub efi/arm*: efifb: expose efifb platform device if GOP is available efi/arm: populate screen_info based on data provided by the UEFI stub

 arch/arm/include/asm/efi.h                |  20 +-
 arch/arm/kernel/efi.c                     |  24 ++
 arch/arm/kernel/setup.c                   |   3 +-
 arch/arm64/include/asm/efi.h              |  11 +-
 arch/arm64/kernel/efi.c                   |   3 +
 arch/arm64/kernel/image.h                 |   1 +
 arch/x86/boot/compressed/eboot.c          | 308 +----------------
 arch/x86/boot/compressed/eboot.h          |  74 ----
 arch/x86/include/asm/efi.h                |   7 +
 arch/x86/kernel/sysfb_efi.c               |  15 +
 drivers/firmware/efi/arm-init.c           |  25 ++
 drivers/firmware/efi/libstub/Makefile     |   2 +-
 drivers/firmware/efi/libstub/arm-stub.c   |  23 ++
 drivers/firmware/efi/libstub/arm32-stub.c |  38 +++
 drivers/firmware/efi/libstub/gop.c        | 354 ++++++++++++++++++++
 drivers/video/fbdev/Kconfig               |   2 +-
 drivers/video/fbdev/efifb.c               |  21 +-
 include/linux/efi.h                       |  89 ++++-
 18 files changed, 615 insertions(+), 405 deletions(-)
 create mode 100644 drivers/firmware/efi/libstub/gop.c
Signature · 1 line
1.9.1
#1 lore raw

PATCH 1/8 efi: make install_configuration_table() boot service usable

This patch redeclares efi_boot_services_t::install_configuration_table as a function pointer so that the boot service is callable as a function.

---
 include/linux/efi.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
include/linux/efi.h +1 -1
index e747eb08b2be..8ba6eb7863aa 100644
@@ -283,7 +283,7 @@ typedef struct {
 	void *register_protocol_notify;
 	void *locate_handle;
 	void *locate_device_path;
-	void *install_configuration_table;
+	efi_status_t (*install_configuration_table)(efi_guid_t *, void *);
 	void *load_image;
 	void *start_image;
 	void *exit;
Signature · 1 line
1.9.1
#2 lore raw

PATCH 1/8 efi: make install_configuration_table() boot service usable

Quoted 7 lines · Ard Biesheuvel

This patch redeclares efi_boot_services_t::install_configuration_table as a function pointer so that the boot service is callable as a function.

---
 include/linux/efi.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Any chance you could fold this patch into the one that actually uses install_configuration_table() on ARM? That way it's clear to see where the users are.

Quoted 16 lines
include/linux/efi.h +1 -1
index e747eb08b2be..8ba6eb7863aa 100644
@@ -283,7 +283,7 @@ typedef struct {
 	void *register_protocol_notify;
 	void *locate_handle;
 	void *locate_device_path;
-	void *install_configuration_table;
+	efi_status_t (*install_configuration_table)(efi_guid_t *, void *);
 	void *load_image;
 	void *start_image;
 	void *exit;
Signature · 1 line
1.9.1
#3 lore raw

PATCH 1/8 efi: make install_configuration_table() boot service usable

Quoted 4 lines · Matt Fleming
Quoted 3 lines · Ard Biesheuvel

This patch redeclares efi_boot_services_t::install_configuration_table as a function pointer so that the boot service is callable as a function.

Quoted 9 lines
Quoted 4 lines
---
 include/linux/efi.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Any chance you could fold this patch into the one that actually uses install_configuration_table() on ARM? That way it's clear to see where the users are.

Sure. Patch #2 actually does the same for locate_handle()

Quoted 16 lines
Quoted 16 lines
include/linux/efi.h +1 -2
index e747eb08b2be..8ba6eb7863aa 100644
@@ -283,7 +283,7 @@ typedef struct {
      void *register_protocol_notify;
      void *locate_handle;
      void *locate_device_path;
-     void *install_configuration_table;
+     efi_status_t (*install_configuration_table)(efi_guid_t *, void *);
      void *load_image;
      void *start_image;
      void *exit;
--

1.9.1

#4 lore raw

PATCH 2/8 efi: libstub: move Graphics Output Protocol handling to generic code

In reply to Ard Biesheuvel

The Graphics Output Protocol code executes in the stub, so create a generic version based on the x86 version in libstub so that we can move all archs to it in subsequent patches. The new source file gop.c is added to the libstub build for all architectures, but is not actually included in any of the final images, since this patch does not wire it up yet.

Note that the generic version uses slightly different ways of casting the protocol methods and some other variables to the correct types, since such method calls are not loosely typed on ARM and arm64 as they are on x86.

---
 arch/arm/include/asm/efi.h            |   4 +-
 arch/arm64/include/asm/efi.h          |   4 +-
 arch/x86/boot/compressed/eboot.h      |  74 ----
 arch/x86/include/asm/efi.h            |   5 +
 drivers/firmware/efi/libstub/Makefile |   2 +-
 drivers/firmware/efi/libstub/gop.c    | 354 ++++++++++++++++++++
 include/linux/efi.h                   |  87 ++++-
 7 files changed, 451 insertions(+), 79 deletions(-)
arch/arm/include/asm/efi.h +3 -1
index e0eea72deb87..daebcfe6c35a 100644
@@ -59,7 +59,9 @@ void efi_virtmap_unload(void);
 
 /* arch specific definitions used by the stub code */
 
-#define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__)
+#define efi_call_early(f, ...)		sys_table_arg->boottime->f(__VA_ARGS__)
+#define __efi_call_early(f, ...)	f(__VA_ARGS__)
+#define efi_is_64bit()			(0)
 
 /*
  * A reasonable upper bound for the uncompressed kernel size is 32 MBytes,
arch/arm64/include/asm/efi.h +3 -1
index 8e88a696c9cb..e3d707131bba 100644
@@ -50,7 +50,9 @@ int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md);
 #define EFI_FDT_ALIGN	SZ_2M   /* used by allocate_new_fdt_and_exit_boot() */
 #define MAX_FDT_OFFSET	SZ_512M
 
-#define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__)
+#define efi_call_early(f, ...)		sys_table_arg->boottime->f(__VA_ARGS__)
+#define __efi_call_early(f, ...)	f(__VA_ARGS__)
+#define efi_is_64bit()			(1)
 
 #define EFI_ALLOC_ALIGN		SZ_64K
 
arch/x86/boot/compressed/eboot.h +0 -74

80 lines not on this page · raw message

arch/x86/include/asm/efi.h +5 -0
index 08b1f2f6ea50..7d5187b66108 100644
@@ -199,6 +199,11 @@ __pure const struct efi_config *__efi_early(void);
 #define efi_call_early(f, ...)						\
 	__efi_early()->call(__efi_early()->f, __VA_ARGS__);
 
+#define __efi_call_early(f, ...)					\
+	__efi_early()->call((unsigned long)f, __VA_ARGS__);
+
+#define efi_is_64bit()		__efi_early()->is64
+
 extern bool efi_reboot_required(void);
 
 #else
drivers/firmware/efi/libstub/Makefile +1 -1
index ad077944aa0e..595f5920a740 100644
@@ -24,7 +24,7 @@ GCOV_PROFILE			:= n
 KASAN_SANITIZE			:= n
 UBSAN_SANITIZE			:= n
 
-lib-y				:= efi-stub-helper.o
+lib-y				:= efi-stub-helper.o gop.o
 
 # include the stub's generic dependencies from lib/ when building for ARM/arm64
 arm-deps := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c fdt_empty_tree.c fdt_sw.c sort.c
drivers/firmware/efi/libstub/gop.c new file +354 -0

354 lines not on this page · raw message

include/linux/efi.h +85 -2

122 lines not on this page · raw message

Signature · 1 line
1.9.1
#5 lore raw

PATCH 2/8 efi: libstub: move Graphics Output Protocol handling to generic code

Quoted 11 lines · Ard Biesheuvel

The Graphics Output Protocol code executes in the stub, so create a generic version based on the x86 version in libstub so that we can move all archs to it in subsequent patches. The new source file gop.c is added to the libstub build for all architectures, but is not actually included in any of the final images, since this patch does not wire it up yet.

Note that the generic version uses slightly different ways of casting the protocol methods and some other variables to the correct types, since such method calls are not loosely typed on ARM and arm64 as they are on x86.

Quoted 9 lines
---
 arch/arm/include/asm/efi.h            |   4 +-
 arch/arm64/include/asm/efi.h          |   4 +-
 arch/x86/boot/compressed/eboot.h      |  74 ----
 arch/x86/include/asm/efi.h            |   5 +
 drivers/firmware/efi/libstub/Makefile |   2 +-
 drivers/firmware/efi/libstub/gop.c    | 354 ++++++++++++++++++++
 include/linux/efi.h                   |  87 ++++-
 7 files changed, 451 insertions(+), 79 deletions(-)

I can totally appreciate why you did the gop code move in stages, but I'd prefer to see the move (deletion from arch/x86 and addition to drivers/firmware/efi) done as a single patch.

The reason is that git will produce a very nice diff stat that shows the number of lines that were simply moved from one file to another without modification.

Which makes it much easier to see which lines *did* change.

As a very quick and dirty example (but this is not what I'm suggesting you do because it'd be too many changes in one patch) I merged this patch with the next one, which produces the following diff stat. The important point are the insertions,

: $ git show --shortstat --summary -C10% e63c02a98c3c
:
: 8 files changed, 133 insertions(+), 1606 deletions(-)
: copy arch/x86/boot/compressed/eboot.c => drivers/firmware/efi/libstub/gop.c (20%)

arch/arm/include/asm/efi.h void efi_virtmap_unload(void); · line 64

Quoted 12 lines
arch/arm/include/asm/efi.h +3 -1
index e0eea72deb87..daebcfe6c35a 100644
@@ -59,7 +59,9 @@ void efi_virtmap_unload(void);
 
 /* arch specific definitions used by the stub code */
 
-#define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__)
+#define efi_call_early(f, ...)		sys_table_arg->boottime->f(__VA_ARGS__)
+#define __efi_call_early(f, ...)	f(__VA_ARGS__)
+#define efi_is_64bit()			(0)

Is there a specific reason that these can't be boolean? I know some people hate them, but I've always been a pretty big fan when the circumstances are right. Plus it is bool on x86.

#6 lore raw

PATCH 3/8 efi/x86: libstub: move to generic GOP code

In reply to Ard Biesheuvel

Switch to the generic Graphics Output Protocol handling in libstub, and remove the now unused code from arch/x86/boot/compressed/eboot.c

---
 arch/x86/boot/compressed/eboot.c | 308 +-------------------
 1 file changed, 1 insertion(+), 307 deletions(-)
arch/x86/boot/compressed/eboot.c +1 -307
index 583d539a4197..52fef606bc54 100644
@@ -571,312 +571,6 @@ free_handle:
 	efi_call_early(free_pool, pci_handle);
 }
 
-static void
-setup_pixel_info(struct screen_info *si, u32 pixels_per_scan_line,
-		 struct efi_pixel_bitmask pixel_info, int pixel_format)
-{
-	if (pixel_format == PIXEL_RGB_RESERVED_8BIT_PER_COLOR) {
-		si->lfb_depth = 32;
-		si->lfb_linelength = pixels_per_scan_line * 4;
-		si->red_size = 8;
-		si->red_pos = 0;
-		si->green_size = 8;
-		si->green_pos = 8;
-		si->blue_size = 8;
-		si->blue_pos = 16;
-		si->rsvd_size = 8;
-		si->rsvd_pos = 24;
-	} else if (pixel_format == PIXEL_BGR_RESERVED_8BIT_PER_COLOR) {
-		si->lfb_depth = 32;
-		si->lfb_linelength = pixels_per_scan_line * 4;
-		si->red_size = 8;
-		si->red_pos = 16;
-		si->green_size = 8;
-		si->green_pos = 8;
-		si->blue_size = 8;
-		si->blue_pos = 0;
-		si->rsvd_size = 8;
-		si->rsvd_pos = 24;
-	} else if (pixel_format == PIXEL_BIT_MASK) {
-		find_bits(pixel_info.red_mask, &si->red_pos, &si->red_size);
-		find_bits(pixel_info.green_mask, &si->green_pos,
-			  &si->green_size);
-		find_bits(pixel_info.blue_mask, &si->blue_pos, &si->blue_size);
-		find_bits(pixel_info.reserved_mask, &si->rsvd_pos,
-			  &si->rsvd_size);
-		si->lfb_depth = si->red_size + si->green_size +
-			si->blue_size + si->rsvd_size;
-		si->lfb_linelength = (pixels_per_scan_line * si->lfb_depth) / 8;
-	} else {
-		si->lfb_depth = 4;
-		si->lfb_linelength = si->lfb_width / 2;
-		si->red_size = 0;
-		si->red_pos = 0;
-		si->green_size = 0;
-		si->green_pos = 0;
-		si->blue_size = 0;
-		si->blue_pos = 0;
-		si->rsvd_size = 0;
-		si->rsvd_pos = 0;
-	}
-}
-
-static efi_status_t
-__gop_query32(struct efi_graphics_output_protocol_32 *gop32,
-	      struct efi_graphics_output_mode_info **info,
-	      unsigned long *size, u64 *fb_base)
-{
-	struct efi_graphics_output_protocol_mode_32 *mode;
-	efi_status_t status;
-	unsigned long m;
-
-	m = gop32->mode;
-	mode = (struct efi_graphics_output_protocol_mode_32 *)m;
-
-	status = efi_early->call(gop32->query_mode, gop32,
-				 mode->mode, size, info);
-	if (status != EFI_SUCCESS)
-		return status;
-
-	*fb_base = mode->frame_buffer_base;
-	return status;
-}
-
-static efi_status_t
-setup_gop32(struct screen_info *si, efi_guid_t *proto,
-	    unsigned long size, 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;
-	u64 fb_base;
-	struct efi_pixel_bitmask pixel_info;
-	int pixel_format;
-	efi_status_t status;
-	u32 *handles = (u32 *)(unsigned long)gop_handle;
-	int i;
-
-	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;
-		bool conout_found = false;
-		void *dummy = NULL;
-		u32 h = handles[i];
-		u64 current_fb_base;
-
-		status = efi_call_early(handle_protocol, h,
-					proto, (void **)&gop32);
-		if (status != EFI_SUCCESS)
-			continue;
-
-		status = efi_call_early(handle_protocol, h,
-					&conout_proto, &dummy);
-		if (status == EFI_SUCCESS)
-			conout_found = true;
-
-		status = __gop_query32(gop32, &info, &size, &current_fb_base);
-		if (status == EFI_SUCCESS && (!first_gop || conout_found)) {
-			/*
-			 * Systems that use the UEFI Console Splitter may
-			 * provide multiple GOP devices, not all of which are
-			 * backed by real hardware. The workaround is to search
-			 * for a GOP implementing the ConOut protocol, and if
-			 * one isn't found, to just fall back to the first GOP.
-			 */
-			width = info->horizontal_resolution;
-			height = info->vertical_resolution;
-			pixel_format = info->pixel_format;
-			pixel_info = info->pixel_information;
-			pixels_per_scan_line = info->pixels_per_scan_line;
-			fb_base = current_fb_base;
-
-			/*
-			 * Once we've found a GOP supporting ConOut,
-			 * don't bother looking any further.
-			 */
-			first_gop = gop32;
-			if (conout_found)
-				break;
-		}
-	}
-
-	/* Did we find any GOPs? */
-	if (!first_gop)
-		goto out;
-
-	/* EFI framebuffer */
-	si->orig_video_isVGA = VIDEO_TYPE_EFI;
-
-	si->lfb_width = width;
-	si->lfb_height = height;
-	si->lfb_base = fb_base;
-
-	ext_lfb_base = (u64)(unsigned long)fb_base >> 32;
-	if (ext_lfb_base) {
-		si->capabilities |= VIDEO_CAPABILITY_64BIT_BASE;
-		si->ext_lfb_base = ext_lfb_base;
-	}
-
-	si->pages = 1;
-
-	setup_pixel_info(si, pixels_per_scan_line, pixel_info, pixel_format);
-
-	si->lfb_size = si->lfb_linelength * si->lfb_height;
-
-	si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS;
-out:
-	return status;
-}
-
-static efi_status_t
-__gop_query64(struct efi_graphics_output_protocol_64 *gop64,
-	      struct efi_graphics_output_mode_info **info,
-	      unsigned long *size, u64 *fb_base)
-{
-	struct efi_graphics_output_protocol_mode_64 *mode;
-	efi_status_t status;
-	unsigned long m;
-
-	m = gop64->mode;
-	mode = (struct efi_graphics_output_protocol_mode_64 *)m;
-
-	status = efi_early->call(gop64->query_mode, gop64,
-				 mode->mode, size, info);
-	if (status != EFI_SUCCESS)
-		return status;
-
-	*fb_base = mode->frame_buffer_base;
-	return status;
-}
-
-static efi_status_t
-setup_gop64(struct screen_info *si, efi_guid_t *proto,
-	    unsigned long size, 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;
-	u64 fb_base;
-	struct efi_pixel_bitmask pixel_info;
-	int pixel_format;
-	efi_status_t status;
-	u64 *handles = (u64 *)(unsigned long)gop_handle;
-	int i;
-
-	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;
-		bool conout_found = false;
-		void *dummy = NULL;
-		u64 h = handles[i];
-		u64 current_fb_base;
-
-		status = efi_call_early(handle_protocol, h,
-					proto, (void **)&gop64);
-		if (status != EFI_SUCCESS)
-			continue;
-
-		status = efi_call_early(handle_protocol, h,
-					&conout_proto, &dummy);
-		if (status == EFI_SUCCESS)
-			conout_found = true;
-
-		status = __gop_query64(gop64, &info, &size, &current_fb_base);
-		if (status == EFI_SUCCESS && (!first_gop || conout_found)) {
-			/*
-			 * Systems that use the UEFI Console Splitter may
-			 * provide multiple GOP devices, not all of which are
-			 * backed by real hardware. The workaround is to search
-			 * for a GOP implementing the ConOut protocol, and if
-			 * one isn't found, to just fall back to the first GOP.
-			 */
-			width = info->horizontal_resolution;
-			height = info->vertical_resolution;
-			pixel_format = info->pixel_format;
-			pixel_info = info->pixel_information;
-			pixels_per_scan_line = info->pixels_per_scan_line;
-			fb_base = current_fb_base;
-
-			/*
-			 * Once we've found a GOP supporting ConOut,
-			 * don't bother looking any further.
-			 */
-			first_gop = gop64;
-			if (conout_found)
-				break;
-		}
-	}
-
-	/* Did we find any GOPs? */
-	if (!first_gop)
-		goto out;
-
-	/* EFI framebuffer */
-	si->orig_video_isVGA = VIDEO_TYPE_EFI;
-
-	si->lfb_width = width;
-	si->lfb_height = height;
-	si->lfb_base = fb_base;
-
-	ext_lfb_base = (u64)(unsigned long)fb_base >> 32;
-	if (ext_lfb_base) {
-		si->capabilities |= VIDEO_CAPABILITY_64BIT_BASE;
-		si->ext_lfb_base = ext_lfb_base;
-	}
-
-	si->pages = 1;
-
-	setup_pixel_info(si, pixels_per_scan_line, pixel_info, pixel_format);
-
-	si->lfb_size = si->lfb_linelength * si->lfb_height;
-
-	si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS;
-out:
-	return status;
-}
-
-/*
- * See if we have Graphics Output Protocol
- */
-static efi_status_t setup_gop(struct screen_info *si, efi_guid_t *proto,
-			      unsigned long size)
-{
-	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_early->is64)
-		status = setup_gop64(si, proto, size, gop_handle);
-	else
-		status = setup_gop32(si, proto, size, gop_handle);
-
-free_handle:
-	efi_call_early(free_pool, gop_handle);
-	return status;
-}
-
 static efi_status_t
 setup_uga32(void **uga_handle, unsigned long size, u32 *width, u32 *height)
 {
@@ -1038,7 +732,7 @@ void setup_graphics(struct boot_params *boot_params)
 				EFI_LOCATE_BY_PROTOCOL,
 				&graphics_proto, NULL, &size, gop_handle);
 	if (status == EFI_BUFFER_TOO_SMALL)
-		status = setup_gop(si, &graphics_proto, size);
+		status = efi_setup_gop(NULL, si, &graphics_proto, size);
 
 	if (status != EFI_SUCCESS) {
 		size = 0;
Signature · 1 line
1.9.1
#7 lore raw

PATCH 4/8 efi/x86: efifb: move DMI based quirks handling out of generic code

In reply to Ard Biesheuvel

The efifb quirks handling based on DMI identification of the platform is specific to x86, so move it to x86 arch code.

---
 arch/x86/include/asm/efi.h  |  2 ++
 arch/x86/kernel/sysfb_efi.c | 15 +++++++++++++++
 drivers/video/fbdev/efifb.c | 15 ++++-----------
 3 files changed, 21 insertions(+), 11 deletions(-)
arch/x86/include/asm/efi.h +2 -0
index 7d5187b66108..790adbc3a64a 100644
@@ -154,6 +154,8 @@ static inline bool efi_runtime_supported(void)
 extern struct console early_efi_console;
 extern void parse_efi_setup(u64 phys_addr, u32 data_len);
 
+extern void efifb_setup_from_dmi(struct screen_info *si, const char *opt);
+
 #ifdef CONFIG_EFI_MIXED
 extern void efi_thunk_runtime_setup(void);
 extern efi_status_t efi_thunk_set_virtual_address_map(
arch/x86/kernel/sysfb_efi.c +15 -0
index b285d4e8c68e..e21a8a7ddcff 100644
@@ -68,6 +68,21 @@ struct efifb_dmi_info efifb_dmi_list[] = {
 	[M_UNKNOWN] = { NULL, 0, 0, 0, 0, OVERRIDE_NONE }
 };
 
+void efifb_setup_from_dmi(struct screen_info *si, const char *opt)
+{
+	int i;
+
+	for (i = 0; i < M_UNKNOWN; i++) {
+		if (efifb_dmi_list[i].base != 0 &&
+		    !strcmp(opt, efifb_dmi_list[i].optname)) {
+			si->lfb_base = efifb_dmi_list[i].base;
+			si->lfb_linelength = efifb_dmi_list[i].stride;
+			si->lfb_width = efifb_dmi_list[i].width;
+			si->lfb_height = efifb_dmi_list[i].height;
+		}
+	}
+}
+
 #define choose_value(dmivalue, fwvalue, field, flags) ({	\
 		typeof(fwvalue) _ret_ = fwvalue;		\
 		if ((flags) & (field))				\
drivers/video/fbdev/efifb.c +4 -11
index 95d293b7445a..dd594369b8a6 100644
@@ -8,6 +8,7 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/efi.h>
 #include <linux/errno.h>
 #include <linux/fb.h>
 #include <linux/platform_device.h>
@@ -15,7 +16,7 @@
 #include <linux/dmi.h>
 #include <linux/pci.h>
 #include <video/vga.h>
-#include <asm/sysfb.h>
+#include <asm/efi.h>
 
 static bool request_mem_succeeded = false;
 
@@ -85,21 +86,13 @@ static struct fb_ops efifb_ops = {
 static int efifb_setup(char *options)
 {
 	char *this_opt;
-	int i;
 
 	if (options && *options) {
 		while ((this_opt = strsep(&options, ",")) != NULL) {
 			if (!*this_opt) continue;
 
-			for (i = 0; i < M_UNKNOWN; i++) {
-				if (efifb_dmi_list[i].base != 0 &&
-				    !strcmp(this_opt, efifb_dmi_list[i].optname)) {
-					screen_info.lfb_base = efifb_dmi_list[i].base;
-					screen_info.lfb_linelength = efifb_dmi_list[i].stride;
-					screen_info.lfb_width = efifb_dmi_list[i].width;
-					screen_info.lfb_height = efifb_dmi_list[i].height;
-				}
-			}
+			efifb_setup_from_dmi(&screen_info, this_opt);
+
 			if (!strncmp(this_opt, "base:", 5))
 				screen_info.lfb_base = simple_strtoul(this_opt+5, NULL, 0);
 			else if (!strncmp(this_opt, "stride:", 7))
Signature · 1 line
1.9.1
#8 lore raw

PATCH 4/8 efi/x86: efifb: move DMI based quirks handling out of generic code

(Cc'ing efifb maintainer and sysfb_efi.c author)

Quoted 9 lines · Ard Biesheuvel

The efifb quirks handling based on DMI identification of the platform is specific to x86, so move it to x86 arch code.

---
 arch/x86/include/asm/efi.h  |  2 ++
 arch/x86/kernel/sysfb_efi.c | 15 +++++++++++++++
 drivers/video/fbdev/efifb.c | 15 ++++-----------
 3 files changed, 21 insertions(+), 11 deletions(-)

I've left the patch content intact below. This looks like a worthwhile change to me. David, Peter, any comments?

Quoted 87 lines
arch/x86/include/asm/efi.h +2 -0
index 7d5187b66108..790adbc3a64a 100644
@@ -154,6 +154,8 @@ static inline bool efi_runtime_supported(void)
 extern struct console early_efi_console;
 extern void parse_efi_setup(u64 phys_addr, u32 data_len);
 
+extern void efifb_setup_from_dmi(struct screen_info *si, const char *opt);
+
 #ifdef CONFIG_EFI_MIXED
 extern void efi_thunk_runtime_setup(void);
 extern efi_status_t efi_thunk_set_virtual_address_map(
arch/x86/kernel/sysfb_efi.c +15 -0
index b285d4e8c68e..e21a8a7ddcff 100644
@@ -68,6 +68,21 @@ struct efifb_dmi_info efifb_dmi_list[] = {
 	[M_UNKNOWN] = { NULL, 0, 0, 0, 0, OVERRIDE_NONE }
 };
 
+void efifb_setup_from_dmi(struct screen_info *si, const char *opt)
+{
+	int i;
+
+	for (i = 0; i < M_UNKNOWN; i++) {
+		if (efifb_dmi_list[i].base != 0 &&
+		    !strcmp(opt, efifb_dmi_list[i].optname)) {
+			si->lfb_base = efifb_dmi_list[i].base;
+			si->lfb_linelength = efifb_dmi_list[i].stride;
+			si->lfb_width = efifb_dmi_list[i].width;
+			si->lfb_height = efifb_dmi_list[i].height;
+		}
+	}
+}
+
 #define choose_value(dmivalue, fwvalue, field, flags) ({	\
 		typeof(fwvalue) _ret_ = fwvalue;		\
 		if ((flags) & (field))				\
drivers/video/fbdev/efifb.c +4 -11
index 95d293b7445a..dd594369b8a6 100644
@@ -8,6 +8,7 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/efi.h>
 #include <linux/errno.h>
 #include <linux/fb.h>
 #include <linux/platform_device.h>
@@ -15,7 +16,7 @@
 #include <linux/dmi.h>
 #include <linux/pci.h>
 #include <video/vga.h>
-#include <asm/sysfb.h>
+#include <asm/efi.h>
 
 static bool request_mem_succeeded = false;
 
@@ -85,21 +86,13 @@ static struct fb_ops efifb_ops = {
 static int efifb_setup(char *options)
 {
 	char *this_opt;
-	int i;
 
 	if (options && *options) {
 		while ((this_opt = strsep(&options, ",")) != NULL) {
 			if (!*this_opt) continue;
 
-			for (i = 0; i < M_UNKNOWN; i++) {
-				if (efifb_dmi_list[i].base != 0 &&
-				    !strcmp(this_opt, efifb_dmi_list[i].optname)) {
-					screen_info.lfb_base = efifb_dmi_list[i].base;
-					screen_info.lfb_linelength = efifb_dmi_list[i].stride;
-					screen_info.lfb_width = efifb_dmi_list[i].width;
-					screen_info.lfb_height = efifb_dmi_list[i].height;
-				}
-			}
+			efifb_setup_from_dmi(&screen_info, this_opt);
+
 			if (!strncmp(this_opt, "base:", 5))
 				screen_info.lfb_base = simple_strtoul(this_opt+5, NULL, 0);
 			else if (!strncmp(this_opt, "stride:", 7))
Signature · 1 line
1.9.1
maintainer
#9 lore raw

PATCH 4/8 efi/x86: efifb: move DMI based quirks handling out of generic code

Quoted 13 lines · Matt Fleming

(Cc'ing efifb maintainer and sysfb_efi.c author)

Quoted 9 lines · Ard Biesheuvel

The efifb quirks handling based on DMI identification of the platform is specific to x86, so move it to x86 arch code.

---
 arch/x86/include/asm/efi.h  |  2 ++
 arch/x86/kernel/sysfb_efi.c | 15 +++++++++++++++
 drivers/video/fbdev/efifb.c | 15 ++++-----------
 3 files changed, 21 insertions(+), 11 deletions(-)
Quoted 2 lines

I've left the patch content intact below. This looks like a worthwhile change to me. David, Peter, any comments?

It looks right to me as well:

Quoted 88 lines
Quoted 88 lines
arch/x86/include/asm/efi.h +2 -0
index 7d5187b66108..790adbc3a64a 100644
@@ -154,6 +154,8 @@ static inline bool efi_runtime_supported(void)
 extern struct console early_efi_console;
 extern void parse_efi_setup(u64 phys_addr, u32 data_len);
 
+extern void efifb_setup_from_dmi(struct screen_info *si, const char *opt);
+
 #ifdef CONFIG_EFI_MIXED
 extern void efi_thunk_runtime_setup(void);
 extern efi_status_t efi_thunk_set_virtual_address_map(
arch/x86/kernel/sysfb_efi.c +15 -0
index b285d4e8c68e..e21a8a7ddcff 100644
@@ -68,6 +68,21 @@ struct efifb_dmi_info efifb_dmi_list[] = {
 	[M_UNKNOWN] = { NULL, 0, 0, 0, 0, OVERRIDE_NONE }
 };
 
+void efifb_setup_from_dmi(struct screen_info *si, const char *opt)
+{
+	int i;
+
+	for (i = 0; i < M_UNKNOWN; i++) {
+		if (efifb_dmi_list[i].base != 0 &&
+		    !strcmp(opt, efifb_dmi_list[i].optname)) {
+			si->lfb_base = efifb_dmi_list[i].base;
+			si->lfb_linelength = efifb_dmi_list[i].stride;
+			si->lfb_width = efifb_dmi_list[i].width;
+			si->lfb_height = efifb_dmi_list[i].height;
+		}
+	}
+}
+
 #define choose_value(dmivalue, fwvalue, field, flags) ({	\
 		typeof(fwvalue) _ret_ = fwvalue;		\
 		if ((flags) & (field))				\
drivers/video/fbdev/efifb.c +4 -11
index 95d293b7445a..dd594369b8a6 100644
@@ -8,6 +8,7 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/efi.h>
 #include <linux/errno.h>
 #include <linux/fb.h>
 #include <linux/platform_device.h>
@@ -15,7 +16,7 @@
 #include <linux/dmi.h>
 #include <linux/pci.h>
 #include <video/vga.h>
-#include <asm/sysfb.h>
+#include <asm/efi.h>
 
 static bool request_mem_succeeded = false;
 
@@ -85,21 +86,13 @@ static struct fb_ops efifb_ops = {
 static int efifb_setup(char *options)
 {
 	char *this_opt;
-	int i;
 
 	if (options && *options) {
 		while ((this_opt = strsep(&options, ",")) != NULL) {
 			if (!*this_opt) continue;
 
-			for (i = 0; i < M_UNKNOWN; i++) {
-				if (efifb_dmi_list[i].base != 0 &&
-				    !strcmp(this_opt, efifb_dmi_list[i].optname)) {
-					screen_info.lfb_base = efifb_dmi_list[i].base;
-					screen_info.lfb_linelength = efifb_dmi_list[i].stride;
-					screen_info.lfb_width = efifb_dmi_list[i].width;
-					screen_info.lfb_height = efifb_dmi_list[i].height;
-				}
-			}
+			efifb_setup_from_dmi(&screen_info, this_opt);
+
 			if (!strncmp(this_opt, "base:", 5))
 				screen_info.lfb_base = simple_strtoul(this_opt+5, NULL, 0);
 			else if (!strncmp(this_opt, "stride:", 7))
Signature · 1 line
1.9.1
Signature · 1 line
        Peter
#10 lore raw

PATCH 5/8 efi: efifb: use builtin_platform_driver and drop unused includes

In reply to Ard Biesheuvel

Since efifb can only be built directly into the kernel, drop the module specific includes and definitions. Drop some other includes we don't need as well.

---
 drivers/video/fbdev/efifb.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)
drivers/video/fbdev/efifb.c +1 -5
index dd594369b8a6..f4c045c0051c 100644
@@ -6,15 +6,12 @@
  *
  */
 
-#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/efi.h>
 #include <linux/errno.h>
 #include <linux/fb.h>
 #include <linux/platform_device.h>
 #include <linux/screen_info.h>
-#include <linux/dmi.h>
-#include <linux/pci.h>
 #include <video/vga.h>
 #include <asm/efi.h>
 
@@ -331,5 +328,4 @@ static struct platform_driver efifb_driver = {
 	.remove = efifb_remove,
 };
 
-module_platform_driver(efifb_driver);
-MODULE_LICENSE("GPL");
+builtin_platform_driver(efifb_driver);
Signature · 1 line
1.9.1
#11 lore raw

PATCH 5/8 efi: efifb: use builtin_platform_driver and drop unused includes

Cc'ing Peter.

Quoted 39 lines · Ard Biesheuvel

Since efifb can only be built directly into the kernel, drop the module specific includes and definitions. Drop some other includes we don't need as well.

---
 drivers/video/fbdev/efifb.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)
drivers/video/fbdev/efifb.c +1 -5
index dd594369b8a6..f4c045c0051c 100644
@@ -6,15 +6,12 @@
  *
  */
 
-#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/efi.h>
 #include <linux/errno.h>
 #include <linux/fb.h>
 #include <linux/platform_device.h>
 #include <linux/screen_info.h>
-#include <linux/dmi.h>
-#include <linux/pci.h>
 #include <video/vga.h>
 #include <asm/efi.h>
 
@@ -331,5 +328,4 @@ static struct platform_driver efifb_driver = {
 	.remove = efifb_remove,
 };
 
-module_platform_driver(efifb_driver);
-MODULE_LICENSE("GPL");
+builtin_platform_driver(efifb_driver);
Signature · 1 line
1.9.1
maintainer
#12 lore raw

PATCH 5/8 efi: efifb: use builtin_platform_driver and drop unused includes

In reply to Ard Biesheuvel
Quoted 3 lines · Ard Biesheuvel

Since efifb can only be built directly into the kernel, drop the module specific includes and definitions. Drop some other includes we don't need as well.

Yeah; this didn't exist when this code was initially written, and it just never got converted. Thanks.

Quoted 36 lines
---
 drivers/video/fbdev/efifb.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)
drivers/video/fbdev/efifb.c +1 -5
index dd594369b8a6..f4c045c0051c 100644
@@ -6,15 +6,12 @@
  *
  */
 
-#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/efi.h>
 #include <linux/errno.h>
 #include <linux/fb.h>
 #include <linux/platform_device.h>
 #include <linux/screen_info.h>
-#include <linux/dmi.h>
-#include <linux/pci.h>
 #include <video/vga.h>
 #include <asm/efi.h>
 
@@ -331,5 +328,4 @@ static struct platform_driver efifb_driver = {
 	.remove = efifb_remove,
 };
 
-module_platform_driver(efifb_driver);
-MODULE_LICENSE("GPL");
+builtin_platform_driver(efifb_driver);
Signature · 1 line
1.9.1
Signature · 1 line
        Peter
#13 lore raw

PATCH 6/8 efi/arm*: libstub: wire up GOP handling into the ARM UEFI stub

In reply to Ard Biesheuvel

This enables the EFI stub side of handling the EFI Graphics Output Protocol. It involves invoking the generic GOP code to discover the GOP handle that also drives the console, and using its metadata to populate the screen_info structure.

For arm64, the stub and the kernel proper live in the same executable, so we can simply access screen_info directly.

For ARM, we need to allocate a struct screen_info in the stub, and install it as a configuration table so that the core kernel can go and fetch it to copy its contents into the real screen_info structure.

---
 arch/arm/include/asm/efi.h                | 12 +++++++
 arch/arm/kernel/setup.c                   |  3 +-
 arch/arm64/include/asm/efi.h              |  3 ++
 arch/arm64/kernel/efi.c                   |  3 ++
 arch/arm64/kernel/image.h                 |  1 +
 drivers/firmware/efi/libstub/arm-stub.c   | 23 ++++++++++++
 drivers/firmware/efi/libstub/arm32-stub.c | 38 ++++++++++++++++++++
 7 files changed, 82 insertions(+), 1 deletion(-)
arch/arm/include/asm/efi.h +12 -0
index daebcfe6c35a..6329b5be1eca 100644
@@ -63,6 +63,18 @@ void efi_virtmap_unload(void);
 #define __efi_call_early(f, ...)	f(__VA_ARGS__)
 #define efi_is_64bit()			(0)
 
+struct screen_info *alloc_screen_info(efi_system_table_t *sys_table_arg);
+void free_screen_info(efi_system_table_t *sys_table, struct screen_info *si);
+
+/*
+ * This GUID is used to pass to the kernel proper the struct screen_info
+ * structure that was populated by the stub based on the GOP protocol instance
+ * associated with ConOut
+ */
+#define LINUX_ARM32_SCREEN_INFO_TABLE_GUID \
+	EFI_GUID(0xe03fc20a, 0x85dc, 0x406e, \
+		 0xb9, 0xe, 0x4a, 0xb5, 0x02, 0x37, 0x1d, 0x95)
+
 /*
  * A reasonable upper bound for the uncompressed kernel size is 32 MBytes,
  * so we will reserve that amount of memory. We have no easy way to tell what
arch/arm/kernel/setup.c +2 -1
index 7d0cba6f1cc5..149a7787b40f 100644
@@ -881,7 +881,8 @@ static void __init request_standard_resources(const struct machine_desc *mdesc)
 		request_resource(&ioport_resource, &lp2);
 }
 
-#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
+#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE) || \
+    defined(CONFIG_EFI)
 struct screen_info screen_info = {
  .orig_video_lines	= 30,
  .orig_video_cols	= 80,
arch/arm64/include/asm/efi.h +3 -0
index e3d707131bba..a6c14f29b970 100644
@@ -54,6 +54,9 @@ int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md);
 #define __efi_call_early(f, ...)	f(__VA_ARGS__)
 #define efi_is_64bit()			(1)
 
+#define alloc_screen_info(x...)		&screen_info
+#define free_screen_info(x...)
+
 #define EFI_ALLOC_ALIGN		SZ_64K
 
 /*
arch/arm64/kernel/efi.c +3 -0
index b6abc852f2a1..6f4b3ea359db 100644
@@ -17,6 +17,9 @@
 
 #include <asm/efi.h>
 
+/* we will fill this structure from the stub, so don't put it in .bss */
+struct screen_info screen_info __section(.data);
+
 int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md)
 {
 	pteval_t prot_val;
arch/arm64/kernel/image.h +1 -0
index 5ff892f40a0a..fa52ebdfc93e 100644
@@ -115,6 +115,7 @@ __efistub___memset		= KALLSYMS_HIDE(__pi_memset);
 __efistub__text			= KALLSYMS_HIDE(_text);
 __efistub__end			= KALLSYMS_HIDE(_end);
 __efistub__edata		= KALLSYMS_HIDE(_edata);
+__efistub_screen_info		= KALLSYMS_HIDE(screen_info);
 
 #endif
 
drivers/firmware/efi/libstub/arm-stub.c +23 -0
index 4deb3e7faa0e..94bd51cfb71e 100644
@@ -147,6 +147,25 @@ void efi_char16_printk(efi_system_table_t *sys_table_arg,
 	out->output_string(out, str);
 }
 
+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;
+	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) {
+		si = alloc_screen_info(sys_table_arg);
+		if (!si)
+			return NULL;
+		efi_setup_gop(sys_table_arg, si, &gop_proto, size);
+	}
+	return si;
+}
 
 /*
  * This function handles the architcture specific differences between arm and
@@ -185,6 +204,7 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,
 	efi_guid_t loaded_image_proto = LOADED_IMAGE_PROTOCOL_GUID;
 	unsigned long reserve_addr = 0;
 	unsigned long reserve_size = 0;
+	struct screen_info *si;
 
 	/* Check if we were booted by the EFI firmware */
 	if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
@@ -233,6 +253,8 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,
 			__nokaslr = true;
 	}
 
+	si = setup_graphics(sys_table);
+
 	status = handle_kernel_image(sys_table, image_addr, &image_size,
 				     &reserve_addr,
 				     &reserve_size,
@@ -305,6 +327,7 @@ fail_free_image:
 	efi_free(sys_table, image_size, *image_addr);
 	efi_free(sys_table, reserve_size, reserve_addr);
 fail_free_cmdline:
+	free_screen_info(sys_table, si);
 	efi_free(sys_table, cmdline_size, (unsigned long)cmdline_ptr);
 fail:
 	return EFI_ERROR;
drivers/firmware/efi/libstub/arm32-stub.c +38 -0
index 495ebd657e38..0fbe00f13186 100644
@@ -9,6 +9,44 @@
 #include <linux/efi.h>
 #include <asm/efi.h>
 
+static const efi_guid_t screen_info_guid = LINUX_ARM32_SCREEN_INFO_TABLE_GUID;
+
+struct screen_info *alloc_screen_info(efi_system_table_t *sys_table_arg)
+{
+	struct screen_info *si;
+	efi_status_t status;
+
+	/*
+	 * Unlike on arm64, where we can directly fill out the screen_info
+	 * structure from the stub, we need to allocate a buffer to hold
+	 * its contents while we hand over to the kernel proper from the
+	 * decompressor.
+	 */
+	status = efi_call_early(allocate_pool, EFI_RUNTIME_SERVICES_DATA,
+				sizeof(*si), (void **)&si);
+
+	if (status != EFI_SUCCESS)
+		return NULL;
+
+	status = efi_call_early(install_configuration_table,
+				(efi_guid_t *)&screen_info_guid, si);
+	if (status == EFI_SUCCESS)
+		return si;
+
+	efi_call_early(free_pool, si);
+	return NULL;
+}
+
+void free_screen_info(efi_system_table_t *sys_table_arg, struct screen_info *si)
+{
+	if (!si)
+		return;
+
+	efi_call_early(install_configuration_table,
+		       (efi_guid_t *)&screen_info_guid, NULL);
+	efi_call_early(free_pool, si);
+}
+
 efi_status_t handle_kernel_image(efi_system_table_t *sys_table,
 				 unsigned long *image_addr,
 				 unsigned long *image_size,
Signature · 1 line
1.9.1
#14 lore raw

PATCH 6/8 efi/arm*: libstub: wire up GOP handling into the ARM UEFI stub

Quoted 39 lines · Ard Biesheuvel
drivers/firmware/efi/libstub/arm32-stub.c +31 -0
index 495ebd657e38..0fbe00f13186 100644
@@ -9,6 +9,44 @@
 #include <linux/efi.h>
 #include <asm/efi.h>
 
+static const efi_guid_t screen_info_guid = LINUX_ARM32_SCREEN_INFO_TABLE_GUID;
+
+struct screen_info *alloc_screen_info(efi_system_table_t *sys_table_arg)
+{
+	struct screen_info *si;
+	efi_status_t status;
+
+	/*
+	 * Unlike on arm64, where we can directly fill out the screen_info
+	 * structure from the stub, we need to allocate a buffer to hold
+	 * its contents while we hand over to the kernel proper from the
+	 * decompressor.
+	 */
+	status = efi_call_early(allocate_pool, EFI_RUNTIME_SERVICES_DATA,
+				sizeof(*si), (void **)&si);
+
+	if (status != EFI_SUCCESS)
+		return NULL;
+
+	status = efi_call_early(install_configuration_table,
+				(efi_guid_t *)&screen_info_guid, si);
+	if (status == EFI_SUCCESS)
+		return si;
+
+	efi_call_early(free_pool, si);
+	return NULL;
+}
+
+void free_screen_info(efi_system_table_t *sys_table_arg, struct screen_info *si)
+{
+	if (!si)

drivers/firmware/efi/libstub/arm32-stub.c line 52

Quoted 10 lines
drivers/firmware/efi/libstub/arm32-stub.c +7 -0
+		return;
+
+	efi_call_early(install_configuration_table,
+		       (efi_guid_t *)&screen_info_guid, NULL);
+	efi_call_early(free_pool, si);
+}
+
 efi_status_t handle_kernel_image(efi_system_table_t *sys_table,
 				 unsigned long *image_addr,
 				 unsigned long *image_size,

So screen_info_guid should probably not be a 'const': you have to cast it away anyway, adding artificial linebreaks and uglifying the code. It's also a bad practice to cast away const-ness, it hinders move-consts-to-readonly-sections efforts.

Otherwise the series looks mostly good to me. Time for new v4.6 merges is short, but if Matt acks it I can still take it into tip:efi/core.

Thanks,

Ingo

#15 lore raw

PATCH 6/8 efi/arm*: libstub: wire up GOP handling into the ARM UEFI stub

Quoted 49 lines · Ingo Molnar
Quoted 46 lines · Ard Biesheuvel
drivers/firmware/efi/libstub/arm32-stub.c +38 -0
index 495ebd657e38..0fbe00f13186 100644
@@ -9,6 +9,44 @@
 #include <linux/efi.h>
 #include <asm/efi.h>
 
+static const efi_guid_t screen_info_guid = LINUX_ARM32_SCREEN_INFO_TABLE_GUID;
+
+struct screen_info *alloc_screen_info(efi_system_table_t *sys_table_arg)
+{
+     struct screen_info *si;
+     efi_status_t status;
+
+     /*
+      * Unlike on arm64, where we can directly fill out the screen_info
+      * structure from the stub, we need to allocate a buffer to hold
+      * its contents while we hand over to the kernel proper from the
+      * decompressor.
+      */
+     status = efi_call_early(allocate_pool, EFI_RUNTIME_SERVICES_DATA,
+                             sizeof(*si), (void **)&si);
+
+     if (status != EFI_SUCCESS)
+             return NULL;
+
+     status = efi_call_early(install_configuration_table,
+                             (efi_guid_t *)&screen_info_guid, si);
+     if (status == EFI_SUCCESS)
+             return si;
+
+     efi_call_early(free_pool, si);
+     return NULL;
+}
+
+void free_screen_info(efi_system_table_t *sys_table_arg, struct screen_info *si)
+{
+     if (!si)
+             return;
+
+     efi_call_early(install_configuration_table,
+                    (efi_guid_t *)&screen_info_guid, NULL);
+     efi_call_early(free_pool, si);
+}
+
Quoted 9 lines

drivers/firmware/efi/libstub/arm32-stub.c line 52

Quoted 3 lines
drivers/firmware/efi/libstub/arm32-stub.c +0 -0
 efi_status_t handle_kernel_image(efi_system_table_t *sys_table,
                               unsigned long *image_addr,
                               unsigned long *image_size,

So screen_info_guid should probably not be a 'const': you have to cast it away anyway, adding artificial linebreaks and uglifying the code. It's also a bad practice to cast away const-ness, it hinders move-consts-to-readonly-sections efforts.

The problem here is that the UEFI spec never uses const qualifiers in its APIs for by-ref parameters that are obviously never modified by the caller, such as these GUIDs. This is __init code regardless (either due to the fact that it is linked into the stub rather than the core kernel, or because we __init-ize it using objcopy) so I don't care deeply, and I am happy to remove it.

Quoted 3 lines

Otherwise the series looks mostly good to me. Time for new v4.6 merges is short, but if Matt acks it I can still take it into tip:efi/core.

Thank you. I am perfectly happy exercising some more caution here, though, considering that our past experiences involving reshuffling stub code for x86 were not a huge success (and broke Linus's laptop, among others')

I was very careful not to introduce cross-object data symbol references (which were the culprit before), and I tested both i386 and x86_64 to the extent feasible to me, but we'd need to confirm that those things are still fully correct before queuing this.

Thanks,
Ard.

#16 lore raw

PATCH 6/8 efi/arm*: libstub: wire up GOP handling into the ARM UEFI stub

Quoted 8 lines · Ard Biesheuvel
Quoted 4 lines

So screen_info_guid should probably not be a 'const': you have to cast it away anyway, adding artificial linebreaks and uglifying the code. It's also a bad practice to cast away const-ness, it hinders move-consts-to-readonly-sections efforts.

The problem here is that the UEFI spec never uses const qualifiers in its APIs for by-ref parameters that are obviously never modified by the caller, such as these GUIDs. [...]

Ah, ok. Two related thoughts came up:

1)

While I was looking at this code and was asking myself why the EFI runtime is generally invoked via a relatively fragile, non-type-checking vararg construct.

Wouldn't you be better off by explicitly defining all the API variants, and then internally calling the EFI runtime?

That would neatly solve such const artifacts as well.

So instead of:

+ status = efi_call_early(allocate_pool, EFI_RUNTIME_SERVICES_DATA,
+ sizeof(*si), (void **)&si);

we could have something like:

	status = efi_early__allocate_pool(EFI_RUNTIME_SERVICES_DATA, sizeof(*si), &si);

	...

	efi_early__free_pool(si);

i.e. it would look a lot more like a properly distributed, typed, structured family of C function APIs, instead of this single central bastard of an ioctl() interface.

There's over 100 invocations of the EFI runtime in the Linux kernel, I think it would be worth the effort. The wrapper inlines should be mostly trivial.

That would also add an opportunity to actually document most of these calls.

2)

Another suggestion: would it make sense to unify the 'EFI' and 'EFI early' calls - is there any deep reason why they are invoked via separate names? Why not use a single namespace:

	efi__allocate_pool()
	efi__free_pool()

and have a 'current EFI configuration' pointer internaly that can be switched from the early to the later variant during bootup. The various typed API wrappers would use this pointer.

Thanks,

Ingo

#17 lore raw

PATCH 6/8 efi/arm*: libstub: wire up GOP handling into the ARM UEFI stub

Quoted 39 lines · Ingo Molnar
Quoted 8 lines · Ard Biesheuvel
Quoted 4 lines

So screen_info_guid should probably not be a 'const': you have to cast it away anyway, adding artificial linebreaks and uglifying the code. It's also a bad practice to cast away const-ness, it hinders move-consts-to-readonly-sections efforts.

The problem here is that the UEFI spec never uses const qualifiers in its APIs for by-ref parameters that are obviously never modified by the caller, such as these GUIDs. [...]

Ah, ok. Two related thoughts came up:

1)

While I was looking at this code and was asking myself why the EFI runtime is generally invoked via a relatively fragile, non-type-checking vararg construct.

Wouldn't you be better off by explicitly defining all the API variants, and then internally calling the EFI runtime?

That would neatly solve such const artifacts as well.

So instead of:

drivers/firmware/efi/libstub/arm32-stub.c +2 -0
+       status = efi_call_early(allocate_pool, EFI_RUNTIME_SERVICES_DATA,
+                               sizeof(*si), (void **)&si);

we could have something like:

        status = efi_early__allocate_pool(EFI_RUNTIME_SERVICES_DATA, sizeof(*si), &si);

        ...

        efi_early__free_pool(si);
Quoted 9 lines

i.e. it would look a lot more like a properly distributed, typed, structured family of C function APIs, instead of this single central bastard of an ioctl() interface.

There's over 100 invocations of the EFI runtime in the Linux kernel, I think it would be worth the effort. The wrapper inlines should be mostly trivial.

That would also add an opportunity to actually document most of these calls.

If only. The ARM and arm64 wrappers actually simply resolve to correctly typed calls. While I am not an expert on the x86 side of things, I think the vararg stuff is needed to be able to perform the thunking required to do function calls using the MS ABI for x86_64.

As far as documentation is concerned, all of these functions and protocol methods are documented in the UEFI spec, which is freely accessible. It may be somewhat redundant to have our own documentation for them.

Quoted 6 lines

2)

Another suggestion: would it make sense to unify the 'EFI' and 'EFI early' calls - is there any deep reason why they are invoked via separate names? Why not use a single namespace:

Quoted 7 lines
        efi__allocate_pool()
        efi__free_pool()

and have a 'current EFI configuration' pointer internaly that can be switched from the early to the later variant during bootup. The various typed API wrappers would use this pointer.

Actually, having statically initialized pointer variables is more of a concern. The nice thing about plain function calls is that they can usually be resolved at link time to relative branches on most architectures, rather than require GOT fixups or other magic to be able to execute in the UEFI environment.

Thanks,
Ard.

#18 lore raw

PATCH 6/8 efi/arm*: libstub: wire up GOP handling into the ARM UEFI stub

Quoted 47 lines · Ard Biesheuvel
Quoted 46 lines · Ingo Molnar
Quoted 8 lines · Ard Biesheuvel
Quoted 4 lines

So screen_info_guid should probably not be a 'const': you have to cast it away anyway, adding artificial linebreaks and uglifying the code. It's also a bad practice to cast away const-ness, it hinders move-consts-to-readonly-sections efforts.

The problem here is that the UEFI spec never uses const qualifiers in its APIs for by-ref parameters that are obviously never modified by the caller, such as these GUIDs. [...]

Ah, ok. Two related thoughts came up:

1)

While I was looking at this code and was asking myself why the EFI runtime is generally invoked via a relatively fragile, non-type-checking vararg construct.

Wouldn't you be better off by explicitly defining all the API variants, and then internally calling the EFI runtime?

That would neatly solve such const artifacts as well.

So instead of:

drivers/firmware/efi/libstub/arm32-stub.c +2 -0
+       status = efi_call_early(allocate_pool, EFI_RUNTIME_SERVICES_DATA,
+                               sizeof(*si), (void **)&si);

we could have something like:

        status = efi_early__allocate_pool(EFI_RUNTIME_SERVICES_DATA, sizeof(*si), &si);

        ...

        efi_early__free_pool(si);

i.e. it would look a lot more like a properly distributed, typed, structured family of C function APIs, instead of this single central bastard of an ioctl() interface.

There's over 100 invocations of the EFI runtime in the Linux kernel, I think it would be worth the effort. The wrapper inlines should be mostly trivial.

Quoted 7 lines
Quoted 2 lines

That would also add an opportunity to actually document most of these calls.

If only. The ARM and arm64 wrappers actually simply resolve to correctly typed calls. While I am not an expert on the x86 side of things, I think the vararg stuff is needed to be able to perform the thunking required to do function calls using the MS ABI for x86_64.

So at least the efi_early calls seem to just be using a function pointer:

  arch/x86/include/asm/efi.h:     __efi_early()->call(__efi_early()->f, __VA_ARGS__);

Furthermore, my suggestion would work with arbitrarily structured thunking: my suggestion was to put a typed C layer in there - and the layer itself could then call the vararg construct internally. It's a C type demuxing, only a syntactic effort, it does not change any real call signature.

Quoted 4 lines

As far as documentation is concerned, all of these functions and protocol methods are documented in the UEFI spec, which is freely accessible. It may be somewhat redundant to have our own documentation for them.

I mean a properly split up typed C interface 'documents itself' to a large degree
- while with opaque varargs bugs can slip in more easily.

This is really an obvious argument ... it's the well known 'why ioctl()s are bad' API argument.

It has no bearing on this series obviously, it's a cleanup suggestion that could be done separately.

Thanks,

Ingo

#19 lore raw

PATCH 6/8 efi/arm*: libstub: wire up GOP handling into the ARM UEFI stub

Quoted 53 lines · Ingo Molnar
Quoted 50 lines · Ard Biesheuvel
Quoted 48 lines · Ingo Molnar
Quoted 8 lines · Ard Biesheuvel
Quoted 4 lines

So screen_info_guid should probably not be a 'const': you have to cast it away anyway, adding artificial linebreaks and uglifying the code. It's also a bad practice to cast away const-ness, it hinders move-consts-to-readonly-sections efforts.

The problem here is that the UEFI spec never uses const qualifiers in its APIs for by-ref parameters that are obviously never modified by the caller, such as these GUIDs. [...]

Ah, ok. Two related thoughts came up:

1)

While I was looking at this code and was asking myself why the EFI runtime is generally invoked via a relatively fragile, non-type-checking vararg construct.

Wouldn't you be better off by explicitly defining all the API variants, and then internally calling the EFI runtime?

That would neatly solve such const artifacts as well.

So instead of:

drivers/firmware/efi/libstub/arm32-stub.c +2 -0
+       status = efi_call_early(allocate_pool, EFI_RUNTIME_SERVICES_DATA,
+                               sizeof(*si), (void **)&si);

we could have something like:

        status = efi_early__allocate_pool(EFI_RUNTIME_SERVICES_DATA, sizeof(*si), &si);

        ...

        efi_early__free_pool(si);

i.e. it would look a lot more like a properly distributed, typed, structured family of C function APIs, instead of this single central bastard of an ioctl() interface.

There's over 100 invocations of the EFI runtime in the Linux kernel, I think it would be worth the effort. The wrapper inlines should be mostly trivial.

That would also add an opportunity to actually document most of these calls.

Quoted 9 lines
Quoted 4 lines

If only. The ARM and arm64 wrappers actually simply resolve to correctly typed calls. While I am not an expert on the x86 side of things, I think the vararg stuff is needed to be able to perform the thunking required to do function calls using the MS ABI for x86_64.

So at least the efi_early calls seem to just be using a function pointer:

  arch/x86/include/asm/efi.h:     __efi_early()->call(__efi_early()->f, __VA_ARGS__);

Indeed. I think the efi_early struct is a separate structure that is set up by the early boot code, and has a number of function pointers of EFI boot services copied into it. Matt should know the details.

Quoted 5 lines

Furthermore, my suggestion would work with arbitrarily structured thunking: my suggestion was to put a typed C layer in there - and the layer itself could then call the vararg construct internally. It's a C type demuxing, only a syntactic effort, it does not change any real call signature.

I would welcome any improvement in this regard. Happy to contribute as well.

Quoted 5 lines
Quoted 4 lines

As far as documentation is concerned, all of these functions and protocol methods are documented in the UEFI spec, which is freely accessible. It may be somewhat redundant to have our own documentation for them.

Quoted 9 lines

I mean a properly split up typed C interface 'documents itself' to a large degree
- while with opaque varargs bugs can slip in more easily.

This is really an obvious argument ... it's the well known 'why ioctl()s are bad' API argument.

It has no bearing on this series obviously, it's a cleanup suggestion that could be done separately.

I will take this up with Matt. There is lots of room for improvement and consolidation between x86 on the one hand and ARM/arm64 on the other hand in other ways as well.

Thanks,
Ard.

#20 lore raw

PATCH 6/8 efi/arm*: libstub: wire up GOP handling into the ARM UEFI stub

Quoted 4 lines · Ard Biesheuvel

Indeed. I think the efi_early struct is a separate structure that is set up by the early boot code, and has a number of function pointers of EFI boot services copied into it. Matt should know the details.

If you look at where the efi_early stuff came from originally, you'll see it was merged as part of the mixed mode code for running 64-bit kernels on 32-bit EFI,

commit 54b52d872680

Author: Matt Fleming <[email protected]>
Date:   Fri Jan 10 15:27:14 2014 +0000

x86/efi: Build our own EFI services pointer table

It's not possible to dereference the EFI System table directly when booting a 64-bit kernel on a 32-bit EFI firmware because the size of pointers don't match.

In preparation for supporting the above use case, build a list of function pointers on boot so that callers don't have to worry about converting pointer sizes through multiple levels of indirection.

You basically cannot ever dereference a pointer in that mode, it's crazy.

The subsequent efi_early() wrapper came when some of the EFI boot stub code was migrated out of arch/x86 into drivers/firmware/efi/libstub.

I'm not suggesting it's the most beautiful code in the world, far from it. It is a massive eyesore that has resulted in type bugs in the past because of all the casting.

I've just never come up with a cleanup patch series that I was happy with.

Quoted 7 lines
Quoted 5 lines

Furthermore, my suggestion would work with arbitrarily structured thunking: my suggestion was to put a typed C layer in there - and the layer itself could then call the vararg construct internally. It's a C type demuxing, only a syntactic effort, it does not change any real call signature.

I would welcome any improvement in this regard. Happy to contribute as well.

The only way I think a typed C layer would be maintainable is if it was automatically generated. We're already suffering from the multitude of different bitness functions, i.e. __setup_efi_pci32() vs __setup_efi_pci64().

#21 lore raw

PATCH 6/8 efi/arm*: libstub: wire up GOP handling into the ARM UEFI stub

In reply to Ard Biesheuvel
Quoted 10 lines · Ard Biesheuvel

Thank you. I am perfectly happy exercising some more caution here, though, considering that our past experiences involving reshuffling stub code for x86 were not a huge success (and broke Linus's laptop, among others')

I was very careful not to introduce cross-object data symbol references (which were the culprit before), and I tested both i386 and x86_64 to the extent feasible to me, but we'd need to confirm that those things are still fully correct before queuing this.

I agree 100% with Ard. It's far too late in the development cycle to be introducing cross-architecture changes, and in particular, changes to the code driving the early boot console.

I haven't reviewed the patches yet, but this is all v4.7 material.

#22 lore raw

PATCH 6/8 efi/arm*: libstub: wire up GOP handling into the ARM UEFI stub

In reply to Ard Biesheuvel
Quoted 13 lines · Ard Biesheuvel

This enables the EFI stub side of handling the EFI Graphics Output Protocol. It involves invoking the generic GOP code to discover the GOP handle that also drives the console, and using its metadata to populate the screen_info structure.

For arm64, the stub and the kernel proper live in the same executable, so we can simply access screen_info directly.

For ARM, we need to allocate a struct screen_info in the stub, and install it as a configuration table so that the core kernel can go and fetch it to copy its contents into the real screen_info structure.

Quoted 9 lines
---
 arch/arm/include/asm/efi.h                | 12 +++++++
 arch/arm/kernel/setup.c                   |  3 +-
 arch/arm64/include/asm/efi.h              |  3 ++
 arch/arm64/kernel/efi.c                   |  3 ++
 arch/arm64/kernel/image.h                 |  1 +
 drivers/firmware/efi/libstub/arm-stub.c   | 23 ++++++++++++
 drivers/firmware/efi/libstub/arm32-stub.c | 38 ++++++++++++++++++++
 7 files changed, 82 insertions(+), 1 deletion(-)

I'd really like to see the ARM and arm64-specific parts split into separate patches, and then the ARM part merged with patch 8.

The main reason I'm being so strict about this is because the ARM use of InstallConfigurationTable() should be a shining example of how to use that scheme for any future developers.

So that if someone wants to use it to pass other data we can say:
"Look at how we did it for ARM and screen_info. Use that as your template."

Of course, if we do get more users we need to think about providing a real API around InstallConfigurationTable(), but that's for future-Matt and future-Ard to worry about.

Quoted 13 lines
arch/arm/include/asm/efi.h +5 -0
index daebcfe6c35a..6329b5be1eca 100644
@@ -63,6 +63,18 @@ void efi_virtmap_unload(void);
 #define __efi_call_early(f, ...)	f(__VA_ARGS__)
 #define efi_is_64bit()			(0)
 
+struct screen_info *alloc_screen_info(efi_system_table_t *sys_table_arg);
+void free_screen_info(efi_system_table_t *sys_table, struct screen_info *si);
+
+/*
+ * This GUID is used to pass to the kernel proper the struct screen_info

arch/arm/include/asm/efi.h void efi_virtmap_unload(void); · line 80

Quoted 10 lines
arch/arm/include/asm/efi.h +7 -0
+ * structure that was populated by the stub based on the GOP protocol instance
+ * associated with ConOut
+ */
+#define LINUX_ARM32_SCREEN_INFO_TABLE_GUID \
+	EFI_GUID(0xe03fc20a, 0x85dc, 0x406e, \
+		 0xb9, 0xe, 0x4a, 0xb5, 0x02, 0x37, 0x1d, 0x95)
+
 /*
  * A reasonable upper bound for the uncompressed kernel size is 32 MBytes,
  * so we will reserve that amount of memory. We have no easy way to tell what

This should go into include/linux/efi.h. We already have precedent for Linux-specific GUIDs there. See LINUX_EFI_CRASH_GUID.

#23 lore raw

PATCH 7/8 efi/arm*: efifb: expose efifb platform device if GOP is available

In reply to Ard Biesheuvel

This allows the efifb driver to be built for ARM and arm64, and adds the registration of a "efi-framebuffer" platform device if the GOP code in the stub has populated screen_info appropriately.

---
 arch/arm/include/asm/efi.h      |  4 ++++
 arch/arm64/include/asm/efi.h    |  4 ++++
 drivers/firmware/efi/arm-init.c | 19 +++++++++++++++++++
 drivers/video/fbdev/Kconfig     |  2 +-
 4 files changed, 28 insertions(+), 1 deletion(-)
arch/arm/include/asm/efi.h +4 -0
index 6329b5be1eca..9b6d441b08fd 100644
@@ -66,6 +66,10 @@ void efi_virtmap_unload(void);
 struct screen_info *alloc_screen_info(efi_system_table_t *sys_table_arg);
 void free_screen_info(efi_system_table_t *sys_table, struct screen_info *si);
 
+static inline void efifb_setup_from_dmi(struct screen_info *si, const char *opt)
+{
+}
+
 /*
  * This GUID is used to pass to the kernel proper the struct screen_info
  * structure that was populated by the stub based on the GOP protocol instance
arch/arm64/include/asm/efi.h +4 -0
index a6c14f29b970..00e9d7099a8f 100644
@@ -57,6 +57,10 @@ int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md);
 #define alloc_screen_info(x...)		&screen_info
 #define free_screen_info(x...)
 
+static inline void efifb_setup_from_dmi(struct screen_info *si, const char *opt)
+{
+}
+
 #define EFI_ALLOC_ALIGN		SZ_64K
 
 /*
drivers/firmware/efi/arm-init.c +19 -0
index 9e15d571b53c..eca9b4f826ee 100644
@@ -17,6 +17,8 @@
 #include <linux/mm_types.h>
 #include <linux/of.h>
 #include <linux/of_fdt.h>
+#include <linux/platform_device.h>
+#include <linux/screen_info.h>
 
 #include <asm/efi.h>
 
@@ -206,4 +208,21 @@ void __init efi_init(void)
 	memblock_mark_nomap(params.mmap & PAGE_MASK,
 			    PAGE_ALIGN(params.mmap_size +
 				       (params.mmap & ~PAGE_MASK)));
+
+	if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI &&
+	    memblock_is_map_memory(screen_info.lfb_base))
+		memblock_mark_nomap(screen_info.lfb_base, screen_info.lfb_size);
+}
+
+static int __init register_gop_device(void)
+{
+	void *pd;
+
+	if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI)
+		return 0;
+
+	/* the efifb driver accesses screen_info directly, no need to pass it */
+	pd = platform_device_register_simple("efi-framebuffer", 0, NULL, 0);
+	return PTR_ERR_OR_ZERO(pd);
 }
+subsys_initcall(register_gop_device);
drivers/video/fbdev/Kconfig +1 -1
index 8ea45a5cd806..ccbaa25aad76 100644
@@ -761,7 +761,7 @@ config FB_VESA
 
 config FB_EFI
 	bool "EFI-based Framebuffer Support"
-	depends on (FB = y) && X86 && EFI
+	depends on (FB = y) && !IA64 && EFI
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
Signature · 1 line
1.9.1
#24 lore raw

PATCH 8/8 efi/arm: populate screen_info based on data provided by the UEFI stub

In reply to Ard Biesheuvel

Unlike on arm64, where we can simply access the screen_info struct directly, ARM requires an intermediate step to get the information discovered by the GOP code in the UEFI stub into the screen_info struct.

So retrieve the dedicated config table we invented for this purpose, and put its contents into the core kernel's copy of struct screen_info.

---
 arch/arm/kernel/efi.c           | 24 ++++++++++++++++++++
 drivers/firmware/efi/arm-init.c |  6 +++++
 2 files changed, 30 insertions(+)
arch/arm/kernel/efi.c +24 -0
index ff8a9d8acfac..8d1119259654 100644
@@ -6,11 +6,35 @@
  * published by the Free Software Foundation.
  */
 
+#define pr_fmt(fmt)     "efi: " fmt
+
 #include <linux/efi.h>
+#include <linux/screen_info.h>
 #include <asm/efi.h>
 #include <asm/mach/map.h>
 #include <asm/mmu_context.h>
 
+static const efi_guid_t __initconst si_tbl = LINUX_ARM32_SCREEN_INFO_TABLE_GUID;
+
+void __init efi_find_screen_info(efi_config_table_t *tbl, u32 num_tables)
+{
+	struct screen_info *si;
+
+	while (num_tables--) {
+		if (efi_guidcmp(tbl->guid, si_tbl) == 0) {
+			si = early_memremap_ro(tbl->table, sizeof(*si));
+			if (!si) {
+				pr_warn("Failed to remap screen_info config table\n");
+				return;
+			}
+			screen_info = *si;
+			early_memunmap(si, sizeof(*si));
+			break;
+		}
+		tbl++;
+	}
+}
+
 int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md)
 {
 	struct map_desc desc = {
drivers/firmware/efi/arm-init.c +6 -0
index eca9b4f826ee..689bf65f8ddf 100644
@@ -112,6 +112,12 @@ static int __init uefi_init(void)
 	retval = efi_config_parse_tables(config_tables, efi.systab->nr_tables,
 					 sizeof(efi_config_table_t), NULL);
 
+	if (IS_ENABLED(CONFIG_ARM)) {
+		extern void efi_find_screen_info(efi_config_table_t *, u32);
+
+		efi_find_screen_info(config_tables, efi.systab->nr_tables);
+	}
+
 	early_memunmap(config_tables, table_size);
 out:
 	early_memunmap(efi.systab,  sizeof(efi_system_table_t));
Signature · 1 line
1.9.1
#25 lore raw

PATCH 8/8 efi/arm: populate screen_info based on data provided by the UEFI stub

Quoted 12 lines · Ard Biesheuvel

Unlike on arm64, where we can simply access the screen_info struct directly, ARM requires an intermediate step to get the information discovered by the GOP code in the UEFI stub into the screen_info struct.

So retrieve the dedicated config table we invented for this purpose, and put its contents into the core kernel's copy of struct screen_info.

---
 arch/arm/kernel/efi.c           | 24 ++++++++++++++++++++
 drivers/firmware/efi/arm-init.c |  6 +++++
 2 files changed, 30 insertions(+)

[...]

Quoted 7 lines
drivers/firmware/efi/arm-init.c +0 -0
index eca9b4f826ee..689bf65f8ddf 100644
@@ -112,6 +112,12 @@ static int __init uefi_init(void)
 	retval = efi_config_parse_tables(config_tables, efi.systab->nr_tables,
 					 sizeof(efi_config_table_t), NULL);

drivers/firmware/efi/arm-init.c static int __init uefi_init(void) · line 123

Quoted 10 lines
drivers/firmware/efi/arm-init.c +6 -0
 
+	if (IS_ENABLED(CONFIG_ARM)) {
+		extern void efi_find_screen_info(efi_config_table_t *, u32);
+
+		efi_find_screen_info(config_tables, efi.systab->nr_tables);
+	}
+
 	early_memunmap(config_tables, table_size);
 out:
 	early_memunmap(efi.systab,  sizeof(efi_system_table_t));

It's unfortunate that this is the first example of putting arch-specific things in arm-init.c. Is there anyway we can move it out into arch/arm?

If not, because efi_find_screen_info() uses all standard data types and function calls, I wouldn't be opposed to just sticking this in efi_config_parse_tables() like we do for EFI_PROPERTIES_TABLE. It's certainly nice to have all config table code in one place.

Also, it would save ARM the effort of looping over the config tables twice.

#26 lore raw

PATCH 8/8 efi/arm: populate screen_info based on data provided by the UEFI stub

Quoted 38 lines · Matt Fleming
Quoted 12 lines · Ard Biesheuvel

Unlike on arm64, where we can simply access the screen_info struct directly, ARM requires an intermediate step to get the information discovered by the GOP code in the UEFI stub into the screen_info struct.

So retrieve the dedicated config table we invented for this purpose, and put its contents into the core kernel's copy of struct screen_info.

---
 arch/arm/kernel/efi.c           | 24 ++++++++++++++++++++
 drivers/firmware/efi/arm-init.c |  6 +++++
 2 files changed, 30 insertions(+)

[...]

Quoted 7 lines
drivers/firmware/efi/arm-init.c +0 -0
index eca9b4f826ee..689bf65f8ddf 100644
@@ -112,6 +112,12 @@ static int __init uefi_init(void)
      retval = efi_config_parse_tables(config_tables, efi.systab->nr_tables,
                                       sizeof(efi_config_table_t), NULL);

drivers/firmware/efi/arm-init.c static int __init uefi_init(void) · line 123

Quoted 10 lines
drivers/firmware/efi/arm-init.c +6 -0
 
+     if (IS_ENABLED(CONFIG_ARM)) {
+             extern void efi_find_screen_info(efi_config_table_t *, u32);
+
+             efi_find_screen_info(config_tables, efi.systab->nr_tables);
+     }
+
      early_memunmap(config_tables, table_size);
 out:
      early_memunmap(efi.systab,  sizeof(efi_system_table_t));

It's unfortunate that this is the first example of putting arch-specific things in arm-init.c. Is there anyway we can move it out into arch/arm?

Quoted 7 lines

If not, because efi_find_screen_info() uses all standard data types and function calls, I wouldn't be opposed to just sticking this in efi_config_parse_tables() like we do for EFI_PROPERTIES_TABLE. It's certainly nice to have all config table code in one place.

Also, it would save ARM the effort of looping over the config tables twice.

I'd actually prefer that, especially since -at some point- we may expose the stub-to-kernel interface as an ABI, for things like Xen dom0 that expose a 'sanitized' EFI environment, and don't boot the dom0 kernel via the stub. There, this config table would be the only way to populate screen_info, and the fact that arm64 *may* do it directly becomes an implementation detail of the stub.

So in v2, I will rename the GUID to drop the ARMxx part, and move its handling into the generic code.

Signature · 1 line
Ard.
#27 lore raw

cover EFI framebuffer support for ARM and arm64

In reply to Ard Biesheuvel
Quoted 7 lines · Ard Biesheuvel

This series adds support to ARM and arm64 for using the kernel's EFI framebuffer driver to drive EFI Graphics Output Protocol (GOP) based framebuffers.

This involves refactoring some of the existing x86 code so it can be reused by ARM and arm64, and wiring it up both in the UEFI stub and in the core kernel into the existing UEFI infrastructure for ARM and arm64.

Given that I have access to a variety of different ARM64 UEFI implementations, how would I go about testing this code? Do I need a specific UEFI implementation and are there any special command line arguments I should pass to the kernel?

--Mark Langsdorf

#28 lore raw

cover EFI framebuffer support for ARM and arm64

(+ Laszlo)

Quoted 12 lines · Mark Langsdorf
Quoted 9 lines · Ard Biesheuvel

This series adds support to ARM and arm64 for using the kernel's EFI framebuffer driver to drive EFI Graphics Output Protocol (GOP) based framebuffers.

This involves refactoring some of the existing x86 code so it can be reused
by ARM and arm64, and wiring it up both in the UEFI stub and in the core kernel into the existing UEFI infrastructure for ARM and arm64.

Quoted 5 lines

Given that I have access to a variety of different ARM64 UEFI implementations, how would I go about testing this code? Do I need a specific UEFI implementation and are there any special command line arguments I should pass to the kernel?

I have tested this myself on QEMU and FVP Base, which are both software models. On bare metal, it would involve a system with a graphics card that the firmware knows how to drive, and I am honestly not sure if any such combinations currently exist, other than the ARM development platforms such as Juno which have an embedded-style (i.e., non-PCI) graphics controller that the firmware knows how to drive out of the box.

The code itself is smart enough to figure which (if any) of the available handles carrying the GOP protocol is the one that is attached to ConOut, and so there is nothing required to enable this other than building it into the kernel and running it on a system with a firmware supported screen attached.

Signature · 1 line
Ard.
#29 lore raw

cover EFI framebuffer support for ARM and arm64

Quoted 29 lines · Ard Biesheuvel

(+ Laszlo)

Quoted 12 lines · Mark Langsdorf
Quoted 9 lines · Ard Biesheuvel

This series adds support to ARM and arm64 for using the kernel's EFI framebuffer driver to drive EFI Graphics Output Protocol (GOP) based framebuffers.

This involves refactoring some of the existing x86 code so it can be reused
by ARM and arm64, and wiring it up both in the UEFI stub and in the core kernel into the existing UEFI infrastructure for ARM and arm64.

Quoted 5 lines

Given that I have access to a variety of different ARM64 UEFI implementations, how would I go about testing this code? Do I need a specific UEFI implementation and are there any special command line arguments I should pass to the kernel?

I have tested this myself on QEMU and FVP Base, which are both software models. On bare metal, it would involve a system with a graphics card that the firmware knows how to drive, and I am honestly not sure if any such combinations currently exist, other than the ARM development platforms such as Juno which have an embedded-style (i.e., non-PCI) graphics controller that the firmware knows how to drive out of the box.

Quoted 6 lines

The code itself is smart enough to figure which (if any) of the available handles carrying the GOP protocol is the one that is attached to ConOut, and so there is nothing required to enable this other than building it into the kernel and running it on a system with a firmware supported screen attached.

How does this deal with caches? Does the GOP driver access the frame buffer as cached or as uncached memory? I suppose it's always uncached?

I'm mostly curious because I'd like to implement support for GOP in U-Boot soon.

Alex

#30 lore raw

cover EFI framebuffer support for ARM and arm64

Quoted 37 lines · Alexander Graf
Quoted 29 lines · Ard Biesheuvel

(+ Laszlo)

Quoted 12 lines · Mark Langsdorf
Quoted 9 lines · Ard Biesheuvel

This series adds support to ARM and arm64 for using the kernel's EFI framebuffer driver to drive EFI Graphics Output Protocol (GOP) based framebuffers.

This involves refactoring some of the existing x86 code so it can be reused
by ARM and arm64, and wiring it up both in the UEFI stub and in the core kernel into the existing UEFI infrastructure for ARM and arm64.

Quoted 5 lines

Given that I have access to a variety of different ARM64 UEFI implementations, how would I go about testing this code? Do I need a specific UEFI implementation and are there any special command line arguments I should pass to the kernel?

I have tested this myself on QEMU and FVP Base, which are both software models. On bare metal, it would involve a system with a graphics card that the firmware knows how to drive, and I am honestly not sure if any such combinations currently exist, other than the ARM development platforms such as Juno which have an embedded-style (i.e., non-PCI) graphics controller that the firmware knows how to drive out of the box.

Quoted 6 lines

The code itself is smart enough to figure which (if any) of the available handles carrying the GOP protocol is the one that is attached to ConOut, and so there is nothing required to enable this other than building it into the kernel and running it on a system with a firmware supported screen attached.

Quoted 3 lines

How does this deal with caches? Does the GOP driver access the frame buffer as cached or as uncached memory? I suppose it's always uncached?

efifb uses ioremap_wt(), so uncached. And we're even worse off than we are with VGA-PCI since PCI at least has a quirks mechanism.

Quoted 3 lines

I'm mostly curious because I'd like to implement support for GOP in U-Boot soon.

OK. On most real ARM hardware, I wouldn't expect this to be a problem. But it will break QEMU's VGA under KVM in the same way as before, I think.