mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-08 12:56:48 +00:00
Refactor the initialization of IoPortAllocator
This commit is contained in:
parent
a2caedafda
commit
74ffe72cad
@ -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::<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
|
||||
}
|
||||
/// Port I/O definition reference: https://bochs.sourceforge.io/techspec/PORTS.LST
|
||||
pub const MAX_IO_PORT: u16 = u16::MAX;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<u16>) {
|
||||
info!("Removing PIO range: {:#x?}", range);
|
||||
|
||||
for i in range {
|
||||
self.allocator.alloc_specific(i as usize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) static IO_PORT_ALLOCATOR: Once<IoPortAllocator> = 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::<RawIoPortRange>() == 0);
|
||||
|
||||
// Iterate through the sensitive I/O port ranges and remove them from the allocator.
|
||||
let io_port_range_count = (end - start) / size_of::<RawIoPortRange>();
|
||||
for i in 0..io_port_range_count {
|
||||
let range_base_addr = __sensitive_io_ports_start as usize + i * size_of::<RawIoPortRange>();
|
||||
// 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),
|
||||
});
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user