Nothing to see here, move along
1use crate::mem::addr;
2use crate::mem::phys::BitmapFrameAllocator;
3use crate::sync::IrqMutex;
4use lancer_core::object_layout::KernelObject;
5use x86_64::PhysAddr;
6
7const SLOTS_PER_FRAME: usize = 64;
8const MAX_FRAMES: usize = 256;
9const SLOT_SIZE: usize = 64;
10const INIT_FRAMES: usize = 192;
11
12struct KernelObjectAllocatorInner {
13 frame_phys: [u64; MAX_FRAMES],
14 bitmap: [u64; MAX_FRAMES],
15 frame_count: usize,
16}
17
18impl KernelObjectAllocatorInner {
19 const fn new() -> Self {
20 Self {
21 frame_phys: [0; MAX_FRAMES],
22 bitmap: [0; MAX_FRAMES],
23 frame_count: 0,
24 }
25 }
26
27 fn install_frames(&mut self, phys_addrs: &[u64]) {
28 phys_addrs
29 .iter()
30 .for_each(|&phys| match self.frame_count < MAX_FRAMES {
31 true => {
32 self.frame_phys[self.frame_count] = phys;
33 self.bitmap[self.frame_count] = 0;
34 self.frame_count += 1;
35 }
36 false => {}
37 });
38 }
39
40 fn alloc_slot(&mut self) -> Option<u64> {
41 (0..self.frame_count).find_map(|fi| {
42 let bm = self.bitmap[fi];
43 match bm == u64::MAX {
44 true => None,
45 false => {
46 let bit = (!bm).trailing_zeros() as usize;
47 self.bitmap[fi] |= 1u64 << bit;
48 Some(self.frame_phys[fi] + (bit * SLOT_SIZE) as u64)
49 }
50 }
51 })
52 }
53
54 fn free_slot(&mut self, phys: u64) -> bool {
55 (0..self.frame_count)
56 .find(|&fi| {
57 let base = self.frame_phys[fi];
58 phys >= base && phys < base + 4096
59 })
60 .map(|fi| {
61 let offset = (phys - self.frame_phys[fi]) as usize;
62 let bit = offset / SLOT_SIZE;
63 let mask = 1u64 << bit;
64 let was_allocated = self.bitmap[fi] & mask != 0;
65 debug_assert!(
66 was_allocated,
67 "kernel_objects: double-free at phys {phys:#x}"
68 );
69 self.bitmap[fi] &= !mask;
70 was_allocated
71 })
72 .unwrap_or(false)
73 }
74}
75
76static KERNEL_OBJ_ALLOC: IrqMutex<KernelObjectAllocatorInner, 3> =
77 IrqMutex::new(KernelObjectAllocatorInner::new());
78
79pub fn init(allocator: &mut BitmapFrameAllocator) {
80 let mut frame_addrs = [0u64; INIT_FRAMES];
81 let count = (0..INIT_FRAMES)
82 .scan((), |_, _| allocator.allocate())
83 .enumerate()
84 .map(|(i, frame)| {
85 let phys = frame.phys_addr();
86 let virt = addr::phys_to_virt(phys);
87 unsafe {
88 core::ptr::write_bytes(virt.as_mut_ptr::<u8>(), 0, 4096);
89 }
90 frame_addrs[i] = phys.as_u64();
91 core::mem::forget(frame);
92 i + 1
93 })
94 .last()
95 .unwrap_or(0);
96
97 {
98 let mut alloc = KERNEL_OBJ_ALLOC.lock();
99 alloc.install_frames(&frame_addrs[..count]);
100 }
101
102 crate::kprintln!(
103 " KernelObjectAllocator: {} frames ({} slots)",
104 count,
105 count * SLOTS_PER_FRAME,
106 );
107}
108
109pub fn alloc_slot() -> Option<u64> {
110 KERNEL_OBJ_ALLOC.lock().alloc_slot()
111}
112
113pub fn write_at<T: KernelObject>(phys: u64, obj: T) {
114 let virt = addr::phys_to_virt(PhysAddr::new(phys));
115 unsafe {
116 core::ptr::write(virt.as_mut_ptr::<T>(), obj);
117 }
118}
119
120pub fn free_slot(phys: u64) {
121 let _ = KERNEL_OBJ_ALLOC.lock().free_slot(phys);
122}