From 9fb4a8be04e22bf81624c3e8783162749ddd46f9 Mon Sep 17 00:00:00 2001 From: Ron Williams Date: Thu, 13 Apr 2023 19:09:07 -0700 Subject: [PATCH] Add AmlHandler read/write of physaddr --- acpid/src/acpi.rs | 269 +++---------------------- acpid/src/aml_physmem.rs | 417 +++++++++++++++++++++++++++++++++++++++ acpid/src/main.rs | 1 + 3 files changed, 442 insertions(+), 245 deletions(-) create mode 100644 acpid/src/aml_physmem.rs diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs index 5b72fb1d26..417cd920fa 100644 --- a/acpid/src/acpi.rs +++ b/acpid/src/acpi.rs @@ -2,7 +2,7 @@ use rustc_hash::FxHashMap; use std::convert::{TryFrom, TryInto}; use std::fmt::Write; use std::ops::Deref; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; use std::{fmt, mem}; use syscall::flag::PhysmapFlags; @@ -19,6 +19,7 @@ use amlserde::{AmlHandleLookup, AmlSerde}; pub mod dmar; use self::dmar::Dmar; +use crate::aml_physmem::{AmlPageCache, AmlPhysMemHandler}; #[cfg(target_arch = "aarch64")] pub const PAGE_SIZE: usize = 4096; @@ -244,15 +245,21 @@ pub struct Ssdt(Sdt); pub struct AmlSymbols { aml_context: AmlContext, // k = name, v = description - cache: FxHashMap, + symbol_cache: FxHashMap, + page_cache: Arc>, list: String, } impl AmlSymbols { pub fn new() -> Self { + let page_cache = Arc::new(Mutex::new(AmlPageCache::default())); Self { - aml_context: AmlContext::new(Box::new(AmlPhysMemHandler), aml::DebugVerbosity::None), - cache: FxHashMap::default(), + aml_context: AmlContext::new( + Box::new(AmlPhysMemHandler::new(Arc::clone(&page_cache))), + aml::DebugVerbosity::None, + ), + symbol_cache: FxHashMap::default(), + page_cache, list: "".to_string(), } } @@ -266,7 +273,7 @@ impl AmlSymbols { } pub fn symbols_cache(&self) -> &FxHashMap { - &self.cache + &self.symbol_cache } pub fn parse_table(&mut self, aml: &[u8]) -> Result<(), AmlError> { @@ -274,7 +281,7 @@ impl AmlSymbols { } pub fn lookup(&self, symbol: &str) -> Option { - if let Some(description) = self.cache.get(symbol) { + if let Some(description) = self.symbol_cache.get(symbol) { log::trace!("Found symbol in cache, {}, {}", symbol, description); return Some(description.to_owned()); } @@ -343,7 +350,7 @@ impl AmlSymbols { log::trace!("Updating symbols list"); self.list = symbols_str; - self.cache = symbol_cache; + self.symbol_cache = symbol_cache; } } @@ -423,6 +430,15 @@ impl AcpiContext { } } } + + if let Ok(mut page_cache) = aml_symbols.page_cache.lock() { + page_cache.clear(); + } else { + log::error!("failed to lock AmlPageCache"); + } + + // force drop of page_cache from the previous if let + {} } pub fn dsdt(&self) -> Option<&Dsdt> { @@ -518,7 +534,7 @@ impl AcpiContext { /// Discard any cached symbols list. To be called if the AML namespace changes. pub fn aml_symbols_reset(&self) { let mut aml_symbols = self.aml_symbols.write(); - aml_symbols.cache = FxHashMap::default(); + aml_symbols.symbol_cache = FxHashMap::default(); aml_symbols.list = "".to_string(); } @@ -825,240 +841,3 @@ impl AmlContainingTable for Ssdt { &*self.0 } } - -struct AmlPhysMemHandler; - -#[cfg(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 { - Pio::::new(port).read() - } - fn read_io_u16(&self, port: u16) -> u16 { - Pio::::new(port).read() - } - fn read_io_u32(&self, port: u16) -> u32 { - Pio::::new(port).read() - } - - fn write_io_u8(&self, port: u16, value: u8) { - Pio::::new(port).write(value) - } - fn write_io_u16(&self, port: u16, value: u16) { - Pio::::new(port).write(value) - } - fn write_io_u32(&self, port: u16, value: u32) { - Pio::::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 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); - } -} - -#[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); - } -} diff --git a/acpid/src/aml_physmem.rs b/acpid/src/aml_physmem.rs new file mode 100644 index 0000000000..ffc6798511 --- /dev/null +++ b/acpid/src/aml_physmem.rs @@ -0,0 +1,417 @@ +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 { + 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::physunmap(self.virt_page) } { + log::error!("physunmap: {:?}", e); + } + } +} + +#[derive(Default)] +pub struct AmlPageCache { + page_cache: FxHashMap, +} + +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(phys_target: usize) -> usize { + assert_eq!( + phys_target & !(size_of::() - 1), + phys_target, + "address {} is not aligned", + phys_target + ); + (phys_target & OFFSET_MASK) / size_of::() + } + /// Read from the given physical address + fn read_from_phys(&mut self, phys_target: usize) -> std::io::Result { + 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::(), + ) + }; + // for debugging only + let _virt_ptr = page_as_slice[Self::sized_index::(phys_target)..].as_ptr() as usize; + + let val = page_as_slice[Self::sized_index::(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( + &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::(), + ) + }; + // for debugging only + let _virt_ptr = page_as_slice[Self::sized_index::(phys_target)..].as_ptr() as usize; + + page_as_slice[Self::sized_index::(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>, +} + +/// Read from a physical address. +/// Generic parameter must be u8, u16, u32 or u64. +impl AmlPhysMemHandler { + pub fn new(page_cache: Arc>) -> 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::(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::(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::(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::(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::(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::(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::(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::(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::::new(port).read() + } + fn read_io_u16(&self, port: u16) -> u16 { + Pio::::new(port).read() + } + fn read_io_u32(&self, port: u16) -> u32 { + Pio::::new(port).read() + } + + fn write_io_u8(&self, port: u16, value: u8) { + Pio::::new(port).write(value) + } + fn write_io_u16(&self, port: u16, value: u16) { + Pio::::new(port).write(value) + } + fn write_io_u32(&self, port: u16, value: u32) { + Pio::::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); + } +} diff --git a/acpid/src/main.rs b/acpid/src/main.rs index 12bea90e48..d94f762938 100644 --- a/acpid/src/main.rs +++ b/acpid/src/main.rs @@ -16,6 +16,7 @@ use syscall::flag::{EventFlags, O_NONBLOCK}; mod acpi; mod scheme; +mod aml_physmem; fn monotonic() -> (u64, u64) { use syscall::call::clock_gettime;