diff --git a/src/kxos-frame/src/config.rs b/src/kxos-frame/src/config.rs index 99cb14c4a..e42bbeaae 100644 --- a/src/kxos-frame/src/config.rs +++ b/src/kxos-frame/src/config.rs @@ -15,4 +15,4 @@ pub const PAGE_SIZE_BITS: usize = 0xc; pub const KVA_START: usize = (usize::MAX) << PAGE_SIZE_BITS; -pub const DEFAULT_LOG_LEVEL: LogLevel = LogLevel::Info; +pub const DEFAULT_LOG_LEVEL: LogLevel = LogLevel::Trace; diff --git a/src/kxos-frame/src/lib.rs b/src/kxos-frame/src/lib.rs index 7c81cd3f7..b947d9dcd 100644 --- a/src/kxos-frame/src/lib.rs +++ b/src/kxos-frame/src/lib.rs @@ -35,6 +35,7 @@ use core::{mem, panic::PanicInfo}; pub use self::error::Error; pub use self::prelude::Result; pub(crate) use self::sync::up::UPSafeCell; + use alloc::vec::Vec; use bootloader::{ boot_info::{FrameBuffer, MemoryRegionKind}, @@ -45,6 +46,8 @@ pub use trap::{allocate_irq, IrqAllocateHandle, TrapFrame}; use trap::{IrqCallbackHandle, IrqLine}; pub use vm::Pod; use x86_64_util::enable_common_cpu_features; +pub use util::AlignExt; + static mut IRQ_CALLBACK_LIST: Vec = Vec::new(); #[cfg(not(feature = "serial_print"))] diff --git a/src/kxos-frame/src/task/processor.rs b/src/kxos-frame/src/task/processor.rs index fb80a8ffa..d84a2e750 100644 --- a/src/kxos-frame/src/task/processor.rs +++ b/src/kxos-frame/src/task/processor.rs @@ -51,7 +51,9 @@ pub(crate) fn get_idle_task_cx_ptr() -> *mut TaskContext { /// call this function to switch to other task by using GLOBAL_SCHEDULER pub fn schedule() { - switch_to_task(fetch_task().expect("no more task found")); + if let Some(task) = fetch_task() { + switch_to_task(task); + } } /// call this function to switch to other task diff --git a/src/kxos-frame/src/task/task.rs b/src/kxos-frame/src/task/task.rs index 30c5cf4fa..6a80b2056 100644 --- a/src/kxos-frame/src/task/task.rs +++ b/src/kxos-frame/src/task/task.rs @@ -128,7 +128,7 @@ impl Task { /// Note that this method cannot be simply named "yield" as the name is /// a Rust keyword. pub fn yield_now() { - todo!() + schedule(); } /// Spawns a task that executes a function. diff --git a/src/kxos-frame/src/util/align_ext.rs b/src/kxos-frame/src/util/align_ext.rs index 0ffc12ba9..dd6eb6ff6 100644 --- a/src/kxos-frame/src/util/align_ext.rs +++ b/src/kxos-frame/src/util/align_ext.rs @@ -2,6 +2,9 @@ /// `u64`, and `usize`, to provide methods to make integers aligned to a /// power of two. pub trait AlignExt { + /// returns whether the number is a power of two + fn is_power_of_two(&self) -> bool; + /// Returns to the smallest number that is greater than or equal to /// `self` and is a multiple of the given power of two. /// @@ -41,6 +44,10 @@ macro_rules! impl_align_ext { ($( $uint_type:ty ),+,) => { $( impl AlignExt for $uint_type { + fn is_power_of_two(&self) -> bool { + (*self != 0) && ((*self & (*self - 1)) == 0) + } + fn align_up(self, align: Self) -> Self { assert!(align.is_power_of_two() && align >= 2); self.checked_add(align - 1).unwrap() & !(align - 1) @@ -69,29 +76,29 @@ mod test { #[test] fn test_align_up() { - let input_ns = [0, 1, 2, 9, 15, 21, 32, 47, 50]; - let input_as = [2, 2, 2, 2, 4, 4, 8, 8, 8]; - let output_ns = [0, 2, 2, 10, 16, 24, 32, 48, 56]; + let input_ns = [0usize, 1, 2, 9, 15, 21, 32, 47, 50]; + let input_as = [2usize, 2, 2, 2, 4, 4, 8, 8, 8]; + let output_ns = [0usize, 2, 2, 10, 16, 24, 32, 48, 56]; for i in 0..input_ns.len() { let n = input_ns[i]; let a = input_as[i]; let n2 = output_ns[i]; - assert!(align_up(n, a) == n2); + assert!(n.align_up(a) == n2); } } #[test] fn test_align_down() { - let input_ns = [0, 1, 2, 9, 15, 21, 32, 47, 50]; - let input_as = [2, 2, 2, 2, 4, 4, 8, 8, 8]; - let output_ns = [0, 0, 2, 8, 12, 20, 32, 40, 48]; + let input_ns = [0usize, 1, 2, 9, 15, 21, 32, 47, 50]; + let input_as = [2usize, 2, 2, 2, 4, 4, 8, 8, 8]; + let output_ns = [0usize, 0, 2, 8, 12, 20, 32, 40, 48]; for i in 0..input_ns.len() { let n = input_ns[i]; let a = input_as[i]; let n2 = output_ns[i]; - assert!(align_down(n, a) == n2); + assert!(n.align_down(a) == n2); } } } diff --git a/src/kxos-std/src/lib.rs b/src/kxos-std/src/lib.rs index 23b30b088..97c2e8113 100644 --- a/src/kxos-std/src/lib.rs +++ b/src/kxos-std/src/lib.rs @@ -44,6 +44,12 @@ pub fn init_process() { process.pid() ); + let hello_c_content = read_hello_c_content(); + // glibc requires the filename starts as "/" + let hello_c_filename = CString::new("/hello_c").unwrap(); + let process = Process::spawn_user_process(hello_c_filename, hello_c_content); + info!("spawn hello_c process, pid = {}", process.pid()); + let fork_content = read_fork_content(); let fork_filename = CString::new("fork").unwrap(); let process = Process::spawn_user_process(fork_filename, fork_content); @@ -52,13 +58,11 @@ pub fn init_process() { process.pid() ); - let hello_c_content = read_hello_c_content(); - // glibc requires the filename starts as "/" - let hello_c_filename = CString::new("/hello_c").unwrap(); - let process = Process::spawn_user_process(hello_c_filename, hello_c_content); - info!("spawn hello_c process, pid = {}", process.pid()); - - loop {} + loop { + // We don't have preemptive scheduler now. + // The long running init process should yield its own execution to allow other tasks to go on. + Process::yield_now(); + } } /// first process never return diff --git a/src/kxos-std/src/memory/init_stack.rs b/src/kxos-std/src/memory/init_stack.rs index 4a128466f..e8df7d698 100644 --- a/src/kxos-std/src/memory/init_stack.rs +++ b/src/kxos-std/src/memory/init_stack.rs @@ -10,6 +10,7 @@ use kxos_frame::{ config::PAGE_SIZE, debug, vm::{Vaddr, VmIo, VmPerm, VmSpace}, + AlignExt, }; use super::{ @@ -252,9 +253,8 @@ impl InitStack { } /// returns the u64 start address fn write_u64(&mut self, val: u64, vm_space: &VmSpace) -> u64 { - let start_address = align_down(self.pos - 8, 8); + let start_address = (self.pos - 8).align_down(8); self.pos = start_address; - // debug!("start_address: 0x{:x}", start_address); vm_space .write_val(start_address, &val) .expect("Write u64 failed"); @@ -289,16 +289,6 @@ impl InitStack { } } -fn is_power_of_two(val: usize) -> bool { - (val != 0) && ((val & (val - 1)) == 0) -} - -/// align should be the pow of 2 -fn align_down(vaddr: usize, align: usize) -> usize { - assert!(is_power_of_two(align)); - vaddr & !(align - 1) -} - /// generate random [u8; 16]. /// FIXME: generate really random value. Now only return array with fixed values. fn generate_random_for_aux_vec() -> [u8; 16] { diff --git a/src/kxos-std/src/process/mod.rs b/src/kxos-std/src/process/mod.rs index 9a90efe45..47e68c1f1 100644 --- a/src/kxos-std/src/process/mod.rs +++ b/src/kxos-std/src/process/mod.rs @@ -7,7 +7,6 @@ use alloc::{ vec::Vec, }; use kxos_frame::cpu::CpuContext; -use kxos_frame::vm::{Vaddr, VmPerm}; // use kxos_frame::{sync::SpinLock, task::Task, user::UserSpace}; use kxos_frame::{ debug, @@ -20,7 +19,6 @@ use spin::Mutex; use crate::memory::mmap_area::MmapArea; use crate::memory::user_heap::UserHeap; use crate::process::task::create_forked_task; -use crate::syscall::mmap::MMapFlags; use self::status::ProcessStatus; use self::task::create_user_task_from_elf; @@ -140,6 +138,7 @@ impl Process { }) } + /// returns the pid pub fn pid(&self) -> usize { self.pid } @@ -183,10 +182,16 @@ impl Process { self.task.send_to_scheduler(); } + /// yield the current process to allow other processes to run + pub fn yield_now() { + Task::yield_now(); + } + fn user_space(&self) -> Option<&Arc> { self.user_space.as_ref() } + /// returns the vm space if the process does have, otherwise None pub fn vm_space(&self) -> Option<&VmSpace> { match self.user_space { None => None, @@ -194,6 +199,7 @@ impl Process { } } + /// returns the user heap if the process does have, otherwise None pub fn user_heap(&self) -> Option<&UserHeap> { match self.user_vm { None => None, @@ -201,6 +207,7 @@ impl Process { } } + /// returns the mmap area if the process does have, otherwise None pub fn mmap_area(&self) -> Option<&MmapArea> { match self.user_vm { None => None, @@ -208,10 +215,13 @@ impl Process { } } + /// whether the process has child process pub fn has_child(&self) -> bool { self.children.lock().len() != 0 } + /// get the first(and only) child process + /// FIXME: deal with multiple children processes pub fn get_child_process(&self) -> Arc { let children_lock = self.children.lock(); let child_len = children_lock.len(); @@ -223,6 +233,7 @@ impl Process { .clone() } + /// Fork a child process /// WorkAround: This function only create a new process, but did not schedule the process to run pub fn fork(parent_context: CpuContext) -> Arc { let child_pid = new_pid(); @@ -271,29 +282,9 @@ impl Process { child } - pub fn mmap(&self, len: usize, vm_perm: VmPerm, flags: MMapFlags, offset: usize) -> Vaddr { - let mmap_area = self - .mmap_area() - .expect("mmap should work on process with mmap area"); - let user_space = self - .user_space() - .expect("mmap should work on process with user space"); - let vm_space = user_space.vm_space(); - mmap_area.mmap(len, offset, vm_perm, flags, vm_space) - } - pub fn filename(&self) -> Option<&CString> { self.filename.as_ref() } - - // pub fn copy_bytes_from_user(&self, vaddr: Vaddr, buf: &mut [u8]) { - // self.user_space() - // .unwrap() - // .vm_space() - // .read_bytes(vaddr, buf) - // .unwrap(); - // } - // } } /// Get the init process diff --git a/src/kxos-std/src/syscall/mod.rs b/src/kxos-std/src/syscall/mod.rs index e1a16da3a..b3577b949 100644 --- a/src/kxos-std/src/syscall/mod.rs +++ b/src/kxos-std/src/syscall/mod.rs @@ -32,6 +32,7 @@ mod gettid; pub mod mmap; mod mprotect; mod readlink; +mod sched_yield; mod tgkill; mod uname; mod write; @@ -45,6 +46,7 @@ const SYS_BRK: u64 = 12; const SYS_RT_SIGACTION: u64 = 13; const SYS_RT_SIGPROCMASK: u64 = 14; const SYS_WRITEV: u64 = 20; +const SYS_SCHED_YIELD: u64 = 24; const SYS_GETPID: u64 = 39; const SYS_FORK: u64 = 57; const SYS_EXIT: u64 = 60; diff --git a/src/kxos-std/src/syscall/sched_yield.rs b/src/kxos-std/src/syscall/sched_yield.rs new file mode 100644 index 000000000..52bcfb70b --- /dev/null +++ b/src/kxos-std/src/syscall/sched_yield.rs @@ -0,0 +1,11 @@ +use kxos_frame::debug; + +use crate::{process::Process, syscall::SYS_SCHED_YIELD}; + +use super::SyscallResult; + +pub fn sys_sched_yield() -> SyscallResult { + debug!("[syscall][id={}][SYS_SCHED_YIELD]", SYS_SCHED_YIELD); + Process::yield_now(); + SyscallResult::Return(0) +}