Skip to contentSkip to conversation

EFI framebuffer support for ARM and arm64

PATCH Superseded Ard Biesheuvel 3 participants 14 messages Apr 1, 2016 – Apr 22, 2016

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

v3 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.

Changes since v2:
- added acks from Peter and David (patches #3 and #4)
- move introduction of typedef of efi_graphics_output_protocol_query_mode to patch #1 (and move it along in a subsequent patch) to fix a transient build issue spotted by the kbuild robot
- register screen_info as platform driver data explicitly, as x86 does (David)
- assign dummy values to screen_info.orig_video_cols/orig_video_lines, this is required by dummycon on ARM

Changes since v1:
- don't use const efi_guid_t and subsequently cast away constness
- update first, then move the x86 GOP code rather than creating a copy and update at the same time, and delete the x86 code later: this should make it easier to spot changes to the code that affect its correct operation on x86
- refactor the ARM changes so that the config table creation and consumption is introduced in the same patch (including the prototype changes for the install_configuration_table() boot service function pointer)
- use true/false rather than 1/0
- split stub changes into 32-bit arm/64-bit arm/common arm
- split platform device changes from platform driver changes (latter is basically only a Kconfig change)

Ard Biesheuvel (9):
efi/x86: prepare GOP handling code for reuse as generic code
efi: libstub: move Graphics Output Protocol handling to generic code efi/x86: efifb: move DMI based quirks handling out of generic code
efi: efifb: use builtin_platform_driver and drop unused includes efi/arm64: libstub: make screen_info accessible to the UEFI stub efi/arm: libstub: make screen_info accessible to the UEFI stub efi/arm*: libstub: wire up GOP protocol to struct screen_info efi/arm*: wire up struct screen_info to efi-framebuffer platform
device
efifb: enable the efi-framebuffer platform driver for ARM and arm64

 arch/arm/include/asm/efi.h                |  11 +-
 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           |  52 ++-
 drivers/firmware/efi/efi.c                |   5 +-
 drivers/firmware/efi/libstub/Makefile     |   2 +-
 drivers/firmware/efi/libstub/arm-stub.c   |  23 ++
 drivers/firmware/efi/libstub/arm32-stub.c |  37 ++
 drivers/firmware/efi/libstub/gop.c        | 354 ++++++++++++++++++++
 drivers/video/fbdev/Kconfig               |   2 +-
 drivers/video/fbdev/efifb.c               |  21 +-
 include/linux/efi.h                       |  97 +++++-
 18 files changed, 619 insertions(+), 407 deletions(-)
 create mode 100644 drivers/firmware/efi/libstub/gop.c
Signature · 1 line
2.5.0
#1 lore raw

PATCH v3 1/9 efi/x86: prepare GOP handling code for reuse as generic code

In preparation of moving this code to drivers/firmware/efi and reusing it on ARM and arm64, apply any changes that will be required to make this code build for other architectures. This should make it easier to track down problems that this move may cause to its operation on x86.

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/x86/boot/compressed/eboot.c | 58 ++++++++++++--------
 arch/x86/boot/compressed/eboot.h |  4 ++
 arch/x86/include/asm/efi.h       |  5 ++
 include/linux/efi.h              |  5 ++
 4 files changed, 49 insertions(+), 23 deletions(-)
arch/x86/boot/compressed/eboot.c +35 -23
index 583d539a4197..10516e22fdcb 100644
@@ -622,19 +622,22 @@ setup_pixel_info(struct screen_info *si, u32 pixels_per_scan_line,
 }
 
 static efi_status_t
-__gop_query32(struct efi_graphics_output_protocol_32 *gop32,
+__gop_query32(efi_system_table_t *sys_table_arg,
+	      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_graphics_output_protocol_query_mode query_mode;
 	efi_status_t status;
 	unsigned long m;
 
 	m = gop32->mode;
 	mode = (struct efi_graphics_output_protocol_mode_32 *)m;
+	query_mode = (void *)(unsigned long)gop32->query_mode;
 
-	status = efi_early->call(gop32->query_mode, gop32,
-				 mode->mode, size, info);
+	status = __efi_call_early(query_mode, (void *)gop32, mode->mode, size,
+				  info);
 	if (status != EFI_SUCCESS)
 		return status;
 
@@ -643,8 +646,8 @@ __gop_query32(struct efi_graphics_output_protocol_32 *gop32,
 }
 
 static efi_status_t
-setup_gop32(struct screen_info *si, efi_guid_t *proto,
-	    unsigned long size, void **gop_handle)
+setup_gop32(efi_system_table_t *sys_table_arg, 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;
@@ -654,7 +657,7 @@ setup_gop32(struct screen_info *si, efi_guid_t *proto,
 	u64 fb_base;
 	struct efi_pixel_bitmask pixel_info;
 	int pixel_format;
-	efi_status_t status;
+	efi_status_t status = EFI_NOT_FOUND;
 	u32 *handles = (u32 *)(unsigned long)gop_handle;
 	int i;
 
@@ -667,7 +670,7 @@ setup_gop32(struct screen_info *si, efi_guid_t *proto,
 		efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID;
 		bool conout_found = false;
 		void *dummy = NULL;
-		u32 h = handles[i];
+		efi_handle_t h = (efi_handle_t)(unsigned long)handles[i];
 		u64 current_fb_base;
 
 		status = efi_call_early(handle_protocol, h,
@@ -680,7 +683,8 @@ setup_gop32(struct screen_info *si, efi_guid_t *proto,
 		if (status == EFI_SUCCESS)
 			conout_found = true;
 
-		status = __gop_query32(gop32, &info, &size, &current_fb_base);
+		status = __gop_query32(sys_table_arg, gop32, &info, &size,
+				       &current_fb_base);
 		if (status == EFI_SUCCESS && (!first_gop || conout_found)) {
 			/*
 			 * Systems that use the UEFI Console Splitter may
@@ -735,19 +739,22 @@ out:
 }
 
 static efi_status_t
-__gop_query64(struct efi_graphics_output_protocol_64 *gop64,
+__gop_query64(efi_system_table_t *sys_table_arg,
+	      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_graphics_output_protocol_query_mode query_mode;
 	efi_status_t status;
 	unsigned long m;
 
 	m = gop64->mode;
 	mode = (struct efi_graphics_output_protocol_mode_64 *)m;
+	query_mode = (void *)(unsigned long)gop64->query_mode;
 
-	status = efi_early->call(gop64->query_mode, gop64,
-				 mode->mode, size, info);
+	status = __efi_call_early(query_mode, (void *)gop64, mode->mode, size,
+				  info);
 	if (status != EFI_SUCCESS)
 		return status;
 
@@ -756,8 +763,8 @@ __gop_query64(struct efi_graphics_output_protocol_64 *gop64,
 }
 
 static efi_status_t
-setup_gop64(struct screen_info *si, efi_guid_t *proto,
-	    unsigned long size, void **gop_handle)
+setup_gop64(efi_system_table_t *sys_table_arg, 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;
@@ -767,7 +774,7 @@ setup_gop64(struct screen_info *si, efi_guid_t *proto,
 	u64 fb_base;
 	struct efi_pixel_bitmask pixel_info;
 	int pixel_format;
-	efi_status_t status;
+	efi_status_t status = EFI_NOT_FOUND;
 	u64 *handles = (u64 *)(unsigned long)gop_handle;
 	int i;
 
@@ -780,7 +787,7 @@ setup_gop64(struct screen_info *si, efi_guid_t *proto,
 		efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID;
 		bool conout_found = false;
 		void *dummy = NULL;
-		u64 h = handles[i];
+		efi_handle_t h = (efi_handle_t)(unsigned long)handles[i];
 		u64 current_fb_base;
 
 		status = efi_call_early(handle_protocol, h,
@@ -793,7 +800,8 @@ setup_gop64(struct screen_info *si, efi_guid_t *proto,
 		if (status == EFI_SUCCESS)
 			conout_found = true;
 
-		status = __gop_query64(gop64, &info, &size, &current_fb_base);
+		status = __gop_query64(sys_table_arg, gop64, &info, &size,
+				       &current_fb_base);
 		if (status == EFI_SUCCESS && (!first_gop || conout_found)) {
 			/*
 			 * Systems that use the UEFI Console Splitter may
@@ -850,8 +858,9 @@ out:
 /*
  * 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 efi_setup_gop(efi_system_table_t *sys_table_arg,
+			   struct screen_info *si, efi_guid_t *proto,
+			   unsigned long size)
 {
 	efi_status_t status;
 	void **gop_handle = NULL;
@@ -867,10 +876,13 @@ static efi_status_t setup_gop(struct screen_info *si, efi_guid_t *proto,
 	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);
+	if (efi_is_64bit()) {
+		status = setup_gop64(sys_table_arg, si, proto, size,
+				     gop_handle);
+	} else {
+		status = setup_gop32(sys_table_arg, si, proto, size,
+				     gop_handle);
+	}
 
 free_handle:
 	efi_call_early(free_pool, gop_handle);
@@ -1038,7 +1050,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;
arch/x86/boot/compressed/eboot.h +4 -0
index d487e727f1ec..4ee5318d7f28 100644
@@ -85,6 +85,10 @@ struct efi_graphics_output_protocol {
 	struct efi_graphics_output_protocol_mode *mode;
 };
 
+typedef efi_status_t (*efi_graphics_output_protocol_query_mode)(
+	struct efi_graphics_output_protocol *, u32, unsigned long *,
+	struct efi_graphics_output_mode_info **);
+
 struct efi_uga_draw_protocol_32 {
 	u32 get_mode;
 	u32 set_mode;
arch/x86/include/asm/efi.h +5 -0
index 53748c45e488..10e440770371 100644
@@ -225,6 +225,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
include/linux/efi.h +5 -0
index 1545098b0565..f6e7724451ca 100644
@@ -21,6 +21,7 @@
 #include <linux/pfn.h>
 #include <linux/pstore.h>
 #include <linux/reboot.h>
+#include <linux/screen_info.h>
 
 #include <asm/page.h>
 
@@ -1318,5 +1319,9 @@ efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
 
 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);
+
 bool efi_runtime_disabled(void);
 #endif /* _LINUX_EFI_H */
Signature · 1 line
2.5.0
#2 lore raw

PATCH v3 2/9 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 other archs to it in subsequent patches. The new source file gop.c is added to the libstub build for all architectures, but only wired up for x86.

---
 arch/arm/include/asm/efi.h            |   4 +-
 arch/arm64/include/asm/efi.h          |   4 +-
 arch/x86/boot/compressed/eboot.c      | 318 ------------------
 arch/x86/boot/compressed/eboot.h      |  78 -----
 drivers/firmware/efi/libstub/Makefile |   2 +-
 drivers/firmware/efi/libstub/gop.c    | 354 ++++++++++++++++++++
 include/linux/efi.h                   |  81 ++++-
 7 files changed, 441 insertions(+), 400 deletions(-)
arch/arm/include/asm/efi.h +3 -1
index e0eea72deb87..ce1aa3454ca8 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()			(false)
 
 /*
  * A reasonable upper bound for the uncompressed kernel size is 32 MBytes,
arch/arm64/include/asm/efi.h +3 -1
index 8e88a696c9cb..bb26f2205973 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()			(true)
 
 #define EFI_ALLOC_ALIGN		SZ_64K
 
arch/x86/boot/compressed/eboot.c +0 -318

324 lines not on this page · raw message

arch/x86/boot/compressed/eboot.h +0 -78

84 lines not on this page · raw message

drivers/firmware/efi/libstub/Makefile +1 -1
index a15841eced4e..ad76fb9bb56f 100644
@@ -25,7 +25,7 @@ KASAN_SANITIZE			:= n
 UBSAN_SANITIZE			:= n
 OBJECT_FILES_NON_STANDARD	:= y
 
-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 +80 -1

99 lines not on this page · raw message

Signature · 1 line
2.5.0
#3 lore raw

PATCH v3 3/9 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 10e440770371..8747abe8872f 100644
@@ -180,6 +180,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
2.5.0
#4 lore raw

PATCH v3 4/9 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
2.5.0
#5 lore raw

PATCH v3 5/9 efi/arm64: libstub: make screen_info accessible to the UEFI stub

In reply to Ard Biesheuvel

Unlike on 32-bit ARM, where we need to pass the stub's version of struct screen_info to the kernel proper via a configuration table, on 64-bit ARM it simply involves making the core kernel's copy of struct screen_info visible to the stub by exposing an __efistub_ alias for it.

---
 arch/arm64/include/asm/efi.h | 3 +++
 arch/arm64/kernel/efi.c      | 3 +++
 arch/arm64/kernel/image.h    | 1 +
 3 files changed, 7 insertions(+)
arch/arm64/include/asm/efi.h +3 -0
index bb26f2205973..ed6c85d3a583 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()			(true)
 
+#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 5e360ce88f10..1428849aece8 100644
@@ -112,6 +112,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
 
Signature · 1 line
2.5.0
#6 lore raw

PATCH v3 5/9 efi/arm64: libstub: make screen_info accessible to the UEFI stub

Quoted 11 lines · Ard Biesheuvel

Unlike on 32-bit ARM, where we need to pass the stub's version of struct screen_info to the kernel proper via a configuration table, on 64-bit ARM it simply involves making the core kernel's copy of struct screen_info visible to the stub by exposing an __efistub_ alias for it.

---
 arch/arm64/include/asm/efi.h | 3 +++
 arch/arm64/kernel/efi.c      | 3 +++
 arch/arm64/kernel/image.h    | 1 +
 3 files changed, 7 insertions(+)

Since I assume this will all go via the EFI tree:

for this patch.

Will

Quoted 43 lines
arch/arm64/include/asm/efi.h +3 -0
index bb26f2205973..ed6c85d3a583 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()			(true)
 
+#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 5e360ce88f10..1428849aece8 100644
@@ -112,6 +112,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
 
Signature · 1 line
2.5.0
#7 lore raw

PATCH v3 6/9 efi/arm: libstub: make screen_info accessible to the UEFI stub

In reply to Ard Biesheuvel

In order to hand over the framebuffer described by the GOP protocol and discovered by the UEFI stub, make struct screen_info accessible by the stub. This involves allocating a loader data buffer and passing it to the kernel proper via a UEFI Configuration Table, since the UEFI stub executes in the context of the decompressor, and cannot access the kernel's copy of struct screen_info directly.

---
 arch/arm/include/asm/efi.h                |  3 ++
 arch/arm/kernel/setup.c                   |  3 +-
 drivers/firmware/efi/arm-init.c           | 34 +++++++++++++++++-
 drivers/firmware/efi/efi.c                |  5 +--
 drivers/firmware/efi/libstub/arm32-stub.c | 37 ++++++++++++++++++++
 include/linux/efi.h                       | 11 +++++-
 6 files changed, 88 insertions(+), 5 deletions(-)
arch/arm/include/asm/efi.h +3 -0
index ce1aa3454ca8..be12877e8609 100644
@@ -63,6 +63,9 @@ void efi_virtmap_unload(void);
 #define __efi_call_early(f, ...)	f(__VA_ARGS__)
 #define efi_is_64bit()			(false)
 
+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);
+
 /*
  * 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 139791ed473d..2916abd6ec01 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,
drivers/firmware/efi/arm-init.c +33 -1
index 64f0e90c9f60..34bbad23da86 100644
@@ -11,12 +11,15 @@
  *
  */
 
+#define pr_fmt(fmt)	"efi: " fmt
+
 #include <linux/efi.h>
 #include <linux/init.h>
 #include <linux/memblock.h>
 #include <linux/mm_types.h>
 #include <linux/of.h>
 #include <linux/of_fdt.h>
+#include <linux/screen_info.h>
 
 #include <asm/efi.h>
 
@@ -53,6 +56,32 @@ static phys_addr_t efi_to_phys(unsigned long addr)
 	return addr;
 }
 
+static __initdata unsigned long screen_info_table = EFI_INVALID_TABLE_ADDR;
+
+static __initdata efi_config_table_type_t arch_tables[] = {
+	{LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID, NULL, &screen_info_table},
+	{NULL_GUID, NULL, NULL}
+};
+
+static void __init init_screen_info(void)
+{
+	struct screen_info *si;
+
+	if (screen_info_table != EFI_INVALID_TABLE_ADDR) {
+		si = early_memremap_ro(screen_info_table, sizeof(*si));
+		if (!si) {
+			pr_err("Could not map screen_info config table\n");
+			return;
+		}
+		screen_info = *si;
+		early_memunmap(si, sizeof(*si));
+
+		/* dummycon on ARM needs non-zero values for columns/lines */
+		screen_info.orig_video_cols = 80;
+		screen_info.orig_video_lines = 25;
+	}
+}
+
 static int __init uefi_init(void)
 {
 	efi_char16_t *c16;
@@ -110,7 +139,8 @@ static int __init uefi_init(void)
 		goto out;
 	}
 	retval = efi_config_parse_tables(config_tables, efi.systab->nr_tables,
-					 sizeof(efi_config_table_t), NULL);
+					 sizeof(efi_config_table_t),
+					 arch_tables);
 
 	early_memunmap(config_tables, table_size);
 out:
@@ -208,4 +238,6 @@ void __init efi_init(void)
 	memblock_mark_nomap(params.mmap & PAGE_MASK,
 			    PAGE_ALIGN(params.mmap_size +
 				       (params.mmap & ~PAGE_MASK)));
+
+	init_screen_info();
 }
drivers/firmware/efi/efi.c +3 -2
index 3a69ed5ecfcb..a6f1f6d543d4 100644
@@ -351,8 +351,9 @@ static __init int match_config_table(efi_guid_t *guid,
 		for (i = 0; efi_guidcmp(table_types[i].guid, NULL_GUID); i++) {
 			if (!efi_guidcmp(*guid, table_types[i].guid)) {
 				*(table_types[i].ptr) = table;
-				pr_cont(" %s=0x%lx ",
-					table_types[i].name, table);
+				if (table_types[i].name)
+					pr_cont(" %s=0x%lx ",
+						table_types[i].name, table);
 				return 1;
 			}
 		}
drivers/firmware/efi/libstub/arm32-stub.c +37 -0
index 6f42be4d0084..e1f0b28e1dcb 100644
@@ -26,6 +26,43 @@ efi_status_t check_platform_features(efi_system_table_t *sys_table_arg)
 	return EFI_SUCCESS;
 }
 
+static efi_guid_t screen_info_guid = LINUX_EFI_ARM_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,
+				&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, &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,
include/linux/efi.h +10 -1
index 647827c113f7..809db602a795 100644
@@ -286,7 +286,7 @@ typedef struct {
 	efi_status_t (*locate_handle)(int, efi_guid_t *, void *,
 				      unsigned long *, efi_handle_t *);
 	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;
@@ -629,6 +629,15 @@ void efi_native_runtime_setup(void);
 	EFI_GUID(0xd3b36f2c, 0xd551, 0x11d4, \
 		 0x9a, 0x46, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
 
+/*
+ * 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_EFI_ARM_SCREEN_INFO_TABLE_GUID \
+	EFI_GUID(0xe03fc20a, 0x85dc, 0x406e, \
+		 0xb9, 0xe, 0x4a, 0xb5, 0x02, 0x37, 0x1d, 0x95)
+
 typedef struct {
 	efi_guid_t guid;
 	u64 table;
Signature · 1 line
2.5.0
#8 lore raw

PATCH v3 7/9 efi/arm*: libstub: wire up GOP protocol to struct screen_info

In reply to Ard Biesheuvel

This adds the code to the ARM and arm64 versions of the UEFI stub to populate struct screen_info based on the information received from the firmware via the GOP protocol.

---
 drivers/firmware/efi/libstub/arm-stub.c | 23 ++++++++++++++++++++
 1 file changed, 23 insertions(+)
drivers/firmware/efi/libstub/arm-stub.c +23 -0
index 128632508fc6..993aa56755f6 100644
@@ -169,6 +169,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
@@ -208,6 +227,7 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,
 	unsigned long reserve_addr = 0;
 	unsigned long reserve_size = 0;
 	int secure_boot = 0;
+	struct screen_info *si;
 
 	/* Check if we were booted by the EFI firmware */
 	if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
@@ -260,6 +280,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,
@@ -341,6 +363,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;
Signature · 1 line
2.5.0
#9 lore raw

PATCH v3 8/9 efi/arm*: wire up struct screen_info to efi-framebuffer platform device

In reply to Ard Biesheuvel

This adds code to the ARM and arm64 EFI init routines to expose a platform device of type 'efi-framebuffer' if struct screen_info has been populated appropriately from the GOP protocol by the stub. Since the framebuffer may potentially be located in system RAM, make sure that the region is reserved and marked MEMBLOCK_NOMAP.

---
 drivers/firmware/efi/arm-init.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
drivers/firmware/efi/arm-init.c +18 -0
index 34bbad23da86..7c5a38c60037 100644
@@ -19,6 +19,7 @@
 #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>
@@ -80,6 +81,10 @@ static void __init init_screen_info(void)
 		screen_info.orig_video_cols = 80;
 		screen_info.orig_video_lines = 25;
 	}
+
+	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 uefi_init(void)
@@ -241,3 +246,16 @@ void __init efi_init(void)
 
 	init_screen_info();
 }
+
+static int __init register_gop_device(void)
+{
+	void *pd;
+
+	if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI)
+		return 0;
+
+	pd = platform_device_register_data(NULL, "efi-framebuffer", 0,
+					   &screen_info, sizeof(screen_info));
+	return PTR_ERR_OR_ZERO(pd);
+}
+subsys_initcall(register_gop_device);
Signature · 1 line
2.5.0
#10 lore raw

PATCH v3 9/9 efifb: enable the efi-framebuffer platform driver for ARM and arm64

In reply to Ard Biesheuvel

Allows the efifb driver to be built for ARM and arm64. This simply involves updating the Kconfig dependency expression, and supplying dummy versions of efifb_setup_from_dmi().

---
 arch/arm/include/asm/efi.h   | 4 ++++
 arch/arm64/include/asm/efi.h | 4 ++++
 drivers/video/fbdev/Kconfig  | 2 +-
 3 files changed, 9 insertions(+), 1 deletion(-)
arch/arm/include/asm/efi.h +4 -0
index be12877e8609..76ce7adde990 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)
+{
+}
+
 /*
  * 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/arm64/include/asm/efi.h +4 -0
index ed6c85d3a583..ec43456e3ef1 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/video/fbdev/Kconfig +1 -1
index 983280e8d93f..e5a391aecde1 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
2.5.0
#11 lore raw

v3 cover EFI framebuffer support for ARM and arm64

In reply to Ard Biesheuvel
Quoted 4 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.

Matt: FYI the memremap() patches for ARM that this series (and the memory attributes one as well, for that matter) depends on have been pulled by Russell and should turn up in -next shortly. That means these patches are good to go, as far as I am concerned (unless there are remaining concerns?)

Thanks,
Ard.

Quoted 63 lines

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.

Changes since v2:
- added acks from Peter and David (patches #3 and #4)
- move introduction of typedef of efi_graphics_output_protocol_query_mode to patch #1 (and move it along in a subsequent patch) to fix a transient build issue spotted by the kbuild robot
- register screen_info as platform driver data explicitly, as x86 does (David)
- assign dummy values to screen_info.orig_video_cols/orig_video_lines, this is required by dummycon on ARM

Changes since v1:
- don't use const efi_guid_t and subsequently cast away constness
- update first, then move the x86 GOP code rather than creating a copy and update at the same time, and delete the x86 code later: this should make it easier to spot changes to the code that affect its correct operation on x86
- refactor the ARM changes so that the config table creation and consumption is introduced in the same patch (including the prototype changes for the install_configuration_table() boot service function pointer)
- use true/false rather than 1/0
- split stub changes into 32-bit arm/64-bit arm/common arm
- split platform device changes from platform driver changes (latter is basically only a Kconfig change)

Ard Biesheuvel (9):
efi/x86: prepare GOP handling code for reuse as generic code
efi: libstub: move Graphics Output Protocol handling to generic code efi/x86: efifb: move DMI based quirks handling out of generic code
efi: efifb: use builtin_platform_driver and drop unused includes efi/arm64: libstub: make screen_info accessible to the UEFI stub efi/arm: libstub: make screen_info accessible to the UEFI stub efi/arm*: libstub: wire up GOP protocol to struct screen_info efi/arm*: wire up struct screen_info to efi-framebuffer platform
device
efifb: enable the efi-framebuffer platform driver for ARM and arm64

 arch/arm/include/asm/efi.h                |  11 +-
 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           |  52 ++-
 drivers/firmware/efi/efi.c                |   5 +-
 drivers/firmware/efi/libstub/Makefile     |   2 +-
 drivers/firmware/efi/libstub/arm-stub.c   |  23 ++
 drivers/firmware/efi/libstub/arm32-stub.c |  37 ++
 drivers/firmware/efi/libstub/gop.c        | 354 ++++++++++++++++++++
 drivers/video/fbdev/Kconfig               |   2 +-
 drivers/video/fbdev/efifb.c               |  21 +-
 include/linux/efi.h                       |  97 +++++-
 18 files changed, 619 insertions(+), 407 deletions(-)
 create mode 100644 drivers/firmware/efi/libstub/gop.c

--
2.5.0

#12 lore raw

v3 cover EFI framebuffer support for ARM and arm64

Quoted 6 lines · Ard Biesheuvel

Matt: FYI the memremap() patches for ARM that this series (and the memory attributes one as well, for that matter) depends on have been pulled by Russell and should turn up in -next shortly. That means these patches are good to go, as far as I am concerned (unless there are remaining concerns?)

Understood. I don't think there were any remaining concerns but I haven't reviewed the v3 series yet. I'll do that and get back to you.

#13 lore raw

v3 cover EFI framebuffer support for ARM and arm64

Quoted 10 lines · Matt Fleming
Quoted 6 lines · Ard Biesheuvel

Matt: FYI the memremap() patches for ARM that this series (and the memory attributes one as well, for that matter) depends on have been pulled by Russell and should turn up in -next shortly. That means these patches are good to go, as far as I am concerned (unless there are remaining concerns?)

Understood. I don't think there were any remaining concerns but I haven't reviewed the v3 series yet. I'll do that and get back to you.

OK, I've gone through this again. Everything looks very nice. It's queued up for v4.7.