Files
RedBear-OS/acpid/src/aml_physmem.rs
T
2023-06-11 11:33:27 +02:00

418 lines
12 KiB
Rust

use num_traits::PrimInt;
use rustc_hash::FxHashMap;
use std::fmt::LowerHex;
use std::mem::size_of;
use std::sync::{Arc, Mutex};
use syscall::{Io, PhysmapFlags, Pio, PAGE_SIZE};
const PAGE_MASK: usize = !(PAGE_SIZE - 1);
const OFFSET_MASK: usize = PAGE_SIZE - 1;
struct MappedPage {
phys_page: usize,
virt_page: usize,
}
impl MappedPage {
fn new(phys_page: usize) -> std::io::Result<Self> {
let virt_page = unsafe {
syscall::physmap(phys_page, PAGE_SIZE, PhysmapFlags::empty())
.map_err(|error| std::io::Error::from_raw_os_error(error.errno))?
};
Ok(Self {
phys_page,
virt_page,
})
}
}
impl Drop for MappedPage {
fn drop(&mut self) {
log::trace!("Drop page {:#x}", self.phys_page);
if let Err(e) = unsafe { syscall::funmap(self.virt_page, PAGE_SIZE) } {
log::error!("funmap (phys): {:?}", e);
}
}
}
#[derive(Default)]
pub struct AmlPageCache {
page_cache: FxHashMap<usize, MappedPage>,
}
impl AmlPageCache {
/// get a virtual address for the given physical page
fn get_page(&mut self, phys_target: usize) -> std::io::Result<&MappedPage> {
let phys_page = phys_target & PAGE_MASK;
if self.page_cache.contains_key(&phys_page) {
log::trace!("re-using cached page {:#x}", phys_page);
Ok(self
.page_cache
.get(&phys_page)
.expect("could not get page after contains=true"))
} else {
let mapped_page = MappedPage::new(phys_page)?;
log::trace!("adding page {:#x} to cache", mapped_page.phys_page);
self.page_cache.insert(phys_page, mapped_page);
Ok(self
.page_cache
.get(&phys_page)
.expect("can't find page that was just inserted"))
}
}
/// The offset into the virtual slice of T that matches the physical target
fn sized_index<T>(phys_target: usize) -> usize {
assert_eq!(
phys_target & !(size_of::<T>() - 1),
phys_target,
"address {} is not aligned",
phys_target
);
(phys_target & OFFSET_MASK) / size_of::<T>()
}
/// Read from the given physical address
fn read_from_phys<T: PrimInt + LowerHex>(&mut self, phys_target: usize) -> std::io::Result<T> {
let mapped_page = self.get_page(phys_target)?;
let page_as_slice = unsafe {
std::slice::from_raw_parts(
mapped_page.virt_page as *const T,
PAGE_SIZE / size_of::<T>(),
)
};
// for debugging only
let _virt_ptr = page_as_slice[Self::sized_index::<T>(phys_target)..].as_ptr() as usize;
let val = page_as_slice[Self::sized_index::<T>(phys_target)];
log::trace!(
"read {:#x}, virt {:#x}, val {:#x}",
phys_target,
_virt_ptr,
val
);
Ok(val)
}
/// Write to the given physical address
fn write_to_phys<T: PrimInt + LowerHex>(
&mut self,
phys_target: usize,
val: T,
) -> std::io::Result<()> {
let mapped_page = self.get_page(phys_target)?;
let page_as_slice = unsafe {
std::slice::from_raw_parts_mut(
mapped_page.virt_page as *mut T,
PAGE_SIZE / size_of::<T>(),
)
};
// for debugging only
let _virt_ptr = page_as_slice[Self::sized_index::<T>(phys_target)..].as_ptr() as usize;
page_as_slice[Self::sized_index::<T>(phys_target)] = val;
log::trace!(
"write {:#x}, virt {:#x}, val {:#x}",
phys_target,
_virt_ptr,
val
);
Ok(())
}
pub fn clear(&mut self) {
log::trace!("Clear page cache");
self.page_cache.clear();
}
}
pub struct AmlPhysMemHandler {
page_cache: Arc<Mutex<AmlPageCache>>,
}
/// Read from a physical address.
/// Generic parameter must be u8, u16, u32 or u64.
impl AmlPhysMemHandler {
pub fn new(page_cache: Arc<Mutex<AmlPageCache>>) -> Self {
Self { page_cache }
}
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
impl aml::Handler for AmlPhysMemHandler {
fn read_u8(&self, address: usize) -> u8 {
log::trace!("read u8 {:X}", address);
if let Ok(mut page_cache) = self.page_cache.lock() {
if let Ok(value) = page_cache.read_from_phys::<u8>(address) {
return value;
}
}
0
}
fn read_u16(&self, address: usize) -> u16 {
log::trace!("read u16 {:X}", address);
if let Ok(mut page_cache) = self.page_cache.lock() {
if let Ok(value) = page_cache.read_from_phys::<u16>(address) {
return value;
}
}
0
}
fn read_u32(&self, address: usize) -> u32 {
log::trace!("read u32 {:X}", address);
if let Ok(mut page_cache) = self.page_cache.lock() {
if let Ok(value) = page_cache.read_from_phys::<u32>(address) {
return value;
}
}
0
}
fn read_u64(&self, address: usize) -> u64 {
log::trace!("read u64 {:X}", address);
if let Ok(mut page_cache) = self.page_cache.lock() {
if let Ok(value) = page_cache.read_from_phys::<u64>(address) {
return value;
}
}
0
}
fn write_u8(&mut self, address: usize, value: u8) {
log::error!("write u8 {:X} = {:X}", address, value);
if let Ok(mut page_cache) = self.page_cache.lock() {
if page_cache.write_to_phys::<u8>(address, value).is_err() {
log::error!("failed to get page {:#x}", address);
}
}
}
fn write_u16(&mut self, address: usize, value: u16) {
log::error!("write u16 {:X} = {:X}", address, value);
if let Ok(mut page_cache) = self.page_cache.lock() {
if page_cache.write_to_phys::<u16>(address, value).is_err() {
log::error!("failed to get page {:#x}", address);
}
}
}
fn write_u32(&mut self, address: usize, value: u32) {
log::error!("write u32 {:X} = {:X}", address, value);
if let Ok(mut page_cache) = self.page_cache.lock() {
if page_cache.write_to_phys::<u32>(address, value).is_err() {
log::error!("failed to get page {:#x}", address);
}
}
}
fn write_u64(&mut self, address: usize, value: u64) {
log::error!("write u64 {:X} = {:X}", address, value);
if let Ok(mut page_cache) = self.page_cache.lock() {
if page_cache.write_to_phys::<u64>(address, value).is_err() {
log::error!("failed to get page {:#x}", address);
}
}
}
// Pio must be enabled via syscall::iopl(3)
fn read_io_u8(&self, port: u16) -> u8 {
Pio::<u8>::new(port).read()
}
fn read_io_u16(&self, port: u16) -> u16 {
Pio::<u16>::new(port).read()
}
fn read_io_u32(&self, port: u16) -> u32 {
Pio::<u32>::new(port).read()
}
fn write_io_u8(&self, port: u16, value: u8) {
Pio::<u8>::new(port).write(value)
}
fn write_io_u16(&self, port: u16, value: u16) {
Pio::<u16>::new(port).write(value)
}
fn write_io_u32(&self, port: u16, value: u32) {
Pio::<u32>::new(port).write(value)
}
fn read_pci_u8(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16) -> u8 {
log::error!("read pci u8 {:X}", _device);
0
}
fn read_pci_u16(
&self,
_segment: u16,
_bus: u8,
_device: u8,
_function: u8,
_offset: u16,
) -> u16 {
log::error!("read pci u16 {:X}", _device);
0
}
fn read_pci_u32(
&self,
_segment: u16,
_bus: u8,
_device: u8,
_function: u8,
_offset: u16,
) -> u32 {
log::error!("read pci u32 {:X}", _device);
0
}
fn write_pci_u8(
&self,
_segment: u16,
_bus: u8,
_device: u8,
_function: u8,
_offset: u16,
_value: u8,
) {
log::error!("write pci u8 {:X}", _device);
}
fn write_pci_u16(
&self,
_segment: u16,
_bus: u8,
_device: u8,
_function: u8,
_offset: u16,
_value: u16,
) {
log::error!("write pci u16 {:X}", _device);
}
fn write_pci_u32(
&self,
_segment: u16,
_bus: u8,
_device: u8,
_function: u8,
_offset: u16,
_value: u32,
) {
log::error!("write pci u32 {:X}", _device);
}
}
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
impl aml::Handler for AmlPhysMemHandler {
fn read_u8(&self, _address: usize) -> u8 {
log::error!("read u8 {:X}", _address);
0
}
fn read_u16(&self, _address: usize) -> u16 {
log::error!("read u16 {:X}", _address);
0
}
fn read_u32(&self, _address: usize) -> u32 {
log::error!("read u32 {:X}", _address);
0
}
fn read_u64(&self, _address: usize) -> u64 {
log::error!("read u64 {:X}", _address);
0
}
fn write_u8(&mut self, _address: usize, _value: u8) {
log::error!("write u8 {:X} = {:X}", _address, _value);
}
fn write_u16(&mut self, _address: usize, _value: u16) {
log::error!("write u16 {:X} = {:X}", _address, _value);
}
fn write_u32(&mut self, _address: usize, _value: u32) {
log::error!("write u32 {:X} = {:X}", _address, _value);
}
fn write_u64(&mut self, _address: usize, _value: u64) {
log::error!("write u64 {:X} = {:X}", _address, _value);
}
fn read_io_u8(&self, port: u16) -> u8 {
log::error!("read io u8 {:X}", port);
0
}
fn read_io_u16(&self, port: u16) -> u16 {
log::error!("read io u16 {:X}", port);
0
}
fn read_io_u32(&self, port: u16) -> u32 {
log::error!("read io u32 {:X}", port);
0
}
fn write_io_u8(&self, port: u16, value: u8) {
log::error!("write io u8 {:X} = {:X}", port, value);
}
fn write_io_u16(&self, port: u16, value: u16) {
log::error!("write io u16 {:X} = {:X}", port, value);
}
fn write_io_u32(&self, port: u16, value: u32) {
log::error!("write io u32 {:X} = {:X}", port, value);
}
fn read_pci_u8(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16) -> u8 {
log::error!("read pci u8 {:X}", _device);
0
}
fn read_pci_u16(
&self,
_segment: u16,
_bus: u8,
_device: u8,
_function: u8,
_offset: u16,
) -> u16 {
log::error!("read pci u8 {:X}", _device);
0
}
fn read_pci_u32(
&self,
_segment: u16,
_bus: u8,
_device: u8,
_function: u8,
_offset: u16,
) -> u32 {
log::error!("read pci u8 {:X}", _device);
0
}
fn write_pci_u8(
&self,
_segment: u16,
_bus: u8,
_device: u8,
_function: u8,
_offset: u16,
_value: u8,
) {
log::error!("write pci u8 {:X}", _device);
}
fn write_pci_u16(
&self,
_segment: u16,
_bus: u8,
_device: u8,
_function: u8,
_offset: u16,
_value: u16,
) {
log::error!("write pci u8 {:X}", _device);
}
fn write_pci_u32(
&self,
_segment: u16,
_bus: u8,
_device: u8,
_function: u8,
_offset: u16,
_value: u32,
) {
log::error!("write pci u8 {:X}", _device);
}
}