Impl MMIO access method

This commit is contained in:
Yuke Peng
2023-05-05 03:07:26 -07:00
committed by Tate, Hongliang Tian
parent e7b9ba116d
commit 5656805520
4 changed files with 126 additions and 0 deletions

View File

@ -0,0 +1,19 @@
use acpi::PciConfigRegions;
pub fn start_address() -> usize {
let start = PciConfigRegions::new(
&*crate::arch::x86::kernel::acpi::ACPI_TABLES
.get()
.unwrap()
.lock(),
)
.unwrap();
// all zero to get the start address
start.physical_address(0, 0, 0, 0).unwrap() as usize
}
pub fn end_address() -> usize {
// 4G-20M
0xFEC0_0000
}

View File

@ -4,6 +4,7 @@ pub mod device;
pub(crate) mod irq; pub(crate) mod irq;
mod kernel; mod kernel;
pub(crate) mod mm; pub(crate) mod mm;
pub(crate) mod mmio;
pub(crate) mod timer; pub(crate) mod timer;
use alloc::fmt; use alloc::fmt;

View File

@ -20,6 +20,7 @@ pub mod config;
pub mod cpu; pub mod cpu;
mod error; mod error;
pub mod logger; pub mod logger;
pub mod mmio;
pub mod prelude; pub mod prelude;
pub mod sync; pub mod sync;
pub mod task; pub mod task;
@ -47,6 +48,7 @@ pub fn init() {
vm::init(); vm::init();
trap::init(); trap::init();
arch::after_all_init(); arch::after_all_init();
mmio::init();
register_irq_common_callback(); register_irq_common_callback();
invoke_c_init_funcs(); invoke_c_init_funcs();
} }

View File

@ -0,0 +1,104 @@
use core::{mem::size_of, ops::Range};
use pod::Pod;
use spin::Once;
use crate::{
vm::{Paddr, Vaddr, VmIo},
Error,
};
static CHECKER: Once<MmioChecker> = Once::new();
pub(crate) fn init() {
CHECKER.call_once(|| MmioChecker {
start: crate::arch::mmio::start_address(),
end: crate::arch::mmio::end_address(),
});
log::info!(
"MMIO start: 0x{:x}, end: 0x{:x}",
CHECKER.get().unwrap().start,
CHECKER.get().unwrap().end
);
}
#[derive(Debug, Clone)]
pub struct Mmio {
virtual_address: Vaddr,
limit: usize,
}
impl VmIo for Mmio {
fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> crate::Result<()> {
self.check_range(offset, buf.len())?;
unsafe {
core::ptr::copy(
self.virtual_address as *const u8,
buf.as_mut_ptr(),
buf.len(),
);
}
Ok(())
}
fn write_bytes(&self, offset: usize, buf: &[u8]) -> crate::Result<()> {
self.check_range(offset, buf.len())?;
unsafe {
core::ptr::copy(buf.as_ptr(), self.virtual_address as *mut u8, buf.len());
}
Ok(())
}
fn read_val<T: Pod>(&self, offset: usize) -> crate::Result<T> {
self.check_range(offset, size_of::<T>())?;
Ok(unsafe { core::ptr::read((self.virtual_address + offset) as *const T) })
}
fn write_val<T: Pod>(&self, offset: usize, new_val: &T) -> crate::Result<()> {
self.check_range(offset, size_of::<T>())?;
unsafe { core::ptr::write((self.virtual_address + offset) as *mut T, *new_val) };
Ok(())
}
}
impl Mmio {
pub fn new(range: Range<Paddr>) -> Option<Mmio> {
if CHECKER.get().unwrap().check(&range) {
Some(Mmio {
virtual_address: crate::vm::paddr_to_vaddr(range.start),
limit: range.len(),
})
} else {
None
}
}
pub fn paddr(&self) -> Paddr {
crate::vm::vaddr_to_paddr(self.virtual_address).unwrap()
}
fn check_range(&self, offset: usize, len: usize) -> crate::Result<()> {
let sum = offset.checked_add(len).ok_or(Error::InvalidArgs)?;
if sum > self.limit {
log::error!(
"attempt to access address out of bounds, limit:0x{:x}, access position:0x{:x}",
self.limit,
sum
);
Err(Error::InvalidArgs)
} else {
Ok(())
}
}
}
struct MmioChecker {
start: Paddr,
end: Paddr,
}
impl MmioChecker {
/// Check whether the physical address is in MMIO region.
fn check(&self, range: &Range<Paddr>) -> bool {
range.start >= self.start && range.end < self.end
}
}