git: 6244b9dc4a03 - main - la57: explain how the trampoline works

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Sun, 20 Oct 2024 17:00:46 UTC
The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=6244b9dc4a03e87246bad1c94067dfe54ff4cdbc

commit 6244b9dc4a03e87246bad1c94067dfe54ff4cdbc
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2024-10-20 15:47:50 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2024-10-20 17:00:23 +0000

    la57: explain how the trampoline works
    
    Reviewed by:    markj, imp (previous version)
    Sponsored by:   The FreeBSD Foundation
    MFC after:      3 days
    Differential revision:  https://reviews.freebsd.org/D47208
---
 sys/amd64/amd64/locore.S | 61 ++++++++++++++++++++++++++++++++----------------
 1 file changed, 41 insertions(+), 20 deletions(-)

diff --git a/sys/amd64/amd64/locore.S b/sys/amd64/amd64/locore.S
index 1ed9085e655c..d39503adadf0 100644
--- a/sys/amd64/amd64/locore.S
+++ b/sys/amd64/amd64/locore.S
@@ -89,15 +89,36 @@ ENTRY(btext)
 0:	hlt
 	jmp	0b
 
-/* la57_trampoline(%rdi pml5) */
+/*
+ * void la57_trampoline(%rdi pml5)
+ *
+ * Entered in 4-level paging long mode on AP, hopefully returns alive in
+ * 5-level paging mode. The parameter is a pointer to a 5-level page
+ * table root. The passed 5-level page table, and the current 4-level page
+ * table, both must map the trampoline code page 1:1 physical, below 4G.
+ * The trampoline must be PIC because it is copied from kernel text into
+ * this page.
+ *
+ * The current paging level cannot be changed while paging is enabled, and
+ * paging cannot be disabled while in long mode.  As consequence, code
+ * switches into the compat mode, then disables paging to descend into
+ * protected mode.  There, the paging level bit CR4.LA57 can be changed,
+ * and code directly jumps back into long mode.
+ *
+ * Falling into the protected mode requires single-purpose GDT entries,
+ * which are provided by the private GDT.  It is the caller's responsibility
+ * to
+ * - restore the GDT and %gsbase after the call
+ * - reset IDT back to long mode.
+ */
 ENTRY(la57_trampoline)
-	movq	%rsp,lst(%rip)
-	movq	%rbx,lst+8(%rip)
-	movq	%rbp,lst+0x10(%rip)
+	movq	%rsp,lst(%rip)		/* save registers into memeory */
+	movq	%rbx,lst+8(%rip)	/* upper halves are not saved .. */
+	movq	%rbp,lst+0x10(%rip)	/* by 64->32->64 switch */
 	movq	%cr4,%rax
-	orq	$CR4_LA57,%rax
+	orq	$CR4_LA57,%rax		/* 5-lvl %cr4 */
 	movq	%rax,lst+0x18(%rip)
-	leaq	la57_trampoline_end(%rip),%rsp
+	leaq	la57_trampoline_end(%rip),%rsp /* priv stack */
 
 	movq	%cr0,%rbp
 	lgdtq	la57_trampoline_gdt_desc(%rip)
@@ -111,45 +132,45 @@ ENTRY(la57_trampoline)
 	.code32
 
 l1:	movl	$(3<<3),%eax
-	movl	%eax,%ss
+	movl	%eax,%ss		/* 32bit paged, priv gdt and stack */
 
 	movl	%cr4,%eax
-	andl	$~(CR4_PGE | CR4_PCIDE),%eax
+	andl	$~(CR4_PGE | CR4_PCIDE),%eax /* clear sensitive paging ctrls */
 	movl	%eax,%cr4
 
 	movl	%ebp,%eax
-	andl	$~CR0_PG,%eax
+	andl	$~CR0_PG,%eax		/* protected mode */
 	movl	%eax,%cr0
 
-	movl	$MSR_EFER,%ecx
-	rdmsr
+	movl	$MSR_EFER,%ecx		/* disable long mode bit */
+	rdmsr				/* to safer tweaking LA57 */
 	andl	$~EFER_LME,%eax
 	wrmsr
 
-	movl	%cr4,%eax
+	movl	%cr4,%eax		/* finally safe to switch bit */
 	orl	$CR4_LA57,%eax
 	movl	%eax,%cr4
 
-	movl	%edi,%cr3
+	movl	%edi,%cr3		/* and load the 5-level pgtable root */
 
 	rdmsr
 	orl	$EFER_LME,%eax
-	wrmsr
+	wrmsr				/* prepare for ... */
 
-	movl	%ebp,%cr0
-	jmp	1f
+	movl	%ebp,%cr0		/* and jump back directly into long */
+	jmp	1f			/* mode from protected by enabling pg */
 
-1:	pushl	$(1<<3)
+1:	pushl	$(1<<3)			/* reload %cs */
 	pushl	%ebx
 	lretl
 	.code64
 
-l2:	movq	lst(%rip),%rsp
+l2:	movq	lst(%rip),%rsp		/* back on C stack */
 	movq	lst+8(%rip),%rbx
 	movq	lst+0x10(%rip),%rbp
 	movq	lst+0x18(%rip),%rax
-	movq	%rax,%cr4
-	retq
+	movq	%rax,%cr4		/* re-enable paging controls */
+	retq				/* back to C */
 	.p2align 4,0
 lst:	.quad	0,0,0,0
 ENTRY(la57_trampoline_gdt_desc)