mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-08 21:06:48 +00:00
Refactor IoPort
This commit is contained in:
parent
ebfb199512
commit
8c7b5d84d1
@ -1,60 +1,55 @@
|
||||
use spin::Mutex;
|
||||
use x86_64::{
|
||||
instructions::port::Port,
|
||||
structures::port::{PortRead, PortWrite},
|
||||
use core::marker::PhantomData;
|
||||
|
||||
pub use x86_64::instructions::port::{
|
||||
PortReadAccess as IoPortReadAccess, PortWriteAccess as IoPortWriteAccess, ReadOnlyAccess,
|
||||
ReadWriteAccess, WriteOnlyAccess,
|
||||
};
|
||||
pub use x86_64::structures::port::{PortRead, PortWrite};
|
||||
|
||||
/// An I/O port, representing a specific address in the I/O address of x86.
|
||||
///
|
||||
/// The following code shows and example to read and write u32 value to an I/O port:
|
||||
///
|
||||
/// ```rust
|
||||
/// static PORT: IoPort<u32> = IoPort::new(0x12);
|
||||
/// static PORT: IoPort<u32, ReadWriteAccess> = unsafe { IoPort::new(0x12) };
|
||||
///
|
||||
/// fn port_value_increase(){
|
||||
/// PORT.write(PORT.read() + 1)
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
pub struct IoPort<T> {
|
||||
addr: u16,
|
||||
port: Mutex<Port<T>>,
|
||||
pub struct IoPort<T, A> {
|
||||
port: u16,
|
||||
value_marker: PhantomData<T>,
|
||||
access_marker: PhantomData<A>,
|
||||
}
|
||||
|
||||
impl<T> IoPort<T> {
|
||||
impl<T, A> IoPort<T, A> {
|
||||
/// Create an I/O port.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is marked unsafe as creating an I/O port is considered
|
||||
/// a privileged operation.
|
||||
pub const unsafe fn new(addr: u16) -> Self {
|
||||
pub const unsafe fn new(port: u16) -> Self {
|
||||
Self {
|
||||
addr,
|
||||
port: Mutex::new(Port::new(addr)),
|
||||
port: port,
|
||||
value_marker: PhantomData,
|
||||
access_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IoPort<T> {
|
||||
/// Get the address of this I/O port.
|
||||
pub fn addr(&self) -> u16 {
|
||||
self.addr
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PortRead> IoPort<T> {
|
||||
/// Reads from the port.
|
||||
impl<T: PortRead, A: IoPortReadAccess> IoPort<T, A> {
|
||||
#[inline]
|
||||
pub fn read(&self) -> T {
|
||||
unsafe { (*self.port.lock()).read() }
|
||||
unsafe { PortRead::read_from_port(self.port) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PortWrite> IoPort<T> {
|
||||
/// Writes to the port.
|
||||
pub fn write(&self, val: T) {
|
||||
unsafe {
|
||||
self.port.lock().write(val);
|
||||
}
|
||||
impl<T: PortWrite, A: IoPortWriteAccess> IoPort<T, A> {
|
||||
#[inline]
|
||||
pub fn write(&self, value: T) {
|
||||
unsafe { PortWrite::write_to_port(self.port, value) }
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,10 @@
|
||||
//! Device-related APIs.
|
||||
pub mod framebuffer;
|
||||
|
||||
mod io_port;
|
||||
pub mod framebuffer;
|
||||
pub mod io_port;
|
||||
pub mod pci;
|
||||
pub mod serial;
|
||||
|
||||
pub use self::io_port::IoPort;
|
||||
|
||||
/// Call after the memory allocator init
|
||||
pub(crate) fn init() {
|
||||
framebuffer::init();
|
||||
|
@ -1,6 +1,7 @@
|
||||
//! PCI bus io port
|
||||
|
||||
use super::io_port::IoPort;
|
||||
use super::io_port::{ReadWriteAccess, WriteOnlyAccess};
|
||||
|
||||
pub static PCI_ADDRESS_PORT: IoPort<u32> = unsafe { IoPort::new(0x0CF8) };
|
||||
pub static PCI_DATA_PORT: IoPort<u32> = unsafe { IoPort::new(0x0CFC) };
|
||||
pub static PCI_ADDRESS_PORT: IoPort<u32, WriteOnlyAccess> = unsafe { IoPort::new(0x0CF8) };
|
||||
pub static PCI_DATA_PORT: IoPort<u32, ReadWriteAccess> = unsafe { IoPort::new(0x0CFC) };
|
||||
|
@ -1,12 +1,13 @@
|
||||
//! A port-mapped UART. Copied from uart_16550.
|
||||
|
||||
use super::io_port::{IoPort, ReadWriteAccess, WriteOnlyAccess};
|
||||
use alloc::{sync::Arc, vec::Vec};
|
||||
use core::fmt::{self, Write};
|
||||
use log::debug;
|
||||
use spin::{Mutex, Once};
|
||||
use trapframe::TrapFrame;
|
||||
use x86_64::instructions::port::{Port, PortWriteOnly};
|
||||
|
||||
use crate::{driver::pic_allocate_irq, trap::IrqAllocateHandle};
|
||||
use core::fmt::{self, Write};
|
||||
use trapframe::TrapFrame;
|
||||
|
||||
bitflags::bitflags! {
|
||||
struct LineSts: u8 {
|
||||
@ -17,16 +18,13 @@ bitflags::bitflags! {
|
||||
|
||||
const SERIAL_DATA_PORT: u16 = 0x3F8;
|
||||
|
||||
static SERIAL_DATA: Mutex<Port<u8>> = Mutex::new(Port::new(SERIAL_DATA_PORT));
|
||||
static SERIAL_INT_EN: Mutex<PortWriteOnly<u8>> =
|
||||
Mutex::new(PortWriteOnly::new(SERIAL_DATA_PORT + 1));
|
||||
static SERIAL_FIFO_CTRL: Mutex<PortWriteOnly<u8>> =
|
||||
Mutex::new(PortWriteOnly::new(SERIAL_DATA_PORT + 2));
|
||||
static SERIAL_LINE_CTRL: Mutex<PortWriteOnly<u8>> =
|
||||
Mutex::new(PortWriteOnly::new(SERIAL_DATA_PORT + 3));
|
||||
static SERIAL_MODEM_CTRL: Mutex<PortWriteOnly<u8>> =
|
||||
Mutex::new(PortWriteOnly::new(SERIAL_DATA_PORT + 4));
|
||||
static SERIAL_LINE_STS: Mutex<Port<u8>> = Mutex::new(Port::new(SERIAL_DATA_PORT + 5));
|
||||
static SERIAL_DATA: IoPort<u8, ReadWriteAccess> = unsafe { IoPort::new(SERIAL_DATA_PORT) };
|
||||
static SERIAL_INT_EN: IoPort<u8, WriteOnlyAccess> = unsafe { IoPort::new(SERIAL_DATA_PORT + 1) };
|
||||
static SERIAL_FIFO_CTRL: IoPort<u8, WriteOnlyAccess> = unsafe { IoPort::new(SERIAL_DATA_PORT + 2) };
|
||||
static SERIAL_LINE_CTRL: IoPort<u8, WriteOnlyAccess> = unsafe { IoPort::new(SERIAL_DATA_PORT + 3) };
|
||||
static SERIAL_MODEM_CTRL: IoPort<u8, WriteOnlyAccess> =
|
||||
unsafe { IoPort::new(SERIAL_DATA_PORT + 4) };
|
||||
static SERIAL_LINE_STS: IoPort<u8, ReadWriteAccess> = unsafe { IoPort::new(SERIAL_DATA_PORT + 5) };
|
||||
|
||||
static CONSOLE_IRQ_CALLBACK: Once<Mutex<IrqAllocateHandle>> = Once::new();
|
||||
static SERIAL_INPUT_CALLBACKS: Mutex<Vec<Arc<dyn Fn(u8) + Send + Sync + 'static>>> =
|
||||
@ -34,30 +32,23 @@ static SERIAL_INPUT_CALLBACKS: Mutex<Vec<Arc<dyn Fn(u8) + Send + Sync + 'static>
|
||||
|
||||
/// Initializes the serial port.
|
||||
pub(crate) fn init() {
|
||||
let mut serial_line_ctrl_lock = SERIAL_LINE_CTRL.lock();
|
||||
let mut serial_int_en_lock = SERIAL_INT_EN.lock();
|
||||
let mut serial_data_lock = SERIAL_DATA.lock();
|
||||
let mut serial_fifo_ctrl_lock = SERIAL_FIFO_CTRL.lock();
|
||||
let mut serial_modem_ctrl_lock = SERIAL_MODEM_CTRL.lock();
|
||||
unsafe {
|
||||
// Disable interrupts
|
||||
serial_int_en_lock.write(0x00);
|
||||
// Enable DLAB
|
||||
serial_line_ctrl_lock.write(0x80);
|
||||
// Set maximum speed to 38400 bps by configuring DLL and DLM
|
||||
serial_data_lock.write(0x03);
|
||||
serial_int_en_lock.write(0x00);
|
||||
// Disable DLAB and set data word length to 8 bits
|
||||
serial_line_ctrl_lock.write(0x03);
|
||||
// Enable FIFO, clear TX/RX queues and
|
||||
// set interrupt watermark at 14 bytes
|
||||
serial_fifo_ctrl_lock.write(0xC7);
|
||||
// Mark data terminal ready, signal request to send
|
||||
// and enable auxilliary output #2 (used as interrupt line for CPU)
|
||||
serial_modem_ctrl_lock.write(0x0B);
|
||||
// Enable interrupts
|
||||
serial_int_en_lock.write(0x01);
|
||||
}
|
||||
// Disable interrupts
|
||||
SERIAL_INT_EN.write(0x00);
|
||||
// Enable DLAB
|
||||
SERIAL_LINE_CTRL.write(0x80);
|
||||
// Set maximum speed to 38400 bps by configuring DLL and DLM
|
||||
SERIAL_DATA.write(0x03);
|
||||
SERIAL_INT_EN.write(0x00);
|
||||
// Disable DLAB and set data word length to 8 bits
|
||||
SERIAL_LINE_CTRL.write(0x03);
|
||||
// Enable FIFO, clear TX/RX queues and
|
||||
// set interrupt watermark at 14 bytes
|
||||
SERIAL_FIFO_CTRL.write(0xC7);
|
||||
// Mark data terminal ready, signal request to send
|
||||
// and enable auxilliary output #2 (used as interrupt line for CPU)
|
||||
SERIAL_MODEM_CTRL.write(0x0B);
|
||||
// Enable interrupts
|
||||
SERIAL_INT_EN.write(0x01);
|
||||
}
|
||||
|
||||
pub fn register_serial_input_callback(f: impl Fn(u8) + Send + Sync + 'static) {
|
||||
@ -95,26 +86,23 @@ fn handle_serial_input(trap_frame: &TrapFrame) {
|
||||
}
|
||||
|
||||
fn line_sts() -> LineSts {
|
||||
LineSts::from_bits_truncate(unsafe { SERIAL_LINE_STS.lock().read() })
|
||||
LineSts::from_bits_truncate(SERIAL_LINE_STS.read())
|
||||
}
|
||||
|
||||
/// Sends a byte on the serial port.
|
||||
pub fn send(data: u8) {
|
||||
let mut lock = SERIAL_DATA.lock();
|
||||
unsafe {
|
||||
match data {
|
||||
8 | 0x7F => {
|
||||
while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
|
||||
lock.write(8);
|
||||
while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
|
||||
lock.write(b' ');
|
||||
while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
|
||||
lock.write(8);
|
||||
}
|
||||
_ => {
|
||||
while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
|
||||
lock.write(data);
|
||||
}
|
||||
match data {
|
||||
8 | 0x7F => {
|
||||
while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
|
||||
SERIAL_DATA.write(8);
|
||||
while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
|
||||
SERIAL_DATA.write(b' ');
|
||||
while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
|
||||
SERIAL_DATA.write(8);
|
||||
}
|
||||
_ => {
|
||||
while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
|
||||
SERIAL_DATA.write(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -122,7 +110,7 @@ pub fn send(data: u8) {
|
||||
/// Receives a byte on the serial port. non-blocking
|
||||
pub fn receive_char() -> Option<u8> {
|
||||
if line_sts().contains(LineSts::INPUT_FULL) {
|
||||
unsafe { Some(SERIAL_DATA.lock().read()) }
|
||||
Some(SERIAL_DATA.read())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -1,12 +1,14 @@
|
||||
use crate::device::io_port::{IoPort, WriteOnlyAccess};
|
||||
use crate::trap::allocate_target_irq;
|
||||
use crate::trap::IrqAllocateHandle;
|
||||
|
||||
use core::sync::atomic::Ordering::Relaxed;
|
||||
use core::sync::atomic::{AtomicBool, AtomicU8};
|
||||
|
||||
static MASTER_CMD: Mutex<PortWriteOnly<u8>> = Mutex::new(PortWriteOnly::new(0x20));
|
||||
static MASTER_DATA: Mutex<PortWriteOnly<u8>> = Mutex::new(PortWriteOnly::new(0x21));
|
||||
static SLAVE_CMD: Mutex<PortWriteOnly<u8>> = Mutex::new(PortWriteOnly::new(0xA0));
|
||||
static SLAVE_DATA: Mutex<PortWriteOnly<u8>> = Mutex::new(PortWriteOnly::new(0xA1));
|
||||
static MASTER_CMD: IoPort<u8, WriteOnlyAccess> = unsafe { IoPort::new(0x20) };
|
||||
static MASTER_DATA: IoPort<u8, WriteOnlyAccess> = unsafe { IoPort::new(0x21) };
|
||||
static SLAVE_CMD: IoPort<u8, WriteOnlyAccess> = unsafe { IoPort::new(0xA0) };
|
||||
static SLAVE_DATA: IoPort<u8, WriteOnlyAccess> = unsafe { IoPort::new(0xA1) };
|
||||
|
||||
const IRQ_OFFSET: u8 = 0x20;
|
||||
|
||||
@ -16,7 +18,6 @@ use alloc::vec::Vec;
|
||||
use lazy_static::lazy_static;
|
||||
use log::info;
|
||||
use spin::Mutex;
|
||||
use x86_64::instructions::port::PortWriteOnly;
|
||||
|
||||
lazy_static! {
|
||||
/// store the irq, although we have APIC for manage interrupts
|
||||
@ -98,36 +99,30 @@ pub(crate) fn disable_temp() {
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) unsafe fn set_mask(master_mask: u8, slave_mask: u8) {
|
||||
let mut master_data_lock = MASTER_DATA.lock();
|
||||
let mut slave_data_lock = SLAVE_DATA.lock();
|
||||
unsafe {
|
||||
// Start initialization
|
||||
MASTER_CMD.lock().write(0x11);
|
||||
SLAVE_CMD.lock().write(0x11);
|
||||
// Start initialization
|
||||
MASTER_CMD.write(0x11);
|
||||
SLAVE_CMD.write(0x11);
|
||||
|
||||
// Set offsets
|
||||
// map master PIC vector 0x00~0x07 to 0x20~0x27 IRQ number
|
||||
master_data_lock.write(IRQ_OFFSET);
|
||||
// map slave PIC vector 0x00~0x07 to 0x28~0x2f IRQ number
|
||||
slave_data_lock.write(IRQ_OFFSET + 0x08);
|
||||
// Set offsets
|
||||
// map master PIC vector 0x00~0x07 to 0x20~0x27 IRQ number
|
||||
MASTER_DATA.write(IRQ_OFFSET);
|
||||
// map slave PIC vector 0x00~0x07 to 0x28~0x2f IRQ number
|
||||
SLAVE_DATA.write(IRQ_OFFSET + 0x08);
|
||||
|
||||
// Set up cascade, there is slave at IRQ2
|
||||
master_data_lock.write(4);
|
||||
slave_data_lock.write(2);
|
||||
// Set up cascade, there is slave at IRQ2
|
||||
MASTER_DATA.write(4);
|
||||
SLAVE_DATA.write(2);
|
||||
|
||||
// Set up interrupt mode (1 is 8086/88 mode, 2 is auto EOI)
|
||||
master_data_lock.write(1);
|
||||
slave_data_lock.write(1);
|
||||
// Set up interrupt mode (1 is 8086/88 mode, 2 is auto EOI)
|
||||
MASTER_DATA.write(1);
|
||||
SLAVE_DATA.write(1);
|
||||
|
||||
// mask interrupts
|
||||
master_data_lock.write(master_mask);
|
||||
slave_data_lock.write(slave_mask);
|
||||
}
|
||||
// mask interrupts
|
||||
MASTER_DATA.write(master_mask);
|
||||
SLAVE_DATA.write(slave_mask);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn ack() {
|
||||
unsafe {
|
||||
MASTER_CMD.lock().write(0x20);
|
||||
}
|
||||
MASTER_CMD.write(0x20);
|
||||
}
|
||||
|
@ -2,20 +2,19 @@ use core::sync::atomic::AtomicU8;
|
||||
use core::sync::atomic::Ordering::Relaxed;
|
||||
|
||||
use acpi::{fadt::Fadt, sdt::Signature};
|
||||
use lazy_static::lazy_static;
|
||||
use spin::Mutex;
|
||||
use x86_64::instructions::port::{PortReadOnly, PortWriteOnly};
|
||||
|
||||
use crate::device::io_port::{IoPort, ReadOnlyAccess, WriteOnlyAccess};
|
||||
use crate::time::Time;
|
||||
|
||||
use super::acpi::ACPI_TABLES;
|
||||
|
||||
static CMOS_ADDRESS: Mutex<PortWriteOnly<u8>> = Mutex::new(PortWriteOnly::new(0x70));
|
||||
static CMOS_DATA: Mutex<PortReadOnly<u8>> = Mutex::new(PortReadOnly::new(0x71));
|
||||
static CMOS_ADDRESS: IoPort<u8, WriteOnlyAccess> = unsafe { IoPort::new(0x70) };
|
||||
static CMOS_DATA: IoPort<u8, ReadOnlyAccess> = unsafe { IoPort::new(0x71) };
|
||||
|
||||
pub(crate) static CENTURY_REGISTER: AtomicU8 = AtomicU8::new(0);
|
||||
|
||||
lazy_static! {
|
||||
lazy_static::lazy_static! {
|
||||
static ref READ_TIME: Mutex<Time> = Mutex::new(Time::default());
|
||||
}
|
||||
|
||||
@ -32,17 +31,13 @@ pub fn init() {
|
||||
}
|
||||
|
||||
pub fn get_cmos(reg: u8) -> u8 {
|
||||
unsafe {
|
||||
CMOS_ADDRESS.lock().write(reg);
|
||||
CMOS_DATA.lock().read()
|
||||
}
|
||||
CMOS_ADDRESS.write(reg);
|
||||
CMOS_DATA.read()
|
||||
}
|
||||
|
||||
pub fn is_updating() -> bool {
|
||||
unsafe {
|
||||
CMOS_ADDRESS.lock().write(0x0A);
|
||||
CMOS_DATA.lock().read() & 0x80 != 0
|
||||
}
|
||||
CMOS_ADDRESS.write(0x0A);
|
||||
CMOS_DATA.read() & 0x80 != 0
|
||||
}
|
||||
|
||||
pub fn read() -> Time {
|
||||
|
@ -1,22 +1,19 @@
|
||||
//! used for PIT Timer
|
||||
|
||||
use spin::Mutex;
|
||||
use x86_64::instructions::port::PortWriteOnly;
|
||||
|
||||
use crate::config::TIMER_FREQ;
|
||||
|
||||
use crate::device::io_port::{IoPort, WriteOnlyAccess};
|
||||
|
||||
const TIMER_RATE: u32 = 1193182;
|
||||
|
||||
static TIMER_PERIOD: Mutex<PortWriteOnly<u8>> = Mutex::new(PortWriteOnly::new(0x40));
|
||||
static TIMER_MOD: Mutex<PortWriteOnly<u8>> = Mutex::new(PortWriteOnly::new(0x43));
|
||||
static TIMER_PERIOD: IoPort<u8, WriteOnlyAccess> = unsafe { IoPort::new(0x40) };
|
||||
static TIMER_MOD: IoPort<u8, WriteOnlyAccess> = unsafe { IoPort::new(0x43) };
|
||||
static TIMER_SQUARE_WAVE: u8 = 0x36;
|
||||
|
||||
pub(crate) fn init() {
|
||||
// Initialize timer.
|
||||
let cycle = TIMER_RATE / TIMER_FREQ as u32;
|
||||
unsafe {
|
||||
TIMER_MOD.lock().write(TIMER_SQUARE_WAVE);
|
||||
TIMER_PERIOD.lock().write((cycle & 0xFF) as _);
|
||||
TIMER_PERIOD.lock().write((cycle >> 8) as _);
|
||||
}
|
||||
TIMER_MOD.write(TIMER_SQUARE_WAVE);
|
||||
TIMER_PERIOD.write((cycle & 0xFF) as _);
|
||||
TIMER_PERIOD.write((cycle >> 8) as _);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user