aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@FreeBSD.org>2024-10-20 15:47:50 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2024-10-20 17:00:23 +0000
commit6244b9dc4a03e87246bad1c94067dfe54ff4cdbc (patch)
tree1092bb151f04595a7022972a82ea5f28360b4866
parenteaab882600d3cf1562a4030e7c91ad3e0861937b (diff)
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
-rw-r--r--sys/amd64/amd64/locore.S61
1 files 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)