In some cases, we expose the kernel's struct screen_info to the EFI stub
directly, so it gets populated before even entering the kernel. This
means the early console is available as soon as the early param parsing
happens, which is nice. It also means we need two different ways to pass
this information, as this trick only works if the EFI stub is baked into
the core kernel image, which is not always the case.
Huacai reports that the preparatory refactoring that was needed to
implement this alternative method for zboot resulted in a non-functional
efifb earlycon for other cases as well, due to the reordering of the
kernel image relocation with the population of the screen_info struct,
and the latter now takes place after copying the image to its new
location, which means we copy the old, uninitialized state.
So let's ensure that the same-image version of alloc_screen_info()
produces the correct screen_info pointer, by taking the displacement of
the loaded image into account.
Reported-by: Huacai Chen <chenhuacai@loongson.cn>
Tested-by: Huacai Chen <chenhuacai@loongson.cn>
Link: https://lore.kernel.org/linux-efi/20230310021749.921041-1-chenhuacai@loongson.cn/
Fixes: 42c8ea3dca
("efi: libstub: Factor out EFI stub entrypoint into separate file")
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
50 lines
1.3 KiB
C
50 lines
1.3 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
#include <linux/efi.h>
|
|
#include <asm/efi.h>
|
|
|
|
#include "efistub.h"
|
|
|
|
/*
|
|
* There are two ways of populating the core kernel's struct screen_info via the stub:
|
|
* - using a configuration table, like below, which relies on the EFI init code
|
|
* to locate the table and copy the contents;
|
|
* - by linking directly to the core kernel's copy of the global symbol.
|
|
*
|
|
* The latter is preferred because it makes the EFIFB earlycon available very
|
|
* early, but it only works if the EFI stub is part of the core kernel image
|
|
* itself. The zboot decompressor can only use the configuration table
|
|
* approach.
|
|
*/
|
|
|
|
static efi_guid_t screen_info_guid = LINUX_EFI_SCREEN_INFO_TABLE_GUID;
|
|
|
|
struct screen_info *__alloc_screen_info(void)
|
|
{
|
|
struct screen_info *si;
|
|
efi_status_t status;
|
|
|
|
status = efi_bs_call(allocate_pool, EFI_ACPI_RECLAIM_MEMORY,
|
|
sizeof(*si), (void **)&si);
|
|
|
|
if (status != EFI_SUCCESS)
|
|
return NULL;
|
|
|
|
status = efi_bs_call(install_configuration_table,
|
|
&screen_info_guid, si);
|
|
if (status == EFI_SUCCESS)
|
|
return si;
|
|
|
|
efi_bs_call(free_pool, si);
|
|
return NULL;
|
|
}
|
|
|
|
void free_screen_info(struct screen_info *si)
|
|
{
|
|
if (!si)
|
|
return;
|
|
|
|
efi_bs_call(install_configuration_table, &screen_info_guid, NULL);
|
|
efi_bs_call(free_pool, si);
|
|
}
|