Skip to content

Commit 48bd19a

Browse files
frame::BuddyAllocator: fix deallocation bug
Each block is a power of two number of pages and the allocator assumed that the buddy size was incremented by power of two which was incorrect since we went from Size8KiB to Size2MiB which introduced the pesky dealloction bug. This is now solved by having the buddy size's as follows: ```rust const BUDDY_SIZE: [u64; 10] = [ Size4KiB::SIZE, // 4 KiB Size4KiB::SIZE * 2, // 8 KiB Size4KiB::SIZE * 4, // 16 KiB Size4KiB::SIZE * 8, // 32 KiB Size4KiB::SIZE * 16, // 64 KiB Size4KiB::SIZE * 32, // 128 KiB Size4KiB::SIZE * 64, // 256 KiB Size4KiB::SIZE * 128, // 512 KiB Size4KiB::SIZE * 256, // 1 MiB Size2MiB::SIZE, // 2 MiB ]; ``` NOTE: The linux buddy allocator has 11 order's, in which the last one is 4 MiB. Should we have that or no? Signed-off-by: Andy-Python-Programmer <[email protected]>
1 parent a04cc49 commit 48bd19a

File tree

4 files changed

+69
-29
lines changed

4 files changed

+69
-29
lines changed

aero.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,7 @@ def run_in_emulator(build_info: BuildInfo, iso_path):
491491
qemu_args += ['-device', 'ramfb',
492492
'-M', 'virt', '-cpu', 'cortex-a72']
493493
elif build_info.target_arch == "x86_64":
494-
qemu_args += ["-cpu", "qemu64,+la57" if args.la57 else "qemu64"]
494+
qemu_args += ["-cpu", "qemu64,+la57" if args.la57 else "max"]
495495
else:
496496
log_error("unknown target architecture")
497497
exit(1)

src/aero_kernel/src/main.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
*/
1919

2020
//! # Aero
21-
//! Aero is a new modern, unix based operating system. It is being developed for educational purposes.
21+
//! Aero is a new modern, unix based operating system. It is being developed for educational
22+
//! purposes.
2223
//!
2324
//! ## Code organization and architecture
2425
//! The code is divided into different *modules*, each representing a *subsystem* of the kernel.

src/aero_kernel/src/mem/paging/frame.rs

Lines changed: 65 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,35 @@ use crate::mem::paging::align_up;
3434
use crate::utils::bitmap::Bitmap;
3535
use crate::utils::sync::Mutex;
3636

37-
static BUDDY_SIZE: [u64; 3] = [Size4KiB::SIZE, Size4KiB::SIZE * 4, Size2MiB::SIZE];
37+
const BUDDY_SIZE: [u64; 10] = [
38+
Size4KiB::SIZE, // 4 KiB
39+
Size4KiB::SIZE * 2, // 8 KiB
40+
Size4KiB::SIZE * 4, // 16 KiB
41+
Size4KiB::SIZE * 8, // 32 KiB
42+
Size4KiB::SIZE * 16, // 64 KiB
43+
Size4KiB::SIZE * 32, // 128 KiB
44+
Size4KiB::SIZE * 64, // 256 KiB
45+
Size4KiB::SIZE * 128, // 512 KiB
46+
Size4KiB::SIZE * 256, // 1 MiB
47+
Size2MiB::SIZE, // 2 MiB
48+
];
49+
50+
const fn order_from_size(size: u64) -> usize {
51+
// UNSTABLE: We cannot make an iterator from `BUDDY_SIZE` or use a for loop
52+
// in const context.
53+
let mut order = 0;
54+
55+
while order < BUDDY_SIZE.len() {
56+
let buddy_size = BUDDY_SIZE[order];
57+
if buddy_size >= size {
58+
return order;
59+
}
60+
61+
order += 1;
62+
}
63+
64+
unreachable!()
65+
}
3866

3967
pub struct LockedFrameAllocator(Once<Mutex<GlobalFrameAllocator>>);
4068

@@ -60,8 +88,12 @@ unsafe impl FrameAllocator<Size4KiB> for LockedFrameAllocator {
6088

6189
self.0.get().map(|m| {
6290
m.lock_irq()
63-
.allocate_frame_inner(0)
64-
.map(|f| PhysFrame::containing_address(f))
91+
.allocate_frame_inner(order_from_size(Size4KiB::SIZE))
92+
.map(|f| {
93+
let frame = PhysFrame::containing_address(f);
94+
frame.as_slice_mut().fill(0);
95+
frame
96+
})
6597
})?
6698
}
6799

@@ -70,10 +102,13 @@ unsafe impl FrameAllocator<Size4KiB> for LockedFrameAllocator {
70102
// let caller = core::panic::Location::caller();
71103
// log::debug!("deallocation request of 4KiB by {:?}", caller);
72104

73-
// self.0
74-
// .get()
75-
// .map(|m| m.lock().deallocate_frame_inner(frame.start_address(), 0))
76-
// .unwrap_or(());
105+
self.0
106+
.get()
107+
.map(|m| {
108+
m.lock_irq()
109+
.deallocate_frame_inner(frame.start_address(), order_from_size(Size4KiB::SIZE))
110+
})
111+
.unwrap_or(());
77112
}
78113
}
79114

