Add unsafe for acquring I/O memory/port

This commit is contained in:
Ruihan Li 2025-05-07 23:40:45 +08:00 committed by Junyang Zhang
parent e1e5f9f575
commit 31dbae5330
5 changed files with 43 additions and 27 deletions

View File

@ -34,23 +34,20 @@ impl SerialPort {
/// ///
/// # Safety /// # Safety
/// ///
/// User must ensure the `port` is valid serial port. /// The caller must ensure that the base port is a valid serial base port and that it has
/// exclusive ownership of the serial ports.
pub const unsafe fn new(port: u16) -> Self { pub const unsafe fn new(port: u16) -> Self {
let data = IoPort::new(port); // SAFETY: The safety is upheld by the caller.
let int_en = IoPort::new(port + 1); unsafe {
let fifo_ctrl = IoPort::new(port + 2); Self {
let line_ctrl = IoPort::new(port + 3); data: IoPort::new(port),
let modem_ctrl = IoPort::new(port + 4); int_en: IoPort::new(port + 1),
let line_status = IoPort::new(port + 5); fifo_ctrl: IoPort::new(port + 2),
let modem_status = IoPort::new(port + 6); line_ctrl: IoPort::new(port + 3),
Self { modem_ctrl: IoPort::new(port + 4),
data, line_status: IoPort::new(port + 5),
int_en, modem_status: IoPort::new(port + 6),
fifo_ctrl, }
line_ctrl,
modem_ctrl,
line_status,
modem_status,
} }
} }

View File

@ -32,12 +32,14 @@ impl FaultEventRegisters {
FaultStatus::from_bits_truncate(self.status.as_ptr().read()) FaultStatus::from_bits_truncate(self.status.as_ptr().read())
} }
/// Creates an instance from base address. /// Creates an instance from the IOMMU base address.
/// ///
/// # Safety /// # Safety
/// ///
/// User must ensure the base_register_vaddr is read from DRHD /// The caller must ensure that the base address is a valid IOMMU base address and that it has
/// exclusive ownership of the IOMMU fault event registers.
unsafe fn new(base_register_vaddr: NonNull<u8>) -> Self { unsafe fn new(base_register_vaddr: NonNull<u8>) -> Self {
// SAFETY: The safety is upheld by the caller.
let (capability, status, mut control, mut data, mut address, upper_address) = unsafe { let (capability, status, mut control, mut data, mut address, upper_address) = unsafe {
let base = base_register_vaddr; let base = base_register_vaddr;
( (
@ -231,9 +233,12 @@ pub(super) static FAULT_EVENT_REGS: Once<SpinLock<FaultEventRegisters, LocalIrqD
/// ///
/// # Safety /// # Safety
/// ///
/// User must ensure the base_register_vaddr is read from DRHD /// The caller must ensure that the base address is a valid IOMMU base address and that it has
/// exclusive ownership of the IOMMU fault event registers.
pub(super) unsafe fn init(base_register_vaddr: NonNull<u8>) { pub(super) unsafe fn init(base_register_vaddr: NonNull<u8>) {
FAULT_EVENT_REGS.call_once(|| SpinLock::new(FaultEventRegisters::new(base_register_vaddr))); FAULT_EVENT_REGS
// SAFETY: The safety is upheld by the caller.
.call_once(|| SpinLock::new(unsafe { FaultEventRegisters::new(base_register_vaddr) }));
} }
fn iommu_fault_handler(_frame: &TrapFrame) { fn iommu_fault_handler(_frame: &TrapFrame) {

View File

@ -30,11 +30,12 @@ pub struct InvalidationRegisters {
} }
impl InvalidationRegisters { impl InvalidationRegisters {
/// Creates an instance from IOMMU base address. /// Creates an instance from the IOMMU base address.
/// ///
/// # Safety /// # Safety
/// ///
/// User must ensure the address is valid. /// The caller must ensure that the base address is a valid IOMMU base address and that it has
/// exclusive ownership of the IOMMU invalidation registers.
pub(super) unsafe fn new(base: NonNull<u8>) -> Self { pub(super) unsafe fn new(base: NonNull<u8>) -> Self {
let offset = { let offset = {
// SAFETY: The safety is upheld by the caller. // SAFETY: The safety is upheld by the caller.

View File

@ -278,8 +278,11 @@ impl IommuRegisters {
io_mem_builder.remove(base_address as usize..(base_address as usize + PAGE_SIZE)); io_mem_builder.remove(base_address as usize..(base_address as usize + PAGE_SIZE));
let base = NonNull::new(paddr_to_vaddr(base_address as usize) as *mut u8).unwrap(); let base = NonNull::new(paddr_to_vaddr(base_address as usize) as *mut u8).unwrap();
// SAFETY: All offsets and sizes are strictly adhered to in the manual, and the base // SAFETY:
// address is obtained from DRHD. // - We trust the ACPI tables (as well as the DRHD in them), from which the base address is
// obtained, so it is a valid IOMMU base address.
// - `io_mem_builder.remove()` guarantees that we have exclusive ownership of all the IOMMU
// registers.
let iommu_regs = unsafe { let iommu_regs = unsafe {
fault::init(base); fault::init(base);

View File

@ -136,6 +136,7 @@ impl IoApicAccess {
/// The caller must ensure that the base address is a valid I/O APIC base address. /// The caller must ensure that the base address is a valid I/O APIC base address.
unsafe fn new(base_address: usize, io_mem_builder: &IoMemAllocatorBuilder) -> Self { unsafe fn new(base_address: usize, io_mem_builder: &IoMemAllocatorBuilder) -> Self {
io_mem_builder.remove(base_address..(base_address + 0x20)); io_mem_builder.remove(base_address..(base_address + 0x20));
if_tdx_enabled!({ if_tdx_enabled!({
assert_eq!( assert_eq!(
base_address % crate::mm::PAGE_SIZE, base_address % crate::mm::PAGE_SIZE,
@ -156,9 +157,18 @@ impl IoApicAccess {
unsafe { tdx_guest::unprotect_gpa_range(base_address, 1).unwrap() }; unsafe { tdx_guest::unprotect_gpa_range(base_address, 1).unwrap() };
}); });
let base = NonNull::new(paddr_to_vaddr(base_address) as *mut u8).unwrap(); let register_addr = NonNull::new(paddr_to_vaddr(base_address) as *mut u32).unwrap();
let register = VolatileRef::new_restricted(WriteOnly, base.cast::<u32>()); // SAFETY:
let data = VolatileRef::new(base.add(0x10).cast::<u32>()); // - The caller guarantees that the memory is an I/O ACPI register.
// - `io_mem_builder.remove()` guarantees that we have exclusive ownership of the register.
let register = unsafe { VolatileRef::new_restricted(WriteOnly, register_addr) };
let data_addr = NonNull::new(paddr_to_vaddr(base_address + 0x10) as *mut u32).unwrap();
// SAFETY:
// - The caller guarantees that the memory is an I/O ACPI register.
// - `io_mem_builder.remove()` guarantees that we have exclusive ownership of the register.
let data = unsafe { VolatileRef::new(data_addr) };
Self { register, data } Self { register, data }
} }