Refactor IoPort

This commit is contained in:
Yuke Peng 2023-03-21 21:09:21 -07:00 committed by Tate, Hongliang Tian
parent ebfb199512
commit 8c7b5d84d1
7 changed files with 109 additions and 140 deletions

View File

@ -1,60 +1,55 @@
use spin::Mutex; use core::marker::PhantomData;
use x86_64::{
instructions::port::Port, pub use x86_64::instructions::port::{
structures::port::{PortRead, PortWrite}, 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. /// 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: /// The following code shows and example to read and write u32 value to an I/O port:
/// ///
/// ```rust /// ```rust
/// static PORT: IoPort<u32> = IoPort::new(0x12); /// static PORT: IoPort<u32, ReadWriteAccess> = unsafe { IoPort::new(0x12) };
/// ///
/// fn port_value_increase(){ /// fn port_value_increase(){
/// PORT.write(PORT.read() + 1) /// PORT.write(PORT.read() + 1)
/// } /// }
/// ``` /// ```
/// ///
pub struct IoPort<T> { pub struct IoPort<T, A> {
addr: u16, port: u16,
port: Mutex<Port<T>>, value_marker: PhantomData<T>,
access_marker: PhantomData<A>,
} }
impl<T> IoPort<T> { impl<T, A> IoPort<T, A> {
/// Create an I/O port. /// Create an I/O port.
/// ///
/// # Safety /// # Safety
/// ///
/// This function is marked unsafe as creating an I/O port is considered /// This function is marked unsafe as creating an I/O port is considered
/// a privileged operation. /// a privileged operation.
pub const unsafe fn new(addr: u16) -> Self { pub const unsafe fn new(port: u16) -> Self {
Self { Self {
addr, port: port,
port: Mutex::new(Port::new(addr)), value_marker: PhantomData,
access_marker: PhantomData,
} }
} }
} }
impl<T> IoPort<T> { impl<T: PortRead, A: IoPortReadAccess> IoPort<T, A> {
/// Get the address of this I/O port. #[inline]
pub fn addr(&self) -> u16 {
self.addr
}
}
impl<T: PortRead> IoPort<T> {
/// Reads from the port.
pub fn read(&self) -> T { pub fn read(&self) -> T {
unsafe { (*self.port.lock()).read() } unsafe { PortRead::read_from_port(self.port) }
} }
} }
impl<T: PortWrite> IoPort<T> { impl<T: PortWrite, A: IoPortWriteAccess> IoPort<T, A> {
/// Writes to the port. #[inline]
pub fn write(&self, val: T) { pub fn write(&self, value: T) {
unsafe { unsafe { PortWrite::write_to_port(self.port, value) }
self.port.lock().write(val);
}
} }
} }

View File

@ -1,12 +1,10 @@
//! Device-related APIs. //! Device-related APIs.
pub mod framebuffer;
mod io_port; pub mod framebuffer;
pub mod io_port;
pub mod pci; pub mod pci;
pub mod serial; pub mod serial;
pub use self::io_port::IoPort;
/// Call after the memory allocator init /// Call after the memory allocator init
pub(crate) fn init() { pub(crate) fn init() {
framebuffer::init(); framebuffer::init();

View File

@ -1,6 +1,7 @@
//! PCI bus io port //! PCI bus io port
use super::io_port::IoPort; 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_ADDRESS_PORT: IoPort<u32, WriteOnlyAccess> = unsafe { IoPort::new(0x0CF8) };
pub static PCI_DATA_PORT: IoPort<u32> = unsafe { IoPort::new(0x0CFC) }; pub static PCI_DATA_PORT: IoPort<u32, ReadWriteAccess> = unsafe { IoPort::new(0x0CFC) };

View File

@ -1,12 +1,13 @@
//! A port-mapped UART. Copied from uart_16550. //! A port-mapped UART. Copied from uart_16550.
use super::io_port::{IoPort, ReadWriteAccess, WriteOnlyAccess};
use alloc::{sync::Arc, vec::Vec}; use alloc::{sync::Arc, vec::Vec};
use core::fmt::{self, Write};
use log::debug; use log::debug;
use spin::{Mutex, Once}; use spin::{Mutex, Once};
use trapframe::TrapFrame;
use x86_64::instructions::port::{Port, PortWriteOnly};
use crate::{driver::pic_allocate_irq, trap::IrqAllocateHandle}; use crate::{driver::pic_allocate_irq, trap::IrqAllocateHandle};
use core::fmt::{self, Write}; use trapframe::TrapFrame;
bitflags::bitflags! { bitflags::bitflags! {
struct LineSts: u8 { struct LineSts: u8 {
@ -17,16 +18,13 @@ bitflags::bitflags! {
const SERIAL_DATA_PORT: u16 = 0x3F8; const SERIAL_DATA_PORT: u16 = 0x3F8;
static SERIAL_DATA: Mutex<Port<u8>> = Mutex::new(Port::new(SERIAL_DATA_PORT)); static SERIAL_DATA: IoPort<u8, ReadWriteAccess> = unsafe { IoPort::new(SERIAL_DATA_PORT) };
static SERIAL_INT_EN: Mutex<PortWriteOnly<u8>> = static SERIAL_INT_EN: IoPort<u8, WriteOnlyAccess> = unsafe { IoPort::new(SERIAL_DATA_PORT + 1) };
Mutex::new(PortWriteOnly::new(SERIAL_DATA_PORT + 1)); static SERIAL_FIFO_CTRL: IoPort<u8, WriteOnlyAccess> = unsafe { IoPort::new(SERIAL_DATA_PORT + 2) };
static SERIAL_FIFO_CTRL: Mutex<PortWriteOnly<u8>> = static SERIAL_LINE_CTRL: IoPort<u8, WriteOnlyAccess> = unsafe { IoPort::new(SERIAL_DATA_PORT + 3) };
Mutex::new(PortWriteOnly::new(SERIAL_DATA_PORT + 2)); static SERIAL_MODEM_CTRL: IoPort<u8, WriteOnlyAccess> =
static SERIAL_LINE_CTRL: Mutex<PortWriteOnly<u8>> = unsafe { IoPort::new(SERIAL_DATA_PORT + 4) };
Mutex::new(PortWriteOnly::new(SERIAL_DATA_PORT + 3)); static SERIAL_LINE_STS: IoPort<u8, ReadWriteAccess> = unsafe { IoPort::new(SERIAL_DATA_PORT + 5) };
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 CONSOLE_IRQ_CALLBACK: Once<Mutex<IrqAllocateHandle>> = Once::new(); static CONSOLE_IRQ_CALLBACK: Once<Mutex<IrqAllocateHandle>> = Once::new();
static SERIAL_INPUT_CALLBACKS: Mutex<Vec<Arc<dyn Fn(u8) + Send + Sync + 'static>>> = 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. /// Initializes the serial port.
pub(crate) fn init() { pub(crate) fn init() {
let mut serial_line_ctrl_lock = SERIAL_LINE_CTRL.lock(); // Disable interrupts
let mut serial_int_en_lock = SERIAL_INT_EN.lock(); SERIAL_INT_EN.write(0x00);
let mut serial_data_lock = SERIAL_DATA.lock(); // Enable DLAB
let mut serial_fifo_ctrl_lock = SERIAL_FIFO_CTRL.lock(); SERIAL_LINE_CTRL.write(0x80);
let mut serial_modem_ctrl_lock = SERIAL_MODEM_CTRL.lock(); // Set maximum speed to 38400 bps by configuring DLL and DLM
unsafe { SERIAL_DATA.write(0x03);
// Disable interrupts SERIAL_INT_EN.write(0x00);
serial_int_en_lock.write(0x00); // Disable DLAB and set data word length to 8 bits
// Enable DLAB SERIAL_LINE_CTRL.write(0x03);
serial_line_ctrl_lock.write(0x80); // Enable FIFO, clear TX/RX queues and
// Set maximum speed to 38400 bps by configuring DLL and DLM // set interrupt watermark at 14 bytes
serial_data_lock.write(0x03); SERIAL_FIFO_CTRL.write(0xC7);
serial_int_en_lock.write(0x00); // Mark data terminal ready, signal request to send
// Disable DLAB and set data word length to 8 bits // and enable auxilliary output #2 (used as interrupt line for CPU)
serial_line_ctrl_lock.write(0x03); SERIAL_MODEM_CTRL.write(0x0B);
// Enable FIFO, clear TX/RX queues and // Enable interrupts
// set interrupt watermark at 14 bytes SERIAL_INT_EN.write(0x01);
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);
}
} }
pub fn register_serial_input_callback(f: impl Fn(u8) + Send + Sync + 'static) { 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 { 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. /// Sends a byte on the serial port.
pub fn send(data: u8) { pub fn send(data: u8) {
let mut lock = SERIAL_DATA.lock(); match data {
unsafe { 8 | 0x7F => {
match data { while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
8 | 0x7F => { SERIAL_DATA.write(8);
while !line_sts().contains(LineSts::OUTPUT_EMPTY) {} while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
lock.write(8); SERIAL_DATA.write(b' ');
while !line_sts().contains(LineSts::OUTPUT_EMPTY) {} while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
lock.write(b' '); SERIAL_DATA.write(8);
while !line_sts().contains(LineSts::OUTPUT_EMPTY) {} }
lock.write(8); _ => {
} while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
_ => { SERIAL_DATA.write(data);
while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
lock.write(data);
}
} }
} }
} }
@ -122,7 +110,7 @@ pub fn send(data: u8) {
/// Receives a byte on the serial port. non-blocking /// Receives a byte on the serial port. non-blocking
pub fn receive_char() -> Option<u8> { pub fn receive_char() -> Option<u8> {
if line_sts().contains(LineSts::INPUT_FULL) { if line_sts().contains(LineSts::INPUT_FULL) {
unsafe { Some(SERIAL_DATA.lock().read()) } Some(SERIAL_DATA.read())
} else { } else {
None None
} }

View File

@ -1,12 +1,14 @@
use crate::device::io_port::{IoPort, WriteOnlyAccess};
use crate::trap::allocate_target_irq; use crate::trap::allocate_target_irq;
use crate::trap::IrqAllocateHandle; use crate::trap::IrqAllocateHandle;
use core::sync::atomic::Ordering::Relaxed; use core::sync::atomic::Ordering::Relaxed;
use core::sync::atomic::{AtomicBool, AtomicU8}; use core::sync::atomic::{AtomicBool, AtomicU8};
static MASTER_CMD: Mutex<PortWriteOnly<u8>> = Mutex::new(PortWriteOnly::new(0x20)); static MASTER_CMD: IoPort<u8, WriteOnlyAccess> = unsafe { IoPort::new(0x20) };
static MASTER_DATA: Mutex<PortWriteOnly<u8>> = Mutex::new(PortWriteOnly::new(0x21)); static MASTER_DATA: IoPort<u8, WriteOnlyAccess> = unsafe { IoPort::new(0x21) };
static SLAVE_CMD: Mutex<PortWriteOnly<u8>> = Mutex::new(PortWriteOnly::new(0xA0)); static SLAVE_CMD: IoPort<u8, WriteOnlyAccess> = unsafe { IoPort::new(0xA0) };
static SLAVE_DATA: Mutex<PortWriteOnly<u8>> = Mutex::new(PortWriteOnly::new(0xA1)); static SLAVE_DATA: IoPort<u8, WriteOnlyAccess> = unsafe { IoPort::new(0xA1) };
const IRQ_OFFSET: u8 = 0x20; const IRQ_OFFSET: u8 = 0x20;
@ -16,7 +18,6 @@ use alloc::vec::Vec;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use log::info; use log::info;
use spin::Mutex; use spin::Mutex;
use x86_64::instructions::port::PortWriteOnly;
lazy_static! { lazy_static! {
/// store the irq, although we have APIC for manage interrupts /// store the irq, although we have APIC for manage interrupts
@ -98,36 +99,30 @@ pub(crate) fn disable_temp() {
#[inline(always)] #[inline(always)]
pub(crate) unsafe fn set_mask(master_mask: u8, slave_mask: u8) { pub(crate) unsafe fn set_mask(master_mask: u8, slave_mask: u8) {
let mut master_data_lock = MASTER_DATA.lock(); // Start initialization
let mut slave_data_lock = SLAVE_DATA.lock(); MASTER_CMD.write(0x11);
unsafe { SLAVE_CMD.write(0x11);
// Start initialization
MASTER_CMD.lock().write(0x11);
SLAVE_CMD.lock().write(0x11);
// Set offsets // Set offsets
// map master PIC vector 0x00~0x07 to 0x20~0x27 IRQ number // map master PIC vector 0x00~0x07 to 0x20~0x27 IRQ number
master_data_lock.write(IRQ_OFFSET); MASTER_DATA.write(IRQ_OFFSET);
// map slave PIC vector 0x00~0x07 to 0x28~0x2f IRQ number // map slave PIC vector 0x00~0x07 to 0x28~0x2f IRQ number
slave_data_lock.write(IRQ_OFFSET + 0x08); SLAVE_DATA.write(IRQ_OFFSET + 0x08);
// Set up cascade, there is slave at IRQ2 // Set up cascade, there is slave at IRQ2
master_data_lock.write(4); MASTER_DATA.write(4);
slave_data_lock.write(2); SLAVE_DATA.write(2);
// Set up interrupt mode (1 is 8086/88 mode, 2 is auto EOI) // Set up interrupt mode (1 is 8086/88 mode, 2 is auto EOI)
master_data_lock.write(1); MASTER_DATA.write(1);
slave_data_lock.write(1); SLAVE_DATA.write(1);
// mask interrupts // mask interrupts
master_data_lock.write(master_mask); MASTER_DATA.write(master_mask);
slave_data_lock.write(slave_mask); SLAVE_DATA.write(slave_mask);
}
} }
#[inline(always)] #[inline(always)]
pub(crate) fn ack() { pub(crate) fn ack() {
unsafe { MASTER_CMD.write(0x20);
MASTER_CMD.lock().write(0x20);
}
} }

View File

@ -2,20 +2,19 @@ use core::sync::atomic::AtomicU8;
use core::sync::atomic::Ordering::Relaxed; use core::sync::atomic::Ordering::Relaxed;
use acpi::{fadt::Fadt, sdt::Signature}; use acpi::{fadt::Fadt, sdt::Signature};
use lazy_static::lazy_static;
use spin::Mutex; use spin::Mutex;
use x86_64::instructions::port::{PortReadOnly, PortWriteOnly};
use crate::device::io_port::{IoPort, ReadOnlyAccess, WriteOnlyAccess};
use crate::time::Time; use crate::time::Time;
use super::acpi::ACPI_TABLES; use super::acpi::ACPI_TABLES;
static CMOS_ADDRESS: Mutex<PortWriteOnly<u8>> = Mutex::new(PortWriteOnly::new(0x70)); static CMOS_ADDRESS: IoPort<u8, WriteOnlyAccess> = unsafe { IoPort::new(0x70) };
static CMOS_DATA: Mutex<PortReadOnly<u8>> = Mutex::new(PortReadOnly::new(0x71)); static CMOS_DATA: IoPort<u8, ReadOnlyAccess> = unsafe { IoPort::new(0x71) };
pub(crate) static CENTURY_REGISTER: AtomicU8 = AtomicU8::new(0); 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()); static ref READ_TIME: Mutex<Time> = Mutex::new(Time::default());
} }
@ -32,17 +31,13 @@ pub fn init() {
} }
pub fn get_cmos(reg: u8) -> u8 { pub fn get_cmos(reg: u8) -> u8 {
unsafe { CMOS_ADDRESS.write(reg);
CMOS_ADDRESS.lock().write(reg); CMOS_DATA.read()
CMOS_DATA.lock().read()
}
} }
pub fn is_updating() -> bool { pub fn is_updating() -> bool {
unsafe { CMOS_ADDRESS.write(0x0A);
CMOS_ADDRESS.lock().write(0x0A); CMOS_DATA.read() & 0x80 != 0
CMOS_DATA.lock().read() & 0x80 != 0
}
} }
pub fn read() -> Time { pub fn read() -> Time {

View File

@ -1,22 +1,19 @@
//! used for PIT Timer //! used for PIT Timer
use spin::Mutex;
use x86_64::instructions::port::PortWriteOnly;
use crate::config::TIMER_FREQ; use crate::config::TIMER_FREQ;
use crate::device::io_port::{IoPort, WriteOnlyAccess};
const TIMER_RATE: u32 = 1193182; const TIMER_RATE: u32 = 1193182;
static TIMER_PERIOD: Mutex<PortWriteOnly<u8>> = Mutex::new(PortWriteOnly::new(0x40)); static TIMER_PERIOD: IoPort<u8, WriteOnlyAccess> = unsafe { IoPort::new(0x40) };
static TIMER_MOD: Mutex<PortWriteOnly<u8>> = Mutex::new(PortWriteOnly::new(0x43)); static TIMER_MOD: IoPort<u8, WriteOnlyAccess> = unsafe { IoPort::new(0x43) };
static TIMER_SQUARE_WAVE: u8 = 0x36; static TIMER_SQUARE_WAVE: u8 = 0x36;
pub(crate) fn init() { pub(crate) fn init() {
// Initialize timer. // Initialize timer.
let cycle = TIMER_RATE / TIMER_FREQ as u32; let cycle = TIMER_RATE / TIMER_FREQ as u32;
unsafe { TIMER_MOD.write(TIMER_SQUARE_WAVE);
TIMER_MOD.lock().write(TIMER_SQUARE_WAVE); TIMER_PERIOD.write((cycle & 0xFF) as _);
TIMER_PERIOD.lock().write((cycle & 0xFF) as _); TIMER_PERIOD.write((cycle >> 8) as _);
TIMER_PERIOD.lock().write((cycle >> 8) as _);
}
} }