mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-24 18:03:25 +00:00
Refactor console
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
0a17d90532
commit
eeac55e2e5
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -629,6 +629,7 @@ dependencies = [
|
|||||||
"acpi",
|
"acpi",
|
||||||
"align_ext",
|
"align_ext",
|
||||||
"aml",
|
"aml",
|
||||||
|
"bit_field",
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
"bitvec",
|
"bitvec",
|
||||||
"buddy_system_allocator",
|
"buddy_system_allocator",
|
||||||
|
@ -21,6 +21,7 @@ inherit-methods-macro = { git = "https://github.com/jinzhao-dev/inherit-methods-
|
|||||||
tdx-guest = { path = "../libs/tdx-guest", optional = true }
|
tdx-guest = { path = "../libs/tdx-guest", optional = true }
|
||||||
bitvec = { version = "1.0", default-features = false, features = ["alloc"] }
|
bitvec = { version = "1.0", default-features = false, features = ["alloc"] }
|
||||||
static_assertions = "1.1.0"
|
static_assertions = "1.1.0"
|
||||||
|
bit_field = "0.10.1"
|
||||||
|
|
||||||
[target.x86_64-custom.dependencies]
|
[target.x86_64-custom.dependencies]
|
||||||
x86_64 = "0.14.2"
|
x86_64 = "0.14.2"
|
||||||
|
112
framework/jinux-frame/src/arch/x86/console.rs
Normal file
112
framework/jinux-frame/src/arch/x86/console.rs
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
use core::fmt::Write;
|
||||||
|
|
||||||
|
use crate::sync::SpinLock;
|
||||||
|
use crate::trap::IrqLine;
|
||||||
|
use alloc::fmt;
|
||||||
|
use alloc::{sync::Arc, vec::Vec};
|
||||||
|
use log::debug;
|
||||||
|
use spin::Once;
|
||||||
|
use trapframe::TrapFrame;
|
||||||
|
|
||||||
|
use super::device::serial::SerialPort;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn print(args: fmt::Arguments) {
|
||||||
|
Stdout.write_fmt(args).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type InputCallback = dyn Fn(u8) + Send + Sync + 'static;
|
||||||
|
|
||||||
|
pub fn register_console_input_callback(f: &'static InputCallback) {
|
||||||
|
SERIAL_INPUT_CALLBACKS.lock_irq_disabled().push(Arc::new(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Stdout;
|
||||||
|
|
||||||
|
impl Write for Stdout {
|
||||||
|
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||||
|
for &c in s.as_bytes() {
|
||||||
|
send(c);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bitflags::bitflags! {
|
||||||
|
struct LineSts: u8 {
|
||||||
|
const INPUT_FULL = 1;
|
||||||
|
const OUTPUT_EMPTY = 1 << 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static CONSOLE_COM1_PORT: SerialPort = unsafe { SerialPort::new(0x3F8) };
|
||||||
|
|
||||||
|
static CONSOLE_IRQ_CALLBACK: Once<SpinLock<IrqLine>> = Once::new();
|
||||||
|
static SERIAL_INPUT_CALLBACKS: SpinLock<Vec<Arc<InputCallback>>> = SpinLock::new(Vec::new());
|
||||||
|
|
||||||
|
/// Initializes the serial port.
|
||||||
|
pub(crate) fn init() {
|
||||||
|
CONSOLE_COM1_PORT.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn callback_init() {
|
||||||
|
let mut irq = crate::arch::x86::kernel::pic::allocate_irq(4).unwrap();
|
||||||
|
irq.on_active(handle_serial_input);
|
||||||
|
CONSOLE_IRQ_CALLBACK.call_once(|| SpinLock::new(irq));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn register_console_callback<F>(callback: F)
|
||||||
|
where
|
||||||
|
F: Fn(&TrapFrame) + Sync + Send + 'static,
|
||||||
|
{
|
||||||
|
CONSOLE_IRQ_CALLBACK
|
||||||
|
.get()
|
||||||
|
.unwrap()
|
||||||
|
.lock_irq_disabled()
|
||||||
|
.on_active(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_serial_input(trap_frame: &TrapFrame) {
|
||||||
|
// debug!("keyboard interrupt was met");
|
||||||
|
let lock = if let Some(lock) = SERIAL_INPUT_CALLBACKS.try_lock() {
|
||||||
|
lock
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let received_char = receive_char().unwrap();
|
||||||
|
debug!("receive char = {:?}", received_char);
|
||||||
|
for callback in lock.iter() {
|
||||||
|
callback(received_char);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn line_sts() -> LineSts {
|
||||||
|
LineSts::from_bits_truncate(CONSOLE_COM1_PORT.line_status.read())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sends a byte on the serial port.
|
||||||
|
pub fn send(data: u8) {
|
||||||
|
match data {
|
||||||
|
8 | 0x7F => {
|
||||||
|
while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
|
||||||
|
CONSOLE_COM1_PORT.data.write(8);
|
||||||
|
while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
|
||||||
|
CONSOLE_COM1_PORT.data.write(b' ');
|
||||||
|
while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
|
||||||
|
CONSOLE_COM1_PORT.data.write(8);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
|
||||||
|
CONSOLE_COM1_PORT.data.write(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Receives a byte on the serial port. non-blocking
|
||||||
|
pub fn receive_char() -> Option<u8> {
|
||||||
|
if line_sts().contains(LineSts::INPUT_FULL) {
|
||||||
|
Some(CONSOLE_COM1_PORT.data.read())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
@ -1,118 +1,63 @@
|
|||||||
//! A port-mapped UART. Copied from uart_16550.
|
//! A port-mapped UART. Copied from uart_16550.
|
||||||
|
|
||||||
use crate::arch::x86::device::io_port::{IoPort, ReadWriteAccess, WriteOnlyAccess};
|
use crate::arch::x86::device::io_port::{IoPort, ReadWriteAccess, WriteOnlyAccess};
|
||||||
use crate::sync::SpinLock;
|
|
||||||
use crate::trap::IrqLine;
|
|
||||||
use alloc::{sync::Arc, vec::Vec};
|
|
||||||
use log::debug;
|
|
||||||
use spin::Once;
|
|
||||||
use trapframe::TrapFrame;
|
|
||||||
|
|
||||||
bitflags::bitflags! {
|
/// A serial port.
|
||||||
struct LineSts: u8 {
|
///
|
||||||
const INPUT_FULL = 1;
|
/// Serial ports are a legacy communications port common on IBM-PC compatible computers.
|
||||||
const OUTPUT_EMPTY = 1 << 5;
|
/// Ref: https://wiki.osdev.org/Serial_Ports
|
||||||
}
|
pub struct SerialPort {
|
||||||
|
pub data: IoPort<u8, ReadWriteAccess>,
|
||||||
|
pub int_en: IoPort<u8, WriteOnlyAccess>,
|
||||||
|
pub fifo_ctrl: IoPort<u8, WriteOnlyAccess>,
|
||||||
|
pub line_ctrl: IoPort<u8, WriteOnlyAccess>,
|
||||||
|
pub modem_ctrl: IoPort<u8, WriteOnlyAccess>,
|
||||||
|
pub line_status: IoPort<u8, ReadWriteAccess>,
|
||||||
|
pub modem_status: IoPort<u8, ReadWriteAccess>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const SERIAL_DATA_PORT: u16 = 0x3F8;
|
impl SerialPort {
|
||||||
|
/// Create a serial port.
|
||||||
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) };
|
/// # Safety
|
||||||
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) };
|
/// User must ensure the `port` is valid serial port.
|
||||||
static SERIAL_MODEM_CTRL: IoPort<u8, WriteOnlyAccess> =
|
pub const unsafe fn new(port: u16) -> Self {
|
||||||
unsafe { IoPort::new(SERIAL_DATA_PORT + 4) };
|
let data = IoPort::new(port);
|
||||||
static SERIAL_LINE_STS: IoPort<u8, ReadWriteAccess> = unsafe { IoPort::new(SERIAL_DATA_PORT + 5) };
|
let int_en = IoPort::new(port + 1);
|
||||||
|
let fifo_ctrl = IoPort::new(port + 2);
|
||||||
static CONSOLE_IRQ_CALLBACK: Once<SpinLock<IrqLine>> = Once::new();
|
let line_ctrl = IoPort::new(port + 3);
|
||||||
#[allow(clippy::type_complexity)]
|
let modem_ctrl = IoPort::new(port + 4);
|
||||||
static SERIAL_INPUT_CALLBACKS: SpinLock<Vec<Arc<dyn Fn(u8) + Send + Sync + 'static>>> =
|
let line_status = IoPort::new(port + 5);
|
||||||
SpinLock::new(Vec::new());
|
let modem_status = IoPort::new(port + 6);
|
||||||
|
Self {
|
||||||
/// Initializes the serial port.
|
data,
|
||||||
pub(crate) fn init() {
|
int_en,
|
||||||
// Disable interrupts
|
fifo_ctrl,
|
||||||
SERIAL_INT_EN.write(0x00);
|
line_ctrl,
|
||||||
// Enable DLAB
|
modem_ctrl,
|
||||||
SERIAL_LINE_CTRL.write(0x80);
|
line_status,
|
||||||
// Set maximum speed to 38400 bps by configuring DLL and DLM
|
modem_status,
|
||||||
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) {
|
|
||||||
SERIAL_INPUT_CALLBACKS.lock_irq_disabled().push(Arc::new(f));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn callback_init() {
|
|
||||||
let mut irq = crate::arch::x86::kernel::pic::allocate_irq(4).unwrap();
|
|
||||||
irq.on_active(handle_serial_input);
|
|
||||||
CONSOLE_IRQ_CALLBACK.call_once(|| SpinLock::new(irq));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn register_serial_input_irq_handler<F>(callback: F)
|
|
||||||
where
|
|
||||||
F: Fn(&TrapFrame) + Sync + Send + 'static,
|
|
||||||
{
|
|
||||||
CONSOLE_IRQ_CALLBACK
|
|
||||||
.get()
|
|
||||||
.unwrap()
|
|
||||||
.lock_irq_disabled()
|
|
||||||
.on_active(callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_serial_input(trap_frame: &TrapFrame) {
|
|
||||||
// debug!("keyboard interrupt was met");
|
|
||||||
let lock = if let Some(lock) = SERIAL_INPUT_CALLBACKS.try_lock() {
|
|
||||||
lock
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
let received_char = receive_char().unwrap();
|
|
||||||
debug!("receive char = {:?}", received_char);
|
|
||||||
for callback in lock.iter() {
|
|
||||||
callback(received_char);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn line_sts() -> LineSts {
|
|
||||||
LineSts::from_bits_truncate(SERIAL_LINE_STS.read())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sends a byte on the serial port.
|
|
||||||
pub fn send(data: u8) {
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Receives a byte on the serial port. non-blocking
|
pub fn init(&self) {
|
||||||
pub fn receive_char() -> Option<u8> {
|
// Disable interrupts
|
||||||
if line_sts().contains(LineSts::INPUT_FULL) {
|
self.int_en.write(0x00);
|
||||||
Some(SERIAL_DATA.read())
|
// Enable DLAB
|
||||||
} else {
|
self.line_ctrl.write(0x80);
|
||||||
None
|
// Set maximum speed to 38400 bps by configuring DLL and DLM
|
||||||
|
self.data.write(0x03);
|
||||||
|
self.int_en.write(0x00);
|
||||||
|
// Disable DLAB and set data word length to 8 bits
|
||||||
|
self.line_ctrl.write(0x03);
|
||||||
|
// Enable FIFO, clear TX/RX queues and
|
||||||
|
// set interrupt watermark at 14 bytes
|
||||||
|
self.fifo_ctrl.write(0xC7);
|
||||||
|
// Mark data terminal ready, signal request to send
|
||||||
|
// and enable auxilliary output #2 (used as interrupt line for CPU)
|
||||||
|
self.modem_ctrl.write(0x0B);
|
||||||
|
// Enable interrupts
|
||||||
|
self.int_en.write(0x01);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
pub mod boot;
|
pub mod boot;
|
||||||
|
pub mod console;
|
||||||
pub(crate) mod cpu;
|
pub(crate) mod cpu;
|
||||||
pub mod device;
|
pub mod device;
|
||||||
pub mod iommu;
|
pub mod iommu;
|
||||||
@ -10,20 +11,17 @@ pub(crate) mod pci;
|
|||||||
pub(crate) mod tdx_guest;
|
pub(crate) mod tdx_guest;
|
||||||
pub(crate) mod timer;
|
pub(crate) mod timer;
|
||||||
|
|
||||||
use alloc::fmt;
|
|
||||||
use core::fmt::Write;
|
|
||||||
use kernel::apic::ioapic;
|
use kernel::apic::ioapic;
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
|
|
||||||
pub(crate) fn before_all_init() {
|
pub(crate) fn before_all_init() {
|
||||||
enable_common_cpu_features();
|
enable_common_cpu_features();
|
||||||
device::serial::init();
|
console::init();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn after_all_init() {
|
pub(crate) fn after_all_init() {
|
||||||
irq::init();
|
irq::init();
|
||||||
mm::init();
|
mm::init();
|
||||||
device::serial::callback_init();
|
|
||||||
kernel::acpi::init();
|
kernel::acpi::init();
|
||||||
match kernel::apic::init() {
|
match kernel::apic::init() {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
@ -34,6 +32,7 @@ pub(crate) fn after_all_init() {
|
|||||||
kernel::pic::enable();
|
kernel::pic::enable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
console::callback_init();
|
||||||
timer::init();
|
timer::init();
|
||||||
match iommu::init() {
|
match iommu::init() {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
@ -50,35 +49,6 @@ pub(crate) fn interrupts_ack() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Stdout;
|
|
||||||
|
|
||||||
impl Write for Stdout {
|
|
||||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
|
||||||
for &c in s.as_bytes() {
|
|
||||||
device::serial::send(c);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn print(args: fmt::Arguments) {
|
|
||||||
Stdout.write_fmt(args).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! print {
|
|
||||||
($fmt: literal $(, $($arg: tt)+)?) => {
|
|
||||||
$crate::arch::x86::print(format_args!($fmt $(, $($arg)+)?))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! println {
|
|
||||||
($fmt: literal $(, $($arg: tt)+)?) => {
|
|
||||||
$crate::arch::x86::print(format_args!(concat!($fmt, "\n") $(, $($arg)+)?))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn enable_common_cpu_features() {
|
fn enable_common_cpu_features() {
|
||||||
use x86_64::registers::{control::Cr4Flags, model_specific::EferFlags, xcontrol::XCr0Flags};
|
use x86_64::registers::{control::Cr4Flags, model_specific::EferFlags, xcontrol::XCr0Flags};
|
||||||
let mut cr4 = x86_64::registers::control::Cr4::read();
|
let mut cr4 = x86_64::registers::control::Cr4::read();
|
||||||
|
19
framework/jinux-frame/src/console.rs
Normal file
19
framework/jinux-frame/src/console.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
use core::fmt::Arguments;
|
||||||
|
|
||||||
|
pub fn print(args: Arguments) {
|
||||||
|
crate::arch::console::print(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! print {
|
||||||
|
($fmt: literal $(, $($arg: tt)+)?) => {
|
||||||
|
$crate::console::print(format_args!($fmt $(, $($arg)+)?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! println {
|
||||||
|
($fmt: literal $(, $($arg: tt)+)?) => {
|
||||||
|
$crate::console::print(format_args!(concat!($fmt, "\n") $(, $($arg)+)?))
|
||||||
|
}
|
||||||
|
}
|
@ -23,6 +23,7 @@ pub mod arch;
|
|||||||
pub mod boot;
|
pub mod boot;
|
||||||
pub mod bus;
|
pub mod bus;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
|
pub mod console;
|
||||||
pub mod cpu;
|
pub mod cpu;
|
||||||
mod error;
|
mod error;
|
||||||
pub mod io_mem;
|
pub mod io_mem;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
pub use jinux_frame::arch::x86::device::serial::register_serial_input_callback;
|
pub use jinux_frame::arch::console::register_console_input_callback;
|
||||||
use spin::Once;
|
use spin::Once;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -9,7 +9,7 @@ use crate::{
|
|||||||
pub static TTY_DRIVER: Once<Arc<TtyDriver>> = Once::new();
|
pub static TTY_DRIVER: Once<Arc<TtyDriver>> = Once::new();
|
||||||
|
|
||||||
pub(super) fn init() {
|
pub(super) fn init() {
|
||||||
register_serial_input_callback(serial_input_callback);
|
register_console_input_callback(&serial_input_callback);
|
||||||
let tty_driver = Arc::new(TtyDriver::new());
|
let tty_driver = Arc::new(TtyDriver::new());
|
||||||
// FIXME: install n_tty into tty_driver?
|
// FIXME: install n_tty into tty_driver?
|
||||||
let n_tty = get_n_tty();
|
let n_tty = get_n_tty();
|
||||||
|
Reference in New Issue
Block a user