From 74ffe72cadfd296108642082d2caf7702f9ebf2d Mon Sep 17 00:00:00 2001 From: Yuke Peng Date: Tue, 15 Apr 2025 11:13:09 +0800 Subject: [PATCH] Refactor the initialization of `IoPortAllocator` --- ostd/src/arch/x86/io.rs | 38 ++------------ ostd/src/arch/x86/mod.rs | 12 +++-- ostd/src/io/io_port/allocator.rs | 85 +++++++++++++++----------------- ostd/src/io/io_port/mod.rs | 1 - ostd/src/io/mod.rs | 21 +++++--- 5 files changed, 64 insertions(+), 93 deletions(-) diff --git a/ostd/src/arch/x86/io.rs b/ostd/src/arch/x86/io.rs index df8fc876..9e1dbfba 100644 --- a/ostd/src/arch/x86/io.rs +++ b/ostd/src/arch/x86/io.rs @@ -4,10 +4,7 @@ use alloc::vec::Vec; use align_ext::AlignExt; -use crate::{ - boot::memory_region::MemoryRegionType, - io::{IoMemAllocatorBuilder, IoPortAllocatorBuilder}, -}; +use crate::{boot::memory_region::MemoryRegionType, io::IoMemAllocatorBuilder}; /// Initializes the allocatable MMIO area based on the x86-64 memory distribution map. /// @@ -58,34 +55,5 @@ pub(super) fn construct_io_mem_allocator_builder() -> IoMemAllocatorBuilder { unsafe { IoMemAllocatorBuilder::new(ranges) } } -/// Initializes the allocatable PIO area outside OSTD based on the x86-64 port distribution map. -pub(super) fn construct_io_port_allocator_builder() -> IoPortAllocatorBuilder { - /// Port I/O definition reference: https://bochs.sourceforge.io/techspec/PORTS.LST - const MAX_IO_PORT: u16 = u16::MAX; - - // SAFETY: `MAX_IO_PORT` is guaranteed not to exceed the maximum value specified by x86-64. - let mut builder = unsafe { IoPortAllocatorBuilder::new(MAX_IO_PORT) }; - - extern "C" { - fn __sensitive_io_ports_start(); - fn __sensitive_io_ports_end(); - } - let start = __sensitive_io_ports_start as usize; - let end = __sensitive_io_ports_end as usize; - - // Iterate through the sensitive I/O port ranges and remove them from the allocator. - assert!((end - start) % (size_of::() * 2) == 0); - let io_port_ranges = (end - start) / (size_of::() * 2); - for i in 0..io_port_ranges { - let range_base_addr = __sensitive_io_ports_start as usize + i * 2 * size_of::(); - let (range_start, range_end) = unsafe { - ( - *(range_base_addr as *const u16), - *((range_base_addr + size_of::()) as *const u16), - ) - }; - builder.remove(range_start..range_end); - } - - builder -} +/// Port I/O definition reference: https://bochs.sourceforge.io/techspec/PORTS.LST +pub const MAX_IO_PORT: u16 = u16::MAX; diff --git a/ostd/src/arch/x86/mod.rs b/ostd/src/arch/x86/mod.rs index cb3bc322..27f57257 100644 --- a/ostd/src/arch/x86/mod.rs +++ b/ostd/src/arch/x86/mod.rs @@ -6,7 +6,7 @@ pub mod boot; pub(crate) mod cpu; pub mod device; pub(crate) mod ex_table; -mod io; +pub(crate) mod io; pub mod iommu; pub(crate) mod irq; pub(crate) mod kernel; @@ -19,7 +19,7 @@ pub mod timer; pub mod trap; use cfg_if::cfg_if; -use io::{construct_io_mem_allocator_builder, construct_io_port_allocator_builder}; +use io::construct_io_mem_allocator_builder; use spin::Once; use x86::cpuid::{CpuId, FeatureInfo}; @@ -81,7 +81,6 @@ pub(crate) unsafe fn late_init_on_bsp() { kernel::acpi::init(); let io_mem_builder = construct_io_mem_allocator_builder(); - let io_port_builder = construct_io_port_allocator_builder(); match kernel::apic::init(&io_mem_builder) { Ok(_) => { @@ -110,9 +109,12 @@ pub(crate) unsafe fn late_init_on_bsp() { // Some driver like serial may use PIC kernel::pic::init(); - // SAFETY: All the system device memory and port I/Os have been removed from the builder. + // SAFETY: + // 1. All the system device memory have been removed from the builder. + // 2. All the port I/O regions belonging to the system device are defined using the macros. + // 3. `MAX_IO_PORT` defined in `crate::arch::io` is the maximum value specified by x86-64. unsafe { - crate::io::init(io_mem_builder, io_port_builder); + crate::io::init(io_mem_builder); } } diff --git a/ostd/src/io/io_port/allocator.rs b/ostd/src/io/io_port/allocator.rs index ccec5759..c6fb6390 100644 --- a/ostd/src/io/io_port/allocator.rs +++ b/ostd/src/io/io_port/allocator.rs @@ -4,11 +4,14 @@ use core::ops::Range; use id_alloc::IdAlloc; -use log::{debug, info}; +use log::debug; use spin::Once; use super::IoPort; -use crate::sync::{LocalIrqDisabled, SpinLock}; +use crate::{ + io::RawIoPortRange, + sync::{LocalIrqDisabled, SpinLock}, +}; /// I/O port allocator that allocates port I/O access to device drivers. pub struct IoPortAllocator { @@ -50,53 +53,47 @@ impl IoPortAllocator { } } -/// Builder for `IoPortAllocator`. -/// -/// The builder must contains the port I/O regions according to architecture specification. Also, OSTD -/// must exclude the port I/O regions of the system device before building the `IoPortAllocator`. -pub(crate) struct IoPortAllocatorBuilder { - allocator: IdAlloc, -} - -impl IoPortAllocatorBuilder { - /// Initializes port I/O region for devices. - /// - /// # Safety - /// - /// User must ensure `max_port` doesn't exceed the maximum value specified by architecture. - pub(crate) unsafe fn new(max_port: u16) -> Self { - info!( - "Creating new I/O port allocator builder, max_port: {:#x?}", - max_port - ); - - Self { - allocator: IdAlloc::with_capacity(max_port as usize), - } - } - - /// Removes access to a specific port I/O range. - /// - /// All drivers in OSTD must use this method to prevent peripheral drivers from accessing illegal port IO range. - pub(crate) fn remove(&mut self, range: Range) { - info!("Removing PIO range: {:#x?}", range); - - for i in range { - self.allocator.alloc_specific(i as usize); - } - } -} - pub(super) static IO_PORT_ALLOCATOR: Once = Once::new(); -/// Initializes the static `IO_PORT_ALLOCATOR` based on builder. +/// Initializes the static `IO_PORT_ALLOCATOR` and removes the system device I/O port regions. /// /// # Safety /// -/// User must ensure all the port I/O regions that belong to the system device have been removed by calling the -/// `remove` function. -pub(crate) unsafe fn init(io_port_builder: IoPortAllocatorBuilder) { +/// User must ensure that: +/// +/// 1. All the port I/O regions belonging to the system device are defined using the macros +/// `sensitive_io_port` and `reserve_io_port_range`. +/// +/// 2. `MAX_IO_PORT` defined in `crate::arch::io` is guaranteed not to exceed the maximum +/// value specified by architecture. +pub(crate) unsafe fn init() { + // SAFETY: `MAX_IO_PORT` is guaranteed not to exceed the maximum value specified by architecture. + let mut allocator = IdAlloc::with_capacity(crate::arch::io::MAX_IO_PORT as usize); + + extern "C" { + fn __sensitive_io_ports_start(); + fn __sensitive_io_ports_end(); + } + let start = __sensitive_io_ports_start as usize; + let end = __sensitive_io_ports_end as usize; + assert!((end - start) % size_of::() == 0); + + // Iterate through the sensitive I/O port ranges and remove them from the allocator. + let io_port_range_count = (end - start) / size_of::(); + for i in 0..io_port_range_count { + let range_base_addr = __sensitive_io_ports_start as usize + i * size_of::(); + // SAFETY: The range is guaranteed to be valid as it is defined in the `.sensitive_io_ports` section. + let port_range = unsafe { *(range_base_addr as *const RawIoPortRange) }; + + assert!(port_range.begin < port_range.end); + debug!("Removing sensitive I/O port range: {:#x?}", port_range); + + for i in port_range.begin..port_range.end { + allocator.alloc_specific(i as usize); + } + } + IO_PORT_ALLOCATOR.call_once(|| IoPortAllocator { - allocator: SpinLock::new(io_port_builder.allocator), + allocator: SpinLock::new(allocator), }); } diff --git a/ostd/src/io/io_port/mod.rs b/ostd/src/io/io_port/mod.rs index 4fb233eb..f4a2e01e 100644 --- a/ostd/src/io/io_port/mod.rs +++ b/ostd/src/io/io_port/mod.rs @@ -8,7 +8,6 @@ mod allocator; use core::{marker::PhantomData, mem::size_of}; pub(super) use self::allocator::init; -pub(crate) use self::allocator::IoPortAllocatorBuilder; use crate::{prelude::*, Error}; /// An I/O port, representing a specific address in the I/O address of x86. diff --git a/ostd/src/io/mod.rs b/ostd/src/io/mod.rs index 2b986575..6a9732c6 100644 --- a/ostd/src/io/mod.rs +++ b/ostd/src/io/mod.rs @@ -13,19 +13,24 @@ mod io_port; pub use self::{io_mem::IoMem, io_port::IoPort}; pub(crate) use self::{ io_mem::IoMemAllocatorBuilder, - io_port::{reserve_io_port_range, sensitive_io_port, IoPortAllocatorBuilder, RawIoPortRange}, + io_port::{reserve_io_port_range, sensitive_io_port, RawIoPortRange}, }; /// Initializes the static allocator based on builder. /// /// # Safety /// -/// User must ensure all the memory and port I/O regions that belong to the system device -/// have been removed by calling the corresponding `remove` function. -pub(crate) unsafe fn init( - io_mem_builder: IoMemAllocatorBuilder, - io_port_builder: IoPortAllocatorBuilder, -) { +/// User must ensure that: +/// +/// 1. All the memory that belong to the system device have been removed +/// by calling the `remove` function. +/// +/// 2. All the port I/O regions belonging to the system device are defined +/// using the macros `sensitive_io_port` and `reserve_io_port_range`. +/// +/// 3. `MAX_IO_PORT` defined in `crate::arch::io` is guaranteed not to +/// exceed the maximum value specified by architecture. +pub(crate) unsafe fn init(io_mem_builder: IoMemAllocatorBuilder) { self::io_mem::init(io_mem_builder); - self::io_port::init(io_port_builder); + self::io_port::init(); }