mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-26 19:03:27 +00:00
add tests and hide some pub functions
This commit is contained in:
@ -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
104
src/Cargo.lock
generated
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
@ -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<ExitStatus> {
|
||||
let status = runner_utils::run_with_timeout(&mut cmd, Duration::from_secs(TEST_TIMEOUT_SECS))?;
|
||||
Ok(status)
|
||||
}
|
||||
|
@ -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]
|
||||
|
@ -1,7 +1,5 @@
|
||||
//! CPU.
|
||||
|
||||
use x86_64::registers::model_specific::FsBase;
|
||||
|
||||
use crate::trap::{CalleeRegs, CallerRegs, SyscallFrame, TrapFrame};
|
||||
|
||||
/// Defines a CPU-local variable.
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
37
src/kxos-frame/src/device/serial.rs
Normal file
37
src/kxos-frame/src/device/serial.rs
Normal 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)*));
|
||||
}
|
@ -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!()
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
@ -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+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,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();
|
||||
|
@ -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();
|
||||
|
@ -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,
|
||||
*,
|
||||
};
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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};
|
||||
|
@ -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};
|
||||
|
@ -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()
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::task::Task;
|
||||
use crate::{prelude::*, println, UPSafeCell};
|
||||
use crate::{prelude::*, UPSafeCell};
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
25
src/tests/test_example.rs
Normal 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");
|
||||
}
|
Reference in New Issue
Block a user