kernel: map and set user stack for initial bootstrap init
The initial bootstrap init (started directly by the kernel via usermode_bootstrap) had RSP = 0 from InterruptStack::init(), which does NOT set RSP. This caused any push/call in the binary to fault on address 0. The Rust panic handler caught the resulting page fault and generated ud2 — visible as 'Invalid opcode fault' at a low RIP before main() ever runs. This was the root cause of the init crash. Fix: - Map 8 pages (32 KiB) of user stack just above the initfs image - Set RSP to the top of the stack - Add debug log showing the mapped region The stack is intentionally small (32 KiB) — enough for Rust _start to run but small enough to detect stack overflow immediately. Once init calls fexec_impl to spawn the real init, the real init gets its own full 8 MB stack via the redox-rt exec path.
This commit is contained in:
+50
-1
@@ -293,7 +293,55 @@ pub unsafe fn usermode_bootstrap(bootstrap: &Bootstrap, token: &mut CleanLockTok
|
||||
debug!("Bootstrap entry point: {:X}", bootstrap_entry);
|
||||
assert_ne!(bootstrap_entry, 0);
|
||||
|
||||
// Start in a minimal environment without any stack.
|
||||
// Map a minimal user stack for the bootstrap process. Without this,
|
||||
// RSP defaults to 0 from InterruptStack::init() and the first `push` or
|
||||
// `call` in the binary triggers a page fault at address 0, which the
|
||||
// C startup turns into `ud2` (Rust panic handler) — visible as
|
||||
// "Invalid opcode fault" at a low RIP before main() ever runs.
|
||||
//
|
||||
// The stack is mapped just above the initfs image in user virtual
|
||||
// memory. The top-of-stack (RSP initial value) points to the END of
|
||||
// the mapped region, since x86-64 stacks grow downward.
|
||||
const BOOTSTRAP_STACK_PAGES: usize = 8; // 32 KiB — enough for Rust _start
|
||||
let stack_base_vaddr = PAGE_SIZE + bootstrap.page_count * PAGE_SIZE;
|
||||
let stack_top_vaddr = stack_base_vaddr + BOOTSTRAP_STACK_PAGES * PAGE_SIZE;
|
||||
{
|
||||
let addr_space = Arc::clone(
|
||||
context::current()
|
||||
.read(token.token())
|
||||
.addr_space()
|
||||
.expect("expected bootstrap context to have an address space"),
|
||||
);
|
||||
let page_count =
|
||||
NonZeroUsize::new(BOOTSTRAP_STACK_PAGES).expect("BOOTSTRAP_STACK_PAGES must be non-zero");
|
||||
let stack_base = Page::containing_address(VirtualAddress::new(stack_base_vaddr));
|
||||
let _base_page = {
|
||||
let mut lock_token = token.token();
|
||||
let mut addr_space_lock = addr_space.acquire_write(lock_token.downgrade());
|
||||
addr_space_lock
|
||||
.mmap(
|
||||
&addr_space,
|
||||
Some(stack_base),
|
||||
page_count,
|
||||
MapFlags::MAP_FIXED_NOREPLACE | MapFlags::PROT_READ | MapFlags::PROT_WRITE,
|
||||
None,
|
||||
|page, flags, mapper, flusher| {
|
||||
let span = PageSpan::new(page, BOOTSTRAP_STACK_PAGES);
|
||||
Ok(Grant::zeroed(
|
||||
span,
|
||||
flags,
|
||||
mapper,
|
||||
flusher,
|
||||
)?)
|
||||
},
|
||||
)
|
||||
.map_err(|e| format!("failed to mmap bootstrap stack: {e:?}"))?;
|
||||
};
|
||||
debug!(
|
||||
"Bootstrap stack mapped at {:#x}..{:#x} ({} pages)",
|
||||
stack_base_vaddr, stack_top_vaddr, BOOTSTRAP_STACK_PAGES
|
||||
);
|
||||
}
|
||||
|
||||
let ctx = context::current();
|
||||
let mut lock = ctx.write(token.token());
|
||||
@@ -303,6 +351,7 @@ pub unsafe fn usermode_bootstrap(bootstrap: &Bootstrap, token: &mut CleanLockTok
|
||||
{
|
||||
regs.init();
|
||||
regs.set_instr_pointer(bootstrap_entry.try_into().unwrap());
|
||||
regs.set_stack_pointer(stack_top_vaddr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user