diff --git a/Cargo.lock b/Cargo.lock index c631b54b..86f2e4ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -81,6 +81,14 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +[[package]] +name = "backtrace" +version = "0.1.0" +dependencies = [ + "arch", + "early-print", +] + [[package]] name = "bit_field" version = "0.10.2" @@ -226,6 +234,7 @@ dependencies = [ "config", "crate_interface", "device-core", + "early-print", "fdt", "log", "memory", @@ -237,7 +246,14 @@ dependencies = [ "spin", "sync", "systype", - "virtio-drivers", + "virtio-drivers 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "early-print" +version = "0.1.0" +dependencies = [ + "sbi-rt", ] [[package]] @@ -559,6 +575,7 @@ dependencies = [ "arch", "async-trait", "async_utils", + "backtrace", "bit_field", "bitflags 2.6.0", "buddy_system_allocator", @@ -567,6 +584,7 @@ dependencies = [ "crate_interface", "downcast-rs", "driver", + "early-print", "executor", "hashbrown", "log", @@ -587,7 +605,7 @@ dependencies = [ "timer", "vfs", "vfs-core", - "virtio-drivers", + "virtio-drivers 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "xmas-elf", ] @@ -678,6 +696,7 @@ dependencies = [ "bitmap-allocator", "buddy_system_allocator", "config", + "early-print", "linked_list_allocator", "log", "riscv", @@ -1246,6 +1265,15 @@ dependencies = [ "time", ] +[[package]] +name = "virtio-drivers" +version = "0.7.3" +dependencies = [ + "bitflags 2.6.0", + "log", + "zerocopy", +] + [[package]] name = "virtio-drivers" version = "0.7.3" diff --git a/config/src/mm.rs b/config/src/mm.rs index 24a3da34..a223b65b 100644 --- a/config/src/mm.rs +++ b/config/src/mm.rs @@ -13,17 +13,19 @@ pub const KERNEL_OFFSET: usize = 0x20_0000; pub const KERNEL_START_PHYS: usize = RAM_START + KERNEL_OFFSET; pub const KERNEL_START: usize = VIRT_START + KERNEL_OFFSET; -pub const KERNEL_STACK_SIZE: usize = 64 * 1024; // 64K -pub const KERNEL_HEAP_SIZE: usize = 32 * 1024 * 1024; // 32M +pub const KERNEL_STACK_SIZE: usize = 64 * 1024; +pub const KERNEL_HEAP_SIZE: usize = 64 * 1024 * 1024; register_mut_const!(pub DTB_ADDR, usize, 0); /// boot pub const HART_START_ADDR: usize = 0x80200000; -pub const USER_STACK_SIZE: usize = 8 * 1024 * 1024; // 8M +pub const USER_STACK_SIZE: usize = 8 * 1024 * 1024; pub const USER_STACK_PRE_ALLOC_SIZE: usize = 4 * PAGE_SIZE; +pub const USER_ELF_PRE_ALLOC_PAGE_CNT: usize = 0; + pub const PAGE_SIZE: usize = 1 << PAGE_SIZE_BITS; pub const PAGE_MASK: usize = PAGE_SIZE - 1; pub const PAGE_SIZE_BITS: usize = 12; @@ -39,7 +41,8 @@ pub const PAGE_TABLE_LEVEL_NUM: usize = 3; /// Dynamic linked interpreter address range in user space pub const DL_INTERP_OFFSET: usize = 0x20_0000_0000; -pub const MAX_BUFFER_CACHE: usize = 0x100; +pub const MAX_BUFFER_HEADS: usize = 0x30000; +pub const MAX_BUFFER_CACHE: usize = 0x1000; pub const MAX_BUFFER_PAGES: usize = MAX_BUFFER_CACHE / MAX_BUFFERS_PER_PAGE; pub const MAX_BUFFERS_PER_PAGE: usize = PAGE_SIZE / BLOCK_SIZE; pub const BUFFER_NEED_CACHE_CNT: usize = 8; diff --git a/crates/backtrace/Cargo.toml b/crates/backtrace/Cargo.toml new file mode 100644 index 00000000..38f42d10 --- /dev/null +++ b/crates/backtrace/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "backtrace" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +arch = { path = "../../arch/" } +early-print = { path = "../early-print/" } diff --git a/crates/backtrace/src/lib.rs b/crates/backtrace/src/lib.rs new file mode 100644 index 00000000..62b2fc00 --- /dev/null +++ b/crates/backtrace/src/lib.rs @@ -0,0 +1,23 @@ +#![no_std] +#![no_main] + +use core::mem::size_of; + +use early_print::early_println; + +pub fn backtrace() { + extern "C" { + fn _stext(); + fn _etext(); + } + unsafe { + let mut current_pc = arch::register::ra(); + let mut current_fp = arch::register::fp(); + + while current_pc >= _stext as usize && current_pc <= _etext as usize && current_fp != 0 { + early_println!("{:#018x}", current_pc - size_of::()); + current_fp = *(current_fp as *const usize).offset(-2); + current_pc = *(current_fp as *const usize).offset(-1); + } + } +} diff --git a/crates/early-print/Cargo.toml b/crates/early-print/Cargo.toml new file mode 100644 index 00000000..8c105643 --- /dev/null +++ b/crates/early-print/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "early-print" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +sbi-rt = { version = "0.0.3", features = ["legacy"] } diff --git a/crates/early-print/src/lib.rs b/crates/early-print/src/lib.rs new file mode 100644 index 00000000..58f87298 --- /dev/null +++ b/crates/early-print/src/lib.rs @@ -0,0 +1,32 @@ +#![no_std] +#![no_main] + +use core::{fmt, fmt::Write}; + +pub struct EarlyStdout; + +impl fmt::Write for EarlyStdout { + fn write_str(&mut self, s: &str) -> fmt::Result { + for s in s.as_bytes() { + sbi_rt::legacy::console_putchar(*s as usize); + } + Ok(()) + } +} + +pub fn early_print(args: fmt::Arguments<'_>) { + EarlyStdout.write_fmt(args).unwrap(); +} + +#[macro_export] +macro_rules! early_print { + ($($arg:tt)*) => {{ + $crate::early_print(format_args!($($arg)*)); + }}; +} + +#[macro_export] +macro_rules! early_println { + () => ($crate::early_print!("\n")); + ($($arg:tt)*) => ($crate::early_print!("{}\n", format_args!($($arg)*))); +} diff --git a/driver/Cargo.toml b/driver/Cargo.toml index 198ec6d3..969c73fb 100644 --- a/driver/Cargo.toml +++ b/driver/Cargo.toml @@ -14,6 +14,7 @@ memory = { path = "../modules/memory/" } systype = { path = "../modules/systype/" } page = { path = "../modules/page/" } device-core = { path = "../modules/device-core/" } +early-print = { path = "../crates/early-print/" } net = { path = "../modules/net/" } bitflags = "2.5" diff --git a/driver/src/lib.rs b/driver/src/lib.rs index d6085fd3..587d65d5 100644 --- a/driver/src/lib.rs +++ b/driver/src/lib.rs @@ -14,6 +14,7 @@ use core::fmt::{self, Write}; use async_utils::block_on; use crate_interface::call_interface; use device_core::{BlockDriverOps, CharDevice, DeviceMajor}; +use early_print::EarlyStdout; use manager::DeviceManager; use memory::PageTable; use spin::Once; @@ -94,42 +95,26 @@ impl Write for Stdout { fn write_str(&mut self, s: &str) -> fmt::Result { if let Some(serial) = unsafe { UART0.lock().as_mut() } { block_on(async { serial.write(s.as_bytes()).await }); - return Ok(()); + Ok(()) + } else { + EarlyStdout.write_str(s) } - for s in s.as_bytes() { - console_putchar(*s as usize); - } - Ok(()) } } -pub fn print(args: fmt::Arguments<'_>) { +pub fn _print(args: fmt::Arguments) { Stdout.write_fmt(args).unwrap(); } -/// print string macro #[macro_export] macro_rules! print { ($($arg:tt)*) => {{ - $crate::print(format_args!($($arg)*)); + $crate::_print(format_args!($($arg)*)); }}; } -/// println string macro #[macro_export] macro_rules! println { - () => { - $crate::print!("\n") - }; - ($($arg:tt)*) => {{ - $crate::print(format_args_nl!($($arg)*)); - }}; -} - -pub fn shutdown() -> ! { - sbi::shutdown() -} - -pub fn set_timer(timer: usize) { - sbi::set_timer(timer) + () => ($crate::print!("\n")); + ($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*))); } diff --git a/driver/src/serial/uart8250.rs b/driver/src/serial/uart8250.rs index 525a29e9..f6e21137 100644 --- a/driver/src/serial/uart8250.rs +++ b/driver/src/serial/uart8250.rs @@ -56,7 +56,7 @@ bitflags! { #[derive(Debug)] pub struct Uart { /// UART MMIO base address - mmio_base: usize, + mmio_base_vaddr: usize, clock_frequency: u32, baud_rate: u32, reg_io_width: usize, @@ -71,7 +71,7 @@ impl Uart { /// base address really points to a serial port device. #[rustversion::attr(since(1.61), const)] pub unsafe fn new( - mmio_base: usize, + mmio_base_vaddr: usize, clock_frequency: usize, baud_rate: usize, reg_io_width: usize, @@ -79,7 +79,7 @@ impl Uart { is_snps: bool, ) -> Self { Self { - mmio_base, + mmio_base_vaddr, clock_frequency: clock_frequency as u32, baud_rate: baud_rate as u32, reg_io_width, @@ -111,7 +111,7 @@ impl Uart { } fn init_u8(&mut self) { - let reg = self.mmio_base as *mut u8; + let reg = self.mmio_base_vaddr as *mut u8; unsafe { // Disable Interrupt @@ -144,7 +144,7 @@ impl Uart { } fn init_u32(&mut self) { - let reg = self.mmio_base as *mut u32; + let reg = self.mmio_base_vaddr as *mut u32; unsafe { // Disable Interrupt @@ -180,14 +180,14 @@ impl Uart { } fn line_sts_u8(&self) -> LineStsFlags { - let ptr = self.mmio_base as *mut u8; + let ptr = self.mmio_base_vaddr as *mut u8; unsafe { LineStsFlags::from_bits_truncate(ptr.byte_add(LSR << self.reg_shift).read_volatile()) } } fn line_sts_u32(&self) -> LineStsFlags { - let ptr = self.mmio_base as *mut u32; + let ptr = self.mmio_base_vaddr as *mut u32; unsafe { LineStsFlags::from_bits_truncate( ptr.byte_add(LSR << self.reg_shift).read_volatile() as u8 @@ -197,7 +197,7 @@ impl Uart { /// Sends a byte on the serial port. pub fn send_u8(&mut self, c: u8) { - let ptr = self.mmio_base as *mut u8; + let ptr = self.mmio_base_vaddr as *mut u8; unsafe { match c { 8 | 0x7F => { @@ -220,7 +220,7 @@ impl Uart { } pub fn send_u32(&mut self, c: u8) { - let ptr = self.mmio_base as *mut u32; + let ptr = self.mmio_base_vaddr as *mut u32; unsafe { match c { 8 | 0x7F => { @@ -244,7 +244,7 @@ impl Uart { /// Receives a byte on the serial port. pub fn receive(&mut self) -> u8 { - let ptr = self.mmio_base as *mut u32; + let ptr = self.mmio_base_vaddr as *mut u32; unsafe { wait_for!(self.line_sts_u8().contains(LineStsFlags::INPUT_FULL)); if self.is_snps { diff --git a/driver/src/virtio/virtio_blk.rs b/driver/src/virtio/virtio_blk.rs index 3d4644ac..36d73c5e 100644 --- a/driver/src/virtio/virtio_blk.rs +++ b/driver/src/virtio/virtio_blk.rs @@ -30,8 +30,15 @@ impl BlockDriverOps for VirtIoBlkDev { BLOCK_SIZE } + fn buffer_head_cnts(&self) -> usize { + self.cache.lock().buffer_heads.len() + } + + fn remove_buffer_page(&self, block_id: usize) { + self.cache.lock().pages.pop(&block_id); + } + fn base_read_block(&self, block_id: usize, buf: &mut [u8]) { - // log::error!("read blk id {}", block_id); let res = self.device.lock().read_blocks(block_id, buf); if res.is_err() { panic!( @@ -76,7 +83,7 @@ impl VirtIoBlkDev { name: "virtio-blk".to_string(), mmio_base, mmio_size, - irq_no: None, // TODO: block device don't support interrupts in this system + irq_no: None, // TODO: support interrupt for block device dtype: DeviceType::Block, }; let blk_dev = Arc::new(Self { diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index f0afc5bc..64240ae5 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -22,6 +22,8 @@ time = { path = "../modules/time/" } timer = { path = "../modules/timer/" } page = { path = "../modules/page/" } net = { path = "../modules/net/" } +early-print = { path = "../crates/early-print/" } +backtrace = { path = "../crates/backtrace/" } cfg-if = "1.0" crate_interface = "0.1" diff --git a/kernel/build.rs b/kernel/build.rs index 9cb0bb13..1a0dad5d 100644 --- a/kernel/build.rs +++ b/kernel/build.rs @@ -21,68 +21,4 @@ fn main() { let dest = PathBuf::from(out_dir).join("linker.ld"); fs::write(&dest, new).unwrap(); println!("cargo:rustc-link-arg=-T{}", dest.display()); - - insert_app_data().unwrap(); -} - -fn insert_app_data() -> Result<()> { - let mut target_path: String = String::from("./target/riscv64gc-unknown-none-elf/"); - let mode = option_env!("MODE").unwrap_or("debug"); - target_path.push_str(mode); - target_path.push('/'); - let mut f = File::create("src/link_app.asm").unwrap(); - let mut apps: Vec<_> = read_dir("../user/src/bin") - .unwrap() - .map(|dir_entry| { - let mut name_with_ext = dir_entry.unwrap().file_name().into_string().unwrap(); - name_with_ext.drain(name_with_ext.find('.').unwrap()..name_with_ext.len()); - name_with_ext - }) - .filter(|name| name == "init_proc") - .collect(); - - apps.sort(); - - writeln!( - f, - r#" - .align 3 - .section .data - .global _num_app -_num_app: - .quad {}"#, - apps.len() - )?; - - for i in 0..apps.len() { - writeln!(f, r#" .quad app_{}_start"#, i)?; - } - writeln!(f, r#" .quad app_{}_end"#, apps.len() - 1)?; - - writeln!( - f, - r#" - .global _app_names -_app_names:"# - )?; - for app in apps.iter() { - writeln!(f, r#" .string "{}""#, app)?; - } - - for (idx, app) in apps.iter().enumerate() { - println!("app_{}: {}", idx, app); - writeln!( - f, - r#" - .section .data - .global app_{0}_start - .global app_{0}_end - .align 3 -app_{0}_start: - .incbin "{2}{1}" -app_{0}_end:"#, - idx, app, target_path - )?; - } - Ok(()) } diff --git a/kernel/src/impls.rs b/kernel/src/impls.rs index 372f1b70..4b48a674 100644 --- a/kernel/src/impls.rs +++ b/kernel/src/impls.rs @@ -14,7 +14,7 @@ use crate::{ /// Print msg with color pub fn print_in_color(args: fmt::Arguments, color_code: u8) { - driver::print(with_color!(color_code, "{}", args)); + driver::_print(with_color!(color_code, "{}", args)); } struct LogIfImpl; @@ -51,7 +51,7 @@ impl LogIf for LogIfImpl { } else { "-".to_string() }; - driver::print(with_color!( + driver::_print(with_color!( ColorCode::White, "{}{}{} {} \r\n", with_color!(level_color, "[{:>5}]", level), diff --git a/kernel/src/ipc/shm.rs b/kernel/src/ipc/shm.rs index 43140a8b..69690dbb 100644 --- a/kernel/src/ipc/shm.rs +++ b/kernel/src/ipc/shm.rs @@ -52,6 +52,7 @@ impl ShmIdDs { shm_nattch: 0, } } + pub fn attach(&mut self, lpid: usize) { // shm_atime is set to the current time. self.shm_atime = get_time_sec(); @@ -91,10 +92,18 @@ impl SharedMemory { } pub struct SharedMemoryManager(pub SpinNoIrqLock>); + impl SharedMemoryManager { pub fn init() -> Self { Self(SpinNoIrqLock::new(HashMap::new())) } + + pub fn attach(&self, shm_id: usize, lpid: usize) { + let mut shm_manager = self.0.lock(); + let shm = shm_manager.get_mut(&shm_id).unwrap(); + shm.shmid_ds.attach(lpid); + } + pub fn detach(&self, shm_id: usize, lpid: usize) { let mut shm_manager = self.0.lock(); let shm = shm_manager.get_mut(&shm_id).unwrap(); diff --git a/kernel/src/loader.rs b/kernel/src/loader.rs deleted file mode 100644 index 28e50b50..00000000 --- a/kernel/src/loader.rs +++ /dev/null @@ -1,62 +0,0 @@ -//! Loading user applications into memory - -/// Get the total number of applications. -use alloc::vec::Vec; -/// get app number -pub fn get_num_app() -> usize { - extern "C" { - fn _num_app(); - } - unsafe { (_num_app as usize as *const usize).read_volatile() } -} -/// get applications data -pub fn get_app_data(app_id: usize) -> &'static [u8] { - extern "C" { - fn _num_app(); - } - let num_app_ptr = _num_app as usize as *const usize; - let num_app = get_num_app(); - let app_start = unsafe { core::slice::from_raw_parts(num_app_ptr.add(1), num_app + 1) }; - assert!(app_id < num_app); - unsafe { - core::slice::from_raw_parts( - app_start[app_id] as *const u8, - app_start[app_id + 1] - app_start[app_id], - ) - } -} - -pub fn init() { - let num_app = get_num_app(); - extern "C" { - fn _app_names(); - } - let mut start = _app_names as usize as *const u8; - let mut v = Vec::with_capacity(num_app); - unsafe { - for _ in 0..num_app { - let mut end = start; - while end.read_volatile() != b'\0' { - end = end.add(1); - } - let slice = core::slice::from_raw_parts(start, end as usize - start as usize); - let str = core::str::from_utf8(slice).unwrap(); - v.push(str); - start = end.add(1); - } - APP_NAMES = Some(v); - } -} - -static mut APP_NAMES: Option> = None; - -#[allow(unused)] -/// get app data from name -pub fn get_app_data_by_name(name: &str) -> Option<&'static [u8]> { - // warn!("app name {}", name); - let app_names = unsafe { APP_NAMES.as_ref().unwrap() }; - let num_app = get_num_app(); - (0..num_app) - .find(|&i| app_names[i] == name) - .map(get_app_data) -} diff --git a/kernel/src/main.rs b/kernel/src/main.rs index 7fa3e452..11c463e4 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -11,14 +11,12 @@ #![feature(stdsimd)] #![feature(riscv_ext_intrinsics)] #![feature(map_try_insert)] -#![feature(format_args_nl)] #![allow(clippy::mut_from_ref)] #![feature(new_uninit)] mod boot; mod impls; mod ipc; -mod loader; mod mm; mod net; mod panic; @@ -33,8 +31,10 @@ use core::{ }; use ::net::init_network; +use driver::BLOCK_DEVICE; +use timer::timelimited_task::ksleep_s; -use crate::processor::hart; +use crate::{processor::hart, task::TASK_MANAGER}; extern crate alloc; @@ -48,7 +48,6 @@ extern crate driver; extern crate logging; global_asm!(include_str!("trampoline.asm")); -global_asm!(include_str!("link_app.asm")); static FIRST_HART: AtomicBool = AtomicBool::new(true); @@ -70,12 +69,28 @@ fn rust_main(hart_id: usize, dtb_addr: usize) { mm::init(); trap::init(); driver::init(); - loader::init(); vfs::init(); task::spawn_kernel_task(async move { - task::add_init_proc(); + task::spawn_init_proc(); }); + // task::spawn_kernel_task(async move { + // loop { + // log::error!( + // "buffer head cnts {}", + // BLOCK_DEVICE.get().unwrap().buffer_head_cnts() + // ); + // ksleep_s(3).await; + // } + // }); + // + // task::spawn_kernel_task(async move { + // loop { + // log::error!("task counts {}", TASK_MANAGER.len()); + // ksleep_s(3).await; + // } + // }); + #[cfg(feature = "smp")] boot::start_harts(hart_id); } else { diff --git a/kernel/src/mm/memory_space/mod.rs b/kernel/src/mm/memory_space/mod.rs index 95c268a7..6b94d3c6 100644 --- a/kernel/src/mm/memory_space/mod.rs +++ b/kernel/src/mm/memory_space/mod.rs @@ -12,14 +12,15 @@ use core::{ ops::{self, Range}, }; +use arch::memory::{sfence_vma_all, sfence_vma_vaddr}; use async_utils::block_on; use config::{ board::MEMORY_END, mm::{ - align_offset_to_page, is_aligned_to_page, DL_INTERP_OFFSET, MMAP_PRE_ALLOC_PAGES, - PAGE_SIZE, USER_STACK_PRE_ALLOC_SIZE, USER_STACK_SIZE, U_SEG_FILE_BEG, U_SEG_FILE_END, - U_SEG_HEAP_BEG, U_SEG_HEAP_END, U_SEG_SHARE_BEG, U_SEG_SHARE_END, U_SEG_STACK_BEG, - U_SEG_STACK_END, VIRT_RAM_OFFSET, + align_offset_to_page, is_aligned_to_page, round_down_to_page, DL_INTERP_OFFSET, + MMAP_PRE_ALLOC_PAGES, PAGE_SIZE, USER_ELF_PRE_ALLOC_PAGE_CNT, USER_STACK_PRE_ALLOC_SIZE, + USER_STACK_SIZE, U_SEG_FILE_BEG, U_SEG_FILE_END, U_SEG_HEAP_BEG, U_SEG_HEAP_END, + U_SEG_SHARE_BEG, U_SEG_SHARE_END, U_SEG_STACK_BEG, U_SEG_STACK_END, VIRT_RAM_OFFSET, }, }; use log::info; @@ -120,7 +121,12 @@ impl MemorySpace { /// Map the sections in the elf. /// /// Return the max end vpn and the first section's va. - pub fn map_elf(&mut self, elf: &ElfFile, offset: VirtAddr) -> (VirtPageNum, VirtAddr) { + pub fn map_elf( + &mut self, + elf_file: Arc, + elf: &ElfFile, + offset: VirtAddr, + ) -> (VirtPageNum, VirtAddr) { let elf_header = elf.header; let ph_count = elf_header.pt2.ph_count(); @@ -151,7 +157,7 @@ impl MemorySpace { if ph_flags.is_execute() { map_perm |= MapPerm::X; } - let vm_area = VmArea::new(start_va..end_va, map_perm, VmAreaType::Elf); + let mut vm_area = VmArea::new(start_va..end_va, map_perm, VmAreaType::Elf); log::debug!("[map_elf] [{start_va:#x}, {end_va:#x}], map_perm: {map_perm:?} start...",); @@ -166,63 +172,63 @@ impl MemorySpace { ph.mem_size() ); - self.push_vma_with_data( - vm_area, - map_offset, - &elf.input[ph.offset() as usize..(ph.offset() + ph.file_size()) as usize], - ); - - log::info!("[map_elf] [{start_va:#x}, {end_va:#x}], map_perm: {map_perm:?}",); + if ph.file_size() == ph.mem_size() && is_aligned_to_page(ph.offset() as usize) { + assert!(!map_perm.contains(MapPerm::W)); + // NOTE: only add cow flag in elf page newly mapped. + // FIXME: mprotect is not checked yet + // WARN: the underlying elf file page cache may be edited, may cause unknown + // behavior + let mut pre_alloc_page_cnt = 0; + for vpn in vm_area.range_vpn() { + let start_offset = ph.offset() as usize; + let offset = start_offset + (vpn - vm_area.start_vpn()) * PAGE_SIZE; + let offset_aligned = round_down_to_page(offset); + if let Some(page) = + block_on(async { elf_file.get_page_at(offset_aligned).await }).unwrap() + { + if pre_alloc_page_cnt < USER_ELF_PRE_ALLOC_PAGE_CNT { + let new_page = Page::new(); + // WARN: area outer than region may should be set to zero + new_page.copy_from_slice(page.bytes_array()); + self.page_table_mut() + .map(vpn, new_page.ppn(), map_perm.into()); + vm_area.pages.insert(vpn, new_page); + unsafe { sfence_vma_vaddr(vpn.into()) }; + } else { + let (pte_flags, ppn) = { + let mut new_flags: PTEFlags = map_perm.into(); + new_flags |= PTEFlags::COW; + new_flags.remove(PTEFlags::W); + (new_flags, page.ppn()) + }; + self.page_table_mut().map(vpn, ppn, pte_flags); + vm_area.pages.insert(vpn, page); + unsafe { sfence_vma_vaddr(vpn.into()) }; + } + pre_alloc_page_cnt += 1; + } else { + break; + } + } + self.push_vma_lazily(vm_area); + log::info!("[map_elf] [{start_va:#x}, {end_va:#x}], map_perm: {map_perm:?}",); + } else { + self.push_vma_with_data( + vm_area, + map_offset, + &elf.input[ph.offset() as usize..(ph.offset() + ph.file_size()) as usize], + ); + } } (max_end_vpn, header_va.into()) } - /// Include sections in elf and TrapContext and user stack, - /// also returns user_sp and entry point. - // PERF: resolve elf file lazily - // TODO: dynamic interpreter - pub fn from_elf(elf_data: &[u8]) -> (Self, usize, usize, Vec) { - const ELF_MAGIC: [u8; 4] = [0x7f, 0x45, 0x4c, 0x46]; - - let mut memory_space = Self::new_user(); - - // map program headers of elf, with U flag - let elf = xmas_elf::ElfFile::new(elf_data).unwrap(); - let elf_header = elf.header; - assert_eq!(elf_header.pt1.magic, ELF_MAGIC, "invalid elf!"); - let entry_point = elf_header.pt2.entry_point() as usize; - let ph_entry_size = elf_header.pt2.ph_entry_size() as usize; - let ph_count = elf_header.pt2.ph_count() as usize; - - let mut auxv = generate_early_auxv(ph_entry_size, ph_count, entry_point); - - auxv.push(AuxHeader::new(AT_BASE, 0)); - - let (max_end_vpn, header_va) = memory_space.map_elf(&elf, 0.into()); - - let ph_head_addr = header_va.0 + elf.header.pt2.ph_offset() as usize; - log::debug!("[from_elf] AT_PHDR ph_head_addr is {ph_head_addr:x} "); - auxv.push(AuxHeader::new(AT_PHDR, ph_head_addr)); - - // map user stack with U flags - let max_end_va: VirtAddr = max_end_vpn.into(); - let user_stack_bottom: usize = usize::from(max_end_va) + PAGE_SIZE; - let user_stack_top = user_stack_bottom + USER_STACK_SIZE; - let ustack_vma = VmArea::new( - user_stack_bottom.into()..user_stack_top.into(), - MapPerm::URW, - VmAreaType::Stack, - ); - memory_space.push_vma(ustack_vma); - log::info!("[from_elf] map ustack: {user_stack_bottom:#x}, {user_stack_top:#x}",); - - memory_space.alloc_heap_lazily(); - - (memory_space, user_stack_top, entry_point, auxv) - } - - pub fn parse_and_map_elf(&mut self, elf_data: &[u8]) -> (usize, Vec) { + pub fn parse_and_map_elf( + &mut self, + elf_file: Arc, + elf_data: &[u8], + ) -> (usize, Vec) { const ELF_MAGIC: [u8; 4] = [0x7f, 0x45, 0x4c, 0x46]; // map program headers of elf, with U flag @@ -237,7 +243,7 @@ impl MemorySpace { auxv.push(AuxHeader::new(AT_BASE, 0)); - let (_max_end_vpn, header_va) = self.map_elf(&elf, 0.into()); + let (_max_end_vpn, header_va) = self.map_elf(elf_file, &elf, 0.into()); let ph_head_addr = header_va.0 + elf.header.pt2.ph_offset() as usize; auxv.push(AuxHeader::new(AT_RANDOM, ph_head_addr)); @@ -294,7 +300,7 @@ impl MemorySpace { let interp_file = interp_dentry.open().ok().unwrap(); let interp_elf_data = block_on(async { interp_file.read_all().await }).ok()?; let interp_elf = xmas_elf::ElfFile::new(&interp_elf_data).unwrap(); - self.map_elf(&interp_elf, DL_INTERP_OFFSET.into()); + self.map_elf(interp_file, &interp_elf, DL_INTERP_OFFSET.into()); Some(interp_elf.header.pt2.entry_point() as usize + DL_INTERP_OFFSET) } else { @@ -347,7 +353,7 @@ impl MemorySpace { vm_area.pages.insert(vpn, page.clone()); } } - self.push_vma(vm_area); + self.push_vma_lazily(vm_area); return ret_addr; } @@ -508,6 +514,7 @@ impl MemorySpace { } _ => { // copy on write + // TODO: MmapFlags::MAP_SHARED let mut new_flags = pte.flags() | PTEFlags::COW; new_flags.remove(PTEFlags::W); pte.set_flags(new_flags); @@ -576,7 +583,7 @@ impl MemorySpace { Ok(start) } - // NOTE: can not alloc all pages from `AddressSpace`, otherwise lmbench + // NOTE: can not alloc all pages from `PageCache`, otherwise lmbench // lat_pagefault will test page fault time as zero. pub fn alloc_mmap_area_lazily( &mut self, @@ -611,18 +618,21 @@ impl MemorySpace { let mut range_vpn = vma.range_vpn(); let length = cmp::min(length, MMAP_PRE_ALLOC_PAGES * PAGE_SIZE); for offset_aligned in (offset..offset + length).step_by(PAGE_SIZE) { - let page = if let Some(page) = page_cache.get_page(offset_aligned) { - page - } else if let Some(page) = block_on(async { file.read_page_at(offset_aligned).await })? - { - page + if let Some(page) = block_on(async { file.get_page_at(offset_aligned).await })? { + let vpn = range_vpn.next().unwrap(); + // TODO: support copy on write for private mapping + if flags.contains(MmapFlags::MAP_PRIVATE) { + let new_page = Page::new(); + new_page.copy_from_slice(page.bytes_array()); + page_table.map(vpn, new_page.ppn(), perm.into()); + vma.pages.insert(vpn, new_page); + } else { + page_table.map(vpn, page.ppn(), perm.into()); + vma.pages.insert(vpn, page); + } } else { - // no page means EOF break; - }; - let vpn = range_vpn.next().unwrap(); - page_table.map(vpn, page.ppn(), perm.into()); - vma.pages.insert(vpn, page); + } } self.push_vma_lazily(vma); Ok(start) diff --git a/kernel/src/mm/memory_space/vm_area.rs b/kernel/src/mm/memory_space/vm_area.rs index c3ec50db..48925599 100644 --- a/kernel/src/mm/memory_space/vm_area.rs +++ b/kernel/src/mm/memory_space/vm_area.rs @@ -419,7 +419,6 @@ impl VmArea { // PERF: copying data vs. lock the area vs. atomic ref cnt let old_page = self.get_page(vpn); - let mut _cnt: usize; let cnt = Arc::strong_count(old_page); if cnt > 1 { // shared now @@ -464,22 +463,13 @@ impl VmArea { } VmAreaType::Mmap => { if !self.mmap_flags.contains(MmapFlags::MAP_ANONYMOUS) { + // file mapping let file = self.backed_file.as_ref().unwrap(); let offset = self.offset + (vpn - self.start_vpn()) * PAGE_SIZE; let offset_aligned = round_down_to_page(offset); if self.mmap_flags.contains(MmapFlags::MAP_SHARED) { - let page = if let Some(page) = - file.inode().page_cache().unwrap().get_page(offset_aligned) - { - page - } else if let Some(page) = - block_on(async { file.read_page_at(offset_aligned).await })? - { - page - } else { - // no page means EOF - unreachable!() - }; + let page = block_on(async { file.get_page_at(offset_aligned).await })? + .unwrap(); page_table.map(vpn, page.ppn(), self.map_perm.into()); self.pages.insert(vpn, page); unsafe { sfence_vma_vaddr(vpn.to_va().into()) }; @@ -487,12 +477,16 @@ impl VmArea { todo!() } } else if self.mmap_flags.contains(MmapFlags::MAP_PRIVATE) { - // private anonymous area - page = Page::new(); - page.fill_zero(); - page_table.map(vpn, page.ppn(), self.map_perm.into()); - self.pages.insert(vpn, page); - unsafe { sfence_vma_vaddr(vpn.to_va().into()) }; + if self.mmap_flags.contains(MmapFlags::MAP_SHARED) { + todo!() + } else { + // private anonymous area + page = Page::new(); + page.fill_zero(); + page_table.map(vpn, page.ppn(), self.map_perm.into()); + self.pages.insert(vpn, page); + unsafe { sfence_vma_vaddr(vpn.to_va().into()) }; + } } } _ => {} diff --git a/kernel/src/panic.rs b/kernel/src/panic.rs index ad721d16..f68f5d9c 100644 --- a/kernel/src/panic.rs +++ b/kernel/src/panic.rs @@ -6,7 +6,9 @@ use core::{ }; use arch::interrupts::disable_interrupt; -use driver::shutdown; +use backtrace::backtrace; +use driver::sbi::shutdown; +use early_print::early_println; use logging::LOG_INITIALIZED; use crate::processor::hart::local_hart; @@ -17,11 +19,11 @@ static PANIC_CNT: AtomicUsize = AtomicUsize::new(0); fn panic(info: &PanicInfo) -> ! { unsafe { disable_interrupt() }; - println!("panic now!!!"); + early_println!("early panic now!!!"); if PANIC_CNT.fetch_add(1, Ordering::Relaxed) > 0 { unsafe { LOG_INITIALIZED.store(false, Ordering::Relaxed) } if let Some(location) = info.location() { - println!( + early_println!( "Hart {} panic at {}:{}, msg: {}", local_hart().hart_id(), location.file(), @@ -29,13 +31,14 @@ fn panic(info: &PanicInfo) -> ! { info.message().unwrap() ); } else if let Some(msg) = info.message() { - println!("Panicked: {}", msg); + early_println!("Panicked: {}", msg); } else { - println!("Unknown panic: {:?}", info); + early_println!("Unknown panic: {:?}", info); } backtrace(); shutdown() } + println!("panic now!!!"); // NOTE: message below is mostly printed in log, if these messages can not be @@ -78,20 +81,3 @@ fn panic(info: &PanicInfo) -> ! { shutdown() } - -pub fn backtrace() { - extern "C" { - fn _stext(); - fn _etext(); - } - unsafe { - let mut current_pc = arch::register::ra(); - let mut current_fp = arch::register::fp(); - - while current_pc >= _stext as usize && current_pc <= _etext as usize && current_fp != 0 { - println!("{:#018x}", current_pc - size_of::()); - current_fp = *(current_fp as *const usize).offset(-2); - current_pc = *(current_fp as *const usize).offset(-1); - } - } -} diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index cb13d1e5..de6b8ecc 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -934,6 +934,10 @@ impl Syscall<'_> { pub async fn sys_ftruncate(&self, fd: usize, length: u64) -> SyscallResult { let task = self.task; let file = task.with_fd_table(|table| table.get_file(fd))?; + log::warn!( + "[sys_ftruncate] file path {}, length:{length}", + file.dentry().path() + ); file.inode().truncate(length as usize) } } diff --git a/kernel/src/syscall/mm.rs b/kernel/src/syscall/mm.rs index 55520a96..6d12dec9 100644 --- a/kernel/src/syscall/mm.rs +++ b/kernel/src/syscall/mm.rs @@ -153,7 +153,6 @@ impl Syscall<'_> { .with_mut_memory_space(|m| m.alloc_mmap_anonymous(perm, flags, length))?; Ok(start_va.bits()) } else { - log::warn!("private copy on write mmap is not implemented yet"); let file = task.with_fd_table(|table| table.get_file(fd))?; if offset + length > file.size() { log::warn!("offset plus length is bigger than file size"); @@ -301,8 +300,8 @@ impl Syscall<'_> { if shmflg.contains(ShmAtFlags::SHM_RDONLY) { map_perm.remove(MapPerm::W); } - let mut shm_manager = SHARED_MEMORY_MANAGER.0.lock(); - if let Some(shm) = shm_manager.get_mut(&shmid) { + let mut ret = 0; + if let Some(shm) = SHARED_MEMORY_MANAGER.0.lock().get_mut(&shmid) { let task = self.task; let ret_addr = task.with_mut_memory_space(|m| { m.attach_shm(shm.size(), shmaddr_aligned, map_perm, &mut shm.pages) @@ -310,11 +309,13 @@ impl Syscall<'_> { task.with_mut_shm_ids(|ids| { ids.insert(ret_addr, shmid); }); - Ok(ret_addr.into()) + ret = ret_addr.into(); } else { // Invalid shmid value - Err(SysError::EINVAL) + return Err(SysError::EINVAL); } + SHARED_MEMORY_MANAGER.attach(shmid, self.task.pid()); + return Ok(ret); } /// When a process no longer uses a shared memory block, it should detach diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 9c5b5425..7cac819b 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -189,6 +189,7 @@ impl<'a> Syscall<'a> { } SYNC => self.sys_do_nothing("sync"), FSYNC => self.sys_do_nothing("fsync"), + FTRUNCATE => self.sys_ftruncate(args[0], args[1] as _).await, // IO PPOLL => { self.sys_ppoll(args[0].into(), args[1], args[2].into(), args[3].into()) diff --git a/kernel/src/syscall/process.rs b/kernel/src/syscall/process.rs index 8bd31de1..d684635b 100644 --- a/kernel/src/syscall/process.rs +++ b/kernel/src/syscall/process.rs @@ -295,7 +295,7 @@ impl Syscall<'_> { let file = task.resolve_path(&path)?.open()?; let elf_data = file.read_all().await?; - task.do_execve(&elf_data, argv, envp); + task.do_execve(file, &elf_data, argv, envp); Ok(0) } diff --git a/kernel/src/task/manager.rs b/kernel/src/task/manager.rs index eef51298..e78e8b45 100644 --- a/kernel/src/task/manager.rs +++ b/kernel/src/task/manager.rs @@ -51,9 +51,9 @@ impl TaskManager { Ok(()) } - // pub fn total_num(&self) -> usize { - // self.0.lock().len() - // } + pub fn len(&self) -> usize { + self.0.lock().len() + } } /// PGid -> Process group diff --git a/kernel/src/task/mod.rs b/kernel/src/task/mod.rs index f4bf4c1d..8165274a 100644 --- a/kernel/src/task/mod.rs +++ b/kernel/src/task/mod.rs @@ -6,17 +6,46 @@ pub mod signal; pub mod task; mod tid; +use alloc::{sync::Arc, vec::Vec}; + +use async_utils::block_on; +use config::mm::USER_STACK_SIZE; pub use manager::TASK_MANAGER; pub use schedule::{spawn_kernel_task, spawn_user_task}; pub use task::Task; pub use tid::{PGid, Pid, Tid}; +use vfs::sys_root_dentry; +use vfs_core::Path; + +use crate::{ + mm::memory_space::{self, init_stack, MemorySpace}, + processor::env::within_sum, + trap::TrapContext, +}; + +pub fn spawn_init_proc() { + let init_proc_path = "/init_proc"; + let argv = Vec::new(); + let envp = Vec::new(); + + let file = Path::new(sys_root_dentry(), sys_root_dentry(), init_proc_path) + .walk() + .unwrap() + .open() + .unwrap(); + let elf_data = block_on(async { file.read_all().await }).unwrap(); + + let mut memory_space = MemorySpace::new_user(); + unsafe { memory_space.switch_page_table() }; + let (entry, auxv) = memory_space.parse_and_map_elf(file, &elf_data); + let sp_init = memory_space.alloc_stack_lazily(USER_STACK_SIZE); + let (sp, argc, argv, envp) = within_sum(|| init_stack(sp_init, argv, envp, auxv)); + memory_space.alloc_heap_lazily(); -use crate::loader::get_app_data_by_name; + let trap_context = TrapContext::new(entry, sp); -pub fn add_init_proc() { - let elf_data = get_app_data_by_name("init_proc").unwrap(); - // let elf_data = get_app_data_by_name("futex_test").unwrap(); - Task::spawn_from_elf(elf_data); + let task = Task::new_init(memory_space, trap_context); + schedule::spawn_user_task(task); } #[macro_export] diff --git a/kernel/src/task/schedule.rs b/kernel/src/task/schedule.rs index 5bad9193..04df8cb8 100644 --- a/kernel/src/task/schedule.rs +++ b/kernel/src/task/schedule.rs @@ -6,7 +6,7 @@ use core::{ time::Duration, }; -use arch::time::get_time_duration; +use arch::time::{get_time_duration, get_time_us}; use async_utils::{get_waker, suspend_now, yield_now}; use timer::{Timer, TIMER_MANAGER}; diff --git a/kernel/src/task/task.rs b/kernel/src/task/task.rs index ec43812d..29c71d0b 100644 --- a/kernel/src/task/task.rs +++ b/kernel/src/task/task.rs @@ -10,7 +10,7 @@ use core::{ task::Waker, }; -use arch::memory::sfence_vma_all; +use arch::{memory::sfence_vma_all, time::get_time_us}; use config::{ mm::{DL_INTERP_OFFSET, USER_STACK_SIZE}, process::INIT_PROC_PID, @@ -26,7 +26,7 @@ use sync::mutex::SpinNoIrqLock; use systype::SysResult; use time::stat::TaskTimeStat; use vfs::{fd_table::FdTable, sys_root_dentry}; -use vfs_core::{is_absolute_path, AtFd, Dentry, InodeMode, Path}; +use vfs_core::{is_absolute_path, AtFd, Dentry, File, InodeMode, Path}; use super::{ resource::CpuMask, @@ -39,7 +39,10 @@ use crate::{ futex::{futex_manager, FutexHashKey, RobustListHead, FUTEX_MANAGER}, shm::SHARED_MEMORY_MANAGER, }, - mm::{memory_space::init_stack, MemorySpace, UserReadPtr, UserWritePtr}, + mm::{ + memory_space::{self, init_stack}, + MemorySpace, UserReadPtr, UserWritePtr, + }, processor::env::within_sum, syscall::{self, CloneFlags}, task::{ @@ -175,10 +178,7 @@ impl Task { itimers: [ITimer;3] ); - // TODO: this function is not clear, may be replaced with exec - pub fn spawn_from_elf(elf_data: &[u8]) { - let (memory_space, user_sp_top, entry_point, _auxv) = MemorySpace::from_elf(elf_data); - let trap_context = TrapContext::new(entry_point, user_sp_top); + pub fn new_init(memory_space: MemorySpace, trap_context: TrapContext) -> Arc { let task = Arc::new(Self { tid: alloc_tid(), leader: None, @@ -205,11 +205,12 @@ impl Task { cpus_allowed: SyncUnsafeCell::new(CpuMask::CPU_ALL), shm_ids: new_shared(BTreeMap::new()), }); + task.thread_group.lock().push(task.clone()); task.memory_space.lock().set_task(&task); TASK_MANAGER.add(&task); - log::debug!("create a new process, pid {}", task.tid()); - schedule::spawn_user_task(task); + + task } pub fn parent(&self) -> Option> { @@ -310,6 +311,7 @@ impl Task { let cwd; let itimers; let robust; + let shm_ids; let sig_handlers = if flags.contains(CloneFlags::SIGHAND) { self.sig_handlers.clone() } else { @@ -324,6 +326,7 @@ impl Task { itimers = self.itimers.clone(); cwd = self.cwd.clone(); robust = self.robust.clone(); + shm_ids = self.shm_ids.clone(); } else { is_leader = true; leader = None; @@ -333,6 +336,10 @@ impl Task { itimers = new_shared([ITimer::ZERO; 3]); cwd = new_shared(self.cwd()); robust = new_shared(RobustListHead::default()); + shm_ids = new_shared(BTreeMap::clone(&self.shm_ids.lock())); + for (_, shm_id) in shm_ids.lock().iter() { + SHARED_MEMORY_MANAGER.attach(*shm_id, tid.0); + } } let memory_space; @@ -377,7 +384,7 @@ impl Task { tid_address: SyncUnsafeCell::new(TidAddress::new()), cpus_allowed: SyncUnsafeCell::new(CpuMask::CPU_ALL), // After a fork(2), the child inherits the attached shared memory segments. - shm_ids: self.shm_ids.clone(), + shm_ids, }); if !flags.contains(CloneFlags::THREAD) { @@ -393,12 +400,17 @@ impl Task { new } - // TODO: figure out what should be reserved across this syscall - pub fn do_execve(self: &Arc, elf_data: &[u8], argv: Vec, envp: Vec) { + pub fn do_execve( + self: &Arc, + elf_file: Arc, + elf_data: &[u8], + argv: Vec, + envp: Vec, + ) { log::debug!("[Task::do_execve] parsing elf"); let mut memory_space = MemorySpace::new_user(); memory_space.set_task(&self.leader()); - let (mut entry, mut auxv) = memory_space.parse_and_map_elf(elf_data); + let (mut entry, mut auxv) = memory_space.parse_and_map_elf(elf_file, elf_data); let elf = xmas_elf::ElfFile::new(elf_data).unwrap(); if let Some(interp_entry_point) = memory_space.load_dl_interp_if_needed(&elf) { @@ -407,6 +419,7 @@ impl Task { } else { auxv.push(AuxHeader::new(AT_BASE, 0)); } + // NOTE: should do termination before switching page table, so that other // threads will trap in by page fault and be handled by `do_exit` log::debug!("[Task::do_execve] terminating all threads except the leader"); diff --git a/kernel/src/trap/user_trap.rs b/kernel/src/trap/user_trap.rs index 11230715..dec9b830 100644 --- a/kernel/src/trap/user_trap.rs +++ b/kernel/src/trap/user_trap.rs @@ -20,9 +20,7 @@ use systype::SysError; use timer::TIMER_MANAGER; use super::{set_kernel_trap, TrapContext}; -use crate::{ - mm::PageFaultAccessType, panic::backtrace, syscall::Syscall, task::Task, trap::set_user_trap, -}; +use crate::{mm::PageFaultAccessType, syscall::Syscall, task::Task, trap::set_user_trap}; /// handle an interrupt, exception, or system call from user space /// return if it is syscall and has been interrupted diff --git a/modules/device-core/src/lib.rs b/modules/device-core/src/lib.rs index c1fa3a42..79bc9412 100644 --- a/modules/device-core/src/lib.rs +++ b/modules/device-core/src/lib.rs @@ -11,6 +11,7 @@ use async_trait::async_trait; use downcast_rs::{impl_downcast, DowncastSync}; use error::DevResult; pub use smoltcp::phy::{Loopback, Medium}; + /// General Device Operations #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub enum DeviceType { @@ -98,6 +99,10 @@ pub trait BlockDriverOps: BaseDriverOps { fn block_size(&self) -> usize; + fn buffer_head_cnts(&self) -> usize; + + fn remove_buffer_page(&self, block_id: usize); + /// Read data form block to buffer fn base_read_block(&self, block_id: usize, buf: &mut [u8]); diff --git a/modules/ext4/src/dentry.rs b/modules/ext4/src/dentry.rs index e61ee5c8..f831a40e 100644 --- a/modules/ext4/src/dentry.rs +++ b/modules/ext4/src/dentry.rs @@ -107,7 +107,7 @@ impl Dentry for Ext4Dentry { .unwrap_or_else(|_| unreachable!()); let sub_dentry = self.get_child(name).unwrap(); let fpath = sub_dentry.path(); - log::debug!("[Ext4Dentry::base_remove] path: {fpath}"); + log::info!("[Ext4Dentry::base_remove] path: {fpath}"); let mut file = inode.file.lock(); if file.check_inode_exist(&fpath, InodeTypes::EXT4_DE_DIR) { // Recursive directory remove diff --git a/modules/memory/Cargo.toml b/modules/memory/Cargo.toml index 56f2352d..ec52f53c 100644 --- a/modules/memory/Cargo.toml +++ b/modules/memory/Cargo.toml @@ -9,6 +9,7 @@ edition = "2021" config = { path = "../../config/" } sync = { path = "../sync/" } arch = { path = "../../arch" } +early-print = { path = "../../crates/early-print/" } buddy_system_allocator = "0.9" linked_list_allocator = "0.10" diff --git a/modules/memory/src/heap.rs b/modules/memory/src/heap.rs index 7ccdaaff..3bb94239 100644 --- a/modules/memory/src/heap.rs +++ b/modules/memory/src/heap.rs @@ -1,11 +1,13 @@ //! The global allocator use core::{ + self, alloc::{GlobalAlloc, Layout}, ptr::NonNull, }; use buddy_system_allocator::Heap as BuddyHeap; use config::mm::KERNEL_HEAP_SIZE; +use early_print::early_println; #[cfg(all(feature = "linked", not(feature = "buddy")))] use linked_list_allocator::Heap as LinkedHeap; use sync::mutex::SpinNoIrqLock; @@ -20,12 +22,28 @@ type GlobalHeap = LockedLinkedHeap; static HEAP_ALLOCATOR: GlobalHeap = GlobalHeap::empty(); /// heap space +#[link_section = ".bss.heap"] static mut HEAP_SPACE: [u8; KERNEL_HEAP_SIZE] = [0; KERNEL_HEAP_SIZE]; /// Panic when heap allocation error occurs. #[alloc_error_handler] pub fn handle_alloc_error(layout: core::alloc::Layout) -> ! { - panic!("Heap allocation error, layout = {:?}", layout); + log::error!("heap alloc error"); + + let inner = HEAP_ALLOCATOR.0.lock(); + let alloc_user = inner.stats_alloc_user(); + let alloc_actual = inner.stats_alloc_actual(); + let total_bytes = inner.stats_total_bytes(); + + early_println!( + "Heap allocation error, layout = {:?}, alloc_user: {}, alloc_actual: {}, total_bytes: {}", + layout, + alloc_user, + alloc_actual, + total_bytes + ); + + panic!(); } struct LockedBuddyHeap(SpinNoIrqLock>); diff --git a/modules/page/src/buffer_cache.rs b/modules/page/src/buffer_cache.rs index 55644a31..4c843727 100644 --- a/modules/page/src/buffer_cache.rs +++ b/modules/page/src/buffer_cache.rs @@ -13,7 +13,7 @@ use config::{ board::BLOCK_SIZE, mm::{ block_page_id, is_aligned_to_block, BUFFER_NEED_CACHE_CNT, MAX_BUFFERS_PER_PAGE, - MAX_BUFFER_PAGES, PAGE_SIZE, + MAX_BUFFER_HEADS, MAX_BUFFER_PAGES, PAGE_SIZE, }, }; use device_core::BlockDriverOps; @@ -22,19 +22,21 @@ use lru::LruCache; use spin::Once; use sync::mutex::SpinNoIrqLock; -use crate::Page; +use crate::{Page, PageKind}; pub struct BufferCache { device: Option>, /// Block page id to `Page`. // NOTE: These `Page`s are pages without file, only exist for caching pure // block data. - pages: LruCache>, + pub pages: LruCache>, /// Block idx to `BufferHead`. + // TODO: add lru support, otherwise may occupy too much heap space // NOTE: Stores all accesses to block device. Some of them will be attached // to pages above, while others with file related will be attached to pages // stored in address space. - buffer_heads: BTreeMap>, + // PERF: perf issue will happen when lru cache is full + pub buffer_heads: LruCache>, } impl BufferCache { @@ -42,7 +44,7 @@ impl BufferCache { Self { device: None, pages: LruCache::new(NonZeroUsize::new(MAX_BUFFER_PAGES).unwrap()), - buffer_heads: BTreeMap::new(), + buffer_heads: LruCache::new(NonZeroUsize::new(MAX_BUFFER_HEADS).unwrap()), } } @@ -79,7 +81,7 @@ impl BufferCache { buffer_head.inc_acc_cnt(); // log::error!("acc cnt {}", buffer_head.acc_cnt()); if buffer_head.need_cache() && !buffer_head.has_cached() { - // log::error!("need cache"); + // log::error!("block id {block_id} need cache"); if let Some(page) = self.pages.get_mut(&block_page_id(block_id)) { // log::error!("has page"); device.base_read_block(block_id, page.block_bytes_array(block_id)); @@ -99,13 +101,20 @@ impl BufferCache { // {block_id}" ); let buffer_head = BufferHead::new_arc(block_id); buffer_head.inc_acc_cnt(); - self.buffer_heads.insert(block_id, buffer_head.clone()); + self.buffer_heads.push(block_id, buffer_head.clone()); buffer_head } } - pub fn get_buffer_head(&self, block_id: usize) -> Arc { - self.buffer_heads.get(&block_id).cloned().unwrap() + pub fn get_buffer_head_or_create(&mut self, block_id: usize) -> Arc { + // self.buffer_heads.get(&block_id).cloned().unwrap() + if let Some(buffer_head) = self.buffer_heads.get_mut(&block_id) { + buffer_head.clone() + } else { + let buffer_head = BufferHead::new_arc(block_id); + self.buffer_heads.push(block_id, buffer_head.clone()); + buffer_head + } } } @@ -158,10 +167,24 @@ impl BufferHead { pub fn init(&self, page: &Arc, offset: usize) { if self.has_cached() { log::error!( - "block id {} already cached, with acc_cnt {}", + "block id {} already cached, with acc_cnt {}, page kind {:?}", self.block_id, - self.acc_cnt() + self.acc_cnt(), + self.page().kind() ); + // only block cache can be transfered to file cache, e.g. a directory is mis + // recognized as block cache + assert!(self.page().kind().is_block_cache()); + assert!(page.kind().is_file_cache()); + match &self.page().kind() { + PageKind::BlockCache(inner) => { + let mut inner = inner.lock(); + let device = inner.device.upgrade().unwrap(); + device.remove_buffer_page(self.block_id); + // block page should be dropped here + } + _ => panic!(), + } } debug_assert!(is_aligned_to_block(offset) && offset < PAGE_SIZE); let mut inner = self.inner.lock(); diff --git a/modules/page/src/page.rs b/modules/page/src/page.rs index f981e2fc..3d5a56c7 100644 --- a/modules/page/src/page.rs +++ b/modules/page/src/page.rs @@ -23,13 +23,27 @@ pub enum PageKind { BlockCache(SpinNoIrqLock), } +impl core::fmt::Debug for PageKind { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("PageKind") + .field("kind", &{ + match self { + PageKind::Normal => "normal", + PageKind::FileCache(_) => "file cache", + PageKind::BlockCache(_) => "block cache", + } + }) + .finish() + } +} + pub struct Page { frame: FrameTracker, kind: PageKind, } pub struct BufferInfo { - device: Weak, + pub device: Weak, buffer_heads: LinkedList, buffer_head_cnts: usize, } diff --git a/modules/timer/src/timelimited_task.rs b/modules/timer/src/timelimited_task.rs index 0ad265ed..23e6fb2e 100644 --- a/modules/timer/src/timelimited_task.rs +++ b/modules/timer/src/timelimited_task.rs @@ -65,6 +65,10 @@ impl Future for IdleFuture { } } +pub async fn ksleep_s(sec: usize) { + TimeLimitedTaskFuture::new(Duration::from_secs(sec as u64), IdleFuture).await; +} + pub async fn ksleep_ms(msec: usize) { TimeLimitedTaskFuture::new(Duration::from_millis(msec as u64), IdleFuture).await; } diff --git a/modules/vfs-core/src/file.rs b/modules/vfs-core/src/file.rs index d2802e1e..8bfccd4e 100644 --- a/modules/vfs-core/src/file.rs +++ b/modules/vfs-core/src/file.rs @@ -72,7 +72,7 @@ pub trait File: Send + Sync + DowncastSync { todo!() } - /// Read a page at `offset_aligned` without address space. + /// Read a page at `offset_aligned` without page cache. async fn read_page_at(&self, offset_aligned: usize) -> SysResult>> { log::trace!("[File::read_page] read offset {offset_aligned}"); @@ -94,10 +94,10 @@ pub trait File: Send + Sync + DowncastSync { let virtio_blk = device .downcast_arc::() .unwrap_or_else(|_| unreachable!()); - let buffer_caches = virtio_blk.cache.lock(); + let mut buffer_caches = virtio_blk.cache.lock(); for offset in (offset_aligned..offset_aligned + len).step_by(BLOCK_SIZE) { let block_id = inode.get_blk_idx(offset)?; - let buffer_head = buffer_caches.get_buffer_head(block_id as usize); + let buffer_head = buffer_caches.get_buffer_head_or_create(block_id as usize); page.insert_buffer_head(buffer_head); } @@ -251,6 +251,19 @@ impl dyn File { Ok(offset_it - offset) } + pub async fn get_page_at(&self, offset_aligned: usize) -> SysResult>> { + let inode = self.inode(); + let page_cache = inode.page_cache().unwrap(); + if let Some(page) = page_cache.get_page(offset_aligned) { + Ok(Some(page)) + } else if let Some(page) = self.read_page_at(offset_aligned).await? { + Ok(Some(page)) + } else { + // no page means EOF + Ok(None) + } + } + /// Called by write(2) and related system calls. /// /// On success, the number of bytes written is returned, and the file offset @@ -301,7 +314,6 @@ impl dyn File { offset_it += len; buf_it = &buf_it[len..]; } - if offset_it > self.size() { log::warn!( "[File::write_at] write beyond file, offset_it:{offset_it}, size:{}", @@ -314,15 +326,18 @@ impl dyn File { let virtio_blk = device .downcast_arc::() .unwrap_or_else(|_| unreachable!()); - let buffer_caches = virtio_blk.cache.lock(); + let mut buffer_caches = virtio_blk.cache.lock(); for offset_aligned_page in (round_down_to_page(old_size)..new_size).step_by(PAGE_SIZE) { let page = page_cache.get_page(offset_aligned_page).unwrap(); for i in page.buffer_head_cnts()..MAX_BUFFERS_PER_PAGE { let offset_aligned_block = offset_aligned_page + i * BLOCK_SIZE; if offset_aligned_block < new_size { let blk_idx = inode.get_blk_idx(offset_aligned_block)?; - let buffer_head = buffer_caches.get_buffer_head(blk_idx); + log::debug!("offset {offset_aligned_block}, blk idx {blk_idx}"); + let buffer_head = buffer_caches.get_buffer_head_or_create(blk_idx); page.insert_buffer_head(buffer_head); + } else { + break; } } } diff --git a/modules/vfs-core/src/inode.rs b/modules/vfs-core/src/inode.rs index fc1f4d97..ff0f4471 100644 --- a/modules/vfs-core/src/inode.rs +++ b/modules/vfs-core/src/inode.rs @@ -152,7 +152,6 @@ impl_downcast!(sync Inode); pub enum InodeState { /// Init state, indicates that this inode is not loaded from disk yet. UnInit, - /// already sync Sync, Dirty, Removed, diff --git a/modules/vfs-core/src/super_block.rs b/modules/vfs-core/src/super_block.rs index efe6c335..db41cf1e 100644 --- a/modules/vfs-core/src/super_block.rs +++ b/modules/vfs-core/src/super_block.rs @@ -18,10 +18,6 @@ pub struct SuperBlockMeta { pub fs_type: Weak, /// Root dentry points to the mount point. pub root_dentry: Once>, - // /// All inodes. - // pub inodes: Mutex>>, - // /// All dirty inodes. - // pub dirty: Mutex>>, } impl SuperBlockMeta { diff --git a/modules/vfs/src/devfs/mod.rs b/modules/vfs/src/devfs/mod.rs index 8fe18cb0..6da6bd22 100644 --- a/modules/vfs/src/devfs/mod.rs +++ b/modules/vfs/src/devfs/mod.rs @@ -19,7 +19,6 @@ use crate::{ mod null; mod rtc; -pub mod stdio; pub mod tty; mod zero; diff --git a/modules/vfs/src/devfs/stdio.rs b/modules/vfs/src/devfs/stdio.rs deleted file mode 100644 index b33b4fe9..00000000 --- a/modules/vfs/src/devfs/stdio.rs +++ /dev/null @@ -1,130 +0,0 @@ -use alloc::{boxed::Box, sync::Arc}; - -use async_trait::async_trait; -use async_utils::yield_now; -use driver::{print, sbi::console_getchar}; -use systype::SyscallResult; -use vfs_core::{File, FileMeta, Inode, InodeMeta, InodeMode}; - -// TODO: This file has a lot to do - -pub struct StdOutInode { - meta: InodeMeta, -} - -pub struct StdOutFile { - meta: FileMeta, -} - -impl StdOutFile { - pub fn new() -> Arc { - let inode = Arc::new(StdOutInode { - meta: InodeMeta::new(InodeMode::CHAR, Arc::::new_zeroed(), 0), - }); - Arc::new(Self { - meta: FileMeta::new(Arc::::new_zeroed(), inode), - }) - } -} - -impl Inode for StdOutInode { - fn meta(&self) -> &vfs_core::InodeMeta { - &self.meta - } - - fn get_attr(&self) -> systype::SysResult { - todo!() - } -} - -#[async_trait] -impl File for StdOutFile { - fn meta(&self) -> &vfs_core::FileMeta { - &self.meta - } - - async fn base_read_at(&self, _offset: usize, _buf: &mut [u8]) -> SyscallResult { - todo!() - } - - async fn base_write_at(&self, _offset: usize, buf: &[u8]) -> SyscallResult { - if let Ok(data) = core::str::from_utf8(buf) { - print!("{}", data); - } else { - (0..buf.len()).for_each(|i| { - log::warn!("User stderr (non-utf8): {} ", buf[i]); - }); - } - Ok(buf.len()) - } - - fn base_read_dir(&self) -> systype::SysResult> { - todo!() - } - - fn flush(&self) -> systype::SysResult { - todo!() - } -} - -pub struct StdInInode { - meta: InodeMeta, -} - -pub struct StdInFile { - meta: FileMeta, -} - -impl StdInFile { - pub fn new() -> Arc { - let inode = Arc::new(StdInInode { - meta: InodeMeta::new(InodeMode::CHAR, Arc::::new_zeroed(), 0), - }); - Arc::new(Self { - meta: FileMeta::new(Arc::::new_zeroed(), inode.clone()), - }) - } -} - -impl Inode for StdInInode { - fn meta(&self) -> &InodeMeta { - &self.meta - } - - fn get_attr(&self) -> systype::SysResult { - todo!() - } -} - -#[async_trait] -impl File for StdInFile { - fn meta(&self) -> &FileMeta { - &self.meta - } - - async fn base_read_at(&self, _offset: usize, buf: &mut [u8]) -> systype::SysResult { - if buf.is_empty() { - return Ok(0); - } - let mut cnt = 0; - while cnt < buf.len() { - let c = console_getchar(); - buf[cnt] = c; - cnt += 1; - yield_now().await; - } - Ok(cnt) - } - - async fn base_write_at(&self, _offset: usize, _buf: &[u8]) -> systype::SysResult { - todo!() - } - - fn base_read_dir(&self) -> systype::SysResult> { - todo!() - } - - fn flush(&self) -> systype::SysResult { - todo!() - } -} diff --git a/modules/vfs/src/devfs/tty.rs b/modules/vfs/src/devfs/tty.rs index b89073b4..5ccc9984 100644 --- a/modules/vfs/src/devfs/tty.rs +++ b/modules/vfs/src/devfs/tty.rs @@ -4,7 +4,7 @@ use core::{cmp, ptr::drop_in_place}; use async_trait::async_trait; use async_utils::{block_on, get_waker, yield_now}; use device_core::{CharDevice, DeviceMajor}; -use driver::{get_device_manager, get_device_manager_mut, print, serial::Serial}; +use driver::{_print, get_device_manager, get_device_manager_mut, serial::Serial}; use ringbuffer::{AllocRingBuffer, RingBuffer}; use spin::Once; use strum::FromRepr; @@ -222,13 +222,6 @@ impl File for TtyFile { } async fn base_write_at(&self, _offset: usize, buf: &[u8]) -> SyscallResult { - let utf8_buf: Vec = buf.iter().filter(|c| c.is_ascii()).map(|c| *c).collect(); - // if PRINT_LOCKED { - // let _locked = PRINT_MUTEX.lock().await; - // print!("{}", unsafe { core::str::from_utf8_unchecked(&utf8_buf) }); - // } else { - // print!("{}", unsafe { core::str::from_utf8_unchecked(&utf8_buf) }); - // } let char_dev = &self .inode() .downcast_arc::() diff --git a/modules/vfs/src/fd_table.rs b/modules/vfs/src/fd_table.rs index d5a33258..6bf156ac 100644 --- a/modules/vfs/src/fd_table.rs +++ b/modules/vfs/src/fd_table.rs @@ -7,7 +7,7 @@ use config::fs::MAX_FD_NUM; use systype::{RLimit, SysError, SysResult}; use vfs_core::{File, OpenFlags}; -use crate::devfs::{stdio, tty::TTY}; +use crate::devfs::tty::TTY; pub type Fd = usize; @@ -30,7 +30,6 @@ impl From for FdFlags { if value.contains(OpenFlags::O_CLOEXEC) { FdFlags::CLOEXEC } else { - log::warn!("[FdFlags::from] unsupported flag"); FdFlags::empty() } } diff --git a/user/src/bin/runtestcase.rs b/user/src/bin/final_tests.rs similarity index 63% rename from user/src/bin/runtestcase.rs rename to user/src/bin/final_tests.rs index 364c965c..5bbb99be 100644 --- a/user/src/bin/runtestcase.rs +++ b/user/src/bin/final_tests.rs @@ -10,26 +10,15 @@ use user_lib::{execve, fork, wait, waitpid}; #[macro_use] extern crate user_lib; -// const TESTCASES: [&str; 0] = []; - -const TESTCASES: [&str; 17] = [ - "cyclictest_testcode.sh", +const TESTCASES: [&str; 8] = [ "busybox_testcode.sh", + "lua_testcode.sh", "time-test", + "libc-bench", "libctest_testcode.sh", "lmbench_testcode.sh", - "lua_testcode.sh", "iozone_testcode.sh", - "libc-bench", "unixbench_testcode.sh", - "netperf_testcode.sh", - "iperf_testcode.sh", - "interrupts-test-1", - "interrupts-test-2", - "copy-file-range-test-1", - "copy-file-range-test-2", - "copy-file-range-test-3", - "copy-file-range-test-4", ]; #[no_mangle] @@ -42,7 +31,12 @@ fn main() -> i32 { if execve( &testname, &[testname.as_ptr(), core::ptr::null::()], - &[core::ptr::null::()], + &[ + "PATH=/:/bin:/sbin:/usr/bin:/usr/local/bin:/usr/local/sbin:\0".as_ptr(), + "LD_LIBRARY_PATH=/:/lib:/lib64/lp64d:/usr/lib:/usr/local/lib:\0".as_ptr(), + "TERM=screen\0".as_ptr(), + core::ptr::null::(), + ], ) != 0 { println!("Error when executing!"); @@ -53,15 +47,13 @@ fn main() -> i32 { waitpid(pid as usize, &mut exit_code); } } - println!(" !TEST FINISH! "); } else { loop { let mut exit_code: i32 = 0; - let _pid = wait(&mut exit_code); - // println!( - // "[initproc] Released a zombie process, pid={}, exit_code={}", - // pid, exit_code, - // ); + let pid = wait(&mut exit_code); + if pid < 0 { + break; + } } } 0 diff --git a/user/src/lib.rs b/user/src/lib.rs index ed1e9c1c..f4d92e6d 100644 --- a/user/src/lib.rs +++ b/user/src/lib.rs @@ -179,7 +179,7 @@ pub fn waitpid(pid: usize, exit_code: &mut i32) -> isize { } pub fn pipe(pipe_fd: &mut [i32]) -> isize { - sys_pipe(pipe_fd.()) + sys_pipe(pipe_fd[0] as *mut _) } pub fn close(fd: usize) -> isize {