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_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/* 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_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    /* Map kernel space */
76    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, // Kernel memory should be shared across all processes
95    };
96    manager.add_memory_map(kernel_map).map_err(|e| panic!("Failed to add kernel memory map: {}", e)).unwrap();
97    /* Pre-map the kernel space */
98    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, // Device memory should be shared
113    };
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    /* User stack page */
129    let num_of_stack_page = 2; // 2 pages for user stack
130    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    /* Guard page */
134   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, // Kernel memory should be shared across all processes
155    };
156    task.vm_manager.add_memory_map(kernel_map).map_err(|e| {
157        panic!("Failed to add kernel memory map: {}", e);
158    }).unwrap();
159    /* Pre-map the kernel space */
160    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    /* Stack page */
166    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, // Device memory should be shared
181    };
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    /* User stack page */
189    let num_of_stack_page = 2; // 2 pages for user stack
190    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    /* Guard page */
193    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    // println!("Trampoline space mapped   : {:#x} - {:#x}", trampoline_vaddr_start, trampoline_vaddr_end);
219    // println!("  Trampoline paddr  : {:#x} - {:#x}", trampoline_start, trampoline_end);
220    // println!("  Trap entry paddr  : {:#x}", trap_entry_paddr);
221    // println!("  Trap frame paddr  : {:#x}", trapframe_paddr);
222    // println!("  Trampoline vaddr  : {:#x} - {:#x}", trampoline_vaddr_start, trampoline_vaddr_end);
223    // println!("  Trap entry vaddr  : {:#x}", trap_entry_vaddr);
224    // println!("  Trap frame vaddr  : {:#x}", trapframe_vaddr);
225    
226    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, // Trampoline should be shared across all processes
240    };
241
242    manager.add_memory_map(trampoline_map)
243        .map_err(|e| panic!("Failed to add trampoline memory map: {}", e)).unwrap();
244    /* Pre-map the trampoline space */
245    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}