hermit/arch/x86_64/mm/
virtualmem.rs1use align_address::Align;
2use free_list::{AllocError, FreeList, PageLayout, PageRange};
3use hermit_sync::InterruptTicketMutex;
4
5use crate::arch::x86_64::mm::VirtAddr;
6use crate::arch::x86_64::mm::paging::{BasePageSize, PageSize};
7
8static KERNEL_FREE_LIST: InterruptTicketMutex<FreeList<16>> =
9 InterruptTicketMutex::new(FreeList::new());
10
11pub fn init() {
12 let range = PageRange::new(
13 kernel_heap_end().as_usize().div_ceil(2),
14 kernel_heap_end().as_usize() + 1,
15 )
16 .unwrap();
17
18 unsafe {
19 KERNEL_FREE_LIST.lock().deallocate(range).unwrap();
20 }
21}
22
23pub fn allocate(size: usize) -> Result<VirtAddr, AllocError> {
24 assert!(size > 0);
25 assert_eq!(
26 size % BasePageSize::SIZE as usize,
27 0,
28 "Size {:#X} is not a multiple of {:#X}",
29 size,
30 BasePageSize::SIZE
31 );
32
33 let layout = PageLayout::from_size(size).unwrap();
34
35 Ok(VirtAddr::new(
36 KERNEL_FREE_LIST
37 .lock()
38 .allocate(layout)?
39 .start()
40 .try_into()
41 .unwrap(),
42 ))
43}
44
45pub fn allocate_aligned(size: usize, align: usize) -> Result<VirtAddr, AllocError> {
46 assert!(size > 0);
47 assert!(align > 0);
48 assert_eq!(
49 size % align,
50 0,
51 "Size {size:#X} is not a multiple of the given alignment {align:#X}"
52 );
53 assert_eq!(
54 align % BasePageSize::SIZE as usize,
55 0,
56 "Alignment {:#X} is not a multiple of {:#X}",
57 align,
58 BasePageSize::SIZE
59 );
60
61 let layout = PageLayout::from_size_align(size, align).unwrap();
62
63 Ok(VirtAddr::new(
64 KERNEL_FREE_LIST
65 .lock()
66 .allocate(layout)?
67 .start()
68 .try_into()
69 .unwrap(),
70 ))
71}
72
73pub fn deallocate(virtual_address: VirtAddr, size: usize) {
74 assert!(
75 virtual_address <= kernel_heap_end(),
76 "Virtual address {virtual_address:p} is not <= kernel_heap_end()"
77 );
78 assert!(
79 virtual_address.is_aligned_to(BasePageSize::SIZE),
80 "Virtual address {:p} is not a multiple of {:#X}",
81 virtual_address,
82 BasePageSize::SIZE
83 );
84 assert!(size > 0);
85 assert_eq!(
86 size % BasePageSize::SIZE as usize,
87 0,
88 "Size {:#X} is not a multiple of {:#X}",
89 size,
90 BasePageSize::SIZE
91 );
92
93 let range = PageRange::from_start_len(virtual_address.as_u64() as usize, size).unwrap();
94
95 unsafe {
96 KERNEL_FREE_LIST.lock().deallocate(range).unwrap();
97 }
98}
99
100pub fn print_information() {
139 let free_list = KERNEL_FREE_LIST.lock();
140 info!("Virtual memory free list:\n{free_list}");
141}
142
143#[inline]
146pub fn kernel_heap_end() -> VirtAddr {
147 use x86_64::structures::paging::PageTableIndex;
148
149 let p4_index = if cfg!(feature = "common-os") {
150 PageTableIndex::new(1)
151 } else {
152 PageTableIndex::new(256)
153 };
154
155 let addr = u64::from(p4_index) << 39;
156 assert_eq!(VirtAddr::new_truncate(addr).p4_index(), p4_index);
157
158 VirtAddr::new_truncate(addr - 1)
159}