Introduce macros that allow system device driver to remove sensitive ports

test

test
This commit is contained in:
Yuke Peng 2025-04-14 16:25:56 +08:00 committed by Tate, Hongliang Tian
parent a038b8401b
commit 92b7961df1
5 changed files with 133 additions and 3 deletions

View File

@ -43,6 +43,14 @@ SECTIONS
__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, .);
.data : AT(ADDR(.data) - KERNEL_VMA_OFFSET) { *(.data .data.*) }

View File

@ -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

View File

@ -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::<u16>() * 2) == 0);
let io_port_ranges = (end - start) / (size_of::<u16>() * 2);
for i in 0..io_port_ranges {
let range_base_addr = __sensitive_io_ports_start as usize + i * 2 * size_of::<u16>();
let (range_start, range_end) = unsafe {
(
*(range_base_addr as *const u16),
*((range_base_addr + size_of::<u16>()) as *const u16),
)
};
builder.remove(range_start..range_end);
}
builder
}

View File

@ -39,6 +39,16 @@ impl<T, A> IoPort<T, A> {
.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::<T>() as u16
}
/// Create an I/O port.
///
/// # Safety
@ -81,3 +91,81 @@ impl<T, A> Drop for IoPort<T, A> {
}
}
}
/// 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<u8, WriteOnlyAccess> = IoPort::new(0x20);
/// /// Master PIC data port
/// static MASTER_DATA: IoPort<u8, WriteOnlyAccess> = 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,
}

View File

@ -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.
///