1use manager::VirtualMemoryManager;
7use vmem::MemoryArea;
8use vmem::VirtualMemoryMap;
9use vmem::VirtualMemoryPermission;
10
11use crate::arch::get_cpu;
12use crate::arch::get_kernel_trapvector_paddr;
13use crate::arch::get_user_trapvector_paddr;
14use crate::arch::set_trapvector;
15use crate::arch::vm::alloc_virtual_address_space;
16use crate::arch::vm::get_page_table;
17use crate::arch::vm::get_root_page_table_idx;
18use crate::arch::Arch;
19use crate::environment::KERNEL_VM_STACK_SIZE;
20use crate::environment::KERNEL_VM_STACK_START;
21use crate::environment::NUM_OF_CPUS;
22use crate::environment::PAGE_SIZE;
23use crate::environment::USER_STACK_TOP;
24use crate::environment::VMMAX;
25use crate::println;
26use crate::sched::scheduler::get_scheduler;
27use crate::task::Task;
28
29extern crate alloc;
30
31pub mod manager;
32pub mod vmem;
33
34unsafe extern "C" {
35 static __KERNEL_SPACE_START: usize;
36 static __KERNEL_SPACE_END: usize;
37 static __TRAMPOLINE_START: usize;
38 static __TRAMPOLINE_END: usize;
39}
40
41static mut KERNEL_VM_MANAGER: Option<VirtualMemoryManager> = None;
42
43pub fn get_kernel_vm_manager() -> &'static mut VirtualMemoryManager {
44 unsafe
45 {
46 match KERNEL_VM_MANAGER {
47 Some(ref mut m) => m,
48 None => {
49 kernel_vm_manager_init();
50 get_kernel_vm_manager()
51 }
52 }
53 }
54}
55
56fn kernel_vm_manager_init() {
57 let manager = VirtualMemoryManager::new();
58
59 unsafe {
60 KERNEL_VM_MANAGER = Some(manager);
61 }
62}
63
64static mut KERNEL_AREA: Option<MemoryArea> = None;
65#[allow(static_mut_refs)]
67pub fn kernel_vm_init(kernel_area: MemoryArea) {
68 let manager = get_kernel_vm_manager();
69
70 let asid = alloc_virtual_address_space(); let root_page_table_idx = get_root_page_table_idx(asid).unwrap();
72 let root_page_table = get_page_table(root_page_table_idx).unwrap();
73 manager.set_asid(asid);
74
75 let kernel_start = kernel_area.start;
77 let kernel_end = kernel_area.end;
78
79 let kernel_area = MemoryArea {
80 start: kernel_start,
81 end: kernel_end,
82 };
83 unsafe {
84 KERNEL_AREA = Some(kernel_area);
85 }
86
87 let kernel_map = VirtualMemoryMap {
88 vmarea: kernel_area,
89 pmarea: kernel_area,
90 permissions:
91 VirtualMemoryPermission::Read as usize |
92 VirtualMemoryPermission::Write as usize |
93 VirtualMemoryPermission::Execute as usize,
94 is_shared: true, };
96 manager.add_memory_map(kernel_map).map_err(|e| panic!("Failed to add kernel memory map: {}", e)).unwrap();
97 root_page_table.map_memory_area(kernel_map).map_err(|e| panic!("Failed to map kernel memory area: {}", e)).unwrap();
99
100 let dev_map = VirtualMemoryMap {
101 vmarea: MemoryArea {
102 start: 0x00,
103 end: 0x7fff_ffff,
104 },
105 pmarea: MemoryArea {
106 start: 0x00,
107 end: 0x7fff_ffff,
108 },
109 permissions:
110 VirtualMemoryPermission::Read as usize |
111 VirtualMemoryPermission::Write as usize,
112 is_shared: true, };
114 manager.add_memory_map(dev_map).map_err(|e| panic!("Failed to add device memory map: {}", e)).unwrap();
115
116 println!("Device space mapped : {:#018x} - {:#018x}", dev_map.vmarea.start, dev_map.vmarea.end);
117 println!("Kernel space mapped : {:#018x} - {:#018x}", kernel_start, kernel_end);
118
119 setup_trampoline(manager);
120
121 root_page_table.switch(manager.get_asid());
122}
123
124pub fn user_vm_init(task: &mut Task) {
125 let asid = alloc_virtual_address_space();
126 task.vm_manager.set_asid(asid);
127
128 let num_of_stack_page = 2; let stack_start = USER_STACK_TOP - num_of_stack_page * PAGE_SIZE;
131 task.allocate_stack_pages(stack_start, num_of_stack_page).map_err(|e| panic!("Failed to allocate user stack pages: {}", e)).unwrap();
132
133 task.allocate_guard_pages(stack_start - PAGE_SIZE, 1).map_err(|e| panic!("Failed to allocate guard page: {}", e)).unwrap();
135
136 setup_trampoline(&mut task.vm_manager);
137}
138
139pub fn user_kernel_vm_init(task: &mut Task) {
140 let asid = alloc_virtual_address_space();
141 let root_page_table_idx = get_root_page_table_idx(asid).unwrap();
142 let root_page_table = get_page_table(root_page_table_idx).unwrap();
143 task.vm_manager.set_asid(asid);
144
145 let kernel_area = unsafe { KERNEL_AREA.unwrap() };
146
147 let kernel_map = VirtualMemoryMap {
148 vmarea: kernel_area,
149 pmarea: kernel_area,
150 permissions:
151 VirtualMemoryPermission::Read as usize |
152 VirtualMemoryPermission::Write as usize |
153 VirtualMemoryPermission::Execute as usize,
154 is_shared: true, };
156 task.vm_manager.add_memory_map(kernel_map).map_err(|e| {
157 panic!("Failed to add kernel memory map: {}", e);
158 }).unwrap();
159 root_page_table.map_memory_area(kernel_map).map_err(|e| {
161 panic!("Failed to map kernel memory area: {}", e);
162 }).unwrap();
163 task.data_size = kernel_area.end + 1;
164
165 task.allocate_stack_pages(KERNEL_VM_STACK_START, KERNEL_VM_STACK_SIZE / PAGE_SIZE).map_err(|e| panic!("Failed to allocate kernel stack pages: {}", e)).unwrap();
167
168 let dev_map = VirtualMemoryMap {
169 vmarea: MemoryArea {
170 start: 0x00,
171 end: 0x7fff_ffff,
172 },
173 pmarea: MemoryArea {
174 start: 0x00,
175 end: 0x7fff_ffff,
176 },
177 permissions:
178 VirtualMemoryPermission::Read as usize |
179 VirtualMemoryPermission::Write as usize,
180 is_shared: true, };
182 task.vm_manager.add_memory_map(dev_map).map_err(|e| panic!("Failed to add device memory map: {}", e)).unwrap();
183
184 setup_trampoline(&mut task.vm_manager);
185}
186
187pub fn setup_user_stack(task: &mut Task) -> usize{
188 let num_of_stack_page = 2; let stack_start = USER_STACK_TOP - num_of_stack_page * PAGE_SIZE;
191 task.allocate_stack_pages(stack_start, num_of_stack_page).map_err(|e| panic!("Failed to allocate user stack pages: {}", e)).unwrap();
192 task.allocate_guard_pages(stack_start - PAGE_SIZE, 1).map_err(|e| panic!("Failed to allocate guard page: {}", e)).unwrap();
194
195 USER_STACK_TOP
196}
197
198static mut TRAMPOLINE_TRAP_VECTOR: Option<usize> = None;
199static mut TRAMPOLINE_TRAPFRAME: [Option<usize>; NUM_OF_CPUS] = [None; NUM_OF_CPUS];
200
201pub fn setup_trampoline(manager: &mut VirtualMemoryManager) {
202 let trampoline_start = unsafe { &__TRAMPOLINE_START as *const usize as usize };
203 let trampoline_end = unsafe { &__TRAMPOLINE_END as *const usize as usize } - 1;
204 let trampoline_size = trampoline_end - trampoline_start;
205
206 let arch = get_cpu();
207 let trampoline_vaddr_start = VMMAX - trampoline_size;
208 let trampoline_vaddr_end = VMMAX;
209
210 let trap_entry_paddr = get_user_trapvector_paddr();
211 let trapframe_paddr = arch.get_trapframe_paddr();
212 let trap_entry_offset = trap_entry_paddr - trampoline_start;
213 let trapframe_offset = trapframe_paddr - trampoline_start;
214
215 let trap_entry_vaddr = trampoline_vaddr_start + trap_entry_offset;
216 let trapframe_vaddr = trampoline_vaddr_start + trapframe_offset;
217
218 let trampoline_map = VirtualMemoryMap {
227 vmarea: MemoryArea {
228 start: trampoline_vaddr_start,
229 end: trampoline_vaddr_end,
230 },
231 pmarea: MemoryArea {
232 start: trampoline_start,
233 end: trampoline_end,
234 },
235 permissions:
236 VirtualMemoryPermission::Read as usize |
237 VirtualMemoryPermission::Write as usize |
238 VirtualMemoryPermission::Execute as usize,
239 is_shared: true, };
241
242 manager.add_memory_map(trampoline_map)
243 .map_err(|e| panic!("Failed to add trampoline memory map: {}", e)).unwrap();
244 manager.get_root_page_table().unwrap().map_memory_area(trampoline_map)
246 .map_err(|e| panic!("Failed to map trampoline memory area: {}", e)).unwrap();
247
248 set_trampoline_trap_vector(trap_entry_vaddr);
249 set_trampoline_trapframe(arch.get_cpuid(), trapframe_vaddr);
250}
251
252pub fn set_trampoline_trap_vector(trap_vector: usize) {
253 unsafe {
254 TRAMPOLINE_TRAP_VECTOR = Some(trap_vector);
255 }
256}
257
258pub fn get_trampoline_trap_vector() -> usize {
259 unsafe {
260 match TRAMPOLINE_TRAP_VECTOR {
261 Some(v) => v,
262 None => panic!("Trampoline is not initialized"),
263 }
264 }
265}
266
267pub fn set_trampoline_trapframe(cpu_id: usize, trap_frame: usize) {
268 unsafe {
269 TRAMPOLINE_TRAPFRAME[cpu_id] = Some(trap_frame);
270 }
271}
272
273pub fn get_trampoline_trapframe(cpu_id: usize) -> usize {
274 unsafe {
275 match TRAMPOLINE_TRAPFRAME[cpu_id] {
276 Some(v) => v,
277 None => panic!("Trampoline is not initialized"),
278 }
279 }
280}
281
282pub fn switch_to_kernel_vm() {
283 let manager = get_kernel_vm_manager();
284 let root_page_table = manager.get_root_page_table().expect("Root page table is not set");
285 set_trapvector(get_kernel_trapvector_paddr());
286 root_page_table.switch(manager.get_asid());
287}
288
289pub fn switch_to_user_vm(cpu: &mut Arch) {
290 let cpu_id = cpu.get_cpuid();
291 let task = get_scheduler().get_current_task(cpu_id).expect("No current task found");
292 let manager = &task.vm_manager;
293 let root_page_table = manager.get_root_page_table().expect("Root page table is not set");
294 set_trapvector(get_trampoline_trap_vector());
295 root_page_table.switch(manager.get_asid());
296}