diff --git a/Makefile b/Makefile index 5de1c3dcb..70f7e153c 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ run: build @cd src && cargo krun test: build - @#cd src && cargo test + @#cd src && cargo ktest docs: @cd src && cargo doc # Build Rust docs diff --git a/src/.cargo/config.toml b/src/.cargo/config.toml index f6a32a218..7716430de 100644 --- a/src/.cargo/config.toml +++ b/src/.cargo/config.toml @@ -6,3 +6,4 @@ runner = "cargo run --package kxos-boot --" kbuild = "build --target x86_64-custom.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem" kimage = "run --target x86_64-custom.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem -- --no-run" krun = "run --target x86_64-custom.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem" +ktest = "test --target x86_64-custom.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem" \ No newline at end of file diff --git a/src/Cargo.lock b/src/Cargo.lock index 6fa02d3cb..e51e342d0 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "anyhow" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26fa4d7e3f2eebadf743988fc8aec9fa9a9e82611acafd77c1462ed6262440a" + [[package]] name = "autocfg" version = "1.1.0" @@ -78,8 +84,10 @@ dependencies = [ name = "kxos-boot" version = "0.1.0" dependencies = [ + "anyhow", "bootloader-locator", "locate-cargo-manifest", + "runner-utils", ] [[package]] @@ -93,6 +101,7 @@ dependencies = [ "lazy_static", "linked_list_allocator", "spin 0.9.4", + "uart_16550", "volatile", "x86_64", ] @@ -116,6 +125,12 @@ dependencies = [ "spin 0.5.2", ] +[[package]] +name = "libc" +version = "0.2.132" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" + [[package]] name = "linked_list_allocator" version = "0.9.1" @@ -136,9 +151,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +checksum = "9f80bf5aacaf25cbfc8210d1cfb718f2bf3b11c4c54e5afe36c236853a8ec390" dependencies = [ "autocfg", "scopeguard", @@ -153,6 +168,34 @@ dependencies = [ "autocfg", ] +[[package]] +name = "proc-macro2" +version = "1.0.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "runner-utils" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9dc6848b056990cd51e72aa5556bdbea4a96013e8b18635d183c84159c2988f" +dependencies = [ + "thiserror", + "wait-timeout", +] + [[package]] name = "rustversion" version = "1.0.9" @@ -195,12 +238,69 @@ dependencies = [ "lock_api", ] +[[package]] +name = "syn" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d0a539a918745651435ac7db7a18761589a94cd7e94cd56999f828bf73c8a57" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c251e90f708e16c49a16f4917dc2131e75222b72edfa9cb7f7c58ae56aae0c09" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "uart_16550" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b074eb9300ad949edd74c529c0e8d451625af71bb948e6b65fe69f72dc1363d9" +dependencies = [ + "bitflags", + "rustversion", + "x86_64", +] + +[[package]] +name = "unicode-ident" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" + [[package]] name = "volatile" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3ca98349dda8a60ae74e04fd90c7fb4d6a4fbe01e6d3be095478aa0b76f6c0c" +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + [[package]] name = "x86_64" version = "0.14.10" diff --git a/src/Cargo.toml b/src/Cargo.toml index 3ec39dda7..22fe9ab7a 100644 --- a/src/Cargo.toml +++ b/src/Cargo.toml @@ -16,12 +16,6 @@ members = [ "kxos-boot", ] -[profile.dev] -panic = "abort" - -[profile.release] -panic = "abort" - [package.metadata.bootloader] map-physical-memory = true physical-memory-offset = "0xFFFF800000000000" diff --git a/src/kxos-boot/Cargo.toml b/src/kxos-boot/Cargo.toml index 3fd45c96e..c41e2dbbf 100644 --- a/src/kxos-boot/Cargo.toml +++ b/src/kxos-boot/Cargo.toml @@ -7,3 +7,5 @@ edition = "2021" [dependencies] bootloader-locator = "0.0.4" # for locating the `bootloader` dependency on disk locate-cargo-manifest = "0.2.0" # for locating the kernel's `Cargo.toml` +runner-utils = "0.0.2" +anyhow = "1.0.32" \ No newline at end of file diff --git a/src/kxos-boot/src/main.rs b/src/kxos-boot/src/main.rs index b989f5ac9..b2999fa22 100644 --- a/src/kxos-boot/src/main.rs +++ b/src/kxos-boot/src/main.rs @@ -1,17 +1,26 @@ +use anyhow::anyhow; use std::{ path::{Path, PathBuf}, - process::Command, + process::{Command, ExitStatus}, + time::Duration, }; - const RUN_ARGS: &[&str] = &["--no-reboot", "-s"]; - -fn main() { +const TEST_ARGS: &[&str] = &[ + "-device", + "isa-debug-exit,iobase=0xf4,iosize=0x04", + "-serial", + "stdio", + "-display", + "none", + "--no-reboot", +]; +const TEST_TIMEOUT_SECS: u64 = 10; +fn main() -> anyhow::Result<()> { let mut args = std::env::args().skip(1); // skip executable name let kernel_binary_path = { let path = PathBuf::from(args.next().unwrap()); path.canonicalize().unwrap() }; - println!("{:?}", kernel_binary_path); let no_boot = if let Some(arg) = args.next() { match arg.as_str() { @@ -26,25 +35,37 @@ fn main() { if no_boot { println!("Created disk image at `{}`", bios.display()); - return; + return Ok(()); } let mut run_cmd = Command::new("qemu-system-x86_64"); run_cmd .arg("-drive") .arg(format!("format=raw,file={}", bios.display())); - run_cmd.args(RUN_ARGS); - let exit_status = run_cmd.status().unwrap(); - if !exit_status.success() { - std::process::exit(exit_status.code().unwrap_or(1)); + let binary_kind = runner_utils::binary_kind(&kernel_binary_path); + if binary_kind.is_test() { + run_cmd.args(TEST_ARGS); + + let exit_status = run_test_command(run_cmd)?; + match exit_status.code() { + Some(33) => {} // success + other => return Err(anyhow!("Test failed (exit code: {:?})", other)), + } + } else { + run_cmd.args(RUN_ARGS); + + let exit_status = run_cmd.status()?; + if !exit_status.success() { + std::process::exit(exit_status.code().unwrap_or(1)); + } } + Ok(()) } pub fn create_disk_images(kernel_binary_path: &Path) -> PathBuf { let bootloader_manifest_path = bootloader_locator::locate_bootloader("bootloader").unwrap(); let kernel_manifest_path = locate_cargo_manifest::locate_manifest().unwrap(); - println!("{:?}", kernel_manifest_path); let mut build_cmd = Command::new(env!("CARGO")); build_cmd.current_dir(bootloader_manifest_path.parent().unwrap()); @@ -78,3 +99,8 @@ pub fn create_disk_images(kernel_binary_path: &Path) -> PathBuf { } disk_image } + +fn run_test_command(mut cmd: Command) -> anyhow::Result { + let status = runner_utils::run_with_timeout(&mut cmd, Duration::from_secs(TEST_TIMEOUT_SECS))?; + Ok(status) +} diff --git a/src/kxos-frame/Cargo.toml b/src/kxos-frame/Cargo.toml index 3a286901f..314892b44 100644 --- a/src/kxos-frame/Cargo.toml +++ b/src/kxos-frame/Cargo.toml @@ -14,7 +14,7 @@ buddy_system_allocator = "0.6" linked_list_allocator = "0.9.0" bootloader = {version="0.10.12"} font8x8 = { version = "0.2.5", default-features = false, features = ["unicode"]} - +uart_16550 = "0.2.0" [dependencies.lazy_static] diff --git a/src/kxos-frame/src/cpu.rs b/src/kxos-frame/src/cpu.rs index 695870c64..7b1567c35 100644 --- a/src/kxos-frame/src/cpu.rs +++ b/src/kxos-frame/src/cpu.rs @@ -1,7 +1,5 @@ //! CPU. -use x86_64::registers::model_specific::FsBase; - use crate::trap::{CalleeRegs, CallerRegs, SyscallFrame, TrapFrame}; /// Defines a CPU-local variable. diff --git a/src/kxos-frame/src/device/framebuffer.rs b/src/kxos-frame/src/device/framebuffer.rs index 8ddc38b6f..a862715b1 100644 --- a/src/kxos-frame/src/device/framebuffer.rs +++ b/src/kxos-frame/src/device/framebuffer.rs @@ -4,7 +4,7 @@ use font8x8::UnicodeFonts; use spin::Mutex; use volatile::Volatile; -pub static WRITER: Mutex> = Mutex::new(None); +pub(crate) static WRITER: Mutex> = Mutex::new(None); pub fn init(framebuffer: &'static mut bootloader::boot_info::FrameBuffer) { let mut writer = Writer { @@ -21,7 +21,7 @@ pub fn init(framebuffer: &'static mut bootloader::boot_info::FrameBuffer) { *global_writer = Some(writer); } -pub struct Writer { +pub(crate) struct Writer { buffer: Volatile<&'static mut [u8]>, info: bootloader::boot_info::FrameBufferInfo, x_pos: usize, diff --git a/src/kxos-frame/src/device/mod.rs b/src/kxos-frame/src/device/mod.rs index be50c7c47..3bd8e1c02 100644 --- a/src/kxos-frame/src/device/mod.rs +++ b/src/kxos-frame/src/device/mod.rs @@ -2,9 +2,10 @@ pub mod framebuffer; mod io_port; +pub mod serial; pub use self::io_port::IoPort; -pub fn init(framebuffer: &'static mut bootloader::boot_info::FrameBuffer) { +pub(crate) fn init(framebuffer: &'static mut bootloader::boot_info::FrameBuffer) { framebuffer::init(framebuffer); } diff --git a/src/kxos-frame/src/device/serial.rs b/src/kxos-frame/src/device/serial.rs new file mode 100644 index 000000000..0582e7d9d --- /dev/null +++ b/src/kxos-frame/src/device/serial.rs @@ -0,0 +1,37 @@ +use lazy_static::lazy_static; +use spin::Mutex; +use uart_16550::SerialPort; + +lazy_static! { + pub(crate) static ref SERIAL: Mutex = { + let mut serial_port = unsafe { SerialPort::new(0x3F8) }; + serial_port.init(); + Mutex::new(serial_port) + }; +} + +#[doc(hidden)] +pub fn _print(args: ::core::fmt::Arguments) { + use core::fmt::Write; + SERIAL + .lock() + .write_fmt(args) + .expect("Printing to serial failed"); +} + +/// Prints to the host through the serial interface. +#[macro_export] +macro_rules! serial_print { + ($($arg:tt)*) => { + $crate::device::serial::_print(format_args!($($arg)*)); + }; +} + +/// Prints to the host through the serial interface, appending a newline. +#[macro_export] +macro_rules! serial_println { + () => ($crate::serial_print!("\n")); + ($fmt:expr) => ($crate::serial_print!(concat!($fmt, "\n"))); + ($fmt:expr, $($arg:tt)*) => ($crate::serial_print!( + concat!($fmt, "\n"), $($arg)*)); +} diff --git a/src/kxos-frame/src/lib.rs b/src/kxos-frame/src/lib.rs index 205350e91..45bf6acc6 100644 --- a/src/kxos-frame/src/lib.rs +++ b/src/kxos-frame/src/lib.rs @@ -3,9 +3,7 @@ #![allow(dead_code)] #![allow(unused_variables)] #![feature(negative_impls)] -#![feature(abi_x86_interrupt)] #![feature(fn_traits)] -#![feature(linked_list_cursors)] #![feature(const_maybe_uninit_zeroed)] #![feature(alloc_error_handler)] #![feature(core_intrinsics)] @@ -14,33 +12,31 @@ extern crate alloc; -pub mod cell; +pub(crate) mod cell; pub mod config; pub mod cpu; pub mod device; mod error; pub mod log; -pub mod mm; +pub(crate) mod mm; pub mod prelude; pub mod sync; pub mod task; pub mod timer; -pub mod trap; +pub(crate) mod trap; pub mod user; mod util; pub mod vm; -pub mod x86_64_util; +pub(crate) mod x86_64_util; -use core::mem; +use core::{mem, panic::PanicInfo}; pub use self::error::Error; -pub use self::sync::up::UPSafeCell; -use alloc::sync::Arc; +pub(crate) use self::sync::up::UPSafeCell; use bootloader::{ boot_info::{FrameBuffer, MemoryRegionKind}, BootInfo, }; -use trap::{IrqLine, TrapFrame}; pub fn init(boot_info: &'static mut BootInfo) { let siz = boot_info.framebuffer.as_ref().unwrap() as *const FrameBuffer as usize; @@ -65,10 +61,55 @@ pub fn init(boot_info: &'static mut BootInfo) { if !memory_init { panic!("memory init failed"); } - } #[inline(always)] -pub const fn zero() -> T { +pub(crate) const fn zero() -> T { unsafe { mem::MaybeUninit::zeroed().assume_init() } } + +pub trait Testable { + fn run(&self) -> (); +} + +impl Testable for T +where + T: Fn(), +{ + fn run(&self) { + serial_print!("{}...\t", core::any::type_name::()); + self(); + serial_println!("[ok]"); + } +} + +pub fn test_runner(tests: &[&dyn Testable]) { + serial_println!("Running {} tests", tests.len()); + for test in tests { + test.run(); + } + exit_qemu(QemuExitCode::Success); +} + +pub fn test_panic_handler(info: &PanicInfo) -> ! { + serial_println!("[failed]"); + serial_println!("Error: {}", info); + exit_qemu(QemuExitCode::Failed); +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum QemuExitCode { + Success = 0x10, + Failed = 0x11, +} + +pub fn exit_qemu(exit_code: QemuExitCode) -> ! { + use x86_64::instructions::port::Port; + + unsafe { + let mut port = Port::new(0xf4); + port.write(exit_code as u32); + } + unreachable!() +} diff --git a/src/kxos-frame/src/log.rs b/src/kxos-frame/src/log.rs index f7640b5d5..4482967a0 100644 --- a/src/kxos-frame/src/log.rs +++ b/src/kxos-frame/src/log.rs @@ -1,12 +1,12 @@ use core::fmt::Arguments; -use crate::device::framebuffer::WRITER; - /// Print log message /// This function should *NOT* be directly called. /// Instead, print logs with macros. +#[cfg(not(test))] #[doc(hidden)] pub fn log_print(args: Arguments) { + use crate::device::framebuffer::WRITER; use core::fmt::Write; use x86_64::instructions::interrupts; @@ -15,6 +15,21 @@ pub fn log_print(args: Arguments) { }); } +/// Print log message +/// This function should *NOT* be directly called. +/// Instead, print logs with macros. +#[cfg(test)] +#[doc(hidden)] +pub fn log_print(args: Arguments) { + use crate::device::serial::SERIAL; + use core::fmt::Write; + + SERIAL + .lock() + .write_fmt(args) + .expect("Printing to serial failed"); +} + /// This macro should not be directly called. #[macro_export] macro_rules! log_print { diff --git a/src/kxos-frame/src/mm/memory_set.rs b/src/kxos-frame/src/mm/memory_set.rs index 5f4e58796..4dcdd92ef 100644 --- a/src/kxos-frame/src/mm/memory_set.rs +++ b/src/kxos-frame/src/mm/memory_set.rs @@ -7,7 +7,6 @@ use crate::{ *, }; use alloc::collections::{btree_map::Entry, BTreeMap}; -use alloc::vec; use core::fmt; pub struct MapArea { @@ -16,7 +15,7 @@ pub struct MapArea { /// start virtual address pub start_va: VirtAddr, /// the size of these area - pub size : usize, + pub size: usize, /// all the map information pub mapper: BTreeMap, } @@ -24,7 +23,7 @@ pub struct MapArea { pub struct MemorySet { pub pt: PageTable, /// all the map area, sort by the start virtual address - areas: BTreeMap, + areas: BTreeMap, } impl MapArea { @@ -35,12 +34,18 @@ impl MapArea { pub fn clone(&self) -> Self { let mut mapper = BTreeMap::new(); for (&va, old) in &self.mapper { - let new = PhysFrame::alloc().unwrap(); - new.as_slice().copy_from_slice(old.physical_frame.exclusive_access().as_slice()); - mapper.insert(va, unsafe{VmFrame::new(new)}); + let new = PhysFrame::alloc().unwrap(); + new.as_slice() + .copy_from_slice(old.physical_frame.exclusive_access().as_slice()); + mapper.insert(va, unsafe { VmFrame::new(new) }); } - Self { start_va: self.start_va, size: self.size, flags: self.flags, mapper } - } + Self { + start_va: self.start_va, + size: self.size, + flags: self.flags, + mapper, + } + } /// This function will map the vitural address to the given physical frames pub fn new( @@ -104,9 +109,9 @@ impl MapArea { let mut remain = data.len(); let mut processed = 0; for (va, pa) in self.mapper.iter() { - if current_start_address >= va.0 && current_start_address = va.0 && current_start_address < va.0 + PAGE_SIZE { + let offset = current_start_address - va.0; + let copy_len = (va.0 + PAGE_SIZE - current_start_address).min(remain); let src = &data[processed..processed + copy_len]; let dst = &mut pa.start_pa().kvaddr().get_bytes_array()[offset..copy_len]; dst.copy_from_slice(src); @@ -115,7 +120,7 @@ impl MapArea { if remain == 0 { return; } - current_start_address = va.0+PAGE_SIZE; + current_start_address = va.0 + PAGE_SIZE; } } } @@ -125,9 +130,9 @@ impl MapArea { let mut remain = data.len(); let mut processed = 0; for (va, pa) in self.mapper.iter() { - if start >= va.0 && start = va.0 && start < va.0 + PAGE_SIZE { + let offset = start - va.0; + let copy_len = (va.0 + PAGE_SIZE - start).min(remain); let src = &mut data[processed..processed + copy_len]; let dst = &pa.start_pa().kvaddr().get_bytes_array()[offset..copy_len]; src.copy_from_slice(dst); @@ -136,7 +141,7 @@ impl MapArea { if remain == 0 { return; } - start = va.0+PAGE_SIZE; + start = va.0 + PAGE_SIZE; } } } @@ -161,15 +166,17 @@ impl MapArea { // } impl MemorySet { - pub fn map(&mut self, area: MapArea) { if area.size > 0 { - // TODO: check overlap - if let Entry::Vacant(e) = self.areas.entry(area.start_va) { - self.pt.map_area(e.insert(area)); - } else { - panic!("MemorySet::map: MapArea starts from {:#x?} is existed!", area.start_va); - } + // TODO: check overlap + if let Entry::Vacant(e) = self.areas.entry(area.start_va) { + self.pt.map_area(e.insert(area)); + } else { + panic!( + "MemorySet::map: MapArea starts from {:#x?} is existed!", + area.start_va + ); + } } } @@ -181,39 +188,38 @@ impl MemorySet { } pub fn unmap(&mut self, va: VirtAddr) -> Result<()> { - if let Some(area) = self.areas.remove(&va){ + if let Some(area) = self.areas.remove(&va) { self.pt.unmap_area(&area); Ok(()) - }else{ + } else { Err(Error::PageFault) } } pub fn clear(&mut self) { for area in self.areas.values_mut() { - self.pt.unmap_area(area); + self.pt.unmap_area(area); } self.areas.clear(); - } - + } pub fn write_bytes(&mut self, addr: usize, data: &[u8]) -> Result<()> { let mut current_addr = addr; let mut remain = data.len(); let start_write = false; - for (va,area) in self.areas.iter_mut(){ - if current_addr>=va.0&& current_addr < area.size+va.0{ - if !area.flags.contains(PTFlags::WRITABLE){ - return Err(Error::PageFault) + for (va, area) in self.areas.iter_mut() { + if current_addr >= va.0 && current_addr < area.size + va.0 { + if !area.flags.contains(PTFlags::WRITABLE) { + return Err(Error::PageFault); } area.write_data(current_addr, data); - remain -= (va.0+area.size-current_addr).min(remain); - if remain ==0{ - return Ok(()) + remain -= (va.0 + area.size - current_addr).min(remain); + if remain == 0 { + return Ok(()); } - current_addr = va.0+area.size; - }else if start_write{ - return Err(Error::PageFault) + current_addr = va.0 + area.size; + } else if start_write { + return Err(Error::PageFault); } } Err(Error::PageFault) @@ -223,16 +229,16 @@ impl MemorySet { let mut current_addr = addr; let mut remain = data.len(); let start_read = false; - for (va,area) in self.areas.iter(){ - if current_addr>=va.0&& current_addr < area.size+va.0{ + for (va, area) in self.areas.iter() { + if current_addr >= va.0 && current_addr < area.size + va.0 { area.read_data(current_addr, data); - remain -= (va.0+area.size-current_addr).min(remain); - if remain ==0{ - return Ok(()) + remain -= (va.0 + area.size - current_addr).min(remain); + if remain == 0 { + return Ok(()); } - current_addr = va.0+area.size; - }else if start_read{ - return Err(Error::PageFault) + current_addr = va.0 + area.size; + } else if start_read { + return Err(Error::PageFault); } } Err(Error::PageFault) @@ -241,11 +247,13 @@ impl MemorySet { impl Clone for MemorySet { fn clone(&self) -> Self { - let mut ms = Self::new(); - for area in self.areas.values() { ms.map(area.clone()); } - ms + let mut ms = Self::new(); + for area in self.areas.values() { + ms.map(area.clone()); + } + ms } - } +} impl Drop for MemorySet { fn drop(&mut self) { self.clear(); diff --git a/src/kxos-frame/src/mm/mod.rs b/src/kxos-frame/src/mm/mod.rs index 5c58732ac..be548c593 100644 --- a/src/kxos-frame/src/mm/mod.rs +++ b/src/kxos-frame/src/mm/mod.rs @@ -31,7 +31,7 @@ bitflags::bitflags! { } } -pub fn init(start: u64, size: u64) { +pub(crate) fn init(start: u64, size: u64) { heap_allocator::init(); frame_allocator::init(start as usize, size as usize); page_table::init(); diff --git a/src/kxos-frame/src/mm/page_table.rs b/src/kxos-frame/src/mm/page_table.rs index d937b74aa..408063668 100644 --- a/src/kxos-frame/src/mm/page_table.rs +++ b/src/kxos-frame/src/mm/page_table.rs @@ -1,6 +1,6 @@ use super::{memory_set::MapArea, *}; use crate::{ - config::{ENTRY_COUNT, KERNEL_OFFSET, PAGE_SIZE, PHYS_OFFSET}, + config::{ENTRY_COUNT, PAGE_SIZE, PHYS_OFFSET}, vm::VmFrame, *, }; diff --git a/src/kxos-frame/src/sync/atomic_bits.rs b/src/kxos-frame/src/sync/atomic_bits.rs index 0cc0dc9dd..38a547ff5 100644 --- a/src/kxos-frame/src/sync/atomic_bits.rs +++ b/src/kxos-frame/src/sync/atomic_bits.rs @@ -61,7 +61,7 @@ impl AtomicBits { } } - /// Clear all the bits. + /// Clear all the bits. pub fn clear(&self) { todo!() } @@ -386,4 +386,4 @@ mod test { let bits = AtomicBits::new_ones(128); assert!(bits.iter().all(|bit| bit == true)); } -} \ No newline at end of file +} diff --git a/src/kxos-frame/src/sync/mod.rs b/src/kxos-frame/src/sync/mod.rs index 0e648d1de..a6e3eb308 100644 --- a/src/kxos-frame/src/sync/mod.rs +++ b/src/kxos-frame/src/sync/mod.rs @@ -1,10 +1,10 @@ +mod atomic_bits; mod rcu; mod spin; -pub mod up; +pub(crate) mod up; mod wait; -mod atomic_bits; -pub use self::atomic_bits::{AtomicBits}; +pub use self::atomic_bits::AtomicBits; +pub use self::rcu::{pass_quiescent_state, OwnerPtr, Rcu, RcuReadGuard, RcuReclaimer}; pub use self::spin::{SpinLock, SpinLockGuard}; pub use self::wait::WaitQueue; -pub use self::rcu::{Rcu, RcuReadGuard, RcuReclaimer, OwnerPtr, pass_quiescent_state}; diff --git a/src/kxos-frame/src/task/mod.rs b/src/kxos-frame/src/task/mod.rs index a064f68cf..8bb868ed3 100644 --- a/src/kxos-frame/src/task/mod.rs +++ b/src/kxos-frame/src/task/mod.rs @@ -5,9 +5,9 @@ mod scheduler; #[allow(clippy::module_inception)] mod task; -pub use self::processor::get_idle_task_cx_ptr; +pub(crate) use self::processor::get_idle_task_cx_ptr; pub use self::scheduler::{set_scheduler, Scheduler}; -pub use self::task::context_switch; -pub use self::task::TaskContext; -pub use self::task::SWITCH_TO_USER_SPACE_TASK; +pub(crate) use self::task::context_switch; +pub(crate) use self::task::TaskContext; +pub(crate) use self::task::SWITCH_TO_USER_SPACE_TASK; pub use self::task::{Task, TaskStatus}; diff --git a/src/kxos-frame/src/task/processor.rs b/src/kxos-frame/src/task/processor.rs index f4dd2778a..b4521dd3f 100644 --- a/src/kxos-frame/src/task/processor.rs +++ b/src/kxos-frame/src/task/processor.rs @@ -45,7 +45,7 @@ pub fn current_task() -> Option> { PROCESSOR.exclusive_access().current() } -pub fn get_idle_task_cx_ptr() -> *mut TaskContext { +pub(crate) fn get_idle_task_cx_ptr() -> *mut TaskContext { PROCESSOR.exclusive_access().get_idle_task_cx_ptr() } diff --git a/src/kxos-frame/src/task/scheduler.rs b/src/kxos-frame/src/task/scheduler.rs index 7ff16c805..a36f0815b 100644 --- a/src/kxos-frame/src/task/scheduler.rs +++ b/src/kxos-frame/src/task/scheduler.rs @@ -1,5 +1,5 @@ use crate::task::Task; -use crate::{prelude::*, println, UPSafeCell}; +use crate::{prelude::*, UPSafeCell}; use lazy_static::lazy_static; diff --git a/src/kxos-frame/src/task/task.rs b/src/kxos-frame/src/task/task.rs index 8c75e59d5..a8c1f2647 100644 --- a/src/kxos-frame/src/task/task.rs +++ b/src/kxos-frame/src/task/task.rs @@ -9,22 +9,22 @@ use crate::trap::{CalleeRegs, SyscallFrame, TrapFrame}; use crate::user::{syscall_switch_to_user_space, trap_switch_to_user_space, UserSpace}; use crate::{prelude::*, UPSafeCell}; -use super::processor::{current_task, schedule, PROCESSOR}; +use super::processor::{current_task, schedule}; use super::scheduler::add_task; core::arch::global_asm!(include_str!("switch.S")); #[derive(Debug, Default, Clone, Copy)] #[repr(C)] -pub struct TaskContext { +pub(crate) struct TaskContext { pub regs: CalleeRegs, pub rip: usize, } extern "C" { - pub fn context_switch(cur: *mut TaskContext, nxt: *const TaskContext); + pub(crate) fn context_switch(cur: *mut TaskContext, nxt: *const TaskContext); } -pub fn context_switch_to_user_space() { +fn context_switch_to_user_space() { let task = Task::current(); let switch_space_task = SWITCH_TO_USER_SPACE_TASK.get(); if task.inner_exclusive_access().is_from_trap { @@ -50,7 +50,7 @@ lazy_static! { /// This variable is mean to switch to user space and then switch back in `UserMode.execute` /// /// When context switch to this task, there is no need to set the current task - pub static ref SWITCH_TO_USER_SPACE_TASK : Cell = unsafe{ + pub(crate) static ref SWITCH_TO_USER_SPACE_TASK : Cell = Cell::new({ let task = Task{ func: Box::new(context_switch_to_user_space), @@ -73,7 +73,7 @@ lazy_static! { - size_of::() - size_of::(); task - })}; + }); } pub struct KernelStack { @@ -99,7 +99,7 @@ pub struct Task { kstack: KernelStack, } -pub struct TaskInner { +pub(crate) struct TaskInner { pub task_status: TaskStatus, pub ctx: TaskContext, /// whether the task from trap. If it is Trap, then you should use read TrapFrame instead of SyscallFrame @@ -113,12 +113,12 @@ impl Task { } /// get inner - pub fn inner_exclusive_access(&self) -> RefMut<'_, TaskInner> { + pub(crate) fn inner_exclusive_access(&self) -> RefMut<'_, TaskInner> { self.task_inner.exclusive_access() } /// get inner - pub fn inner_ctx(&self) -> TaskContext { + pub(crate) fn inner_ctx(&self) -> TaskContext { self.task_inner.exclusive_access().ctx } @@ -180,7 +180,7 @@ impl Task { Ok(arc_self) } - pub fn syscall_frame(&self) -> &mut SyscallFrame { + pub(crate) fn syscall_frame(&self) -> &mut SyscallFrame { unsafe { &mut *(self .kstack @@ -192,7 +192,7 @@ impl Task { } } - pub fn trap_frame(&self) -> &mut TrapFrame { + pub(crate) fn trap_frame(&self) -> &mut TrapFrame { unsafe { &mut *(self.kstack.frame.end_pa().kvaddr().get_mut::() as *mut TrapFrame) .sub(1) diff --git a/src/kxos-frame/src/trap/handler.rs b/src/kxos-frame/src/trap/handler.rs index 693d20fb7..7d8e4d0d3 100644 --- a/src/kxos-frame/src/trap/handler.rs +++ b/src/kxos-frame/src/trap/handler.rs @@ -5,7 +5,7 @@ use crate::task::{ use super::{irq::IRQ_LIST, *}; #[no_mangle] -pub extern "C" fn syscall_handler(f: &'static mut SyscallFrame) -> isize { +pub(crate) extern "C" fn syscall_handler(f: &'static mut SyscallFrame) -> isize { let r = &f.caller; let current = Task::current(); current.inner_exclusive_access().is_from_trap = false; @@ -28,8 +28,8 @@ const PAGE_FAULT: usize = 14; const TIMER: usize = 32; #[no_mangle] -pub extern "C" fn trap_handler(f: &'static mut TrapFrame) { - if !is_from_kernel(f.cs){ +pub(crate) extern "C" fn trap_handler(f: &'static mut TrapFrame) { + if !is_from_kernel(f.cs) { let current = Task::current(); current.inner_exclusive_access().is_from_trap = true; } @@ -40,11 +40,10 @@ pub extern "C" fn trap_handler(f: &'static mut TrapFrame) { } } - -fn is_from_kernel(cs:usize)->bool{ - if cs&0x3==0{ +fn is_from_kernel(cs: usize) -> bool { + if cs & 0x3 == 0 { true - }else{ + } else { false } } diff --git a/src/kxos-frame/src/trap/mod.rs b/src/kxos-frame/src/trap/mod.rs index 92b873ab3..5b315e54a 100644 --- a/src/kxos-frame/src/trap/mod.rs +++ b/src/kxos-frame/src/trap/mod.rs @@ -64,10 +64,9 @@ extern "C" { /// 所有的中断向量push一个id后跳转到trao_entry static __vectors: [usize; 256]; fn syscall_entry(); - pub fn syscall_return(f: &SyscallFrame) -> !; } -pub fn init() { +pub(crate) fn init() { static mut GDT: [usize; 7] = [ 0, 0x00209800_00000000, // KCODE, EXECUTABLE | USER_SEGMENT | PRESENT | LONG_MODE diff --git a/src/kxos-frame/src/user.rs b/src/kxos-frame/src/user.rs index ac0b0ef01..b431143fd 100644 --- a/src/kxos-frame/src/user.rs +++ b/src/kxos-frame/src/user.rs @@ -7,12 +7,14 @@ use crate::prelude::*; use crate::task::{context_switch, Task, TaskContext, SWITCH_TO_USER_SPACE_TASK}; use crate::trap::{SyscallFrame, TrapFrame}; use crate::vm::VmSpace; -use crate::x86_64_util::get_return_address; extern "C" { - pub fn syscall_switch_to_user_space(cpu_context: &CpuContext, syscall_frame: &SyscallFrame); + pub(crate) fn syscall_switch_to_user_space( + cpu_context: &CpuContext, + syscall_frame: &SyscallFrame, + ); /// cpu_context may delete in the future - pub fn trap_switch_to_user_space(cpu_context: &CpuContext, trap_frame: &TrapFrame); + pub(crate) fn trap_switch_to_user_space(cpu_context: &CpuContext, trap_frame: &TrapFrame); } /// A user space. @@ -108,7 +110,9 @@ impl<'a> UserMode<'a> { /// After handling the user event and updating the user-mode CPU context, /// this method can be invoked again to go back to the user space. pub fn execute(&mut self) -> UserEvent { - self.user_space.vm_space().activate(); + unsafe { + self.user_space.vm_space().activate(); + } if !self.executed { self.current.syscall_frame().caller.rcx = self.user_space.cpu_ctx.gp_regs.rip as usize; self.current.syscall_frame().callee.rsp = self.user_space.cpu_ctx.gp_regs.rsp as usize; @@ -137,7 +141,7 @@ impl<'a> UserMode<'a> { UserEvent::Exception } else { self.context = CpuContext::from(*self.current.syscall_frame()); - println!("[kernel] syscall id:{}",self.context.gp_regs.rax); + println!("[kernel] syscall id:{}", self.context.gp_regs.rax); println!("[kernel] rsp: 0x{:x}", self.context.gp_regs.rsp); UserEvent::Syscall } diff --git a/src/kxos-frame/src/vm/space.rs b/src/kxos-frame/src/vm/space.rs index a081cd109..551995e72 100644 --- a/src/kxos-frame/src/vm/space.rs +++ b/src/kxos-frame/src/vm/space.rs @@ -32,8 +32,8 @@ impl VmSpace { memory_set: unsafe { UPSafeCell::new(MemorySet::new()) }, } } - - pub fn activate(&self) { + /// Activate the page table, load root physical address to cr3 + pub unsafe fn activate(&self) { x86_64_util::set_cr3(self.memory_set.exclusive_access().pt.root_pa.0); } @@ -49,7 +49,7 @@ impl VmSpace { flags.insert(PTFlags::WRITABLE); } // if options.perm.contains(VmPerm::U) { - flags.insert(PTFlags::USER); + flags.insert(PTFlags::USER); // } if options.addr.is_none() { return Err(Error::InvalidArgs); diff --git a/src/src/main.rs b/src/src/main.rs index 6e3af3304..6ec11ab8c 100644 --- a/src/src/main.rs +++ b/src/src/main.rs @@ -2,7 +2,8 @@ #![no_main] #![feature(custom_test_frameworks)] #![forbid(unsafe_code)] -// #![feature(default_alloc_error_handler)] +#![test_runner(kxos_frame::test_runner)] +#![reexport_test_harness_main = "test_main"] extern crate kxos_frame; use bootloader::{entry_point, BootInfo}; @@ -12,12 +13,8 @@ use kxos_frame::println; entry_point!(kernel_main); fn kernel_main(boot_info: &'static mut BootInfo) -> ! { - // turn the screen gray - // if let Some(framebuffer) = boot_info.framebuffer.as_mut() { - // for byte in framebuffer.buffer_mut() { - // *byte = 0x00; - // } - // } + #[cfg(test)] + test_main(); kxos_frame::init(boot_info); println!("[kernel] finish init kxos_frame"); @@ -26,9 +23,20 @@ fn kernel_main(boot_info: &'static mut BootInfo) -> ! { loop {} } - +#[cfg(not(test))] #[panic_handler] -fn panic(_info: &PanicInfo) -> ! { - println!("[panic]:{:?}", _info); +fn panic(info: &PanicInfo) -> ! { + println!("[panic]:{:?}", info); loop {} } + +#[cfg(test)] +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + kxos_frame::test_panic_handler(info); +} + +#[test_case] +fn trivial_assertion() { + assert_eq!(1, 1); +} diff --git a/src/tests/test_example.rs b/src/tests/test_example.rs new file mode 100644 index 000000000..bfde06d49 --- /dev/null +++ b/src/tests/test_example.rs @@ -0,0 +1,25 @@ +#![no_std] +#![no_main] +#![feature(custom_test_frameworks)] +#![test_runner(kxos_frame::test_runner)] +#![reexport_test_harness_main = "test_main"] +use bootloader::{entry_point, BootInfo}; +use core::panic::PanicInfo; + +entry_point!(kernel_test_main); + +fn kernel_test_main(boot_info: &'static mut BootInfo) -> ! { + kxos_frame::init(boot_info); + test_main(); + loop {} +} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + kxos_frame::test_panic_handler(info) +} + +#[test_case] +fn test_println() { + kxos_frame::println!("test_println output"); +}