git: 83d988288675 - main - sys: do not allow entering vm_fault() on boot until VM is initialized

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Mon, 19 Jan 2026 16:20:46 UTC
The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=83d98828867591b5d842573ed6edcec7392f82df

commit 83d98828867591b5d842573ed6edcec7392f82df
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2026-01-18 21:14:59 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2026-01-19 16:20:36 +0000

    sys: do not allow entering vm_fault() on boot until VM is initialized
    
    On amd64, a hack sets td_critnest to 1 in hammer_time(), and then clear
    it before returning from hammer_time(), which is too early.  Instead,
    set TDP_NOFAULTING for thread0, and clear the flag after vm_init() finished.
    
    Noted by:       adrian
    Reviewed by:    adrian (previous version), markj
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D54768
---
 sys/amd64/amd64/machdep.c |  5 +----
 sys/kern/init_main.c      | 12 +++++++++++-
 sys/vm/vm_init.c          |  8 ++++++++
 3 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c
index 2fce1a7e64b6..cae58181000f 100644
--- a/sys/amd64/amd64/machdep.c
+++ b/sys/amd64/amd64/machdep.c
@@ -1518,13 +1518,11 @@ hammer_time(u_int64_t modulep, u_int64_t physfree)
 
 	/*
 	 * We initialize the PCB pointer early so that exception
-	 * handlers will work.  Also set up td_critnest to short-cut
-	 * the page fault handler.
+	 * handlers will work.
 	 */
 	cpu_max_ext_state_size = sizeof(struct savefpu);
 	set_top_of_stack_td(&thread0);
 	thread0.td_pcb = get_pcb_td(&thread0);
-	thread0.td_critnest = 1;
 
 	/*
 	 * The console and kdb should be initialized even earlier than here,
@@ -1615,7 +1613,6 @@ hammer_time(u_int64_t modulep, u_int64_t physfree)
 #ifdef FDT
 	x86_init_fdt();
 #endif
-	thread0.td_critnest = 0;
 
 	kasan_init();
 	kmsan_init();
diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c
index 4144297d674c..39357b8d4440 100644
--- a/sys/kern/init_main.c
+++ b/sys/kern/init_main.c
@@ -104,7 +104,17 @@ void mi_startup(void);				/* Should be elsewhere */
 static struct session session0;
 static struct pgrp pgrp0;
 struct	proc proc0;
-struct thread0_storage thread0_st __aligned(32);
+struct thread0_storage thread0_st __aligned(32) = {
+	.t0st_thread = {
+		/*
+		 * thread0.td_pflags is set with TDP_NOFAULTING to
+		 * short-cut the vm page fault handler until it is
+		 * ready.  It is cleared in vm_init() after VM
+		 * initialization.
+		 */
+		.td_pflags = TDP_NOFAULTING,
+	},
+};
 struct	vmspace vmspace0;
 struct	proc *initproc;
 
diff --git a/sys/vm/vm_init.c b/sys/vm/vm_init.c
index a0d3651ba266..2764b438d27b 100644
--- a/sys/vm/vm_init.c
+++ b/sys/vm/vm_init.c
@@ -159,6 +159,14 @@ vm_mem_init(void *dummy)
 	pmap_init();
 	vm_pager_init();
 
+	/*
+	 * Now we can properly handle calls into vm_fault() from
+	 * kernel page faults during initialization, typically to
+	 * panic.  Clear the nofaulting flag set for thread0 in the
+	 * image, see kern/init_main.c
+	 */
+	curthread->td_pflags &= ~TDP_NOFAULTING;
+
 #ifdef INVARIANTS
 	vm_check_pagesizes();
 #endif