Skip to content

Commit 52d86b4

Browse files
committed
[Kernel - Rust] PMM supports contiguous allocations
1 parent bcf6db4 commit 52d86b4

File tree

1 file changed

+92
-9
lines changed
  • rust_kernel_libs/pmm/src

1 file changed

+92
-9
lines changed

rust_kernel_libs/pmm/src/lib.rs

+92-9
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// live in reserved blocks.
33
// This makes it dangerous to use, for example, println or anything that will invoke string
44
// formatting machinery.
5-
#![no_std]
5+
#![cfg_attr(target_os = "axle_kernel", no_std)]
66
#![feature(format_args_nl)]
77
#![feature(cstr_from_bytes_until_nul)]
88
#![feature(default_alloc_error_handler)]
@@ -12,9 +12,13 @@ extern crate ffi_bindings;
1212
use core::ffi::CStr;
1313
use core::usize::MAX;
1414
use heapless::spsc::Queue;
15-
use heapless::Vec;
1615
use spin::Mutex;
1716

17+
#[cfg(target_os = "axle_kernel")]
18+
use heapless::Vec;
19+
#[cfg(not(target_os = "axle_kernel"))]
20+
use std::vec::Vec;
21+
1822
use ffi_bindings::cstr_core::CString;
1923
use ffi_bindings::{
2024
assert, boot_info_get, println, BootInfo, PhysicalMemoryRegionType, _panic,
@@ -42,13 +46,19 @@ const MAX_FRAMES_ALLOCATOR_CAN_BOOKKEEP: usize = MAX_MEMORY_ALLOCATOR_CAN_BOOKKE
4246
const CONTIGUOUS_CHUNK_POOL_SIZE: usize = MEGABYTE * 128;
4347
const MAX_CONTIGUOUS_CHUNK_FRAMES: usize = CONTIGUOUS_CHUNK_POOL_SIZE / PAGE_SIZE;
4448

45-
#[derive(Debug, Copy, Clone)]
46-
struct PhysicalFrame(u64);
49+
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
50+
struct PhysicalFrame(usize);
4751

48-
#[derive(Debug, Copy, Clone)]
52+
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4953
struct ContiguousChunk {
5054
base: PhysicalFrame,
51-
size: u64,
55+
size: usize,
56+
}
57+
58+
impl ContiguousChunk {
59+
fn new(base: PhysicalFrame, size: usize) -> Self {
60+
Self { base, size }
61+
}
5262
}
5363

5464
struct ContiguousChunkPoolDescription {
@@ -64,26 +74,72 @@ impl ContiguousChunkPoolDescription {
6474

6575
struct ContiguousChunkPool {
6676
pool_description: Option<ContiguousChunkPoolDescription>,
77+
78+
#[cfg(target_os = "axle_kernel")]
6779
allocated_chunks: Vec<ContiguousChunk, MAX_CONTIGUOUS_CHUNK_FRAMES>,
68-
free_frames: Vec<PhysicalFrame, MAX_CONTIGUOUS_CHUNK_FRAMES>,
80+
#[cfg(target_os = "axle_kernel")]
81+
free_chunks: Vec<ContiguousChunk, MAX_CONTIGUOUS_CHUNK_FRAMES>,
82+
#[cfg(not(target_os = "axle_kernel"))]
83+
allocated_chunks: Vec<ContiguousChunk>,
84+
#[cfg(not(target_os = "axle_kernel"))]
85+
free_chunks: Vec<ContiguousChunk>,
6986
}
87+
extern crate alloc;
7088

7189
impl ContiguousChunkPool {
7290
const fn new() -> Self {
7391
Self {
7492
pool_description: None,
7593
allocated_chunks: Vec::new(),
76-
free_frames: Vec::new(),
94+
free_chunks: Vec::new(),
7795
}
7896
}
7997

8098
fn set_pool_description(&mut self, base: usize, total_size: usize) {
99+
println!("Setting pool description");
81100
self.pool_description = Some(ContiguousChunkPoolDescription::new(base, total_size));
101+
// Start off with a single free chunk the size of the entire pool
102+
#[cfg(target_os = "axle_kernel")]
103+
self.free_chunks
104+
.push(ContiguousChunk::new(PhysicalFrame(base), total_size))
105+
.unwrap();
106+
#[cfg(not(target_os = "axle_kernel"))]
107+
self.free_chunks
108+
.push(ContiguousChunk::new(PhysicalFrame(base), total_size));
82109
}
83110

84111
fn is_pool_configured(&self) -> bool {
85112
self.pool_description.is_some()
86113
}
114+
115+
fn alloc(&mut self, size: usize) -> usize {
116+
// Look for a chunk big enough to satisfy the allocation
117+
let mut chunk_to_drop = None;
118+
let mut allocated_chunk = None;
119+
for mut chunk in self.free_chunks.iter_mut() {
120+
// Is the chunk large enough to satisfy this allocation?
121+
if chunk.size >= size {
122+
let chunk_base = chunk.base.0;
123+
let new_size = chunk.size - size;
124+
if new_size == 0 {
125+
// Remove the chunk entirely
126+
chunk_to_drop = Some(chunk.clone());
127+
} else {
128+
// Shrink the chunk to account for the fact that part of it is now allocated
129+
chunk.base = PhysicalFrame(chunk_base + size);
130+
chunk.size -= size;
131+
}
132+
// And add an allocated chunk
133+
allocated_chunk = Some(ContiguousChunk::new(PhysicalFrame(chunk_base), size));
134+
self.allocated_chunks.push(allocated_chunk.unwrap());
135+
break;
136+
}
137+
}
138+
if let Some(chunk_to_drop) = chunk_to_drop {
139+
self.free_chunks.retain(|i| *i == chunk_to_drop);
140+
}
141+
allocated_chunk.unwrap().base.0
142+
}
87143
}
88144

89145
/// If we have a maximum of 16GB of RAM tracked, each array to track the frames will occupy 512kb.
@@ -174,5 +230,32 @@ pub unsafe fn pmm_free(frame_addr: usize) {
174230

175231
#[no_mangle]
176232
pub unsafe fn pmm_alloc_continuous_range(size: usize) -> usize {
177-
todo!()
233+
let ret = CONTIGUOUS_CHUNK_POOL.alloc(size);
234+
printf(
235+
"pmm_alloc_contiguous_range(0x%p) = 0x%p\n\0".as_ptr() as *const u8,
236+
size,
237+
ret,
238+
);
239+
ret
240+
}
241+
242+
#[cfg(test)]
243+
mod test {
244+
use crate::{ContiguousChunk, ContiguousChunkPool, PhysicalFrame};
245+
246+
#[test]
247+
fn basic_allocation() {
248+
// Given an empty pool
249+
let mut pool = Box::new(ContiguousChunkPool::new());
250+
pool.set_pool_description(0x10000, 0x20000);
251+
// When I allocate a block
252+
let allocated_chunk = pool.alloc(0x4000);
253+
// Then it's allocated at the beginning
254+
assert_eq!(allocated_chunk, 0x10000);
255+
// And the free chunks are split as expected
256+
assert_eq!(
257+
pool.free_chunks,
258+
vec![ContiguousChunk::new(PhysicalFrame(0x14000), 0x1c000)]
259+
);
260+
}
178261
}

0 commit comments

Comments
 (0)