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_root_pagetable;
17use crate::arch::Arch;
18use crate::early_println;
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 = get_root_pagetable(asid).unwrap();
72 manager.set_asid(asid);
73
74 let kernel_start = kernel_area.start;
76 let kernel_end = kernel_area.end;
77
78 let kernel_area = MemoryArea {
79 start: kernel_start,
80 end: kernel_end,
81 };
82 unsafe {
83 KERNEL_AREA = Some(kernel_area);
84 }
85
86 let kernel_map = VirtualMemoryMap {
87 vmarea: kernel_area,
88 pmarea: kernel_area,
89 permissions:
90 VirtualMemoryPermission::Read as usize |
91 VirtualMemoryPermission::Write as usize |
92 VirtualMemoryPermission::Execute as usize,
93 is_shared: true, };
95 manager.add_memory_map(kernel_map).map_err(|e| panic!("Failed to add kernel memory map: {}", e)).unwrap();
96 root_page_table.map_memory_area(asid, kernel_map).map_err(|e| panic!("Failed to map kernel memory area: {}", e)).unwrap();
98
99 let dev_map = VirtualMemoryMap {
100 vmarea: MemoryArea {
101 start: 0x00,
102 end: 0x7fff_ffff,
103 },
104 pmarea: MemoryArea {
105 start: 0x00,
106 end: 0x7fff_ffff,
107 },
108 permissions:
109 VirtualMemoryPermission::Read as usize |
110 VirtualMemoryPermission::Write as usize,
111 is_shared: true, };
113 manager.add_memory_map(dev_map).map_err(|e| panic!("Failed to add device memory map: {}", e)).unwrap();
114
115 early_println!("Device space mapped : {:#018x} - {:#018x}", dev_map.vmarea.start, dev_map.vmarea.end);
116 early_println!("Kernel space mapped : {:#018x} - {:#018x}", kernel_start, kernel_end);
117
118 setup_trampoline(manager);
119
120 root_page_table.switch(manager.get_asid());
121}
122
123pub fn user_vm_init(task: &mut Task) {
124 let asid = alloc_virtual_address_space();
125 task.vm_manager.set_asid(asid);
126
127 let num_of_stack_page = 4; let stack_start = USER_STACK_TOP - num_of_stack_page * PAGE_SIZE;
130 task.allocate_stack_pages(stack_start, num_of_stack_page).map_err(|e| panic!("Failed to allocate user stack pages: {}", e)).unwrap();
131
132 task.allocate_guard_pages(stack_start - PAGE_SIZE, 1).map_err(|e| panic!("Failed to allocate guard page: {}", e)).unwrap();
134
135 setup_trampoline(&mut task.vm_manager);
136}
137
138pub fn user_kernel_vm_init(task: &mut Task) {
139 let asid = alloc_virtual_address_space();
140 let root_page_table = get_root_pagetable(asid).unwrap();
141 task.vm_manager.set_asid(asid);
142
143 let kernel_area = unsafe { KERNEL_AREA.unwrap() };
144
145 let kernel_map = VirtualMemoryMap {
146 vmarea: kernel_area,
147 pmarea: kernel_area,
148 permissions:
149 VirtualMemoryPermission::Read as usize |
150 VirtualMemoryPermission::Write as usize |
151 VirtualMemoryPermission::Execute as usize,
152 is_shared: true, };
154 task.vm_manager.add_memory_map(kernel_map).map_err(|e| {
155 panic!("Failed to add kernel memory map: {}", e);
156 }).unwrap();
157 root_page_table.map_memory_area(asid, kernel_map).map_err(|e| {
159 panic!("Failed to map kernel memory area: {}", e);
160 }).unwrap();
161 task.data_size = kernel_area.end + 1;
162
163 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();
165
166 let dev_map = VirtualMemoryMap {
167 vmarea: MemoryArea {
168 start: 0x00,
169 end: 0x7fff_ffff,
170 },
171 pmarea: MemoryArea {
172 start: 0x00,
173 end: 0x7fff_ffff,
174 },
175 permissions:
176 VirtualMemoryPermission::Read as usize |
177 VirtualMemoryPermission::Write as usize,
178 is_shared: true, };
180 task.vm_manager.add_memory_map(dev_map).map_err(|e| panic!("Failed to add device memory map: {}", e)).unwrap();
181
182 setup_trampoline(&mut task.vm_manager);
183}
184
185pub fn setup_user_stack(task: &mut Task) -> (usize, usize) {
186 let num_of_stack_page = 4; let stack_base = USER_STACK_TOP - num_of_stack_page * PAGE_SIZE;
189 task.allocate_stack_pages(stack_base, num_of_stack_page).map_err(|e| panic!("Failed to allocate user stack pages: {}", e)).unwrap();
190 task.allocate_guard_pages(stack_base - PAGE_SIZE, 1).map_err(|e| panic!("Failed to allocate guard page: {}", e)).unwrap();
192
193 (stack_base, USER_STACK_TOP)
194}
195
196static mut TRAMPOLINE_TRAP_VECTOR: Option<usize> = None;
197static mut TRAMPOLINE_TRAPFRAME: [Option<usize>; NUM_OF_CPUS] = [None; NUM_OF_CPUS];
198
199pub fn setup_trampoline(manager: &mut VirtualMemoryManager) {
200 let trampoline_start = unsafe { &__TRAMPOLINE_START as *const usize as usize };
201 let trampoline_end = unsafe { &__TRAMPOLINE_END as *const usize as usize } - 1;
202 let trampoline_size = trampoline_end - trampoline_start;
203
204 let arch = get_cpu();
205 let trampoline_vaddr_start = VMMAX - trampoline_size;
206 let trampoline_vaddr_end = VMMAX;
207
208 let trap_entry_paddr = get_user_trapvector_paddr();
209 let trapframe_paddr = arch.get_trapframe_paddr();
210 let trap_entry_offset = trap_entry_paddr - trampoline_start;
211 let trapframe_offset = trapframe_paddr - trampoline_start;
212
213 let trap_entry_vaddr = trampoline_vaddr_start + trap_entry_offset;
214 let trapframe_vaddr = trampoline_vaddr_start + trapframe_offset;
215
216 let trampoline_map = VirtualMemoryMap {
225 vmarea: MemoryArea {
226 start: trampoline_vaddr_start,
227 end: trampoline_vaddr_end,
228 },
229 pmarea: MemoryArea {
230 start: trampoline_start,
231 end: trampoline_end,
232 },
233 permissions:
234 VirtualMemoryPermission::Read as usize |
235 VirtualMemoryPermission::Write as usize |
236 VirtualMemoryPermission::Execute as usize,
237 is_shared: true, };
239
240 manager.add_memory_map(trampoline_map)
241 .map_err(|e| panic!("Failed to add trampoline memory map: {}", e)).unwrap();
242 manager.get_root_page_table().unwrap().map_memory_area(manager.get_asid(), trampoline_map)
244 .map_err(|e| panic!("Failed to map trampoline memory area: {}", e)).unwrap();
245
246 set_trampoline_trap_vector(trap_entry_vaddr);
247 set_trampoline_trapframe(arch.get_cpuid(), trapframe_vaddr);
248}
249
250pub fn set_trampoline_trap_vector(trap_vector: usize) {
251 unsafe {
252 TRAMPOLINE_TRAP_VECTOR = Some(trap_vector);
253 }
254}
255
256pub fn get_trampoline_trap_vector() -> usize {
257 unsafe {
258 match TRAMPOLINE_TRAP_VECTOR {
259 Some(v) => v,
260 None => panic!("Trampoline is not initialized"),
261 }
262 }
263}
264
265pub fn set_trampoline_trapframe(cpu_id: usize, trap_frame: usize) {
266 unsafe {
267 TRAMPOLINE_TRAPFRAME[cpu_id] = Some(trap_frame);
268 }
269}
270
271pub fn get_trampoline_trapframe(cpu_id: usize) -> usize {
272 unsafe {
273 match TRAMPOLINE_TRAPFRAME[cpu_id] {
274 Some(v) => v,
275 None => panic!("Trampoline is not initialized"),
276 }
277 }
278}
279
280pub fn switch_to_kernel_vm() {
281 let manager = get_kernel_vm_manager();
282 let root_page_table = manager.get_root_page_table().expect("Root page table is not set");
283 set_trapvector(get_kernel_trapvector_paddr());
284 root_page_table.switch(manager.get_asid());
285}
286
287pub fn switch_to_user_vm(cpu: &mut Arch) {
288 let cpu_id = cpu.get_cpuid();
289 let task = get_scheduler().get_current_task(cpu_id).expect("No current task found");
290 let manager = &task.vm_manager;
291 let root_page_table = manager.get_root_page_table().expect("Root page table is not set");
292 set_trapvector(get_trampoline_trap_vector());
293 root_page_table.switch(manager.get_asid());
294}