From: Alexander Shishkin <alexander.shishkin@xxxxxxxxxxxxxxx> Of all the EFI runtime services, set_virtual_address_map() is the only one that is called at its lower mapping, which LASS prohibits regardless of EFLAGS.AC setting. The only way to allow this to happen is to disable LASS in the CR4 register. Disable LASS around this low address EFI call. Signed-off-by: Alexander Shishkin <alexander.shishkin@xxxxxxxxxxxxxxx> Signed-off-by: Kirill A. Shutemov <kirill.shutemov@xxxxxxxxxxxxxxx> --- arch/x86/platform/efi/efi.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 463b784499a8..5b23c0daedef 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -787,6 +787,7 @@ static void __init __efi_enter_virtual_mode(void) int count = 0, pg_shift = 0; void *new_memmap = NULL; efi_status_t status; + unsigned long lass; unsigned long pa; if (efi_alloc_page_tables()) { @@ -825,11 +826,25 @@ static void __init __efi_enter_virtual_mode(void) efi_sync_low_kernel_mappings(); + /* + * set_virtual_address_map() is the only service located at lower + * addresses, so LASS has to be disabled around it. + * + * Note that flipping RFLAGS.AC is not sufficient for this, as it only + * permits data accesses and not instruction fetch. The entire LASS + * needs to be disabled. + */ + lass = cr4_read_shadow() & X86_CR4_LASS; + cr4_clear_bits(lass); + status = efi_set_virtual_address_map(efi.memmap.desc_size * count, efi.memmap.desc_size, efi.memmap.desc_version, (efi_memory_desc_t *)pa, efi_systab_phys); + + cr4_set_bits(lass); + if (status != EFI_SUCCESS) { pr_err("Unable to switch EFI into virtual mode (status=%lx)!\n", status); -- 2.47.2