diff --git a/README.md b/README.md index a5514c8..87ccf86 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ > **NOTE** > -> *This project is at an extremely early stage of development — almost nothing has been implemented yet, and everything is immature. The README.md was also written by AI; it looks impressive but actual functionality is far from complete. Please do not take this early, rough project too seriously. I will update this notice myself once a stable release is ready.* +> *{Intro:Multi-architecture(now only riscv64gc on qemu-virt first, do it bad first, then reconstruct later) toykernel, with "framekernel" target inspired by "Asterinas",with an "Alpine-like" userland target(musl + BusyBox).}This project is at an extremely early stage of development — almost nothing has been implemented yet, and everything is immature. The README.md was also written by AI; it looks impressive but actual functionality is far from complete. Please do not take this early, rough project too seriously. I will update this notice myself once a stable release is ready.* # racho diff --git a/framework/build.rs b/framework/build.rs new file mode 100644 index 0000000..7d99f04 --- /dev/null +++ b/framework/build.rs @@ -0,0 +1,61 @@ +use std::fs::{File, read_dir}; +use std::io::{Result, Write}; +use std::path::PathBuf; + +fn main() { + let manifest_dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()); + let target_dir = manifest_dir + .parent() + .unwrap() + .join("target") + .join("riscv64gc-unknown-none-elf") + .join("release"); + + let target_path = target_dir.to_string_lossy().into_owned(); + insert_app_data(&target_path).unwrap(); +} + +fn insert_app_data(target_path: &str) -> Result<()> { + let mut f = File::create("src/link_app.S").unwrap(); + let mut apps: Vec<_> = read_dir("../user_lib/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 + }) + .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)?; + + for (idx, app) in apps.iter().enumerate() { + println!("app_{}: {}", idx, app); + writeln!( + f, + r#" + .section .data + .global app_{0}_start + .global app_{0}_end + app_{0}_start: + .incbin "{1}/{2}" + app_{0}_end:"#, + idx, target_path, app + )?; + } + Ok(()) +} diff --git a/kernel/src/linker-qemu.ld b/framework/linker-qemu.ld similarity index 84% rename from kernel/src/linker-qemu.ld rename to framework/linker-qemu.ld index 93bbc37..ec094d0 100644 --- a/kernel/src/linker-qemu.ld +++ b/framework/linker-qemu.ld @@ -33,6 +33,13 @@ SECTIONS *(.sdata .sdata.*) } + . = ALIGN(8); + .init_array : { + __init_array_start = .; + KEEP(*(.init_array .init_array.*)) + __init_array_end = .; + } + . = ALIGN(4K); edata = .; sbss_with_stack = .; diff --git a/framework/src/boot.rs b/framework/src/boot.rs index e640830..da7f2e5 100644 --- a/framework/src/boot.rs +++ b/framework/src/boot.rs @@ -11,6 +11,9 @@ unsafe extern "C" { fn sbss_with_stack(); fn ekernel(); fn strampoline(); + fn _num_app(); + fn __alltraps(); + fn __restore(); } pub fn clear_bss() { @@ -41,3 +44,76 @@ define_addr_getter!(ebss_addr, ebss); define_addr_getter!(sbss_with_stack_addr, sbss_with_stack); define_addr_getter!(ekernel_addr, ekernel); define_addr_getter!(strampoline_addr, strampoline); + +pub fn get_num_app() -> usize { + unsafe { (_num_app as *const () as *const usize).read_volatile() } +} + +pub fn get_app_data(app_id: usize) -> &'static [u8] { + let num_app = get_num_app(); + let num_app_ptr = _num_app as *const () as *const usize; + 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 alltraps_addr() -> usize { + __alltraps as *const () as usize +} + +pub fn restore_addr() -> usize { + __restore as *const () as usize +} + +pub trait Kernel { + fn main() -> !; +} + +pub fn boot() -> ! { + clear_bss(); + K::main() +} + +#[macro_export] +macro_rules! register_kernel { + ($kernel:ty) => { + #[used] + #[unsafe(link_section = ".init_array")] + static _FRAMEWORK_BOOT_KERNEL: unsafe extern "C" fn() = { + unsafe extern "C" fn __framework_boot() { + $crate::boot::<$kernel>(); + } + __framework_boot + }; + }; +} + +#[unsafe(no_mangle)] +pub fn rust_main() -> ! { + clear_bss(); + execute_init_array(); + panic!("No kernel entry registered in .init_array"); +} + +unsafe extern "C" { + fn __init_array_start(); + fn __init_array_end(); +} + +fn execute_init_array() { + let start = __init_array_start as *const () as *const usize; + let end = __init_array_end as *const () as *const usize; + let count = (end as usize - start as usize) / size_of::(); + for i in 0..count { + let func: unsafe extern "C" fn() = + unsafe { core::mem::transmute(*start.add(i)) }; + unsafe { + func(); + } + } +} diff --git a/kernel/src/entry.asm b/framework/src/entry.asm similarity index 100% rename from kernel/src/entry.asm rename to framework/src/entry.asm diff --git a/framework/src/lib.rs b/framework/src/lib.rs index aa5ac85..18f3a2a 100644 --- a/framework/src/lib.rs +++ b/framework/src/lib.rs @@ -1,14 +1,26 @@ #![no_std] + +use core::arch::global_asm; + +global_asm!(include_str!("entry.asm")); +global_asm!(include_str!("link_app.S")); +global_asm!(include_str!("trap/trap.S")); + mod boot; mod memory; +mod sync; +mod task; mod trap; pub use boot::{ - clear_bss, ebss_addr, edata_addr, ekernel_addr, erodata_addr, etext_addr, sbss_addr, - sbss_with_stack_addr, sdata_addr, skernel_addr, srodata_addr, stext_addr, strampoline_addr, + Kernel, alltraps_addr, boot, clear_bss, ebss_addr, edata_addr, ekernel_addr, erodata_addr, + etext_addr, get_app_data, get_num_app, restore_addr, sbss_addr, sbss_with_stack_addr, + sdata_addr, skernel_addr, srodata_addr, stext_addr, strampoline_addr, }; pub use memory::{ - KERNEL_HEAP_SIZE, heap_region, init_heap_allocator, phys_to_byte_slice, phys_to_ref, - phys_to_slice, sfence_vma, write_satp, + KERNEL_HEAP_SIZE, fence_i, heap_region, init_heap_allocator, phys_to_byte_slice, phys_to_ref, + phys_to_slice, sfence_vma, write_satp, zero_memory, }; -pub use trap::{set_sie_enable_stimer, set_stvec}; +pub use sync::UPSafeCell; +pub use task::{TaskContext, context_switch}; +pub use trap::{restore_to_user, set_sie_enable_stimer, set_stvec}; diff --git a/framework/src/link_app.S b/framework/src/link_app.S new file mode 100644 index 0000000..6fadbf3 --- /dev/null +++ b/framework/src/link_app.S @@ -0,0 +1,39 @@ + + .align 3 + .section .data + .global _num_app + _num_app: + .quad 4 + .quad app_0_start + .quad app_1_start + .quad app_2_start + .quad app_3_start + .quad app_3_end + + .section .data + .global app_0_start + .global app_0_end + app_0_start: + .incbin "/home/shyweeds/Projects/racho/target/riscv64gc-unknown-none-elf/release/00power_3" + app_0_end: + + .section .data + .global app_1_start + .global app_1_end + app_1_start: + .incbin "/home/shyweeds/Projects/racho/target/riscv64gc-unknown-none-elf/release/01power_5" + app_1_end: + + .section .data + .global app_2_start + .global app_2_end + app_2_start: + .incbin "/home/shyweeds/Projects/racho/target/riscv64gc-unknown-none-elf/release/02power_7" + app_2_end: + + .section .data + .global app_3_start + .global app_3_end + app_3_start: + .incbin "/home/shyweeds/Projects/racho/target/riscv64gc-unknown-none-elf/release/03sleep" + app_3_end: diff --git a/framework/src/memory.rs b/framework/src/memory.rs index 8d25626..bf7cc69 100644 --- a/framework/src/memory.rs +++ b/framework/src/memory.rs @@ -41,3 +41,17 @@ pub fn sfence_vma() { asm!("sfence.vma"); } } + +pub fn zero_memory(phys_addr: usize, len: usize) { + for addr in phys_addr..phys_addr + len { + unsafe { + (addr as *mut u8).write_volatile(0); + } + } +} + +pub fn fence_i() { + unsafe { + asm!("fence.i"); + } +} diff --git a/kernel/src/sync/up.rs b/framework/src/sync.rs similarity index 50% rename from kernel/src/sync/up.rs rename to framework/src/sync.rs index cc31f37..4c324e2 100644 --- a/kernel/src/sync/up.rs +++ b/framework/src/sync.rs @@ -1,5 +1,4 @@ -//! Uniprocessor interior mutability primitives - +//! only guaranteed in uniprocessor env use core::cell::{RefCell, RefMut}; pub struct UPSafeCell { @@ -9,14 +8,13 @@ pub struct UPSafeCell { unsafe impl Sync for UPSafeCell {} impl UPSafeCell { - /// User is responsible to guarantee that inner struct is only used in - /// uniprocessor. - pub unsafe fn new(value: T) -> Self { + /// only used in the uniprocessor please + pub fn new(val: T) -> Self { Self { - inner: RefCell::new(value), + inner: RefCell::new(val), } } - /// Exclusive access inner data in UPSafeCell. Panic if the data has been borrowed + /// exclusive access inner data in UPSafeCell. Panic if the data has been borrowed pub fn exclusive_access(&self) -> RefMut<'_, T> { self.inner.borrow_mut() } diff --git a/framework/src/task.rs b/framework/src/task.rs new file mode 100644 index 0000000..b60fdc1 --- /dev/null +++ b/framework/src/task.rs @@ -0,0 +1,17 @@ +mod context; + +pub use context::TaskContext; +use core::arch::global_asm; + +global_asm!(include_str!("task/switch.S")); + +unsafe extern "C" { + unsafe fn __switch(current_taskcx_ptr: *mut (), next_taskcx_ptr: *const ()); +} + +// in the core of framework, we can never depend on structs in kernel, or it will be a mess +pub fn context_switch(current_taskcx_ptr: *mut TaskContext, next_taskcx_ptr: *const TaskContext) { + unsafe { + __switch(current_taskcx_ptr as *mut (), next_taskcx_ptr as *const ()); + } +} diff --git a/kernel/src/task/context.rs b/framework/src/task/context.rs similarity index 65% rename from kernel/src/task/context.rs rename to framework/src/task/context.rs index 87ac8a9..d13dd70 100644 --- a/kernel/src/task/context.rs +++ b/framework/src/task/context.rs @@ -1,7 +1,5 @@ //! Implementation of [`TaskContext`] -use crate::trap::trap_return; - /// Task Context #[derive(Copy, Clone)] #[repr(C)] @@ -25,10 +23,17 @@ impl TaskContext { } /// set Task Context{__restore ASM function: trap_return, sp: kstack_ptr, s: s_0..12} - pub fn goto_trap_return(kstack_ptr: usize) -> Self { + // pub fn goto_trap_return(kstack_ptr: usize) -> Self { + // Self { + // ra: trap_return as *const () as usize, + // sp: kstack_ptr, + // s: [0; 12], + // } + // } + pub fn new(return_addr: usize, kernel_sp: usize) -> Self { Self { - ra: trap_return as *const () as usize, - sp: kstack_ptr, + ra: return_addr, + sp: kernel_sp, s: [0; 12], } } diff --git a/kernel/src/task/switch.S b/framework/src/task/switch.S similarity index 100% rename from kernel/src/task/switch.S rename to framework/src/task/switch.S diff --git a/framework/src/trap.rs b/framework/src/trap.rs index 5153340..96a0af0 100644 --- a/framework/src/trap.rs +++ b/framework/src/trap.rs @@ -1,7 +1,9 @@ +use core::arch::asm; use riscv::{ self, register::{sie, stvec, utvec::TrapMode}, }; + pub fn set_stvec(addr: usize, mode: TrapMode) { unsafe { stvec::write(addr, mode); @@ -12,3 +14,19 @@ pub fn set_sie_enable_stimer() { sie::set_stimer(); } } + +pub fn restore_to_user(trap_cx_ptr: usize, user_satp: usize, trampoline_base: usize) -> ! { + let alltraps = crate::boot::alltraps_addr(); + let restore = crate::boot::restore_addr(); + let restore_va = restore - alltraps + trampoline_base; + unsafe { + asm!( + "fence.i", + "jr {restore_va}", + restore_va = in(reg) restore_va, + in("a0") trap_cx_ptr, + in("a1") user_satp, + options(noreturn) + ); + } +} diff --git a/kernel/src/trap/trap.S b/framework/src/trap/trap.S similarity index 100% rename from kernel/src/trap/trap.S rename to framework/src/trap/trap.S diff --git a/kernel/build.rs b/kernel/build.rs index 3bb255b..aa37a57 100644 --- a/kernel/build.rs +++ b/kernel/build.rs @@ -1,9 +1,11 @@ -use std::fs::{File, read_dir}; -use std::io::{Result, Write}; use std::path::PathBuf; fn main() { - println!("cargo:rustc-link-arg=-Tkernel/src/linker-qemu.ld"); + let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); + println!( + "cargo:rustc-link-arg=-T{}/../framework/linker-qemu.ld", + manifest_dir + ); println!("cargo:rerun-if-changed=../user_lib/src/"); let manifest_dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()); @@ -16,51 +18,4 @@ fn main() { let target_path = target_dir.to_string_lossy().into_owned(); println!("cargo:rerun-if-changed={}", target_path); - - insert_app_data(&target_path).unwrap(); -} - -fn insert_app_data(target_path: &str) -> Result<()> { - let mut f = File::create("src/link_app.S").unwrap(); - let mut apps: Vec<_> = read_dir("../user_lib/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 - }) - .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)?; - - for (idx, app) in apps.iter().enumerate() { - println!("app_{}: {}", idx, app); - writeln!( - f, - r#" - .section .data - .global app_{0}_start - .global app_{0}_end - app_{0}_start: - .incbin "{1}/{2}" - app_{0}_end:"#, - idx, target_path, app - )?; - } - Ok(()) } diff --git a/kernel/src/loader.rs b/kernel/src/loader.rs index 3858e81..6d553bb 100644 --- a/kernel/src/loader.rs +++ b/kernel/src/loader.rs @@ -1,5 +1,3 @@ -use core::arch::asm; - use crate::config::*; use crate::trap::TrapContext; @@ -29,9 +27,7 @@ impl KernelStack { } pub fn push_context(&self, trap_cx: TrapContext) -> usize { let trap_cx_ptr = (self.get_sp() - size_of::()) as *mut TrapContext; - unsafe { - *trap_cx_ptr = trap_cx; - } + *framework::phys_to_ref(trap_cx_ptr as usize) = trap_cx; trap_cx_ptr as usize } } @@ -43,10 +39,7 @@ impl UserStack { /// get total number of the application pub fn get_num_app() -> usize { - unsafe extern "C" { - safe fn _num_app(); - } - unsafe { (_num_app as *const usize).read_volatile() } + framework::get_num_app() } /// Get the base address of the i-th application @@ -57,54 +50,18 @@ pub fn get_base_i(app_id: usize) -> usize { /// Load the user app at /// [APP_BASE_ADDRESS + n * APP_SIZE_LIMIT, APP_BASE_ADDRESS + (n + 1) * APP_SIZE_LIMIT]). pub fn load_apps() { - unsafe extern "C" { - safe fn _num_app(); - } let num_app = get_num_app(); - let num_app_ptr = _num_app as *const usize; - let app_start = unsafe { core::slice::from_raw_parts(num_app_ptr.add(1), num_app + 1) }; - // load apps for i in 0..num_app { let base_i = get_base_i(i); - // Clear the memory region where the app will be loaded - for addr in base_i..(base_i + APP_SIZE_LIMIT) { - unsafe { - (addr as *mut u8).write_volatile(0); - } - } - // load app from data section to memory - let src = unsafe { - core::slice::from_raw_parts(app_start[i] as *const u8, app_start[i + 1] - app_start[i]) - }; - let dst = unsafe { core::slice::from_raw_parts_mut(base_i as *mut u8, src.len()) }; - dst.copy_from_slice(src); - // Memory fence about fetching the instruction memory - // It is guaranteed that a subsequent instruction fetch must - // observes all previous writes to the instruction memory. - // Therefore, fence.i must be executed after we have loaded - // the code of the next app into the instruction memory. - // See also: riscv non-priv spec chapter 3, 'Zifencei' extension. - unsafe { - asm!("fence.i"); - } + framework::zero_memory(base_i, APP_SIZE_LIMIT); + let app_data = framework::get_app_data(i); + let dst = framework::phys_to_byte_slice(base_i, app_data.len()); + dst.copy_from_slice(app_data); + framework::fence_i(); } } /// Get application data (raw ELF bytes) pub fn get_app_data(app_id: usize) -> &'static [u8] { - unsafe extern "C" { - safe fn _num_app(); - } - let num_app_ptr = _num_app as *const () as *const usize; - let num_app = get_num_app(); - // .add(1) skips the first metadata element (which stores the app count); - // subsequent elements are base addresses of each 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], - ) - } + framework::get_app_data(app_id) } diff --git a/kernel/src/logging.rs b/kernel/src/logging.rs index da25c7b..62fbcef 100644 --- a/kernel/src/logging.rs +++ b/kernel/src/logging.rs @@ -44,5 +44,4 @@ pub fn init() { info!("[kernel test01] info log test!"); debug!("[kernel test01] debug log test!"); trace!("[kernel test01] trace log test!"); - info!("[kernel test01] log init finished!(check if the above looks ok)"); } diff --git a/kernel/src/main.rs b/kernel/src/main.rs index 38b80da..716d859 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -14,52 +14,24 @@ mod loader; mod logging; mod mm; mod sbi; -mod sync; mod timer; +mod trap; pub mod syscall; pub mod task; -pub mod trap; -use core::arch::global_asm; -use framework::clear_bss; -use log::*; - -global_asm!(include_str!("entry.asm")); -global_asm!(include_str!("link_app.S")); - -#[allow(unused)] -fn heap_test() { - use alloc::boxed::Box; - use alloc::vec::Vec; - - let bss_range = framework::sbss_addr()..framework::ebss_addr(); - let a = Box::new(5); - assert_eq!(*a, 5); - assert!(bss_range.contains(&(a.as_ref() as *const _ as *const () as usize))); - drop(a); - let mut v: Vec = Vec::new(); - for i in 0..500 { - v.push(i); +struct RachoKernel; + +impl framework::Kernel for RachoKernel { + fn main() -> ! { + logging::init(); + mm::init(); + trap::init(); + trap::enable_timer_interrupt(); + timer::set_next_trigger(); + task::run_first_task(); + panic!("Unreachable in main!"); } - for i in 0..500 { - assert_eq!(v[i], i); - } - assert!(bss_range.contains(&(v.as_ptr() as *const _ as *const () as usize))); - drop(v); - info!("[kernel test02] heap init test passed!"); } -#[unsafe(no_mangle)] -pub fn rust_main() -> ! { - clear_bss(); - logging::init(); - mm::init(); - // NOTE: finished removed (only necessary unsafe in framework) all the unsafe in the "mm::init" - // TODO: 7.22 remove necessary(minimal) unsafe to framework in trap::init(); - trap::init(); // NOTE: ToSafeRust: ok! - trap::enable_timer_interrupt(); // NOTE: ToSafeRust: ok! - timer::set_next_trigger(); // NOTE: ToSafeRust: ok! - task::run_first_task(); - panic!("Unreachable in rust_main!"); -} +framework::register_kernel!(RachoKernel); diff --git a/kernel/src/mm.rs b/kernel/src/mm.rs index 946e210..8e470f2 100644 --- a/kernel/src/mm.rs +++ b/kernel/src/mm.rs @@ -18,7 +18,25 @@ pub use heap_allocator::init_heap; pub use memory_set::{KERNEL_SPACE, MapPermission, MemorySet}; pub use page_table::translate_byte_buffer; -use crate::heap_test; +pub fn heap_test() { + use alloc::boxed::Box; + use alloc::vec::Vec; + + let bss_range = framework::sbss_addr()..framework::ebss_addr(); + let a = Box::new(5); + assert_eq!(*a, 5); + assert!(bss_range.contains(&(a.as_ref() as *const _ as *const () as usize))); + drop(a); + let mut v: Vec = Vec::new(); + for i in 0..500 { + v.push(i); + } + for i in 0..500 { + assert_eq!(v[i], i); + } + assert!(bss_range.contains(&(v.as_ptr() as *const _ as *const () as usize))); + drop(v); +} /// initiate the heap allocator, frame allocator and kernel space pub fn init() { diff --git a/kernel/src/mm/frame_allocator.rs b/kernel/src/mm/frame_allocator.rs index b9f0fbc..ef5f7c0 100644 --- a/kernel/src/mm/frame_allocator.rs +++ b/kernel/src/mm/frame_allocator.rs @@ -2,10 +2,9 @@ use core::fmt::{self, Debug, Formatter}; use crate::boards::MEMORY_END; use crate::mm::address::{PhysAddr, PhysPageNum}; -use crate::sync::UPSafeCell; use alloc::vec::Vec; +use framework::UPSafeCell; use lazy_static::lazy_static; -use log::info; /// manage a frame which has the same lifecycle as the tracker /// Uses RAII: the lifecycle of a PhysPageNum is bound to a FrameTracker @@ -99,7 +98,7 @@ impl FrameAllocator for StackFrameAllocator { type FrameAllocatorImpl = StackFrameAllocator; lazy_static! { pub static ref FRAME_ALLOCATOR: UPSafeCell = - unsafe { UPSafeCell::new(FrameAllocatorImpl::new()) }; + UPSafeCell::new(FrameAllocatorImpl::new()); } // We wrap the stack-based frame allocator in a UPSafeCell. Before any @@ -134,7 +133,6 @@ fn frame_dealloc(ppn: PhysPageNum) { #[allow(unused)] /// a simple test for frame allocator pub fn frame_allocator_test() { - info!("[kernel test03] frame allocator init test ..."); let mut v: Vec = Vec::new(); for i in 0..5 { let frame = frame_alloc().unwrap(); @@ -148,5 +146,4 @@ pub fn frame_allocator_test() { v.push(frame); } drop(v); - info!("[kernel test03] frame allocator init test ok!"); } diff --git a/kernel/src/mm/memory_set.rs b/kernel/src/mm/memory_set.rs index 9205203..1baee12 100644 --- a/kernel/src/mm/memory_set.rs +++ b/kernel/src/mm/memory_set.rs @@ -1,19 +1,17 @@ use alloc::collections::btree_map::BTreeMap; -use alloc::vec::Vec; use alloc::sync::Arc; +use alloc::vec::Vec; use bitflags::bitflags; use lazy_static::lazy_static; -use log::info; lazy_static! { /// Create the global kernel address space instance - pub static ref KERNEL_SPACE: Arc> = Arc::new(unsafe{ - UPSafeCell::new(MemorySet::new_kernel()) - }); + pub static ref KERNEL_SPACE: Arc> = Arc::new( + framework::UPSafeCell::new(MemorySet::new_kernel()) + ); } use crate::mm::page_table::PageTableEntry; -use crate::sync::UPSafeCell; use crate::{ boards::{MEMORY_END, MMIO}, config::{PAGE_SIZE, TRAMPOLINE, TRAP_CONTEXT, USER_STACK_SIZE}, @@ -166,26 +164,29 @@ impl MemorySet { // NOTE: new_kernel() implementation completed on 6.29 // Build the kernel's address space pub fn new_kernel() -> Self { - info!("[kernel test03] KERNEL_SPACE init ..."); let mut memory_set = Self::new_bare(); // map trampoline memory_set.map_trampoline(); // map kernel sections println!( ".text [{:#x}, {:#x})", - framework::stext_addr(), framework::etext_addr() + framework::stext_addr(), + framework::etext_addr() ); println!( ".rodata [{:#x}, {:#x})", - framework::srodata_addr(), framework::erodata_addr() + framework::srodata_addr(), + framework::erodata_addr() ); println!( ".data [{:#x}, {:#x})", - framework::sdata_addr(), framework::edata_addr() + framework::sdata_addr(), + framework::edata_addr() ); println!( ".bss [{:#x}, {:#x})", - framework::sbss_with_stack_addr(), framework::ebss_addr() + framework::sbss_with_stack_addr(), + framework::ebss_addr() ); println!("mapping .text section"); memory_set.push( @@ -249,7 +250,6 @@ impl MemorySet { None, ); } - info!("[kernel test03] KERNEL_SPACE init ok!"); memory_set } // TODO: 6.30 add nothing @@ -338,11 +338,9 @@ impl MemorySet { } // Activate the address space management pub fn active(&self) { - info!("[kernel notice] enable virtual memory ...!"); let satp = self.page_table.token(); framework::write_satp(satp); framework::sfence_vma(); - info!("[kernel notice] enable virtual memory ok!"); } pub fn translate(&self, vpn: VirtPageNum) -> Option { self.page_table.translate(vpn) @@ -354,12 +352,10 @@ impl MemorySet { #[allow(unused)] pub fn remap_test() { let mut kernel_space = KERNEL_SPACE.exclusive_access(); - let mid_text: VirtAddr = - ((framework::stext_addr() + framework::etext_addr()) / 2).into(); + let mid_text: VirtAddr = ((framework::stext_addr() + framework::etext_addr()) / 2).into(); let mid_rodata: VirtAddr = ((framework::srodata_addr() + framework::erodata_addr()) / 2).into(); - let mid_data: VirtAddr = - ((framework::sdata_addr() + framework::edata_addr()) / 2).into(); + let mid_data: VirtAddr = ((framework::sdata_addr() + framework::edata_addr()) / 2).into(); assert!( !kernel_space .page_table diff --git a/kernel/src/sync.rs b/kernel/src/sync.rs deleted file mode 100644 index 1ccdd2e..0000000 --- a/kernel/src/sync.rs +++ /dev/null @@ -1,4 +0,0 @@ -//! Synchronization and interior mutability primitives - -mod up; -pub use up::UPSafeCell; diff --git a/kernel/src/task.rs b/kernel/src/task.rs index b87db94..fc400d0 100644 --- a/kernel/src/task.rs +++ b/kernel/src/task.rs @@ -1,21 +1,78 @@ use alloc::vec::Vec; use lazy_static::*; -use crate::info; +use crate::config::TRAP_CONTEXT; +use crate::config::kernel_stack_position; use crate::loader::get_app_data; use crate::loader::get_num_app; +use crate::mm::KERNEL_SPACE; +use crate::mm::MapPermission; +use crate::mm::MemorySet; +use crate::mm::PhysPageNum; +use crate::mm::VirtAddr; use crate::sbi::shutdown; -use crate::sync::UPSafeCell; use crate::trap::TrapContext; +use crate::trap::trap_handler; +use crate::trap::trap_return; +use framework::UPSafeCell; +use framework::{TaskContext, context_switch}; + +#[derive(Copy, Clone, PartialEq)] +/// task status: UnInit, Ready, Running, Exited +pub enum TaskStatus { + UnInit, + Ready, + Running, + Exited, +} -mod context; -mod switch; -mod task; +/// task contrl block structure +pub struct TaskControlBlock { + pub task_status: TaskStatus, + pub task_cx: TaskContext, + pub memory_set: MemorySet, + pub trap_cx_ppn: PhysPageNum, + pub base_size: usize, +} -use crate::task::context::TaskContext; -use crate::task::switch::__switch; -use crate::task::task::TaskControlBlock; -use crate::task::task::TaskStatus; +impl TaskControlBlock { + pub fn new(elf_data: &[u8], app_id: usize) -> Self { + let (memory_set, user_sp, entry_point) = MemorySet::from_elf(elf_data); + let trap_cx_ppn = memory_set + .translate(VirtAddr::from(TRAP_CONTEXT).into()) + .unwrap() + .ppn(); + let task_status = TaskStatus::Ready; + let (kernel_stack_bottom, kernel_stack_top) = kernel_stack_position(app_id); + KERNEL_SPACE.exclusive_access().insert_framed_area( + kernel_stack_bottom.into(), + kernel_stack_top.into(), + MapPermission::R | MapPermission::W, + ); + let task_control_block = Self { + task_status, + task_cx: TaskContext::new(trap_return as *const () as usize, kernel_stack_top), + memory_set, + trap_cx_ppn, + base_size: user_sp, + }; + let trap_cx = task_control_block.get_trap_cx(); + *trap_cx = TrapContext::app_init_context( + entry_point, + user_sp, + KERNEL_SPACE.exclusive_access().token(), + kernel_stack_top, + trap_handler as *const () as usize, + ); + task_control_block + } + pub fn get_user_token(&self) -> usize { + self.memory_set.token() + } + pub fn get_trap_cx(&self) -> &'static mut TrapContext { + self.trap_cx_ppn.get_mut() + } +} pub struct TaskManagerInner { tasks: Vec, @@ -29,22 +86,18 @@ pub struct TaskManager { lazy_static! { pub static ref TASK_MANAGER: TaskManager = { - info!("[kernel test07] init TASK_MANAGER ...!"); let num_app = get_num_app(); println!("num_app = {}", num_app); let mut tasks: Vec = Vec::new(); for i in 0..num_app { tasks.push(TaskControlBlock::new(get_app_data(i), i)); } - info!("[kernel test07] init TASK_MANAGER ok!"); TaskManager { num_app, - inner: unsafe { - UPSafeCell::new(TaskManagerInner { - tasks, - current_task: 0, - }) - }, + inner: UPSafeCell::new(TaskManagerInner { + tasks, + current_task: 0, + }), } }; } @@ -55,15 +108,10 @@ impl TaskManager { let task0 = &mut inner.tasks[0]; task0.task_status = TaskStatus::Running; let next_task_cx_ptr = &task0.task_cx as *const TaskContext; + let fake_task_context = &mut TaskContext::zero_init() as *mut TaskContext; drop(inner); - let mut fake_task_context = TaskContext::zero_init(); - - info!("[kernel test08] use 'switch.S' to load the first task's context ...!"); - unsafe { - __switch(&mut fake_task_context as *mut TaskContext, next_task_cx_ptr); - } - + context_switch(fake_task_context, next_task_cx_ptr); panic!("unreachable in run_first_task") } @@ -96,14 +144,8 @@ impl TaskManager { let current_task_cx_ptr = &mut inner.tasks[current].task_cx as *mut TaskContext; let next_task_cx_ptr = &inner.tasks[next].task_cx as *const TaskContext; drop(inner); - info!( - "[kernel notice] run_next_task(): next task exist!Use __switch(task a, task b) to switch task!" - ); - unsafe { - __switch(current_task_cx_ptr, next_task_cx_ptr); - } + context_switch(current_task_cx_ptr, next_task_cx_ptr); } else { - info!("[kernel notice] next task not exists! All applications completed! shutdown!"); shutdown(false); } } diff --git a/kernel/src/task/switch.rs b/kernel/src/task/switch.rs deleted file mode 100644 index b1c2854..0000000 --- a/kernel/src/task/switch.rs +++ /dev/null @@ -1,17 +0,0 @@ -//! Rust wrapper around `__switch` -//! -//! Switching to a different task's context actually happens here! - -use super::TaskContext; -use core::arch::global_asm; - -global_asm!(include_str!("switch.S")); - -unsafe extern "C" { - /// Switching to the context of `next_task_cx_ptr`, - /// saving the current context in `current_task_cx_ptr`. - pub unsafe fn __switch( - current_task_cx_ptr: *mut TaskContext, - next_task_cx_ptr: *const TaskContext, - ); -} diff --git a/kernel/src/task/task.rs b/kernel/src/task/task.rs deleted file mode 100644 index 844d463..0000000 --- a/kernel/src/task/task.rs +++ /dev/null @@ -1,75 +0,0 @@ -//! Types related to task management - -use super::context::TaskContext; -use crate::config::TRAP_CONTEXT; -use crate::config::kernel_stack_position; -use crate::mm::KERNEL_SPACE; -use crate::mm::MapPermission; -use crate::mm::MemorySet; -use crate::mm::PhysPageNum; -use crate::mm::VirtAddr; -use crate::trap::TrapContext; -use crate::trap::trap_handler; - -/// task contrl block structure -pub struct TaskControlBlock { - pub task_status: TaskStatus, - pub task_cx: TaskContext, - // 地址的应用空间 - pub memory_set: MemorySet, - // trap context实际在的physpagenum - pub trap_cx_ppn: PhysPageNum, - // 统计了应用数据的大小 - pub base_size: usize, -} - -impl TaskControlBlock { - pub fn new(elf_data: &[u8], app_id: usize) -> Self { - // memory_set with elf program headers/trampoline/trap context/user stack - let (memory_set, user_sp, entry_point) = MemorySet::from_elf(elf_data); - let trap_cx_ppn = memory_set - .translate(VirtAddr::from(TRAP_CONTEXT).into()) - .unwrap() - .ppn(); - let task_status = TaskStatus::Ready; - // map kernel-stack in kernel space - let (kernel_stack_bottom, kernel_stack_top) = kernel_stack_position(app_id); - KERNEL_SPACE.exclusive_access().insert_framed_area( - kernel_stack_bottom.into(), - kernel_stack_top.into(), - MapPermission::R | MapPermission::W, - ); - let task_control_block = Self { - task_status, - task_cx: TaskContext::goto_trap_return(kernel_stack_top), - memory_set, - trap_cx_ppn, - base_size: user_sp, - }; - // prepare TrapContext in user space - let trap_cx = task_control_block.get_trap_cx(); - *trap_cx = TrapContext::app_init_context( - entry_point, - user_sp, - KERNEL_SPACE.exclusive_access().token(), - kernel_stack_top, - trap_handler as *const () as usize, - ); - task_control_block - } - pub fn get_user_token(&self) -> usize { - self.memory_set.token() - } - pub fn get_trap_cx(&self) -> &'static mut TrapContext { - self.trap_cx_ppn.get_mut() - } -} - -#[derive(Copy, Clone, PartialEq)] -/// task status: UnInit, Ready, Running, Exited -pub enum TaskStatus { - UnInit, - Ready, - Running, - Exited, -} diff --git a/kernel/src/timer.rs b/kernel/src/timer.rs index a825187..ebfa261 100644 --- a/kernel/src/timer.rs +++ b/kernel/src/timer.rs @@ -1,7 +1,6 @@ //! RISC-V timer-related functionality use crate::{boards::CLOCK_FREQ, sbi::set_timer}; -use log::info; use riscv::register::time; const TICKS_PER_SEC: usize = 1000; @@ -19,7 +18,5 @@ pub fn get_time_ms() -> usize { /// set the next timer interrupt pub fn set_next_trigger() { - info!("[kernel test06] set timer to control the frequency of timer interrupt ...!"); set_timer(get_time() + CLOCK_FREQ / TICKS_PER_SEC); - info!("[kernel test06] set timer to control the frequency of timer interrupt ok!"); } diff --git a/kernel/src/trap.rs b/kernel/src/trap.rs index 72c6cb2..ec9eecc 100644 --- a/kernel/src/trap.rs +++ b/kernel/src/trap.rs @@ -12,13 +12,10 @@ //! was. For example, timer interrupts trigger task preemption, and syscalls go //! to [`syscall()`]. -use core::arch::{asm, global_asm}; - -use log::info; use riscv::register::{ scause::{self, Exception, Interrupt, Trap}, - sie, stval, - stvec::{self, TrapMode}, + stval, + stvec::TrapMode, }; use crate::config::{TRAMPOLINE, TRAP_CONTEXT}; @@ -31,13 +28,10 @@ use crate::timer::set_next_trigger; mod context; pub use context::TrapContext; -global_asm!(include_str!("trap/trap.S")); - pub fn init() { set_kernel_trap_entry(); } -#[unsafe(no_mangle)] /// Unimplement: traps/interrupts/exceptions from kernel mode /// TODO: Chapter 9: I/O device pub fn trap_from_kernel() -> ! { @@ -45,22 +39,16 @@ pub fn trap_from_kernel() -> ! { } fn set_kernel_trap_entry() { - info!("[kernel test04] set kernel trap entry ..."); framework::set_stvec(trap_from_kernel as *const () as usize, TrapMode::Direct); - info!("[kernel test04] set kernel trap entry ok!"); } /// timer interrupt enabled pub fn enable_timer_interrupt() { - info!("[kernel test05] use sie to enable stimer interrupt ...!"); framework::set_sie_enable_stimer(); - info!("[kernel test05] use sie to enable stimer interrupt ok!"); } -#[unsafe(no_mangle)] /// handle an interrupt, exception, or system call from user space pub fn trap_handler() -> ! { - info!("[kernel notice] trap_handler(): Haha, Userspace fall into Trap!"); set_kernel_trap_entry(); let cx = current_trap_cx(); let scause = scause::read(); @@ -69,7 +57,6 @@ pub fn trap_handler() -> ! { Trap::Exception(Exception::UserEnvCall) => { cx.sepc += 4; cx.x[10] = syscall(cx.x[17], [cx.x[10], cx.x[11], cx.x[12]]) as usize; - info!("[kernel notice] trap_handler(): Haha, give user syscall()!"); } Trap::Exception(Exception::StoreFault) | Trap::Exception(Exception::StorePageFault) @@ -79,29 +66,17 @@ pub fn trap_handler() -> ! { "[kernel] PageFault in application, bad addr = {:#x}, bad instruction = {:#x}, kernel killed it!", stval, cx.sepc ); - info!( - "[kernel notice] trap_handler(): Haha, user task pagefault, kernel skip it and go next!" - ); exit_current_and_run_next(); } Trap::Exception(Exception::IllegalInstruction) => { println!("[kernel] IllegalInstruction in application, kernel killed it."); - info!( - "[kernel notice] trap_handler(): Haha, user have IllegalInstruction, kernel skip it and go next!" - ); exit_current_and_run_next(); } Trap::Interrupt(Interrupt::SupervisorTimer) => { - info!( - "[kernel notice] trap_handler(): Haha, timer interrupt comes, reset the timer and switch to the next task!" - ); set_next_trigger(); suspend_current_and_run_next(); } _ => { - info!( - "[kernel notice] trap_handler(): Haha, unknown case of trap, i have no idea with what happened!" - ); panic!( "Unsupported trap {:?}, stval = {:#x}!", scause.cause(), @@ -113,39 +88,15 @@ pub fn trap_handler() -> ! { } fn set_user_trap_entry() { - info!("[kernel test10] (stvec) setting user trap entry ...!"); framework::set_stvec(TRAMPOLINE, TrapMode::Direct); - info!("[kernel test10] (stvec) setting user trap entry ok!"); } -#[unsafe(no_mangle)] /// set the new addr of __restore asm function in TRAMPOINE page, /// set the reg a0 = trap_cx_ptr, reg a1 = phy addr of usr page table, /// finally, jump to new addr of __restore asm function pub fn trap_return() -> ! { - info!( - "[kernel test09] in '__switch(task a,task b)' call 'ret' or trap_handler() call trap_return(), let PC=ra(trap_return())!" - ); set_user_trap_entry(); let trap_cx_ptr = TRAP_CONTEXT; let user_satp = current_user_token(); - unsafe extern "C" { - unsafe fn __alltraps(); - unsafe fn __restore(); - } - let restore_va = - __restore as *const () as usize - __alltraps as *const () as usize + TRAMPOLINE; - info!( - "[kernel notice] jr {restore_va}, goto '__restore' and 'sret' to userspace, until user fall into the trap->goto trap_handler addr stored in 'stvec' !" - ); - unsafe { - asm!( - "fence.i", - "jr {restore_va}", - restore_va = in(reg) restore_va, - in("a0") trap_cx_ptr, - in("a1") user_satp, - options(noreturn) - ); - } + framework::restore_to_user(trap_cx_ptr, user_satp, TRAMPOLINE); }