@@ -85,7 +120,7 @@ unsafe impl FrameAllocator<Size2MiB> for LockedFrameAllocator {
85120

86121
self.0.get().map(|m| {
87122
m.lock_irq()
88-
.allocate_frame_inner(2)
123+
.allocate_frame_inner(order_from_size(Size2MiB::SIZE))
89124
.map(|f| PhysFrame::containing_address(f))
90125
})?
91126
}
@@ -99,7 +134,7 @@ unsafe impl FrameAllocator<Size2MiB> for LockedFrameAllocator {
99134
.get()
100135
.map(|m| {
101136
m.lock_irq()
102-
.deallocate_frame_inner(frame.start_address(), 2)
137+
.deallocate_frame_inner(frame.start_address(), order_from_size(Size2MiB::SIZE))
103138
})
104139
.unwrap_or(());
105140
}
@@ -150,7 +185,7 @@ impl<'a> Iterator for RangeMemoryIter<'a> {
150185
#[repr(usize)]
151186
pub enum BuddyOrdering {
152187
Size4KiB = 0,
153-
Size8KiB = 2,
188+
Size8KiB = 1,
154189
}
155190

156191
// FIXME: REMOVE THIS FUNCTION
@@ -247,35 +282,32 @@ unsafe impl Send for BootAllocRef {}
247282

248283
static VM_FRAMES: Once<Vec<VmFrame>> = Once::new();
249284

250-
/// Buddy allocator combines power-of-two allocator with free buffer
251-
/// coalescing.
285+
/// Buddy allocator combines power-of-two allocator with free buffer coalescing.
252286
///
253287
/// ## Overview
254288
///
255289
/// Overview of the buddy allocation algorithm:
256290
///
257-
/// * Memory is broken up into large blocks of pages where each block
258-
/// is a power of two number of pages.
291+
/// * Memory is broken up into large blocks of pages where each block is a power of two number of
292+
/// pages.
259293
///
260-
/// * If a block of the desired size is not available, a larger block is
261-
/// broken up in half and the two blocks are marked as buddies then one half
262-
/// is used for the allocation and the other half is marked free.
294+
/// * If a block of the desired size is not available, a larger block is broken up in half and the
295+
/// two blocks are marked as buddies then one half is used for the allocation and the other half
296+
/// is marked free.
263297
///
264-
/// * The blocks are continuously halved as necessary until a block of the
265-
/// desired size is available.
298+
/// * The blocks are continuously halved as necessary until a block of the desired size is
299+
/// available.
266300
///
267-
/// * When a block is later freed, the buddy is examined and the two coalesced
268-
/// if it is free.
301+
/// * When a block is later freed, the buddy is examined and the two coalesced if it is free.
269302
pub struct GlobalFrameAllocator {
270-
buddies: [Bitmap<BootAllocRef>; 3],
271-
free: [usize; 3],
303+
buddies: [Bitmap<BootAllocRef>; 10],
304+
free: [usize; 10],
272305

273306
base: PhysAddr,
274307
end: PhysAddr,
275308
}
276309

277310
impl GlobalFrameAllocator {
278-
/// Create a new global frame allocator from the memory map provided by the bootloader.
279311
fn new(memory_map: &mut [NonNullPtr<LimineMemmapEntry>]) -> Self {
280312
// Find a memory map entry that is big enough to fit all of the items in
281313
// range memory iter.
@@ -350,8 +382,15 @@ impl GlobalFrameAllocator {
350382
Bitmap::empty(bref.clone()),
351383
Bitmap::empty(bref.clone()),
352384
Bitmap::empty(bref.clone()),
385+
Bitmap::empty(bref.clone()),
386+
Bitmap::empty(bref.clone()),
387+
Bitmap::empty(bref.clone()),
388+
Bitmap::empty(bref.clone()),
389+
Bitmap::empty(bref.clone()),
390+
Bitmap::empty(bref.clone()),
391+
Bitmap::empty(bref.clone()),
353392
],
354-
free: [0; 3],
393+
free: [0; 10],
355394
};
356395

357396
let size = this.end - this.base;
@@ -455,7 +494,7 @@ impl GlobalFrameAllocator {
455494
let idx = self.get_bit_idx(addr, order);
456495

457496
let buddy = &mut self.buddies[order];
458-
let change = buddy.is_set(idx) == true;
497+
let change = buddy.is_set(idx);
459498

460499
if change {
461500
buddy.set(idx, false);

src/aero_kernel/src/mem/paging/page_table.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ impl PageTableEntry {
129129
///
130130
/// - `FrameError::FrameNotPresent` if the entry doesn't have the `PRESENT` flag set.
131131
/// - `FrameError::HugeFrame` if the entry has the `HUGE_PAGE` flag set (for huge pages the
132-
/// `addr` function must be used)
132+
/// `addr` function must be used)
133133
pub fn frame(&self) -> Result<PhysFrame, FrameError> {
134134
if !self.flags().contains(PageTableFlags::PRESENT) {
135135
Err(FrameError::FrameNotPresent)

0 commit comments

Comments
 (0)