From 8c7b5d84d1f58280510c99d182c0838c59d27475 Mon Sep 17 00:00:00 2001 From: Yuke Peng Date: Tue, 21 Mar 2023 21:09:21 -0700 Subject: [PATCH] Refactor IoPort --- .../jinux-frame/src/device/io_port.rs | 51 +++++----- src/framework/jinux-frame/src/device/mod.rs | 6 +- src/framework/jinux-frame/src/device/pci.rs | 5 +- .../jinux-frame/src/device/serial.rs | 96 ++++++++----------- src/framework/jinux-frame/src/driver/pic.rs | 53 +++++----- src/framework/jinux-frame/src/driver/rtc.rs | 21 ++-- .../jinux-frame/src/driver/timer/pit.rs | 17 ++-- 7 files changed, 109 insertions(+), 140 deletions(-) diff --git a/src/framework/jinux-frame/src/device/io_port.rs b/src/framework/jinux-frame/src/device/io_port.rs index 2af657f2..2af83f91 100644 --- a/src/framework/jinux-frame/src/device/io_port.rs +++ b/src/framework/jinux-frame/src/device/io_port.rs @@ -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 = IoPort::new(0x12); +/// static PORT: IoPort = unsafe { IoPort::new(0x12) }; /// /// fn port_value_increase(){ /// PORT.write(PORT.read() + 1) /// } /// ``` /// -pub struct IoPort { - addr: u16, - port: Mutex>, +pub struct IoPort { + port: u16, + value_marker: PhantomData, + access_marker: PhantomData, } -impl IoPort { +impl IoPort { /// 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 IoPort { - /// Get the address of this I/O port. - pub fn addr(&self) -> u16 { - self.addr - } -} - -impl IoPort { - /// Reads from the port. +impl IoPort { + #[inline] pub fn read(&self) -> T { - unsafe { (*self.port.lock()).read() } + unsafe { PortRead::read_from_port(self.port) } } } -impl IoPort { - /// Writes to the port. - pub fn write(&self, val: T) { - unsafe { - self.port.lock().write(val); - } +impl IoPort { + #[inline] + pub fn write(&self, value: T) { + unsafe { PortWrite::write_to_port(self.port, value) } } } diff --git a/src/framework/jinux-frame/src/device/mod.rs b/src/framework/jinux-frame/src/device/mod.rs index dc1ccce4..289c5761 100644 --- a/src/framework/jinux-frame/src/device/mod.rs +++ b/src/framework/jinux-frame/src/device/mod.rs @@ -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(); diff --git a/src/framework/jinux-frame/src/device/pci.rs b/src/framework/jinux-frame/src/device/pci.rs index 8bd646be..ae854598 100644 --- a/src/framework/jinux-frame/src/device/pci.rs +++ b/src/framework/jinux-frame/src/device/pci.rs @@ -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 = unsafe { IoPort::new(0x0CF8) }; -pub static PCI_DATA_PORT: IoPort = unsafe { IoPort::new(0x0CFC) }; +pub static PCI_ADDRESS_PORT: IoPort = unsafe { IoPort::new(0x0CF8) }; +pub static PCI_DATA_PORT: IoPort = unsafe { IoPort::new(0x0CFC) }; diff --git a/src/framework/jinux-frame/src/device/serial.rs b/src/framework/jinux-frame/src/device/serial.rs index 544b4f96..d2012ccc 100644 --- a/src/framework/jinux-frame/src/device/serial.rs +++ b/src/framework/jinux-frame/src/device/serial.rs @@ -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> = Mutex::new(Port::new(SERIAL_DATA_PORT)); -static SERIAL_INT_EN: Mutex> = - Mutex::new(PortWriteOnly::new(SERIAL_DATA_PORT + 1)); -static SERIAL_FIFO_CTRL: Mutex> = - Mutex::new(PortWriteOnly::new(SERIAL_DATA_PORT + 2)); -static SERIAL_LINE_CTRL: Mutex> = - Mutex::new(PortWriteOnly::new(SERIAL_DATA_PORT + 3)); -static SERIAL_MODEM_CTRL: Mutex> = - Mutex::new(PortWriteOnly::new(SERIAL_DATA_PORT + 4)); -static SERIAL_LINE_STS: Mutex> = Mutex::new(Port::new(SERIAL_DATA_PORT + 5)); +static SERIAL_DATA: IoPort = unsafe { IoPort::new(SERIAL_DATA_PORT) }; +static SERIAL_INT_EN: IoPort = unsafe { IoPort::new(SERIAL_DATA_PORT + 1) }; +static SERIAL_FIFO_CTRL: IoPort = unsafe { IoPort::new(SERIAL_DATA_PORT + 2) }; +static SERIAL_LINE_CTRL: IoPort = unsafe { IoPort::new(SERIAL_DATA_PORT + 3) }; +static SERIAL_MODEM_CTRL: IoPort = + unsafe { IoPort::new(SERIAL_DATA_PORT + 4) }; +static SERIAL_LINE_STS: IoPort = unsafe { IoPort::new(SERIAL_DATA_PORT + 5) }; static CONSOLE_IRQ_CALLBACK: Once> = Once::new(); static SERIAL_INPUT_CALLBACKS: Mutex>> = @@ -34,30 +32,23 @@ static SERIAL_INPUT_CALLBACKS: Mutex /// 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 { if line_sts().contains(LineSts::INPUT_FULL) { - unsafe { Some(SERIAL_DATA.lock().read()) } + Some(SERIAL_DATA.read()) } else { None } diff --git a/src/framework/jinux-frame/src/driver/pic.rs b/src/framework/jinux-frame/src/driver/pic.rs index 813d3bbc..cda3ebfd 100644 --- a/src/framework/jinux-frame/src/driver/pic.rs +++ b/src/framework/jinux-frame/src/driver/pic.rs @@ -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> = Mutex::new(PortWriteOnly::new(0x20)); -static MASTER_DATA: Mutex> = Mutex::new(PortWriteOnly::new(0x21)); -static SLAVE_CMD: Mutex> = Mutex::new(PortWriteOnly::new(0xA0)); -static SLAVE_DATA: Mutex> = Mutex::new(PortWriteOnly::new(0xA1)); +static MASTER_CMD: IoPort = unsafe { IoPort::new(0x20) }; +static MASTER_DATA: IoPort = unsafe { IoPort::new(0x21) }; +static SLAVE_CMD: IoPort = unsafe { IoPort::new(0xA0) }; +static SLAVE_DATA: IoPort = 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); } diff --git a/src/framework/jinux-frame/src/driver/rtc.rs b/src/framework/jinux-frame/src/driver/rtc.rs index fd41f00e..f591d02d 100644 --- a/src/framework/jinux-frame/src/driver/rtc.rs +++ b/src/framework/jinux-frame/src/driver/rtc.rs @@ -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> = Mutex::new(PortWriteOnly::new(0x70)); -static CMOS_DATA: Mutex> = Mutex::new(PortReadOnly::new(0x71)); +static CMOS_ADDRESS: IoPort = unsafe { IoPort::new(0x70) }; +static CMOS_DATA: IoPort = unsafe { IoPort::new(0x71) }; pub(crate) static CENTURY_REGISTER: AtomicU8 = AtomicU8::new(0); -lazy_static! { +lazy_static::lazy_static! { static ref READ_TIME: Mutex