1use crate::sbi::shutdown;
4use crate::sync::UPSafeCell;
5use crate::trap::TrapContext;
6use core::arch::asm;
7use lazy_static::*;
8
9const USER_STACK_SIZE: usize = 4096 * 2;
10const KERNEL_STACK_SIZE: usize = 4096 * 2;
11const MAX_APP_NUM: usize = 16;
12const APP_BASE_ADDRESS: usize = 0x80400000;
13const APP_SIZE_LIMIT: usize = 0x20000;
14
15#[repr(align(4096))]
16struct KernelStack {
17 data: [u8; KERNEL_STACK_SIZE],
18}
19
20#[repr(align(4096))]
21struct UserStack {
22 data: [u8; USER_STACK_SIZE],
23}
24
25static KERNEL_STACK: KernelStack = KernelStack {
26 data: [0; KERNEL_STACK_SIZE],
27};
28static USER_STACK: UserStack = UserStack {
29 data: [0; USER_STACK_SIZE],
30};
31
32impl KernelStack {
33 fn get_sp(&self) -> usize {
34 self.data.as_ptr() as usize + KERNEL_STACK_SIZE
35 }
36 pub fn push_context(&self, cx: TrapContext) -> &'static mut TrapContext {
37 let cx_ptr = (self.get_sp() - core::mem::size_of::<TrapContext>()) as *mut TrapContext;
38 unsafe {
39 *cx_ptr = cx;
40 }
41 unsafe { cx_ptr.as_mut().unwrap() }
42 }
43}
44
45impl UserStack {
46 fn get_sp(&self) -> usize {
47 self.data.as_ptr() as usize + USER_STACK_SIZE
48 }
49}
50
51struct AppManager {
52 num_app: usize,
53 current_app: usize,
54 app_start: [usize; MAX_APP_NUM + 1],
55}
56
57impl AppManager {
58 pub fn print_app_info(&self) {
59 println!("[kernel] num_app = {}", self.num_app);
60 for i in 0..self.num_app {
61 println!(
62 "[kernel] app_{} [{:#x}, {:#x})",
63 i,
64 self.app_start[i],
65 self.app_start[i + 1]
66 );
67 }
68 }
69
70 fn load_app(&self, app_id: usize) {
71 if app_id >= self.num_app {
72 println!("All applications completed!");
73 shutdown(false);
74 }
75 println!("[kernel] Loading app_{}", app_id);
76 unsafe {
77 core::slice::from_raw_parts_mut(APP_BASE_ADDRESS as *mut u8, APP_SIZE_LIMIT).fill(0);
79 let app_src = core::slice::from_raw_parts(
80 self.app_start[app_id] as *const u8,
81 self.app_start[app_id + 1] - self.app_start[app_id],
82 );
83 let app_dst =
84 core::slice::from_raw_parts_mut(APP_BASE_ADDRESS as *mut u8, app_src.len());
85 app_dst.copy_from_slice(app_src);
86 asm!("fence.i");
93 }
94 }
95
96 pub fn get_current_app(&self) -> usize {
97 self.current_app
98 }
99
100 pub fn move_to_next_app(&mut self) {
101 self.current_app += 1;
102 }
103}
104
105lazy_static! {
106 static ref APP_MANAGER: UPSafeCell<AppManager> = unsafe {
107 UPSafeCell::new({
108 unsafe extern "C" {
109 safe fn _num_app();
110 }
111 let num_app_ptr = linker_symbol_addr!(_num_app) as *const usize;
112 let num_app = num_app_ptr.read_volatile();
113 let mut app_start: [usize; MAX_APP_NUM + 1] = [0; MAX_APP_NUM + 1];
114 let app_start_raw: &[usize] =
115 core::slice::from_raw_parts(num_app_ptr.add(1), num_app + 1);
116 app_start[..=num_app].copy_from_slice(app_start_raw);
117 AppManager {
118 num_app,
119 current_app: 0,
120 app_start,
121 }
122 })
123 };
124}
125
126pub fn init() {
128 print_app_info();
129}
130
131pub fn print_app_info() {
133 APP_MANAGER.exclusive_access().print_app_info();
134}
135
136pub fn run_next_app() -> ! {
138 let mut app_manager = APP_MANAGER.exclusive_access();
139 let current_app = app_manager.get_current_app();
140 app_manager.load_app(current_app);
141 app_manager.move_to_next_app();
142 drop(app_manager);
143 unsafe extern "C" {
146 unsafe fn __restore(cx_addr: usize);
147 }
148 unsafe {
149 __restore(KERNEL_STACK.push_context(TrapContext::app_init_context(
150 APP_BASE_ADDRESS,
151 USER_STACK.get_sp(),
152 )) as *const _ as usize);
153 }
154 panic!("Unreachable in batch::run_current_app!");
155}