163 lines
4.3 KiB
Rust
163 lines
4.3 KiB
Rust
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<AppManager> = 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::<TrapContext>()) 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!()
|
|
}
|
|
}
|