From 92b7961df1859757e402a0334ac4564622e6f312 Mon Sep 17 00:00:00 2001 From: Yuke Peng Date: Mon, 14 Apr 2025 16:25:56 +0800 Subject: [PATCH] Introduce macros that allow system device driver to remove sensitive ports test test --- osdk/src/base_crate/riscv64.ld.template | 8 +++ osdk/src/base_crate/x86_64.ld.template | 8 +++ ostd/src/arch/x86/io.rs | 27 +++++++- ostd/src/io/io_port/mod.rs | 88 +++++++++++++++++++++++++ ostd/src/io/mod.rs | 5 +- 5 files changed, 133 insertions(+), 3 deletions(-) diff --git a/osdk/src/base_crate/riscv64.ld.template b/osdk/src/base_crate/riscv64.ld.template index a40f0e29..8e8e2a86 100644 --- a/osdk/src/base_crate/riscv64.ld.template +++ b/osdk/src/base_crate/riscv64.ld.template @@ -42,6 +42,14 @@ SECTIONS KEEP(*(SORT(.init_array .init_array.*))) __einit_array = .; } + + # A list of the sensitive IoPort ranges in OSTD which will be used during + # the initialization of IoPortAllocator. + .sensitive_io_ports : AT(ADDR(.sensitive_io_ports) - KERNEL_VMA_OFFSET) { + __sensitive_io_ports_start = .; + KEEP(*(.sensitive_io_ports)) + __sensitive_io_ports_end = .; + } . = DATA_SEGMENT_RELRO_END(0, .); diff --git a/osdk/src/base_crate/x86_64.ld.template b/osdk/src/base_crate/x86_64.ld.template index 1efcd96f..a90253ba 100644 --- a/osdk/src/base_crate/x86_64.ld.template +++ b/osdk/src/base_crate/x86_64.ld.template @@ -113,6 +113,14 @@ SECTIONS __einit_array = .; } : rodata + # A list of the sensitive IoPort ranges in OSTD which will be used during + # the initialization of IoPortAllocator. + .sensitive_io_ports : AT(ADDR(.sensitive_io_ports) - KERNEL_VMA) { + __sensitive_io_ports_start = .; + KEEP(*(.sensitive_io_ports)) + __sensitive_io_ports_end = .; + } : rodata + .rodata : AT(ADDR(.rodata) - KERNEL_VMA) { *(.rodata .rodata.*) } : rodata diff --git a/ostd/src/arch/x86/io.rs b/ostd/src/arch/x86/io.rs index 51e3b6b1..df8fc876 100644 --- a/ostd/src/arch/x86/io.rs +++ b/ostd/src/arch/x86/io.rs @@ -58,11 +58,34 @@ pub(super) fn construct_io_mem_allocator_builder() -> IoMemAllocatorBuilder { unsafe { IoMemAllocatorBuilder::new(ranges) } } -/// Initializes the allocatable PIO area based on the x86-64 port distribution map. +/// 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. - unsafe { IoPortAllocatorBuilder::new(MAX_IO_PORT) } + 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 } diff --git a/ostd/src/io/io_port/mod.rs b/ostd/src/io/io_port/mod.rs index 371dcb98..4fb233eb 100644 --- a/ostd/src/io/io_port/mod.rs +++ b/ostd/src/io/io_port/mod.rs @@ -39,6 +39,16 @@ impl IoPort { .ok_or(Error::AccessDenied) } + /// Returns the port number. + pub const fn port(&self) -> u16 { + self.port + } + + /// Returns the size of the I/O port. + pub const fn size(&self) -> u16 { + size_of::() as u16 + } + /// Create an I/O port. /// /// # Safety @@ -81,3 +91,81 @@ impl Drop for IoPort { } } } + +/// Reserves an I/O port range which may refer to the port I/O range used by the +/// system device driver. +/// +/// # Example +/// ``` +/// reserve_io_port_range!(0x60..0x64); +/// ``` +macro_rules! reserve_io_port_range { + ($range:expr) => { + crate::const_assert!( + $range.start < $range.end, + "I/O port range must be valid (start < end)" + ); + + const _: () = { + #[used] + #[link_section = ".sensitive_io_ports"] + static _RANGE: crate::io::RawIoPortRange = crate::io::RawIoPortRange { + begin: $range.start, + end: $range.end, + }; + }; + }; +} + +/// Declares one or multiple sensitive I/O ports. +/// +/// # Safety +/// +/// User must ensures that: +/// - The I/O port is valid and doesn't overlap with other sensitive I/O ports. +/// - The I/O port is used by the target system device driver. +/// +/// # Example +/// ``` norun +/// sensitive_io_port! { +/// unsafe { +/// /// Master PIC command port +/// static MASTER_CMD: IoPort = IoPort::new(0x20); +/// /// Master PIC data port +/// static MASTER_DATA: IoPort = IoPort::new(0x21); +/// } +/// } +/// ``` +macro_rules! sensitive_io_port { + (unsafe { $( + $(#[$meta:meta])* + $vis:vis static $name:ident: IoPort<$size:ty, $access:ty> = IoPort::new($port:expr); + )* }) => { + $( + $(#[$meta])* + $vis static $name: IoPort<$size, $access> = { + #[used] + #[link_section = ".sensitive_io_ports"] + static _RESERVED_IO_PORT_RANGE: crate::io::RawIoPortRange = crate::io::RawIoPortRange { + begin: $name.port(), + end: $name.port() + $name.size(), + }; + + unsafe { + IoPort::new($port) + } + }; + )* + }; +} + +pub(crate) use reserve_io_port_range; +pub(crate) use sensitive_io_port; + +#[doc(hidden)] +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub(crate) struct RawIoPortRange { + pub(crate) begin: u16, + pub(crate) end: u16, +} diff --git a/ostd/src/io/mod.rs b/ostd/src/io/mod.rs index 2bc488a7..2b986575 100644 --- a/ostd/src/io/mod.rs +++ b/ostd/src/io/mod.rs @@ -11,7 +11,10 @@ mod io_mem; mod io_port; pub use self::{io_mem::IoMem, io_port::IoPort}; -pub(crate) use self::{io_mem::IoMemAllocatorBuilder, io_port::IoPortAllocatorBuilder}; +pub(crate) use self::{ + io_mem::IoMemAllocatorBuilder, + io_port::{reserve_io_port_range, sensitive_io_port, IoPortAllocatorBuilder, RawIoPortRange}, +}; /// Initializes the static allocator based on builder. ///