diff --git a/kernel/src/memory/process_memory.rs b/kernel/src/memory/process_memory.rs index 9750c46e..7280e471 100644 --- a/kernel/src/memory/process_memory.rs +++ b/kernel/src/memory/process_memory.rs @@ -2319,20 +2319,29 @@ pub fn map_user_stack_to_process_with_phys( process_page_table: &mut ProcessPageTable, user_stack_bottom: VirtAddr, user_stack_top: VirtAddr, - phys_bottom: u64, + physical_frames: &[u64], ) -> Result<(), &'static str> { use crate::memory::arch_stub::{Page, PageTableFlags, PhysAddr, PhysFrame, Size4KiB}; let stack_size = user_stack_top.as_u64() - user_stack_bottom.as_u64(); - let num_pages = stack_size / 4096; + let num_pages = (stack_size / 4096) as usize; + + if physical_frames.len() != num_pages { + log::error!( + "Stack frame count mismatch: stack pages={} physical_frames={}", + num_pages, + physical_frames.len() + ); + return Err("Stack frame count mismatch"); + } let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::USER_ACCESSIBLE; - for i in 0..num_pages { - let page_offset = i * 4096; + for (i, frame_phys) in physical_frames.iter().copied().enumerate() { + let page_offset = (i as u64) * 4096; let user_vaddr = VirtAddr::new(user_stack_bottom.as_u64() + page_offset); - let phys_addr = PhysAddr::new(phys_bottom + page_offset); + let phys_addr = PhysAddr::new(frame_phys); let page = Page::::containing_address(user_vaddr); let frame = PhysFrame::::containing_address(phys_addr); diff --git a/kernel/src/memory/stack.rs b/kernel/src/memory/stack.rs index e0914ae3..d548ba97 100644 --- a/kernel/src/memory/stack.rs +++ b/kernel/src/memory/stack.rs @@ -32,6 +32,9 @@ pub struct GuardedStack { /// Privilege level of the stack #[allow(dead_code)] privilege: ThreadPrivilege, + /// Physical frames backing each stack page, in ascending virtual-page order. + #[cfg(target_arch = "aarch64")] + physical_frames: alloc::vec::Vec, } impl GuardedStack { @@ -87,6 +90,8 @@ impl GuardedStack { stack_top, stack_size, privilege, + #[cfg(target_arch = "aarch64")] + physical_frames: alloc::vec::Vec::new(), }) } @@ -128,6 +133,11 @@ impl GuardedStack { self.stack_size } + #[cfg(target_arch = "aarch64")] + pub fn physical_frames(&self) -> &[u64] { + &self.physical_frames + } + /// Find free virtual address space for stack allocation /// /// This function uses a simple incrementing allocator. The bounds checking is @@ -327,19 +337,12 @@ pub fn allocate_stack_with_privilege( // Allocate physical frames for the stack // We track all frames and verify they're contiguous - let mut first_frame_phys: Option = None; - let mut prev_frame_phys: Option = None; + let mut frames = alloc::vec::Vec::with_capacity(stack_pages); - for i in 0..stack_pages { + for _ in 0..stack_pages { let frame = allocate_frame().ok_or("out of memory for stack")?; let phys = frame.start_address().as_u64(); - - if i == 0 { - first_frame_phys = Some(phys); - } - // Note: We don't log non-contiguous frames here - just accept them - // For simple stacks this works fine even if frames aren't contiguous - prev_frame_phys = Some(phys); + frames.push(phys); // Zero the frame via HHDM let virt = HHDM_BASE + phys; @@ -348,8 +351,18 @@ pub fn allocate_stack_with_privilege( } } - let stack_phys = first_frame_phys.ok_or("no frames allocated")?; - let last_frame_phys = prev_frame_phys.ok_or("no frames allocated")?; + let stack_phys = *frames.first().ok_or("no frames allocated")?; + let last_frame_phys = *frames.last().ok_or("no frames allocated")?; + + let contiguous = frames + .windows(2) + .all(|pair| pair[1] == pair[0].saturating_add(4096)); + if !contiguous { + crate::serial_println!( + "ARM64 stack allocator: non-contiguous physical frames: {:x?}", + frames + ); + } // Calculate virtual addresses via HHDM // Layout: [guard page][stack pages...] @@ -364,6 +377,7 @@ pub fn allocate_stack_with_privilege( stack_top, stack_size: size, privilege, + physical_frames: frames, }) } diff --git a/kernel/src/process/manager.rs b/kernel/src/process/manager.rs index 20d762e6..906251a0 100644 --- a/kernel/src/process/manager.rs +++ b/kernel/src/process/manager.rs @@ -435,18 +435,6 @@ impl ProcessManager { "Failed to allocate user stack" })?; - // The kernel_stack.top() is an HHDM address - extract physical address - let kernel_stack_top = kernel_stack.top().as_u64(); - let hhdm_base = crate::arch_impl::aarch64::constants::HHDM_BASE; - let stack_phys_top = kernel_stack_top - hhdm_base; - let stack_phys_bottom = stack_phys_top - USER_STACK_SIZE as u64; - - crate::serial_println!( - "manager.create_process [ARM64]: Stack physical range {:#x}-{:#x}", - stack_phys_bottom, - stack_phys_top - ); - // Calculate userspace stack addresses // Stack grows down, so stack_top is the highest address let user_stack_top = USER_STACK_REGION_START; @@ -462,9 +450,6 @@ impl ProcessManager { process.user_stack_top = user_stack_top; process.user_stack_bottom = user_stack_bottom; - // Store the kernel-accessible stack (for potential kernel access later) - process.stack = Some(Box::new(kernel_stack)); - // Map the physical stack frames into the process page table at USERSPACE addresses log::debug!("ARM64: Mapping user stack pages into process page table..."); crate::serial_println!( @@ -472,10 +457,10 @@ impl ProcessManager { ); let initial_tpidr_el0 = if let Some(ref mut page_table) = process.page_table { crate::serial_println!( - "manager.create_process [ARM64]: map_user_stack_to_process user_bottom={:#x} user_top={:#x} phys_bottom={:#x}", + "manager.create_process [ARM64]: map_user_stack_to_process user_bottom={:#x} user_top={:#x} frames={}", user_stack_bottom, user_stack_top, - stack_phys_bottom + kernel_stack.physical_frames().len() ); // Map physical frames to userspace addresses @@ -483,7 +468,7 @@ impl ProcessManager { page_table, VirtAddr::new(user_stack_bottom), VirtAddr::new(user_stack_top), - stack_phys_bottom, + kernel_stack.physical_frames(), ) .map_err(|e| { crate::serial_println!( @@ -506,6 +491,9 @@ impl ProcessManager { return Err("Process page table not available for stack mapping"); }; + // Store the kernel-accessible stack (for potential kernel access later) + process.stack = Some(Box::new(kernel_stack)); + // Create the main thread with USERSPACE stack top crate::serial_println!("manager.create_process [ARM64]: Creating main thread"); let user_stack_top_vaddr = VirtAddr::new(user_stack_top); @@ -633,12 +621,6 @@ impl ProcessManager { stack::allocate_stack_with_privilege(USER_STACK_SIZE, StackPrivilege::User) .map_err(|_| "Failed to allocate user stack")?; - // Extract physical address from HHDM address - let kernel_stack_top = kernel_stack.top().as_u64(); - let hhdm_base = crate::arch_impl::aarch64::constants::HHDM_BASE; - let stack_phys_top = kernel_stack_top - hhdm_base; - let stack_phys_bottom = stack_phys_top - USER_STACK_SIZE as u64; - // Calculate userspace stack addresses let user_stack_top = USER_STACK_REGION_START; let user_stack_bottom = user_stack_top - USER_STACK_SIZE as u64; @@ -652,7 +634,6 @@ impl ProcessManager { process.memory_usage.stack_size = USER_STACK_SIZE; process.user_stack_top = user_stack_top; process.user_stack_bottom = user_stack_bottom; - process.stack = Some(Box::new(kernel_stack)); // Map the physical stack frames into the process page table let initial_tpidr_el0 = if let Some(ref mut page_table) = process.page_table { @@ -660,7 +641,7 @@ impl ProcessManager { page_table, VirtAddr::new(user_stack_bottom), VirtAddr::new(user_stack_top), - stack_phys_bottom, + kernel_stack.physical_frames(), ) .map_err(|e| { log::error!( @@ -675,6 +656,8 @@ impl ProcessManager { return Err("Process page table not available for stack mapping"); }; + process.stack = Some(Box::new(kernel_stack)); + // Set up argc/argv/envp/auxv on the stack following Linux ABI // The stack is now mapped, so we can write to it via physical addresses let default_env: [&[u8]; 5] = [