208 lines
5.2 KiB
Rust
208 lines
5.2 KiB
Rust
use super::page_pool::PagePool;
|
|
use super::process_memory::ProcessMemory;
|
|
use super::*;
|
|
use types::address::PhysicalAddress;
|
|
use types::bounded::PageCount;
|
|
use types::generation::Generation;
|
|
use types::id::{ProcessId, RegionId};
|
|
|
|
fn base() -> PhysicalAddress {
|
|
PhysicalAddress::from_raw(0x8000_0000)
|
|
}
|
|
|
|
fn process(id: u16) -> ProcessId {
|
|
ProcessId::from_raw(id)
|
|
}
|
|
|
|
fn pages(n: u16) -> PageCount {
|
|
PageCount::new(n).unwrap()
|
|
}
|
|
|
|
// --- PagePool tests ---
|
|
|
|
#[test]
|
|
fn new_pool_has_all_pages_free() {
|
|
let pool = PagePool::new(base(), 100);
|
|
assert_eq!(pool.free_count(), 100);
|
|
}
|
|
|
|
#[test]
|
|
fn allocate_reduces_free_count() {
|
|
let mut pool = PagePool::new(base(), 100);
|
|
pool.allocate(10).unwrap();
|
|
assert_eq!(pool.free_count(), 90);
|
|
}
|
|
|
|
#[test]
|
|
fn allocate_returns_base_aligned_address() {
|
|
let mut pool = PagePool::new(base(), 100);
|
|
let addr = pool.allocate(1).unwrap();
|
|
assert_eq!(addr, base());
|
|
}
|
|
|
|
#[test]
|
|
fn allocate_sequential_returns_contiguous() {
|
|
let mut pool = PagePool::new(base(), 100);
|
|
let a = pool.allocate(4).unwrap();
|
|
let b = pool.allocate(4).unwrap();
|
|
assert_eq!(a, base());
|
|
assert_eq!(b, base().offset(4));
|
|
}
|
|
|
|
#[test]
|
|
fn allocate_too_many_returns_none() {
|
|
let mut pool = PagePool::new(base(), 10);
|
|
assert!(pool.allocate(11).is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn free_then_reallocate() {
|
|
let mut pool = PagePool::new(base(), 10);
|
|
let addr = pool.allocate(5).unwrap();
|
|
assert_eq!(pool.free_count(), 5);
|
|
assert!(pool.free(addr, 5));
|
|
assert_eq!(pool.free_count(), 10);
|
|
let addr2 = pool.allocate(5).unwrap();
|
|
assert_eq!(addr2, base());
|
|
}
|
|
|
|
#[test]
|
|
fn free_out_of_range_returns_false() {
|
|
let mut pool = PagePool::new(base(), 10);
|
|
assert!(!pool.free(PhysicalAddress::from_raw(0), 1));
|
|
}
|
|
|
|
#[test]
|
|
fn allocate_fragmented_finds_gap() {
|
|
let mut pool = PagePool::new(base(), 10);
|
|
let a = pool.allocate(3).unwrap();
|
|
let _b = pool.allocate(3).unwrap();
|
|
let _c = pool.allocate(3).unwrap();
|
|
pool.free(a, 3);
|
|
// now pages 0-2 are free, 3-8 allocated, 9 free
|
|
// asking for 3 contiguous should find 0-2
|
|
let d = pool.allocate(3).unwrap();
|
|
assert_eq!(d, base());
|
|
}
|
|
|
|
#[test]
|
|
fn allocate_exact_remaining() {
|
|
let mut pool = PagePool::new(base(), 5);
|
|
let addr = pool.allocate(5).unwrap();
|
|
assert_eq!(addr, base());
|
|
assert_eq!(pool.free_count(), 0);
|
|
assert!(pool.allocate(1).is_none());
|
|
}
|
|
|
|
// --- ProcessMemory tests ---
|
|
|
|
#[test]
|
|
fn new_process_memory_has_zero_pages() {
|
|
let pm = ProcessMemory::new(process(0), 100);
|
|
assert_eq!(pm.page_count(), 0);
|
|
assert_eq!(pm.limit(), 100);
|
|
}
|
|
|
|
#[test]
|
|
fn grant_pages_within_limit() {
|
|
let mut pm = ProcessMemory::new(process(0), 100);
|
|
assert!(pm.grant(10).is_ok());
|
|
assert_eq!(pm.page_count(), 10);
|
|
}
|
|
|
|
#[test]
|
|
fn grant_pages_exceeding_limit_fails() {
|
|
let mut pm = ProcessMemory::new(process(0), 10);
|
|
assert!(pm.grant(11).is_err());
|
|
assert_eq!(pm.page_count(), 0);
|
|
}
|
|
|
|
#[test]
|
|
fn release_pages_reduces_count() {
|
|
let mut pm = ProcessMemory::new(process(0), 100);
|
|
pm.grant(20).unwrap();
|
|
assert!(pm.release(5).is_ok());
|
|
assert_eq!(pm.page_count(), 15);
|
|
}
|
|
|
|
#[test]
|
|
fn release_more_than_owned_fails() {
|
|
let mut pm = ProcessMemory::new(process(0), 100);
|
|
pm.grant(5).unwrap();
|
|
assert!(pm.release(10).is_err());
|
|
assert_eq!(pm.page_count(), 5);
|
|
}
|
|
|
|
#[test]
|
|
fn grant_up_to_exact_limit() {
|
|
let mut pm = ProcessMemory::new(process(0), 10);
|
|
pm.grant(10).unwrap();
|
|
assert!(pm.grant(1).is_err());
|
|
}
|
|
|
|
// --- MemoryRegion tests ---
|
|
|
|
#[test]
|
|
fn memory_region_construction_and_accessors() {
|
|
let region = MemoryRegion::new(
|
|
RegionId::from_raw(1),
|
|
process(0),
|
|
base(),
|
|
pages(4),
|
|
Generation::initial(),
|
|
);
|
|
assert_eq!(region.id(), RegionId::from_raw(1));
|
|
assert_eq!(region.owner(), process(0));
|
|
assert_eq!(region.base(), base());
|
|
assert_eq!(region.size(), pages(4));
|
|
assert_eq!(region.generation(), &Generation::initial());
|
|
}
|
|
|
|
// --- RegionTable tests ---
|
|
|
|
#[test]
|
|
fn region_table_insert_and_get() {
|
|
let mut table = RegionTable::new();
|
|
let id = table.insert(MemoryRegion::new(
|
|
RegionId::from_raw(0),
|
|
process(0),
|
|
base(),
|
|
pages(4),
|
|
Generation::initial(),
|
|
));
|
|
assert!(id.is_some());
|
|
let rid = id.unwrap();
|
|
assert!(table.get(rid).is_some());
|
|
}
|
|
|
|
#[test]
|
|
fn region_table_remove() {
|
|
let mut table = RegionTable::new();
|
|
let id = table.insert(MemoryRegion::new(
|
|
RegionId::from_raw(0),
|
|
process(0),
|
|
base(),
|
|
pages(4),
|
|
Generation::initial(),
|
|
)).unwrap();
|
|
let removed = table.remove(id);
|
|
assert!(removed.is_some());
|
|
assert!(table.get(id).is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn region_table_regions_for_process() {
|
|
let mut table = RegionTable::new();
|
|
table.insert(MemoryRegion::new(
|
|
RegionId::from_raw(0), process(0), base(), pages(4), Generation::initial(),
|
|
));
|
|
table.insert(MemoryRegion::new(
|
|
RegionId::from_raw(1), process(1), base(), pages(4), Generation::initial(),
|
|
));
|
|
table.insert(MemoryRegion::new(
|
|
RegionId::from_raw(2), process(0), base(), pages(2), Generation::initial(),
|
|
));
|
|
assert_eq!(table.regions_for_process(process(0)).count(), 2);
|
|
assert_eq!(table.regions_for_process(process(1)).count(), 1);
|
|
}
|