106 lines
2.7 KiB
Rust
106 lines
2.7 KiB
Rust
use std::{
|
|
alloc::{Layout, alloc_zeroed},
|
|
hint::{likely, unlikely},
|
|
};
|
|
|
|
use crate::memory::{
|
|
PhysAddr, RandomAccessMemory,
|
|
ram::{NUM_PAGES, Page, idx},
|
|
};
|
|
|
|
pub struct ArrayStore {
|
|
pages: Box<[*mut Page; NUM_PAGES]>,
|
|
}
|
|
|
|
unsafe impl Send for ArrayStore {}
|
|
impl ArrayStore {
|
|
pub fn new() -> Self {
|
|
let pages = vec![0 as *mut Page; 2 << 20]
|
|
.into_boxed_slice()
|
|
.try_into()
|
|
.unwrap();
|
|
Self { pages }
|
|
}
|
|
|
|
fn alloc(&mut self) -> *mut Page {
|
|
let layout = Layout::from_size_align(4096, 4096).unwrap();
|
|
unsafe { alloc_zeroed(layout) as *mut Page }
|
|
}
|
|
}
|
|
|
|
impl RandomAccessMemory for ArrayStore {
|
|
#[inline(always)]
|
|
fn read_word(&self, addr: PhysAddr) -> u32 {
|
|
debug_assert_eq!(addr % 4, 0);
|
|
let (idx, offset) = idx(addr);
|
|
|
|
if likely(!self.pages[idx].is_null()) {
|
|
return unsafe { (self.pages[idx] as *const u32).byte_add(offset).read() };
|
|
}
|
|
|
|
// Slow path: MMIO, fault, etc — never inlined
|
|
// Since we're only reading, we can safely return 0
|
|
return 0;
|
|
}
|
|
|
|
#[inline(always)]
|
|
fn read_byte(&self, addr: PhysAddr) -> u8 {
|
|
let (idx, offset) = idx(addr);
|
|
|
|
if likely(!self.pages[idx].is_null()) {
|
|
return unsafe { (self.pages[idx] as *const u8).byte_add(offset).read() };
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#[inline(always)]
|
|
fn read_page(&self, addr: PhysAddr) -> &[u8; 4096] {
|
|
debug_assert_eq!(addr % 4096, 0);
|
|
let (idx, _) = idx(addr);
|
|
|
|
if likely(!self.pages[idx].is_null()) {
|
|
return unsafe { &*(self.pages[idx] as *const [u8; 4096]) };
|
|
}
|
|
|
|
return &[0; 4096];
|
|
}
|
|
|
|
#[inline(always)]
|
|
fn write_byte(&mut self, addr: PhysAddr, value: u8) {
|
|
let (idx, offset) = idx(addr);
|
|
|
|
if unlikely(self.pages[idx].is_null()) {
|
|
self.pages[idx] = self.alloc();
|
|
}
|
|
|
|
unsafe {
|
|
(self.pages[idx] as *mut u8).byte_add(offset).write(value);
|
|
}
|
|
}
|
|
|
|
#[inline(always)]
|
|
fn write_word(&mut self, addr: PhysAddr, value: u32) {
|
|
debug_assert_eq!(addr % 4, 0);
|
|
let (idx, offset) = idx(addr);
|
|
|
|
if unlikely(self.pages[idx].is_null()) {
|
|
self.pages[idx] = self.alloc();
|
|
}
|
|
|
|
unsafe { (self.pages[idx] as *mut u32).byte_add(offset).write(value) }
|
|
}
|
|
|
|
#[inline(always)]
|
|
fn write_page(&mut self, addr: PhysAddr, value: &[u8; 4096]) {
|
|
debug_assert_eq!(addr % 4096, 0);
|
|
let (idx, _) = idx(addr);
|
|
|
|
if unlikely(self.pages[idx].is_null()) {
|
|
self.pages[idx] = self.alloc();
|
|
}
|
|
|
|
unsafe { (self.pages[idx] as *mut [u8; 4096]).write(*value) }
|
|
}
|
|
}
|