kernel/vm/
mod.rs

1//! Virtual memory module.
2//! 
3//! This module provides the virtual memory abstraction for the kernel. It
4//! includes functions for managing virtual address spaces.
5
6use 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/* Initialize MMU and enable paging */
66#[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(); /* Kernel ASID */
71    let root_page_table = get_root_pagetable(asid).unwrap();
72    manager.set_asid(asid);
73
74    /* Map kernel space */
75    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, // Kernel memory should be shared across all processes
94    };
95    manager.add_memory_map(kernel_map).map_err(|e| panic!("Failed to add kernel memory map: {}", e)).unwrap();
96    /* Pre-map the kernel space */
97    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, // Device memory should be shared
112    };
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    /* User stack page */
128    let num_of_stack_page = 4; // 4 pages for user stack
129    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    /* Guard page */
133   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, // Kernel memory should be shared across all processes
153    };
154    task.vm_manager.add_memory_map(kernel_map).map_err(|e| {
155        panic!("Failed to add kernel memory map: {}", e);
156    }).unwrap();
157    /* Pre-map the kernel space */
158    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    /* Stack page */
164    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, // Device memory should be shared
179    };
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    /* User stack page */
187    let num_of_stack_page = 4; // 4 pages for user stack
188    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    /* Guard page */
191    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    // println!("Trampoline space mapped   : {:#x} - {:#x}", trampoline_vaddr_start, trampoline_vaddr_end);
217    // println!("  Trampoline paddr  : {:#x} - {:#x}", trampoline_start, trampoline_end);
218    // println!("  Trap entry paddr  : {:#x}", trap_entry_paddr);
219    // println!("  Trap frame paddr  : {:#x}", trapframe_paddr);
220    // println!("  Trampoline vaddr  : {:#x} - {:#x}", trampoline_vaddr_start, trampoline_vaddr_end);
221    // println!("  Trap entry vaddr  : {:#x}", trap_entry_vaddr);
222    // println!("  Trap frame vaddr  : {:#x}", trapframe_vaddr);
223    
224    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, // Trampoline should be shared across all processes
238    };
239
240    manager.add_memory_map(trampoline_map)
241        .map_err(|e| panic!("Failed to add trampoline memory map: {}", e)).unwrap();
242    /* Pre-map the trampoline space */
243    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}