git: 89589b6d3fba - main - amd64: add LASS support

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Wed, 11 Feb 2026 16:05:20 UTC
The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=89589b6d3fbac43eb7c6b3cdbdd6f077888b2142

commit 89589b6d3fbac43eb7c6b3cdbdd6f077888b2142
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2024-10-24 02:12:25 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2026-02-11 16:04:30 +0000

    amd64: add LASS support
    
    In short, LASS enforces all kernel memory accesses to have bit 63 set to
    1, and all userspace accesses have bit 63 set to 0.  Violations of these
    rules cause #GP. There are natural loopholes, like SMAP with rflags.AC=1
    allows kernel to access userspace.
    
    Enablement is simple, we need to set CR4.LASS bit on all CPUs.  There
    are complications when kernel has to execute code at low addresses, e.g.
    for la57 trampoline, or calling into EFI RT.  The patch turns CR4.LASS
    off around these regions.
    
    LASS is officially documented in SDM, since at least rev. 085, October
    2024.  Tested in simics.
    
    Reviewed by:    markj
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D55218
---
 sys/amd64/amd64/efirt_machdep.c |  4 ++++
 sys/amd64/amd64/initcpu.c       | 13 +++++++++++++
 sys/amd64/amd64/machdep.c       |  1 +
 sys/amd64/amd64/pmap.c          |  9 +++++++++
 sys/amd64/include/md_var.h      |  1 +
 5 files changed, 28 insertions(+)

diff --git a/sys/amd64/amd64/efirt_machdep.c b/sys/amd64/amd64/efirt_machdep.c
index fe5d60c978dd..203b2b264587 100644
--- a/sys/amd64/amd64/efirt_machdep.c
+++ b/sys/amd64/amd64/efirt_machdep.c
@@ -348,6 +348,8 @@ efi_arch_enter(void)
 	 */
 	if (!pmap_pcid_enabled)
 		invltlb();
+	if (lass_enabled)
+		load_cr4(rcr4() & ~CR4_LASS);
 	return (0);
 }
 
@@ -357,6 +359,8 @@ efi_arch_leave(void)
 	pmap_t curpmap;
 	uint64_t cr3;
 
+	if (lass_enabled)
+		load_cr4(rcr4() | CR4_LASS);
 	curpmap = &curproc->p_vmspace->vm_pmap;
 	cr3 = curpmap->pm_cr3;
 	if (pmap_pcid_enabled) {
diff --git a/sys/amd64/amd64/initcpu.c b/sys/amd64/amd64/initcpu.c
index 7f317674907e..4c57c27596ad 100644
--- a/sys/amd64/amd64/initcpu.c
+++ b/sys/amd64/amd64/initcpu.c
@@ -290,6 +290,19 @@ initializecpu(void)
 	if (cpu_stdext_feature2 & CPUID_STDEXT2_PKU)
 		cr4 |= CR4_PKE;
 
+	/*
+	 * Any CPU having Linear Address Space Separation (LASS)
+	 * should have SMAP, but check it to be sure.  Otherwise
+	 * userspace accesses from kernel cannot work.
+	 */
+	if (IS_BSP() && (cpu_stdext_feature4 & CPUID_STDEXT4_LASS) != 0 &&
+	    (cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0) {
+		lass_enabled = 1;
+		TUNABLE_INT_FETCH("hw.lass", &lass_enabled);
+	}
+	if (lass_enabled)
+		cr4 |= CR4_LASS;
+
 	/*
 	 * If SMEP is present, we only need to flush RSB (by default)
 	 * on context switches, to prevent cross-process ret2spec
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c
index b0da0b763b22..e9bb27a54dfb 100644
--- a/sys/amd64/amd64/machdep.c
+++ b/sys/amd64/amd64/machdep.c
@@ -204,6 +204,7 @@ int cold = 1;
 long Maxmem = 0;
 long realmem = 0;
 int late_console = 1;
+int lass_enabled = 0;
 
 struct kva_md_info kmi;
 
diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c
index 243a6625bece..8695dd61316e 100644
--- a/sys/amd64/amd64/pmap.c
+++ b/sys/amd64/amd64/pmap.c
@@ -1737,6 +1737,7 @@ pmap_bootstrap_la57(vm_paddr_t *firstaddr)
 {
 	void (*la57_tramp)(uint64_t pml5);
 	pml5_entry_t *pt;
+	uint64_t cr4;
 
 	if ((cpu_stdext_feature2 & CPUID_STDEXT2_LA57) == 0)
 		return;
@@ -1757,8 +1758,16 @@ pmap_bootstrap_la57(vm_paddr_t *firstaddr)
 	    KERNSTART + amd64_loadaddr());
 	printf("Calling la57 trampoline at %p, KPML5phys %#lx ...",
 	    la57_tramp, KPML5phys);
+	if (lass_enabled) {
+		cr4 = rcr4();
+		load_cr4(cr4 & ~CR4_LASS);
+	}
 	la57_tramp(KPML5phys);
 	printf(" alive in la57 mode\n");
+	if (lass_enabled) {
+		cr4 = rcr4();
+		load_cr4(cr4 | CR4_LASS);
+	}
 }
 
 static void
diff --git a/sys/amd64/include/md_var.h b/sys/amd64/include/md_var.h
index 19eab48168f7..7bb8ace27061 100644
--- a/sys/amd64/include/md_var.h
+++ b/sys/amd64/include/md_var.h
@@ -45,6 +45,7 @@ extern int	hw_ibrs_disable;
 extern int	hw_ssb_disable;
 extern int	nmi_flush_l1d_sw;
 extern int	syscall_ret_l1d_flush_mode;
+extern int	lass_enabled;
 
 extern vm_paddr_t intel_graphics_stolen_base;
 extern vm_paddr_t intel_graphics_stolen_size;