diff --git a/Cargo.lock b/Cargo.lock index f97d334..341b763 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -217,7 +217,7 @@ dependencies = [ [[package]] name = "ggos_kernel" -version = "0.9.1" +version = "0.9.3" dependencies = [ "bit_field", "bitflags", diff --git a/pkg/app/hello/src/main.rs b/pkg/app/hello/src/main.rs index 72395a7..58382dd 100644 --- a/pkg/app/hello/src/main.rs +++ b/pkg/app/hello/src/main.rs @@ -9,6 +9,19 @@ fn main() -> usize { println!("Hello, world!!!"); let time = lib::sys_time(); println!("Now at: {}", time); + + println!("Huge stack testing..."); + + let mut stack = [0u64; 0x1000]; + + for i in 0..stack.len() { + stack[i] = i as u64; + } + + for i in 0..stack.len() / 256 { + println!("{:#05x} == {:#05x}", i * 256, stack[i * 256]); + } + println!("Exiting..."); 233 diff --git a/pkg/elf/src/lib.rs b/pkg/elf/src/lib.rs index 3ae9a22..d66cd86 100644 --- a/pkg/elf/src/lib.rs +++ b/pkg/elf/src/lib.rs @@ -74,8 +74,10 @@ pub fn map_stack( // create a stack let stack_start = Page::containing_address(VirtAddr::new(addr)); let stack_end = stack_start + pages; + trace!("Page Range: {:?}({})", Page::range(stack_start, stack_end), pages); let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE; + trace!("Flags: {:?}", flags); for page in Page::range(stack_start, stack_end) { let frame = frame_allocator diff --git a/pkg/kernel/Cargo.toml b/pkg/kernel/Cargo.toml index 24a4d90..b74d9b6 100644 --- a/pkg/kernel/Cargo.toml +++ b/pkg/kernel/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ggos_kernel" -version = "0.9.1" +version = "0.9.3" edition = "2021" authors = ["GZTime "] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/pkg/kernel/src/interrupt/handlers.rs b/pkg/kernel/src/interrupt/handlers.rs index de3adb2..7cd22e4 100644 --- a/pkg/kernel/src/interrupt/handlers.rs +++ b/pkg/kernel/src/interrupt/handlers.rs @@ -163,12 +163,12 @@ pub extern "x86-interrupt" fn page_fault_handler( stack_frame: InterruptStackFrame, err_code: PageFaultErrorCode, ) { - warn!( - "EXCEPTION: PAGE FAULT, ERROR_CODE: {:?}\n\nTrying to access: {:#x}\n{:#?}", - err_code, Cr2::read(), stack_frame - ); - - crate::process::force_show_info(); - - panic!("Cannot handle page fault!"); + if let Err(()) = crate::process::handle_page_fault(Cr2::read(), err_code) { + warn!( + "EXCEPTION: PAGE FAULT, ERROR_CODE: {:?}\n\nTrying to access: {:#x}\n{:#?}", + err_code, Cr2::read(), stack_frame + ); + crate::process::force_show_info(); + panic!("Cannot handle page fault!"); + } } diff --git a/pkg/kernel/src/process/manager.rs b/pkg/kernel/src/process/manager.rs index d924738..41ce130 100644 --- a/pkg/kernel/src/process/manager.rs +++ b/pkg/kernel/src/process/manager.rs @@ -33,7 +33,10 @@ impl ProcessManager { } fn current_mut(&mut self) -> &mut Process { - self.processes.iter_mut().find(|x| x.pid() == self.cur_pid).unwrap() + self.processes + .iter_mut() + .find(|x| x.pid() == self.cur_pid) + .unwrap() } fn pid_mut(&mut self, pid: ProcessId) -> &mut Process { @@ -161,16 +164,14 @@ impl ProcessManager { trace!( "Init stack frame with: \n entry: {:#x}\n stack: {:#x}", elf.header.pt2.entry_point(), - STACK_BOT + STACK_SIZE + STACK_INIT_TOP ); p.init_stack_frame( VirtAddr::new_truncate(elf.header.pt2.entry_point()), - VirtAddr::new_truncate(STACK_BOT + STACK_SIZE), + VirtAddr::new_truncate(STACK_INIT_TOP), ); p.init_elf(&elf); trace!("{:#?}", &p); - // info!("Spawn process: {}#{}", p.name(), p.pid()); - // info!("Spawn process:\n\n{:?}\n", p); let pid = p.pid(); self.processes.push(p); pid @@ -233,6 +234,26 @@ impl ProcessManager { }); } + pub fn handle_page_fault( + &mut self, + addr: VirtAddr, + err_code: PageFaultErrorCode, + ) -> Result<(), ()> { + if !err_code.contains(PageFaultErrorCode::PROTECTION_VIOLATION) + { + let cur_proc = self.current_mut(); + trace!("Checking if {:#x} is on current process's stack", addr); + if cur_proc.is_on_stack(addr) { + cur_proc.try_alloc_new_stack_page(addr).unwrap(); + Ok(()) + } else { + Err(()) + } + } else { + Err(()) + } + } + pub fn kill(&mut self, pid: ProcessId, ret: isize) { let p = self.processes.iter().find(|x| x.pid() == pid); @@ -243,7 +264,12 @@ impl ProcessManager { let p = p.unwrap(); - debug!("Killing process {}#{} with ret code: {}", p.name(), pid, ret); + debug!( + "Killing process {}#{} with ret code: {}", + p.name(), + pid, + ret + ); let parent = p.parent(); let children = p.children(); diff --git a/pkg/kernel/src/process/mod.rs b/pkg/kernel/src/process/mod.rs index 69f1499..36b8506 100644 --- a/pkg/kernel/src/process/mod.rs +++ b/pkg/kernel/src/process/mod.rs @@ -17,17 +17,29 @@ use crate::{filesystem::get_volume, Registers, Resource}; use alloc::{string::String, vec, collections::BTreeMap}; use x86_64::{ registers::control::{Cr3, Cr2}, - structures::idt::InterruptStackFrame, + structures::idt::InterruptStackFrame, VirtAddr, }; use x86_64::structures::idt::PageFaultErrorCode; use self::manager::init_PROCESS_MANAGER; use self::sync::init_SEMAPHORES; -const STACK_BOT: u64 = 0x0000_2000_0000_0000; -const STACK_PAGES: u64 = 0x100; -const STACK_SIZE: u64 = STACK_PAGES * crate::memory::PAGE_SIZE; -const STACK_START_MASK: u64 = !(STACK_SIZE - 1); +// 0xffff_ff00_0000_0000 is the kernel's address space +const STACK_MAX_BOT: u64 = 0x0000_4000_0000_0000; +// stack max addr, every thread has a stack space +// from 0x????_????_0000_0000 to 0x????_????_ffff_ffff +// 0x100000000 bytes -> 4GiB +// allow 0x2000 (4096) threads run as a time +// 0x????_2000_????_???? -> 0x????_4000_????_???? +// init alloc stack has size of 0x2000 (2 frames) +// every time we meet a page fault, we will alloc 2 frames, again +const STACK_MAX_PAGES: u64 = 0x100000; +const STACK_MAX_SIZE: u64 = STACK_MAX_PAGES * crate::memory::PAGE_SIZE; +const STACK_START_MASK: u64 = !(STACK_MAX_SIZE - 1); +// [bot..0x2000_0000_0000..top..0x4000_ffff_ffff] +// init stack: [0x4000_ffff_e000_..0x4000_ffff_ffff] +const STACT_INIT_BOT: u64 = STACK_MAX_BOT + STACK_MAX_SIZE - 0x2000; +const STACK_INIT_TOP: u64 = STACK_MAX_BOT + STACK_MAX_SIZE - 1; #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum ProgramStatus { @@ -271,3 +283,9 @@ pub fn force_show_info() { debug!("{:#?}", get_process_manager_for_sure().current()) } + +pub fn handle_page_fault(addr: VirtAddr, err_code: PageFaultErrorCode) -> Result<(), ()> { + x86_64::instructions::interrupts::without_interrupts(|| { + get_process_manager_for_sure().handle_page_fault(addr, err_code) + }) +} diff --git a/pkg/kernel/src/process/process.rs b/pkg/kernel/src/process/process.rs index bc1bd08..a67d29e 100644 --- a/pkg/kernel/src/process/process.rs +++ b/pkg/kernel/src/process/process.rs @@ -10,7 +10,7 @@ use core::intrinsics::copy_nonoverlapping; use x86_64::registers::control::{Cr3, Cr3Flags}; use x86_64::registers::rflags::RFlags; use x86_64::structures::idt::{InterruptStackFrame, InterruptStackFrameValue}; -use x86_64::structures::paging::mapper::CleanUp; +use x86_64::structures::paging::mapper::{CleanUp, MapToError}; use x86_64::structures::paging::page::PageRangeInclusive; use x86_64::structures::paging::*; use x86_64::{PhysAddr, VirtAddr}; @@ -34,6 +34,7 @@ pub struct Process { pub struct ProcessData { env: BTreeMap, code_segements: Option>, + stack_segement: Option, file_handles: BTreeMap, } @@ -47,9 +48,11 @@ impl ProcessData { file_handles.insert(2, Resource::Console(StdIO::Stderr)); // 3 is the file self let code_segements = None; + let stack_segement = None; Self { env, code_segements, + stack_segement, file_handles, } } @@ -169,18 +172,7 @@ impl Process { } // 3. create page table object - let page_table_raw = unsafe { - (physical_to_virtual(page_table_addr.start_address().as_u64()) as *mut PageTable) - .as_mut() - } - .unwrap(); - - let page_table = unsafe { - OffsetPageTable::new( - page_table_raw, - VirtAddr::new_truncate(crate::memory::PHYSICAL_OFFSET as u64), - ) - }; + let page_table = Self::page_table_from_phyframe(page_table_addr); (page_table, page_table_addr) } @@ -242,68 +234,104 @@ impl Process { self.parent } - fn clone_stack(&self, offset: u64) { - // assume that every thread stack is the same size (STACK_PAGES * PAGE_SIZE) - let cur_stack_start = self.stack_frame.stack_pointer.as_u64() & STACK_START_MASK; - let offset_stack_start = STACK_BOT + offset; + pub fn is_on_stack(&self, addr: VirtAddr) -> bool { + if let Some(stack_range) = self.proc_data.stack_segement { + let addr = addr.as_u64(); + let cur_stack_bot = stack_range.start.start_address().as_u64(); + trace!("Current stack bot: {:#x}", cur_stack_bot); + trace!("Address to access: {:#x}", addr); + if addr & STACK_START_MASK != cur_stack_bot & STACK_START_MASK { + false // not in current stack range + } else { + true + } + } else { + false + } + } + pub fn try_alloc_new_stack_page(&mut self, addr: VirtAddr) -> Result<(), MapToError> { + let alloc = &mut *get_frame_alloc_for_sure(); + let start_page = Page::::containing_address(addr); + let pages = self.proc_data.stack_segement.unwrap().start - start_page; + let page_table = self.page_table.as_mut().unwrap(); + debug!("Fill missing pages...[{:?} -> {:?})", start_page, self.proc_data.stack_segement.unwrap().start); + + elf::map_stack(addr.as_u64(), pages, page_table, alloc)?; + + let end_page = self.proc_data.stack_segement.unwrap().end; + let new_stack = Page::range_inclusive(start_page, end_page); + self.proc_data.stack_segement = Some(new_stack); + Ok(()) + } + + fn clone_stack(&self, cur_stack_base: u64, new_stack_base: u64, stack_size: usize) { trace!( "Clone stack: {:#x} -> {:#x}", - cur_stack_start, - offset_stack_start + cur_stack_base, + new_stack_base ); - - // copy stack unsafe { copy_nonoverlapping::( - cur_stack_start as *mut u8, - offset_stack_start as *mut u8, - STACK_SIZE as usize, + cur_stack_base as *mut u8, + new_stack_base as *mut u8, + stack_size * Size4KiB::SIZE as usize, ); } } + fn page_table_from_phyframe(frame: PhysFrame) -> OffsetPageTable<'static> { + unsafe { + OffsetPageTable::new( + (physical_to_virtual(frame.start_address().as_u64()) as *mut PageTable) + .as_mut() + .unwrap(), + VirtAddr::new_truncate(crate::memory::PHYSICAL_OFFSET as u64), + ) + } + } + pub fn fork(&mut self) -> Process { // deep clone page is not impl yet, so we put the thread stack to a new mem let frame_alloc = &mut *get_frame_alloc_for_sure(); - // use the same page table with the parent, but remap stack with offset - // offset to STACK_BOT - let mut offset = (self.children.len() as u64 + 1) * STACK_SIZE; + // use the same page table with the parent, but remap stack with new offset + let stack_info = self.proc_data.stack_segement.unwrap(); + + let mut new_stack_base = stack_info.start.start_address().as_u64() + - (self.children.len() as u64 + 1) * STACK_MAX_SIZE; while let Err(_) = elf::map_stack( - STACK_BOT + offset, - STACK_PAGES, + new_stack_base, + stack_info.count() as u64, self.page_table.as_mut().unwrap(), frame_alloc, ) { - trace!("Map thread stack to {:#x} failed.", STACK_BOT + offset); - offset += STACK_SIZE; + trace!("Map thread stack to {:#x} failed.", new_stack_base); + new_stack_base -= STACK_MAX_SIZE; // stack grow down } - trace!("Map thread stack to {:#x} succeed.", STACK_BOT + offset); - - self.clone_stack(offset); + trace!("Map thread stack to {:#x} succeed.", new_stack_base); + let cur_stack_base = stack_info.start.start_address().as_u64(); + // make new stack frame let mut new_stack_frame = self.stack_frame.clone(); - - // offset to current stack_start - let offset = STACK_BOT + offset - self.stack_frame.stack_pointer.as_u64() & STACK_START_MASK; - new_stack_frame.stack_pointer += offset + STACK_SIZE; - - let page_table_raw = unsafe { - (physical_to_virtual(self.page_table_addr.0.start_address().as_u64()) as *mut PageTable) - .as_mut() - } - .unwrap(); - - let owned_page_table = unsafe { - OffsetPageTable::new( - page_table_raw, - VirtAddr::new_truncate(crate::memory::PHYSICAL_OFFSET as u64), - ) - }; - + // cal new stack pointer + new_stack_frame.stack_pointer += new_stack_base - cur_stack_base; + // clone new stack content + self.clone_stack(cur_stack_base, new_stack_base, stack_info.count()); + // create owned page table (same as parent) + let owned_page_table = Self::page_table_from_phyframe(self.page_table_addr.0); + // clone proc data + let mut owned_proc_data = self.proc_data.clone(); + // record new stack range + owned_proc_data.stack_segement = Some(Page::range_inclusive( + Page::containing_address(VirtAddr::new_truncate(new_stack_base)), + Page::containing_address(VirtAddr::new_truncate( + new_stack_base + stack_info.count() as u64 * Size4KiB::SIZE - 1, + )), + )); + // create new process let mut child = Self { pid: ProcessId::new(), name: self.name.clone(), @@ -315,11 +343,13 @@ impl Process { page_table_addr: (self.page_table_addr.0, Cr3::read().1), page_table: Some(owned_page_table), children: Vec::new(), - proc_data: self.proc_data.clone(), + proc_data: owned_proc_data, }; + // record child pid self.add_child(child.pid); + // fork ret value self.regs.rax = u16::from(child.pid) as usize; child.regs.rax = 0; @@ -355,10 +385,17 @@ impl Process { let mut page_table = self.page_table.take().unwrap(); let code_segements = elf::load_elf(elf, &mut page_table, alloc).unwrap(); - elf::map_stack(STACK_BOT, STACK_PAGES, &mut page_table, alloc).unwrap(); + + elf::map_stack(STACT_INIT_BOT, 2, &mut page_table, alloc).unwrap(); + + let stack_segement = Page::range_inclusive( + Page::containing_address(VirtAddr::new_truncate(STACT_INIT_BOT)), + Page::containing_address(VirtAddr::new_truncate(STACK_INIT_TOP)), + ); self.page_table = Some(page_table); self.proc_data.code_segements = Some(code_segements); + self.proc_data.stack_segement = Some(stack_segement) } } @@ -369,11 +406,11 @@ impl Drop for Process { let start_count = frame_deallocator.recycled_count(); trace!("Free stack for {}#{}", self.name, self.pid); - // only free stack, 0 is set by manager - let stack_start = self.stack_frame.stack_pointer.as_u64() & STACK_START_MASK; + + let stack = self.proc_data.stack_segement.unwrap(); elf::unmap_stack( - stack_start, - STACK_PAGES, + stack.start.start_address().as_u64(), + stack.count() as u64, page_table, frame_deallocator, true, @@ -426,6 +463,7 @@ impl core::fmt::Debug for Process { f.field("stack_top", &self.stack_frame.stack_pointer); f.field("cpu_flags", &self.stack_frame.cpu_flags); f.field("instruction_pointer", &self.stack_frame.instruction_pointer); + f.field("stack", &self.proc_data.stack_segement); f.field("regs", &self.regs); f.finish() } diff --git a/pkg/kernel/src/utils/logger.rs b/pkg/kernel/src/utils/logger.rs index 470064a..689edc3 100644 --- a/pkg/kernel/src/utils/logger.rs +++ b/pkg/kernel/src/utils/logger.rs @@ -13,7 +13,6 @@ pub fn init() { }); info!("Current log level: {}", log::max_level()); - info!("Logger Initialized."); }