You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
rCore-Tutorial-v3-tests/os/src/batch.rs

130 lines
3.7 KiB

use core::cell::RefCell;
use lazy_static::*;
use crate::trap::TrapContext;
const USER_STACK_SIZE: usize = 4096 * 2;
const KERNEL_STACK_SIZE: usize = 4096 * 2;
const MAX_APP_NUM: usize = 16;
const APP_BASE_ADDRESS: usize = 0x80040000;
const APP_SIZE_LIMIT: usize = 0x20000;
#[repr(align(4096))]
struct KernelStack {
data: [u8; KERNEL_STACK_SIZE],
}
#[repr(align(4096))]
struct UserStack {
data: [u8; USER_STACK_SIZE],
}
static KERNEL_STACK: KernelStack = KernelStack { data: [0; KERNEL_STACK_SIZE] };
static USER_STACK: UserStack = UserStack { data: [0; USER_STACK_SIZE] };
impl KernelStack {
fn get_sp(&self) -> usize {
self.data.as_ptr() as usize + KERNEL_STACK_SIZE
}
pub fn push_context(&self, cx: TrapContext) -> &'static mut TrapContext {
let cx_ptr = (self.get_sp() - core::mem::size_of::<TrapContext>()) as *mut TrapContext;
unsafe { *cx_ptr = cx; }
unsafe { cx_ptr.as_mut().unwrap() }
}
}
impl UserStack {
fn get_sp(&self) -> usize {
self.data.as_ptr() as usize + USER_STACK_SIZE
}
}
struct AppManager {
inner: RefCell<AppManagerInner>,
}
struct AppManagerInner {
num_app: usize,
current_app: usize,
app_start: [usize; MAX_APP_NUM + 1],
}
unsafe impl Sync for AppManager {}
impl AppManagerInner {
pub fn print_app_info(&self) {
println!("[kernel] num_app = {}", self.num_app);
for i in 0..self.num_app {
println!("[kernel] app_{} [{:#x}, {:#x})", i, self.app_start[i], self.app_start[i + 1]);
}
}
unsafe fn load_app(&self, app_id: usize) {
if app_id >= self.num_app {
panic!("All applications completed!");
}
println!("[kernel] Loading app_{}", app_id);
// clear icache
llvm_asm!("fence.i" :::: "volatile");
// clear app area
(APP_BASE_ADDRESS..APP_BASE_ADDRESS + APP_SIZE_LIMIT).for_each(|addr| {
(addr as *mut u8).write_volatile(0);
});
let app_src = core::slice::from_raw_parts(
self.app_start[app_id] as *const u8,
self.app_start[app_id + 1] - self.app_start[app_id]
);
let app_dst = core::slice::from_raw_parts_mut(
APP_BASE_ADDRESS as *mut u8,
app_src.len()
);
app_dst.copy_from_slice(app_src);
}
pub fn get_current_app(&self) -> usize { self.current_app }
pub fn move_to_next_app(&mut self) {
self.current_app += 1;
}
}
lazy_static! {
static ref APP_MANAGER: AppManager = AppManager {
inner: RefCell::new({
extern "C" { fn _num_app(); }
let num_app_ptr = _num_app as usize as *const usize;
let num_app = unsafe { num_app_ptr.read_volatile() };
let mut app_start: [usize; MAX_APP_NUM + 1] = [0; MAX_APP_NUM + 1];
let app_start_raw: &[usize] = unsafe {
core::slice::from_raw_parts(num_app_ptr.add(1), num_app + 1)
};
app_start[..=num_app].copy_from_slice(app_start_raw);
AppManagerInner {
num_app,
current_app: 0,
app_start,
}
}),
};
}
pub fn init() {
print_app_info();
}
pub fn print_app_info() {
APP_MANAGER.inner.borrow().print_app_info();
}
pub fn run_next_app() -> ! {
let current_app = APP_MANAGER.inner.borrow().get_current_app();
unsafe {
APP_MANAGER.inner.borrow().load_app(current_app);
}
APP_MANAGER.inner.borrow_mut().move_to_next_app();
extern "C" { fn __restore(cx_addr: usize); }
unsafe {
__restore(KERNEL_STACK.push_context(
TrapContext::app_init_context(APP_BASE_ADDRESS, USER_STACK.get_sp())
) as *const _ as usize);
}
panic!("Unreachable in batch::run_current_app!");
}