mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 05:02:12 +00:00
First batch of EFI fixes for v6.3:
- Set the NX compat flag for arm64 and zboot, to ensure compatibility with EFI firmware that complies with tightening requirements imposed across the ecosystem. - Improve identification of Ampere Altra systems based on SMBIOS data. - Fix some issues related to the EFI framebuffer that were introduced as a result from some refactoring related to zboot and the merge with sysfb. - Makefile tweak to avoid rebuilding vmlinuz unnecessarily. - Fix efi_random_alloc() return value on out of memory condition. -----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQQQm/3uucuRGn1Dmh0wbglWLn0tXAUCZBxfeAAKCRAwbglWLn0t XJzfAQCiRPMpm5YomKDLdAtjXfwEbyevlYN/gDInAdX5ETzPqgD/WDSEmj3cqh+V Es3u5P/7ICC/qgCleq87qpUk0IPwEwo= =u0Zg -----END PGP SIGNATURE----- Merge tag 'efi-fixes-for-v6.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi Pull EFI fixes from Ard Biesheuvel: - Set the NX compat flag for arm64 and zboot, to ensure compatibility with EFI firmware that complies with tightening requirements imposed across the ecosystem. - Improve identification of Ampere Altra systems based on SMBIOS data. - Fix some issues related to the EFI framebuffer that were introduced as a result from some refactoring related to zboot and the merge with sysfb. - Makefile tweak to avoid rebuilding vmlinuz unnecessarily. - Fix efi_random_alloc() return value on out of memory condition. * tag 'efi-fixes-for-v6.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi: efi/libstub: randomalloc: Return EFI_OUT_OF_RESOURCES on failure efi/libstub: Use relocated version of kernel's struct screen_info efi/libstub: zboot: Add compressed image to make targets efi: sysfb_efi: Add quirk for Lenovo Yoga Book X91F/L efi: sysfb_efi: Fix DMI quirks not working for simpledrm efi/libstub: smbios: Drop unused 'recsize' parameter arm64: efi: Use SMBIOS processor version to key off Ampere quirk efi/libstub: smbios: Use length member instead of record struct size efi: earlycon: Reprobe after parsing config tables arm64: efi: Set NX compat flag in PE/COFF header efi/libstub: arm64: Remap relocated image with strict permissions efi/libstub: zboot: Mark zboot EFI application as NX compatible
This commit is contained in:
commit
877c20b104
@ -66,7 +66,7 @@
|
||||
.long .Lefi_header_end - .L_head // SizeOfHeaders
|
||||
.long 0 // CheckSum
|
||||
.short IMAGE_SUBSYSTEM_EFI_APPLICATION // Subsystem
|
||||
.short 0 // DllCharacteristics
|
||||
.short IMAGE_DLL_CHARACTERISTICS_NX_COMPAT // DllCharacteristics
|
||||
.quad 0 // SizeOfStackReserve
|
||||
.quad 0 // SizeOfStackCommit
|
||||
.quad 0 // SizeOfHeapReserve
|
||||
|
@ -215,6 +215,14 @@ efi_earlycon_write(struct console *con, const char *str, unsigned int num)
|
||||
}
|
||||
}
|
||||
|
||||
static bool __initdata fb_probed;
|
||||
|
||||
void __init efi_earlycon_reprobe(void)
|
||||
{
|
||||
if (fb_probed)
|
||||
setup_earlycon("efifb");
|
||||
}
|
||||
|
||||
static int __init efi_earlycon_setup(struct earlycon_device *device,
|
||||
const char *opt)
|
||||
{
|
||||
@ -222,15 +230,17 @@ static int __init efi_earlycon_setup(struct earlycon_device *device,
|
||||
u16 xres, yres;
|
||||
u32 i;
|
||||
|
||||
if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI)
|
||||
fb_wb = opt && !strcmp(opt, "ram");
|
||||
|
||||
if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI) {
|
||||
fb_probed = true;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
fb_base = screen_info.lfb_base;
|
||||
if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE)
|
||||
fb_base |= (u64)screen_info.ext_lfb_base << 32;
|
||||
|
||||
fb_wb = opt && !strcmp(opt, "ram");
|
||||
|
||||
si = &screen_info;
|
||||
xres = si->lfb_width;
|
||||
yres = si->lfb_height;
|
||||
|
@ -72,6 +72,9 @@ static void __init init_screen_info(void)
|
||||
if (memblock_is_map_memory(screen_info.lfb_base))
|
||||
memblock_mark_nomap(screen_info.lfb_base,
|
||||
screen_info.lfb_size);
|
||||
|
||||
if (IS_ENABLED(CONFIG_EFI_EARLYCON))
|
||||
efi_earlycon_reprobe();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,4 +44,4 @@ OBJCOPYFLAGS_vmlinuz.efi := -O binary
|
||||
$(obj)/vmlinuz.efi: $(obj)/vmlinuz.efi.elf FORCE
|
||||
$(call if_changed,objcopy)
|
||||
|
||||
targets += zboot-header.o vmlinuz.o vmlinuz.efi.elf vmlinuz.efi
|
||||
targets += zboot-header.o vmlinuz vmlinuz.o vmlinuz.efi.elf vmlinuz.efi
|
||||
|
@ -85,8 +85,10 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
|
||||
}
|
||||
}
|
||||
|
||||
if (image->image_base != _text)
|
||||
if (image->image_base != _text) {
|
||||
efi_err("FIRMWARE BUG: efi_loaded_image_t::image_base has bogus value\n");
|
||||
image->image_base = _text;
|
||||
}
|
||||
|
||||
if (!IS_ALIGNED((u64)_text, SEGMENT_ALIGN))
|
||||
efi_err("FIRMWARE BUG: kernel image not aligned on %dk boundary\n",
|
||||
@ -139,6 +141,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
|
||||
*image_addr = *reserve_addr;
|
||||
memcpy((void *)*image_addr, _text, kernel_size);
|
||||
caches_clean_inval_pou(*image_addr, *image_addr + kernel_codesize);
|
||||
efi_remap_image(*image_addr, *reserve_size, kernel_codesize);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
@ -16,20 +16,43 @@
|
||||
|
||||
static bool system_needs_vamap(void)
|
||||
{
|
||||
const u8 *type1_family = efi_get_smbios_string(1, family);
|
||||
const struct efi_smbios_type4_record *record;
|
||||
const u32 __aligned(1) *socid;
|
||||
const u8 *version;
|
||||
|
||||
/*
|
||||
* Ampere eMAG, Altra, and Altra Max machines crash in SetTime() if
|
||||
* SetVirtualAddressMap() has not been called prior.
|
||||
* SetVirtualAddressMap() has not been called prior. Most Altra systems
|
||||
* can be identified by the SMCCC soc ID, which is conveniently exposed
|
||||
* via the type 4 SMBIOS records. Otherwise, test the processor version
|
||||
* field. eMAG systems all appear to have the processor version field
|
||||
* set to "eMAG".
|
||||
*/
|
||||
if (!type1_family || (
|
||||
strcmp(type1_family, "eMAG") &&
|
||||
strcmp(type1_family, "Altra") &&
|
||||
strcmp(type1_family, "Altra Max")))
|
||||
record = (struct efi_smbios_type4_record *)efi_get_smbios_record(4);
|
||||
if (!record)
|
||||
return false;
|
||||
|
||||
efi_warn("Working around broken SetVirtualAddressMap()\n");
|
||||
return true;
|
||||
socid = (u32 *)record->processor_id;
|
||||
switch (*socid & 0xffff000f) {
|
||||
static char const altra[] = "Ampere(TM) Altra(TM) Processor";
|
||||
static char const emag[] = "eMAG";
|
||||
|
||||
default:
|
||||
version = efi_get_smbios_string(&record->header, 4,
|
||||
processor_version);
|
||||
if (!version || (strncmp(version, altra, sizeof(altra) - 1) &&
|
||||
strncmp(version, emag, sizeof(emag) - 1)))
|
||||
break;
|
||||
|
||||
fallthrough;
|
||||
|
||||
case 0x0a160001: // Altra
|
||||
case 0x0a160002: // Altra Max
|
||||
efi_warn("Working around broken SetVirtualAddressMap()\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
efi_status_t check_platform_features(void)
|
||||
|
@ -5,6 +5,15 @@
|
||||
|
||||
#include "efistub.h"
|
||||
|
||||
static unsigned long screen_info_offset;
|
||||
|
||||
struct screen_info *alloc_screen_info(void)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_ARM))
|
||||
return __alloc_screen_info();
|
||||
return (void *)&screen_info + screen_info_offset;
|
||||
}
|
||||
|
||||
/*
|
||||
* EFI entry point for the generic EFI stub used by ARM, arm64, RISC-V and
|
||||
* LoongArch. This is the entrypoint that is described in the PE/COFF header
|
||||
@ -56,6 +65,8 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
|
||||
return status;
|
||||
}
|
||||
|
||||
screen_info_offset = image_addr - (unsigned long)image->image_base;
|
||||
|
||||
status = efi_stub_common(handle, image, image_addr, cmdline_ptr);
|
||||
|
||||
efi_free(image_size, image_addr);
|
||||
|
@ -47,11 +47,6 @@
|
||||
static u64 virtmap_base = EFI_RT_VIRTUAL_BASE;
|
||||
static bool flat_va_mapping = (EFI_RT_VIRTUAL_OFFSET != 0);
|
||||
|
||||
struct screen_info * __weak alloc_screen_info(void)
|
||||
{
|
||||
return &screen_info;
|
||||
}
|
||||
|
||||
void __weak free_screen_info(struct screen_info *si)
|
||||
{
|
||||
}
|
||||
|
@ -1062,6 +1062,7 @@ efi_enable_reset_attack_mitigation(void) { }
|
||||
void efi_retrieve_tpm2_eventlog(void);
|
||||
|
||||
struct screen_info *alloc_screen_info(void);
|
||||
struct screen_info *__alloc_screen_info(void);
|
||||
void free_screen_info(struct screen_info *si);
|
||||
|
||||
void efi_cache_sync_image(unsigned long image_base,
|
||||
@ -1074,6 +1075,8 @@ struct efi_smbios_record {
|
||||
u16 handle;
|
||||
};
|
||||
|
||||
const struct efi_smbios_record *efi_get_smbios_record(u8 type);
|
||||
|
||||
struct efi_smbios_type1_record {
|
||||
struct efi_smbios_record header;
|
||||
|
||||
@ -1087,14 +1090,46 @@ struct efi_smbios_type1_record {
|
||||
u8 family;
|
||||
};
|
||||
|
||||
#define efi_get_smbios_string(__type, __name) ({ \
|
||||
int size = sizeof(struct efi_smbios_type ## __type ## _record); \
|
||||
struct efi_smbios_type4_record {
|
||||
struct efi_smbios_record header;
|
||||
|
||||
u8 socket;
|
||||
u8 processor_type;
|
||||
u8 processor_family;
|
||||
u8 processor_manufacturer;
|
||||
u8 processor_id[8];
|
||||
u8 processor_version;
|
||||
u8 voltage;
|
||||
u16 external_clock;
|
||||
u16 max_speed;
|
||||
u16 current_speed;
|
||||
u8 status;
|
||||
u8 processor_upgrade;
|
||||
u16 l1_cache_handle;
|
||||
u16 l2_cache_handle;
|
||||
u16 l3_cache_handle;
|
||||
u8 serial_number;
|
||||
u8 asset_tag;
|
||||
u8 part_number;
|
||||
u8 core_count;
|
||||
u8 enabled_core_count;
|
||||
u8 thread_count;
|
||||
u16 processor_characteristics;
|
||||
u16 processor_family2;
|
||||
u16 core_count2;
|
||||
u16 enabled_core_count2;
|
||||
u16 thread_count2;
|
||||
u16 thread_enabled;
|
||||
};
|
||||
|
||||
#define efi_get_smbios_string(__record, __type, __name) ({ \
|
||||
int off = offsetof(struct efi_smbios_type ## __type ## _record, \
|
||||
__name); \
|
||||
__efi_get_smbios_string(__type, off, size); \
|
||||
__efi_get_smbios_string((__record), __type, off); \
|
||||
})
|
||||
|
||||
const u8 *__efi_get_smbios_string(u8 type, int offset, int recsize);
|
||||
const u8 *__efi_get_smbios_string(const struct efi_smbios_record *record,
|
||||
u8 type, int offset);
|
||||
|
||||
void efi_remap_image(unsigned long image_base, unsigned alloc_size,
|
||||
unsigned long code_size);
|
||||
|
@ -101,6 +101,7 @@ efi_status_t efi_random_alloc(unsigned long size,
|
||||
* to calculate the randomly chosen address, and allocate it directly
|
||||
* using EFI_ALLOCATE_ADDRESS.
|
||||
*/
|
||||
status = EFI_OUT_OF_RESOURCES;
|
||||
for (map_offset = 0; map_offset < map->map_size; map_offset += map->desc_size) {
|
||||
efi_memory_desc_t *md = (void *)map->map + map_offset;
|
||||
efi_physical_addr_t target;
|
||||
|
@ -15,18 +15,11 @@
|
||||
* 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.
|
||||
*
|
||||
* In order to support both methods from the same build of the EFI stub
|
||||
* library, provide this dummy global definition of struct screen_info. If it
|
||||
* is required to satisfy a link dependency, it means we need to override the
|
||||
* __weak alloc and free methods with the ones below, and those will be pulled
|
||||
* in as well.
|
||||
*/
|
||||
struct screen_info screen_info;
|
||||
|
||||
static efi_guid_t screen_info_guid = LINUX_EFI_SCREEN_INFO_TABLE_GUID;
|
||||
|
||||
struct screen_info *alloc_screen_info(void)
|
||||
struct screen_info *__alloc_screen_info(void)
|
||||
{
|
||||
struct screen_info *si;
|
||||
efi_status_t status;
|
||||
|
@ -22,21 +22,30 @@ struct efi_smbios_protocol {
|
||||
u8 minor_version;
|
||||
};
|
||||
|
||||
const u8 *__efi_get_smbios_string(u8 type, int offset, int recsize)
|
||||
const struct efi_smbios_record *efi_get_smbios_record(u8 type)
|
||||
{
|
||||
struct efi_smbios_record *record;
|
||||
efi_smbios_protocol_t *smbios;
|
||||
efi_status_t status;
|
||||
u16 handle = 0xfffe;
|
||||
const u8 *strtable;
|
||||
|
||||
status = efi_bs_call(locate_protocol, &EFI_SMBIOS_PROTOCOL_GUID, NULL,
|
||||
(void **)&smbios) ?:
|
||||
efi_call_proto(smbios, get_next, &handle, &type, &record, NULL);
|
||||
if (status != EFI_SUCCESS)
|
||||
return NULL;
|
||||
return record;
|
||||
}
|
||||
|
||||
strtable = (u8 *)record + recsize;
|
||||
const u8 *__efi_get_smbios_string(const struct efi_smbios_record *record,
|
||||
u8 type, int offset)
|
||||
{
|
||||
const u8 *strtable;
|
||||
|
||||
if (!record)
|
||||
return NULL;
|
||||
|
||||
strtable = (u8 *)record + record->length;
|
||||
for (int i = 1; i < ((u8 *)record)[offset]; i++) {
|
||||
int len = strlen(strtable);
|
||||
|
||||
|
@ -63,7 +63,7 @@ __efistub_efi_zboot_header:
|
||||
.long .Lefi_header_end - .Ldoshdr
|
||||
.long 0
|
||||
.short IMAGE_SUBSYSTEM_EFI_APPLICATION
|
||||
.short 0
|
||||
.short IMAGE_DLL_CHARACTERISTICS_NX_COMPAT
|
||||
#ifdef CONFIG_64BIT
|
||||
.quad 0, 0, 0, 0
|
||||
#else
|
||||
|
@ -57,6 +57,11 @@ void __weak efi_cache_sync_image(unsigned long image_base,
|
||||
// executable code loaded into memory to be safe for execution.
|
||||
}
|
||||
|
||||
struct screen_info *alloc_screen_info(void)
|
||||
{
|
||||
return __alloc_screen_info();
|
||||
}
|
||||
|
||||
asmlinkage efi_status_t __efiapi
|
||||
efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab)
|
||||
{
|
||||
|
@ -272,6 +272,14 @@ static const struct dmi_system_id efifb_dmi_swap_width_height[] __initconst = {
|
||||
"IdeaPad Duet 3 10IGL5"),
|
||||
},
|
||||
},
|
||||
{
|
||||
/* Lenovo Yoga Book X91F / X91L */
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
/* Non exact match to match F + L versions */
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X91"),
|
||||
},
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
@ -341,7 +349,7 @@ static const struct fwnode_operations efifb_fwnode_ops = {
|
||||
#ifdef CONFIG_EFI
|
||||
static struct fwnode_handle efifb_fwnode;
|
||||
|
||||
__init void sysfb_apply_efi_quirks(struct platform_device *pd)
|
||||
__init void sysfb_apply_efi_quirks(void)
|
||||
{
|
||||
if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI ||
|
||||
!(screen_info.capabilities & VIDEO_CAPABILITY_SKIP_QUIRKS))
|
||||
@ -355,7 +363,10 @@ __init void sysfb_apply_efi_quirks(struct platform_device *pd)
|
||||
screen_info.lfb_height = temp;
|
||||
screen_info.lfb_linelength = 4 * screen_info.lfb_width;
|
||||
}
|
||||
}
|
||||
|
||||
__init void sysfb_set_efifb_fwnode(struct platform_device *pd)
|
||||
{
|
||||
if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI && IS_ENABLED(CONFIG_PCI)) {
|
||||
fwnode_init(&efifb_fwnode, &efifb_fwnode_ops);
|
||||
pd->dev.fwnode = &efifb_fwnode;
|
||||
|
@ -81,6 +81,8 @@ static __init int sysfb_init(void)
|
||||
if (disabled)
|
||||
goto unlock_mutex;
|
||||
|
||||
sysfb_apply_efi_quirks();
|
||||
|
||||
/* try to create a simple-framebuffer device */
|
||||
compatible = sysfb_parse_mode(si, &mode);
|
||||
if (compatible) {
|
||||
@ -107,7 +109,7 @@ static __init int sysfb_init(void)
|
||||
goto unlock_mutex;
|
||||
}
|
||||
|
||||
sysfb_apply_efi_quirks(pd);
|
||||
sysfb_set_efifb_fwnode(pd);
|
||||
|
||||
ret = platform_device_add_data(pd, si, sizeof(*si));
|
||||
if (ret)
|
||||
|
@ -141,7 +141,7 @@ __init struct platform_device *sysfb_create_simplefb(const struct screen_info *s
|
||||
if (!pd)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
sysfb_apply_efi_quirks(pd);
|
||||
sysfb_set_efifb_fwnode(pd);
|
||||
|
||||
ret = platform_device_add_resources(pd, &res, 1);
|
||||
if (ret)
|
||||
|
@ -693,6 +693,7 @@ efi_guid_to_str(efi_guid_t *guid, char *out)
|
||||
}
|
||||
|
||||
extern void efi_init (void);
|
||||
extern void efi_earlycon_reprobe(void);
|
||||
#ifdef CONFIG_EFI
|
||||
extern void efi_enter_virtual_mode (void); /* switch EFI to virtual mode, if possible */
|
||||
#else
|
||||
|
@ -70,11 +70,16 @@ static inline void sysfb_disable(void)
|
||||
#ifdef CONFIG_EFI
|
||||
|
||||
extern struct efifb_dmi_info efifb_dmi_list[];
|
||||
void sysfb_apply_efi_quirks(struct platform_device *pd);
|
||||
void sysfb_apply_efi_quirks(void);
|
||||
void sysfb_set_efifb_fwnode(struct platform_device *pd);
|
||||
|
||||
#else /* CONFIG_EFI */
|
||||
|
||||
static inline void sysfb_apply_efi_quirks(struct platform_device *pd)
|
||||
static inline void sysfb_apply_efi_quirks(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void sysfb_set_efifb_fwnode(struct platform_device *pd)
|
||||
{
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user