use core::arch::asm; use lazy_static::lazy_static; use crate::log_information; use crate::sbi::shutdown; use crate::sync::single_cell::SingleCell; use crate::trap::context::TrapContext; const MAX_APP_NUMBER: usize = 32; const APP_BASE_ADDRESS: usize = 0x80400000; const APP_SIZE_LIMIT: usize = 0x20000; struct AppManager { app_count: usize, current: usize, start_addresses: [usize; MAX_APP_NUMBER + 1], } lazy_static! { static ref APP_MANAGER: SingleCell = unsafe { SingleCell::new({ extern "C" { fn _num_app(); } let num_app_ptr = _num_app as usize as *const usize; let num_app = num_app_ptr.read_volatile(); let mut start_addresses: [usize; MAX_APP_NUMBER + 1] = [0; MAX_APP_NUMBER + 1]; let start_addresses_raw: &[usize] = core::slice::from_raw_parts(num_app_ptr.add(1), num_app + 1); start_addresses[..=num_app].copy_from_slice(start_addresses_raw); AppManager { app_count: num_app, current: 0, start_addresses, } }) }; } impl AppManager { pub fn print_app_information(&self) { log_information!("[kernel] Application count is {}.", self.app_count); for i in 0..self.app_count { log_information!( "[kernel] Application_{} ({:#x} -> {:#x})", i, self.start_addresses[i], self.start_addresses[i + 1] ); } } pub fn get_current_app(&self) -> usize { self.current } pub fn move_to_next_app(&mut self) { self.current += 1; } unsafe fn load_app(&self, app_id: usize) { if app_id >= self.app_count { panic!("Application id is invalid!"); } log_information!("[kernel] Loading application_{}...", app_id); core::slice::from_raw_parts_mut(APP_BASE_ADDRESS as *mut u8, APP_SIZE_LIMIT).fill(0); let app_source = core::slice::from_raw_parts( self.start_addresses[app_id] as *const u8, self.start_addresses[app_id + 1] - self.start_addresses[app_id], ); let app_destination = core::slice::from_raw_parts_mut(APP_BASE_ADDRESS as *mut u8, app_source.len()); app_destination.copy_from_slice(app_source); // 保证指令缓存的更新 // 因为上述代码会修改指令数据段 asm!("fence.i"); } } const USER_STACK_SIZE: usize = 4096 * 2; const KERNEL_STACK_SIZE: usize = 4096 * 2; #[repr(align(4096))] struct UserStack { data: [u8; USER_STACK_SIZE], } impl UserStack { fn get_sp(&self) -> usize { self.data.as_ptr() as usize + USER_STACK_SIZE } } #[repr(align(4096))] struct KernelStack { data: [u8; KERNEL_STACK_SIZE], } impl KernelStack { fn get_sp(&self) -> usize { self.data.as_ptr() as usize + KERNEL_STACK_SIZE } pub fn push_context(&self, context: TrapContext) -> &'static mut TrapContext { let context_pointer = (self.get_sp() - size_of::()) as *mut TrapContext; unsafe { *context_pointer = context; context_pointer.as_mut().unwrap() } } } static KERNEL_STACK: KernelStack = KernelStack { data: [0; KERNEL_STACK_SIZE], }; static USER_STACK: UserStack = UserStack { data: [0; USER_STACK_SIZE], }; pub fn print_app_information() { let app_manager = APP_MANAGER.exclusive_borrow(); app_manager.print_app_information(); } pub fn run_next_application() -> ! { let mut app_manager = APP_MANAGER.exclusive_borrow(); let current_app = app_manager.get_current_app(); if current_app >= app_manager.app_count { log_information!("Run out of applications, the os will stop!"); shutdown(true); } unsafe { app_manager.load_app(current_app); } app_manager.move_to_next_app(); // We must drop resource manually // As this function will never return! drop(app_manager); extern "C" { fn __restore(context_address: usize); } unsafe { let context_address = KERNEL_STACK.push_context(TrapContext::init_application_context( APP_BASE_ADDRESS, USER_STACK.get_sp(), )) as *const _ as usize; __restore(context_address); unreachable!() } }