hermit/arch/x86_64/mm/
virtualmem.rs

1use 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
100/*pub fn reserve(virtual_address: VirtAddr, size: usize) {
101	assert!(
102		virtual_address >= VirtAddr(mm::kernel_end_address().as_u64()),
103		"Virtual address {:#X} is not >= KERNEL_END_ADDRESS",
104		virtual_address
105	);
106	assert!(
107		virtual_address <= kernel_heap_end(),
108		"Virtual address {:#X} is not <= kernel_heap_end()",
109		virtual_address
110	);
111	assert_eq!(
112		virtual_address % BasePageSize::SIZE,
113		0,
114		"Virtual address {:#X} is not a multiple of {:#X}",
115		virtual_address,
116		BasePageSize::SIZE
117	);
118	assert!(size > 0);
119	assert_eq!(
120		size % BasePageSize::SIZE as usize,
121		0,
122		"Size {:#X} is not a multiple of {:#X}",
123		size,
124		BasePageSize::SIZE
125	);
126
127	let result = KERNEL_FREE_LIST
128		.lock()
129		.reserve(virtual_address.as_usize(), size);
130	assert!(
131		result.is_ok(),
132		"Could not reserve {:#X} bytes of virtual memory at {:#X}",
133		size,
134		virtual_address
135	);
136}*/
137
138pub fn print_information() {
139	let free_list = KERNEL_FREE_LIST.lock();
140	info!("Virtual memory free list:\n{free_list}");
141}
142
143/// End of the virtual memory address space reserved for kernel memory (inclusive).
144/// The virtual memory address space reserved for the task heap starts after this.
145#[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}