Skip to content

Commit

Permalink
efi/arm/libstub: Make screen_info accessible to the UEFI stub
Browse files Browse the repository at this point in the history
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.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
Cc: Borislav Petkov <bp@alien8.de>
Cc: David Herrmann <dh.herrmann@gmail.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Peter Jones <pjones@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Will Deacon <will.deacon@arm.com>
Cc: linux-efi@vger.kernel.org
Link: http://lkml.kernel.org/r/1461614832-17633-22-git-send-email-matt@codeblueprint.co.uk
Signed-off-by: Ingo Molnar <mingo@kernel.org>
  • Loading branch information
Ard Biesheuvel authored and Ingo Molnar committed Apr 28, 2016
1 parent 57fdb89 commit 801820b
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 5 deletions.
3 changes: 3 additions & 0 deletions arch/arm/include/asm/efi.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,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
Expand Down
3 changes: 2 additions & 1 deletion arch/arm/kernel/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -883,7 +883,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,
Expand Down
34 changes: 33 additions & 1 deletion drivers/firmware/efi/arm-init.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand Down Expand Up @@ -51,6 +54,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;
Expand Down Expand Up @@ -108,7 +137,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:
Expand Down Expand Up @@ -223,4 +253,6 @@ void __init efi_init(void)
PAGE_ALIGN(params.mmap_size +
(params.mmap & ~PAGE_MASK)));
}

init_screen_info();
}
5 changes: 3 additions & 2 deletions drivers/firmware/efi/efi.c
Original file line number Diff line number Diff line change
Expand Up @@ -353,8 +353,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;
}
}
Expand Down
37 changes: 37 additions & 0 deletions drivers/firmware/efi/libstub/arm32-stub.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
11 changes: 10 additions & 1 deletion include/linux/efi.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -633,6 +633,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;
Expand Down

0 comments on commit 801820b

Please sign in to comment.