diff --git a/src/kxos-frame/src/log.rs b/src/kxos-frame/src/log.rs index 9eaaac11..f7640b5d 100644 --- a/src/kxos-frame/src/log.rs +++ b/src/kxos-frame/src/log.rs @@ -19,7 +19,7 @@ pub fn log_print(args: Arguments) { #[macro_export] macro_rules! log_print { ($($arg:tt)*) => { - (kxos_frame::log::log_print(format_args!($($arg)*))) + $crate::log::log_print(format_args!($($arg)*)) }; } diff --git a/src/kxos-std/src/lib.rs b/src/kxos-std/src/lib.rs index 065a8732..187cfd8d 100644 --- a/src/kxos-std/src/lib.rs +++ b/src/kxos-std/src/lib.rs @@ -4,7 +4,9 @@ #![allow(dead_code)] #![allow(unused_variables)] #![feature(const_btree_new)] +#![feature(cstr_from_bytes_until_nul)] +use kxos_frame::println; use process::Process; extern crate alloc; @@ -18,6 +20,12 @@ pub fn init() { process::fifo_scheduler::init(); } +pub fn run_first_kernel_task() { + Process::spawn_kernel_task(|| { + println!("hello world from kernel"); + }); +} + pub fn run_first_process() { let elf_file_content = read_elf_content(); Process::spawn_from_elf(elf_file_content); diff --git a/src/kxos-std/src/memory/elf.rs b/src/kxos-std/src/memory/elf.rs index 50470e19..ff39e2f9 100644 --- a/src/kxos-std/src/memory/elf.rs +++ b/src/kxos-std/src/memory/elf.rs @@ -1,9 +1,10 @@ -use core::ops::Range; +use core::{ops::Range, cmp::Ordering}; use alloc::vec::Vec; +use alloc::vec; use kxos_frame::{ - vm::{Vaddr, VmAllocOptions, VmFrameVec, VmIo, VmPerm, VmSpace}, - Error, + vm::{Vaddr, VmAllocOptions, VmFrameVec, VmIo, VmPerm, VmSpace, VmMapOptions}, + Error, config::PAGE_SIZE, }; use xmas_elf::{ header, @@ -23,6 +24,7 @@ pub struct ElfSegment<'a> { range: Range, data: &'a [u8], type_: program::Type, + vm_perm: VmPerm, } impl<'a> ElfSegment<'a> { @@ -40,13 +42,30 @@ impl<'a> ElfSegment<'a> { Err(_) => return Err(ElfError::from("")), Ok(data) => data, }; + let vm_perm = Self::parse_segment_perm(segment)?; Ok(Self { range: start..end, type_, data, + vm_perm, }) } + pub fn parse_segment_perm(segment: ProgramHeader<'a>) -> Result { + let flags = segment.flags(); + if !flags.is_read() { + return Err(ElfError::UnreadableSegment); + } + let mut vm_perm = VmPerm::R; + if flags.is_write() { + vm_perm |= VmPerm::W; + } + if flags.is_execute() { + vm_perm |= VmPerm::X; + } + Ok(vm_perm) + } + pub fn is_loadable(&self) -> bool { self.type_ == program::Type::Load } @@ -58,6 +77,29 @@ impl<'a> ElfSegment<'a> { pub fn end_address(&self) -> Vaddr { self.range.end } + + fn copy_and_map(&self, vm_space: &VmSpace) -> Result<(), ElfError> { + if !self.is_page_aligned() { + return Err(ElfError::SegmentNotPageAligned); + } + let vm_page_range = VmPageRange::new_range(self.start_address()..self.end_address()); + let page_number = vm_page_range.len(); + // allocate frames + let vm_alloc_options = VmAllocOptions::new(page_number); + let mut frames = VmFrameVec::allocate(&vm_alloc_options)?; + // copy segment + frames.write_bytes(0, self.data)?; + // map segment + let mut vm_map_options = VmMapOptions::new(); + vm_map_options.addr(Some(self.start_address())); + vm_map_options.perm(self.vm_perm); + vm_space.map(frames, &vm_map_options)?; + Ok(()) + } + + fn is_page_aligned(&self) -> bool { + self.start_address() % PAGE_SIZE == 0 + } } impl<'a> ElfLoadInfo<'a> { @@ -116,28 +158,11 @@ impl<'a> ElfLoadInfo<'a> { Ok(VmPageRange::new_range(elf_start_address..elf_end_address)) } - pub fn map_self(&self, vm_space: &VmSpace, frames: VmFrameVec) -> Result<(), ElfError> { - let mut vm_page_range = self.vm_page_range()?; - let vm_perm = ElfLoadInfo::perm(); - vm_page_range.map_to(vm_space, frames, vm_perm); - Ok(()) - } - - pub fn copy_elf(&self) -> Result { - let vm_page_range = self.vm_page_range()?; - // calculate offset - let offset = vm_page_range.start_address(); - // allocate frames - let page_number = vm_page_range.len(); - let options = VmAllocOptions::new(page_number); - let mut frames = VmFrameVec::allocate(&options)?; - - for segment in self.segments.iter().filter(|segment| segment.is_loadable()) { - let start_address = segment.start_address(); - frames.write_bytes(start_address - offset, segment.data)?; + pub fn copy_and_map(&self, vm_space: &VmSpace) -> Result<(), ElfError> { + for segment in self.segments.iter() { + segment.copy_and_map(vm_space)?; } - - Ok(frames) + Ok(()) } pub fn map_and_clear_user_stack(&self, vm_space: &VmSpace) { @@ -154,8 +179,20 @@ impl<'a> ElfLoadInfo<'a> { self.entry_point as u64 } - pub fn user_stack_bottom(&self) -> u64 { - self.user_stack.stack_bottom as u64 + pub fn user_stack_top(&self) -> u64 { + self.user_stack.stack_top() as u64 + } + + /// read content from vmspace to ensure elf data is correctly copied to user space + pub fn debug_check_map_result(&self, vm_space: &VmSpace) { + for segment in self.segments.iter() { + let start_address = segment.start_address(); + let len = segment.data.len(); + let mut read_buffer = vec![0;len]; + vm_space.read_bytes(start_address, &mut read_buffer).expect("read bytes failed"); + let res = segment.data.cmp(&read_buffer); + assert_eq!(res, Ordering::Equal); + } } } @@ -198,6 +235,8 @@ pub enum ElfError { FrameError(Error), NoSegment, UnsupportedElfType, + SegmentNotPageAligned, + UnreadableSegment, WithInfo(&'static str), } diff --git a/src/kxos-std/src/memory/mod.rs b/src/kxos-std/src/memory/mod.rs index 24eac88a..f2aadb5b 100644 --- a/src/kxos-std/src/memory/mod.rs +++ b/src/kxos-std/src/memory/mod.rs @@ -1,7 +1,7 @@ pub mod elf; pub mod user_stack; pub mod vm_page; -use kxos_frame::vm::VmSpace; +use kxos_frame::{vm::VmSpace, debug}; use self::elf::{ElfError, ElfLoadInfo}; @@ -15,8 +15,9 @@ pub fn load_elf_to_vm_space<'a>( vm_space: &VmSpace, ) -> Result, ElfError> { let elf_load_info = ElfLoadInfo::parse_elf_data(elf_file_content)?; - let to_frames = elf_load_info.copy_elf()?; - elf_load_info.map_self(vm_space, to_frames)?; + elf_load_info.copy_and_map(vm_space)?; + elf_load_info.debug_check_map_result(vm_space); + debug!("map elf success"); elf_load_info.map_and_clear_user_stack(vm_space); Ok(elf_load_info) } diff --git a/src/kxos-std/src/memory/user_stack.rs b/src/kxos-std/src/memory/user_stack.rs index 4b209f13..321be355 100644 --- a/src/kxos-std/src/memory/user_stack.rs +++ b/src/kxos-std/src/memory/user_stack.rs @@ -7,32 +7,39 @@ pub const USER_STACK_BASE: Vaddr = 0x0000_0000_1000_0000; pub const USER_STACK_SIZE: usize = 0x1000 * 16; // 64KB pub struct UserStack { - pub stack_bottom: Vaddr, + /// The low address of user stack + pub stack_base: Vaddr, stack_size: usize, vm_space: Option>, } impl UserStack { - // initialize user stack on fixed position - pub const fn new(stack_bottom: Vaddr, stack_size: usize) -> Self { + /// initialize user stack on base addr + pub const fn new(stack_base: Vaddr, stack_size: usize) -> Self { Self { - stack_bottom, + stack_base, stack_size, vm_space: None, } } + /// This function only work for first process pub const fn new_default_config() -> Self { Self { - stack_bottom: USER_STACK_BASE, + stack_base: USER_STACK_BASE, stack_size: USER_STACK_SIZE, vm_space: None, } } + /// the user stack top(high address), used to setup rsp + pub const fn stack_top(&self) -> Vaddr { + self.stack_base + self.stack_size + } + pub fn map_and_zeroed(&self, vm_space: &VmSpace) { let mut vm_page_range = - VmPageRange::new_range(self.stack_bottom..(self.stack_bottom + self.stack_size)); + VmPageRange::new_range(self.stack_base..(self.stack_base + self.stack_size)); let vm_perm = UserStack::perm(); vm_page_range.map_zeroed(vm_space, vm_perm); } diff --git a/src/kxos-std/src/process/mod.rs b/src/kxos-std/src/process/mod.rs index 27410c2a..5c5adeb2 100644 --- a/src/kxos-std/src/process/mod.rs +++ b/src/kxos-std/src/process/mod.rs @@ -2,7 +2,7 @@ use core::sync::atomic::{AtomicUsize, Ordering}; use alloc::sync::Arc; // use kxos_frame::{sync::SpinLock, task::Task, user::UserSpace}; -use kxos_frame::task::Task; +use kxos_frame::{task::Task, debug}; use self::task::spawn_user_task_from_elf; @@ -33,6 +33,14 @@ impl Process { exit_code, } } + + pub fn spawn_kernel_task(task_fn: F) -> Self where F: Fn() + Send + Sync + 'static { + let pid = new_pid(); + debug!("pid = {}" , pid); + let task = Task::spawn(task_fn, None::, None).expect("spawn kernel task failed"); + let exit_code = 0; + Self { pid, task, exit_code } + } } /// create a new pid for new process diff --git a/src/kxos-std/src/process/task.rs b/src/kxos-std/src/process/task.rs index dae94058..7da322d8 100644 --- a/src/kxos-std/src/process/task.rs +++ b/src/kxos-std/src/process/task.rs @@ -17,7 +17,7 @@ pub fn spawn_user_task_from_elf(elf_file_content: &[u8]) -> Arc { // set entry point cpu_ctx.gp_regs.rip = elf_load_info.entry_point(); // set user stack - cpu_ctx.gp_regs.rsp = elf_load_info.user_stack_bottom(); + cpu_ctx.gp_regs.rsp = elf_load_info.user_stack_top(); let user_space = Arc::new(UserSpace::new(vm_space, cpu_ctx)); diff --git a/src/kxos-std/src/syscall/mod.rs b/src/kxos-std/src/syscall/mod.rs index 40491efd..c1f80f82 100644 --- a/src/kxos-std/src/syscall/mod.rs +++ b/src/kxos-std/src/syscall/mod.rs @@ -1,3 +1,4 @@ +use alloc::ffi::CString; use alloc::vec; use alloc::{sync::Arc, vec::Vec}; use kxos_frame::cpu::CpuContext; @@ -8,8 +9,8 @@ use kxos_frame::info; use crate::process::task::HandlerResult; -const SYS_WRITE: u64 = 64; -const SYS_EXIT: u64 = 93; +const SYS_WRITE: u64 = 1; +const SYS_EXIT: u64 = 60; pub struct SyscallFrame { syscall_number: u64, @@ -69,9 +70,9 @@ pub fn sys_write(fd: u64, user_buf_ptr: u64, user_buf_len: u64) -> SyscallResult let user_buffer = copy_bytes_from_user(user_space, user_buf_ptr as usize, user_buf_len as usize) .expect("read user buffer failed"); - let content = alloc::str::from_utf8(user_buffer.as_slice()).expect("Invalid content"); + let content = CString::from_vec_with_nul(user_buffer).expect("read string failed"); // TODO: print content - info!("Message from user mode: {}", content); + info!("Message from user mode: {:?}", content); SyscallResult::Return(0) } else { panic!("Unsupported fd number {}", fd);