Nothing to see here, move along
1use limine::memory_map::Entry;
2use x86_64::PhysAddr;
3
4use super::RawSlice;
5use super::addr;
6use super::phys::BitmapFrameAllocator;
7use crate::sync::IrqMutex;
8
9const PAGE_SIZE: u64 = 4096;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum RefcountError {
13 OutOfRange(PhysAddr),
14 Overflow(PhysAddr),
15 Underflow(PhysAddr),
16}
17
18static REFCOUNTS: IrqMutex<RawSlice<u16>, 4> = IrqMutex::new(RawSlice::empty());
19
20pub fn init(memory_map: &[&Entry]) {
21 let max_addr = memory_map
22 .iter()
23 .filter(|entry| entry.entry_type == limine::memory_map::EntryType::USABLE)
24 .map(|entry| entry.base + entry.length)
25 .fold(0u64, u64::max);
26
27 let total_frames = (max_addr / PAGE_SIZE) as usize;
28 let bytes_needed = total_frames * 2;
29 let frames_needed = bytes_needed.div_ceil(PAGE_SIZE as usize);
30
31 let allocator = BitmapFrameAllocator;
32 let phys_base = allocator
33 .allocate_contiguous(frames_needed)
34 .expect("[refcount] failed to allocate contiguous frames for refcount table");
35
36 let virt = addr::phys_to_virt(phys_base);
37 let ptr = virt.as_u64() as *mut u16;
38
39 unsafe {
40 core::ptr::write_bytes(ptr, 0, total_frames);
41 }
42
43 let mut rc = REFCOUNTS.lock();
44 rc.init(ptr, total_frames);
45}
46
47pub fn increment(phys: PhysAddr) -> Result<(), RefcountError> {
48 let idx = (phys.as_u64() / PAGE_SIZE) as usize;
49 let mut rc = REFCOUNTS.lock();
50 let slot = rc
51 .as_slice_mut()
52 .get_mut(idx)
53 .ok_or(RefcountError::OutOfRange(phys))?;
54 let new = slot.checked_add(1).ok_or(RefcountError::Overflow(phys))?;
55 *slot = new;
56 Ok(())
57}
58
59pub fn decrement(phys: PhysAddr) -> Result<u16, RefcountError> {
60 let idx = (phys.as_u64() / PAGE_SIZE) as usize;
61 let mut rc = REFCOUNTS.lock();
62 let slot = rc
63 .as_slice_mut()
64 .get_mut(idx)
65 .ok_or(RefcountError::OutOfRange(phys))?;
66 let new = slot.checked_sub(1).ok_or(RefcountError::Underflow(phys))?;
67 *slot = new;
68 Ok(new)
69}
70
71#[allow(dead_code)]
72pub fn get(phys: PhysAddr) -> u16 {
73 let idx = (phys.as_u64() / PAGE_SIZE) as usize;
74 let rc = REFCOUNTS.lock();
75 if idx < rc.len() {
76 rc.as_slice()[idx]
77 } else {
78 0
79 }
80}