1pub mod allocator;
4pub mod vmm;
5
6use crate::arch::x86_64::paging::{get_root, Pagetable};
7use crate::defs::*;
8use crate::machine::multiboot;
9use crate::mm::allocator::buddy::BuddyAllocator;
10use crate::mm::allocator::IRQLockedHeap;
11use crate::proc::sync::spin::SpinMutexIRQ;
12use alloc::alloc::{alloc, alloc_zeroed, dealloc, Layout};
13use alloc::vec::Vec;
14use core::arch::asm;
15use core::ops::{Deref, Range};
16use lazy_static::lazy_static;
17
18#[global_allocator]
19static ALLOCATOR: IRQLockedHeap = IRQLockedHeap::empty();
20
21static PFA: SpinMutexIRQ<BuddyAllocator> =
29 SpinMutexIRQ::new(BuddyAllocator::default());
30
31lazy_static! {
32 pub static ref KSTACK_ALLOCATOR: SpinMutexIRQ<KStackAllocator> =
33 SpinMutexIRQ::new(KStackAllocator::new());
34}
35
36pub fn init() {
38 let mbi = multiboot::get_mb_info().unwrap();
39 let mmapinfo = unsafe { mbi.get_mmap() }.unwrap();
40 let buf_start = mmapinfo.mmap_addr;
41 let buf_len = mmapinfo.mmap_length;
42 let buf_end = buf_start + buf_len;
43 let mut curr = buf_start as u64;
44 let mut largest_phy_range: Option<Range<u64>> = None;
46 loop {
47 if curr >= buf_end as u64 {
48 break;
49 }
50 let mblock = unsafe { &*(curr as *const multiboot::MultibootMmap) };
51 curr += mblock.size as u64;
52 curr += 4;
53 if mblock.mtype != multiboot::MultibootMmap::MTYPE_RAM {
54 continue;
55 }
56 if mblock.get_end() <= ExternSyms::KERNEL_PM_START as u64 {
57 continue;
58 }
59 let mut r = mblock.get_range();
60 if r.contains(&(ExternSyms::KERNEL_PM_END as u64)) {
61 assert!(
62 r.contains(&(ExternSyms::KERNEL_PM_START as u64)),
63 "FATAL: kernel physical map cross physical blocks, how?"
64 );
65 r.start = ExternSyms::KERNEL_PM_END as u64;
66 }
67 match largest_phy_range {
69 None => largest_phy_range = Some(r),
70 Some(ref lr) => {
71 if (r.end - r.start) > (lr.end - lr.start) {
72 largest_phy_range = Some(r);
73 }
74 }
75 }
76 }
77
78 let pr = &largest_phy_range.expect("Can't find usable physical block");
82 let prange_pfa = pr.start..pr.start + 2 * Mem::MIN_PHY_MEM;
83 let prange_heap = pr.start + Mem::MIN_PHY_MEM..pr.end;
84 unsafe { PFA.lock().init(prange_pfa.start, prange_pfa.end) };
86 println!("[mm] PFA initialized: {:X?}", PFA.lock().deref());
87
88 unsafe {
90 ALLOCATOR.lock().init(
91 P2V(prange_heap.start).unwrap() as *mut u8,
92 (prange_heap.end - prange_heap.start) as usize,
93 );
94 }
95 println!(
96 "[init] mm: heap alloc initialized @ {:#X} - {:#X}",
97 P2V(prange_heap.start).unwrap(),
98 P2V(prange_heap.end).unwrap()
99 );
100}
101
102pub struct KStackAllocator {
104 pool: Vec<u64>,
105}
106
107impl KStackAllocator {
111 const KSTACK_ALLOC_POOL_CAP: usize = 16;
112 const KSTACK_LAYOUT: Layout = unsafe {
113 Layout::from_size_align_unchecked(
114 Mem::KERNEL_STACK_SIZE as usize,
115 Mem::KERNEL_STACK_SIZE as usize,
116 )
117 };
118
119 pub fn new() -> Self {
120 let p = Vec::with_capacity(Self::KSTACK_ALLOC_POOL_CAP);
121 Self { pool: p }
122 }
123
124 pub unsafe fn allocate(&mut self) -> u64 {
126 if let Some(addr) = self.pool.pop() {
127 return addr;
128 } else {
129 return alloc(Self::KSTACK_LAYOUT) as u64;
130 }
131 }
132
133 pub unsafe fn free(&mut self, addr: u64) {
136 if self.pool.len() < Self::KSTACK_ALLOC_POOL_CAP {
137 self.pool.push(addr);
138 } else {
139 dealloc(addr as *mut u8, Self::KSTACK_LAYOUT);
140 }
141 }
142
143 pub unsafe fn populate(&mut self) {
146 for _ in 0..Self::KSTACK_ALLOC_POOL_CAP {
147 self.pool.push(alloc(Self::KSTACK_LAYOUT) as u64);
148 }
149 }
150}
151
152const LAYOUT_4K_ALIGNED: Layout =
153 unsafe { Layout::from_size_align_unchecked(0x1000, 0x1000) };
154
155pub fn allocate_4k() -> u64 {
158 return unsafe { alloc(LAYOUT_4K_ALIGNED) } as u64;
159}
160pub fn allocate_4k_zeroed() -> u64 {
161 return unsafe { alloc_zeroed(LAYOUT_4K_ALIGNED) } as u64;
162}
163
164pub fn allocate_frame_4k() -> Option<u64> {
166 let f = PFA.lock().alloc_frame(0)?;
167 Some(f.get_paddr())
168}
169
170pub fn allocate_frame_4k_zeroed() -> Option<u64> {
172 if let Some(pa) = allocate_frame_4k() {
173 let va = P2V(pa).unwrap();
174 unsafe {
175 core::slice::from_raw_parts_mut(
176 va as *mut u8,
177 Mem::PAGE_SIZE as usize,
178 )
179 .fill(0)
180 };
181 Some(pa)
182 } else {
183 None
184 }
185}
186
187pub unsafe fn free_frame_4k(paddr: u64) {
191 PFA.lock().free_frame_by_pa(paddr, 0);
192}
193
194pub fn buddy_info() { PFA.lock().print_debug_info(); }
195
196pub fn invlpg(va: u64) { unsafe { asm!("invlpg [{0}]", in(reg) va) }; }
198
199pub fn flush_tlb() {
201 unsafe {
202 asm!(
203 "
204 push rax;
205 mov rax, cr3;
206 mov cr3, rax;
207 pop rax;
208 "
209 )
210 }
211}
212
213pub unsafe fn drop_init_mapping() {
221 let pt: &mut Pagetable = unsafe { &mut *(get_root() as *mut Pagetable) };
222 pt.entries[0].set_unused();
223 flush_tlb();
224}