mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-15 08:16:47 +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 align_ext::AlignExt;
|
||||||
|
|
||||||
use crate::{
|
use crate::{boot::memory_region::MemoryRegionType, io::IoMemAllocatorBuilder};
|
||||||
boot::memory_region::MemoryRegionType,
|
|
||||||
io::{IoMemAllocatorBuilder, IoPortAllocatorBuilder},
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Initializes the allocatable MMIO area based on the x86-64 memory distribution map.
|
/// 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) }
|
unsafe { IoMemAllocatorBuilder::new(ranges) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initializes the allocatable PIO area outside OSTD based on the x86-64 port distribution map.
|
/// Port I/O definition reference: https://bochs.sourceforge.io/techspec/PORTS.LST
|
||||||
pub(super) fn construct_io_port_allocator_builder() -> IoPortAllocatorBuilder {
|
pub const MAX_IO_PORT: u16 = u16::MAX;
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
|
@ -6,7 +6,7 @@ pub mod boot;
|
|||||||
pub(crate) mod cpu;
|
pub(crate) mod cpu;
|
||||||
pub mod device;
|
pub mod device;
|
||||||
pub(crate) mod ex_table;
|
pub(crate) mod ex_table;
|
||||||
mod io;
|
pub(crate) mod io;
|
||||||
pub mod iommu;
|
pub mod iommu;
|
||||||
pub(crate) mod irq;
|
pub(crate) mod irq;
|
||||||
pub(crate) mod kernel;
|
pub(crate) mod kernel;
|
||||||
@ -19,7 +19,7 @@ pub mod timer;
|
|||||||
pub mod trap;
|
pub mod trap;
|
||||||
|
|
||||||
use cfg_if::cfg_if;
|
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 spin::Once;
|
||||||
use x86::cpuid::{CpuId, FeatureInfo};
|
use x86::cpuid::{CpuId, FeatureInfo};
|
||||||
|
|
||||||
@ -81,7 +81,6 @@ pub(crate) unsafe fn late_init_on_bsp() {
|
|||||||
kernel::acpi::init();
|
kernel::acpi::init();
|
||||||
|
|
||||||
let io_mem_builder = construct_io_mem_allocator_builder();
|
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) {
|
match kernel::apic::init(&io_mem_builder) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
@ -110,9 +109,12 @@ pub(crate) unsafe fn late_init_on_bsp() {
|
|||||||
// Some driver like serial may use PIC
|
// Some driver like serial may use PIC
|
||||||
kernel::pic::init();
|
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 {
|
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 core::ops::Range;
|
||||||
|
|
||||||
use id_alloc::IdAlloc;
|
use id_alloc::IdAlloc;
|
||||||
use log::{debug, info};
|
use log::debug;
|
||||||
use spin::Once;
|
use spin::Once;
|
||||||
|
|
||||||
use super::IoPort;
|
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.
|
/// I/O port allocator that allocates port I/O access to device drivers.
|
||||||
pub struct IoPortAllocator {
|
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();
|
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
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// User must ensure all the port I/O regions that belong to the system device have been removed by calling the
|
/// User must ensure that:
|
||||||
/// `remove` function.
|
///
|
||||||
pub(crate) unsafe fn init(io_port_builder: IoPortAllocatorBuilder) {
|
/// 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 {
|
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};
|
use core::{marker::PhantomData, mem::size_of};
|
||||||
|
|
||||||
pub(super) use self::allocator::init;
|
pub(super) use self::allocator::init;
|
||||||
pub(crate) use self::allocator::IoPortAllocatorBuilder;
|
|
||||||
use crate::{prelude::*, Error};
|
use crate::{prelude::*, Error};
|
||||||
|
|
||||||
/// An I/O port, representing a specific address in the I/O address of x86.
|
/// 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 use self::{io_mem::IoMem, io_port::IoPort};
|
||||||
pub(crate) use self::{
|
pub(crate) use self::{
|
||||||
io_mem::IoMemAllocatorBuilder,
|
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.
|
/// Initializes the static allocator based on builder.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// User must ensure all the memory and port I/O regions that belong to the system device
|
/// User must ensure that:
|
||||||
/// have been removed by calling the corresponding `remove` function.
|
///
|
||||||
pub(crate) unsafe fn init(
|
/// 1. All the memory that belong to the system device have been removed
|
||||||
io_mem_builder: IoMemAllocatorBuilder,
|
/// by calling the `remove` function.
|
||||||
io_port_builder: IoPortAllocatorBuilder,
|
///
|
||||||
) {
|
/// 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_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