add tests and hide some pub functions

This commit is contained in:
Yuke Peng
2022-08-31 23:25:26 -07:00
parent 7e733a83eb
commit f1f20f5b61
28 changed files with 400 additions and 142 deletions

View File

@ -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

View File

@ -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"

104
src/Cargo.lock generated
View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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()));
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().unwrap();
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<ExitStatus> {
let status = runner_utils::run_with_timeout(&mut cmd, Duration::from_secs(TEST_TIMEOUT_SECS))?;
Ok(status)
}

View File

@ -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]

View File

@ -1,7 +1,5 @@
//! CPU.
use x86_64::registers::model_specific::FsBase;
use crate::trap::{CalleeRegs, CallerRegs, SyscallFrame, TrapFrame};
/// Defines a CPU-local variable.

View File

@ -4,7 +4,7 @@ use font8x8::UnicodeFonts;
use spin::Mutex;
use volatile::Volatile;
pub static WRITER: Mutex<Option<Writer>> = Mutex::new(None);
pub(crate) static WRITER: Mutex<Option<Writer>> = 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,

View File

@ -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);
}

View File

@ -0,0 +1,37 @@
use lazy_static::lazy_static;
use spin::Mutex;
use uart_16550::SerialPort;
lazy_static! {
pub(crate) static ref SERIAL: Mutex<SerialPort> = {
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)*));
}

View File

@ -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>() -> T {
pub(crate) const fn zero<T>() -> T {
unsafe { mem::MaybeUninit::zeroed().assume_init() }
}
pub trait Testable {
fn run(&self) -> ();
}
impl<T> Testable for T
where
T: Fn(),
{
fn run(&self) {
serial_print!("{}...\t", core::any::type_name::<T>());
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!()
}

View File

@ -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 {

View File

@ -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<VirtAddr, VmFrame>,
}
@ -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<VirtAddr,MapArea>,
areas: BTreeMap<VirtAddr, MapArea>,
}
impl MapArea {
@ -36,10 +35,16 @@ impl MapArea {
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)});
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
@ -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+PAGE_SIZE{
let offset = current_start_address-va.0;
let copy_len = (va.0+PAGE_SIZE - current_start_address).min(remain);
if 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+PAGE_SIZE{
let offset = start-va.0;
let copy_len = (va.0+PAGE_SIZE - start).min(remain);
if 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,14 +166,16 @@ 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);
panic!(
"MemorySet::map: MapArea starts from {:#x?} is existed!",
area.start_va
);
}
}
}
@ -181,10 +188,10 @@ 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)
}
}
@ -196,24 +203,23 @@ impl MemorySet {
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)
@ -242,10 +248,12 @@ 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()); }
for area in self.areas.values() {
ms.map(area.clone());
}
ms
}
}
}
impl Drop for MemorySet {
fn drop(&mut self) {
self.clear();

View File

@ -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();

View File

@ -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,
*,
};

View File

@ -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};

View File

@ -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};

View File

@ -45,7 +45,7 @@ pub fn current_task() -> Option<Arc<Task>> {
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()
}

View File

@ -1,5 +1,5 @@
use crate::task::Task;
use crate::{prelude::*, println, UPSafeCell};
use crate::{prelude::*, UPSafeCell};
use lazy_static::lazy_static;

View File

@ -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<Task> = unsafe{
pub(crate) static ref SWITCH_TO_USER_SPACE_TASK : Cell<Task> =
Cell::new({
let task = Task{
func: Box::new(context_switch_to_user_space),
@ -73,7 +73,7 @@ lazy_static! {
- size_of::<usize>()
- size_of::<SyscallFrame>();
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::<TrapFrame>() as *mut TrapFrame)
.sub(1)

View File

@ -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
}
}

View File

@ -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

View File

@ -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 {
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
}

View File

@ -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);
}

View File

@ -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);
}

25
src/tests/test_example.rs Normal file
View File

@ -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");
}