From 4820b2dd73543a6fbd5db547d009529d0fe11ccd Mon Sep 17 00:00:00 2001 From: littleblack111 Date: Sun, 6 Sep 2026 18:07:30 +0800 Subject: new: earlyprintk --- kernel/src/init.rs | 2 + kernel/src/init/acpi.rs | 0 kernel/src/init/earlyprintk.rs | 24 +++++++++ kernel/src/io/output/serial/uart_16550.rs | 82 +++++++++++++++++++++++++++++-- kernel/src/main.rs | 14 +++++- 5 files changed, 116 insertions(+), 6 deletions(-) create mode 100644 kernel/src/init.rs create mode 100644 kernel/src/init/acpi.rs create mode 100644 kernel/src/init/earlyprintk.rs diff --git a/kernel/src/init.rs b/kernel/src/init.rs new file mode 100644 index 0000000..ef51b1f --- /dev/null +++ b/kernel/src/init.rs @@ -0,0 +1,2 @@ +pub mod acpi; +pub mod earlyprintk; diff --git a/kernel/src/init/acpi.rs b/kernel/src/init/acpi.rs new file mode 100644 index 0000000..e69de29 diff --git a/kernel/src/init/earlyprintk.rs b/kernel/src/init/earlyprintk.rs new file mode 100644 index 0000000..01c50fa --- /dev/null +++ b/kernel/src/init/earlyprintk.rs @@ -0,0 +1,24 @@ +use spin::{lazylock::LazyLock, mutex::Mutex}; + +use crate::io::output::serial::uart_16550::{SerialPortBitMask, Uart16550}; + +// TODO: use linkme instead +pub static EARLY_PRINTK_SERIAL: LazyLock> = LazyLock::new(|| { + Mutex::new(unsafe { Uart16550::init(SerialPortBitMask::COM1, [const { None }; 4]).unwrap() }) +}); + +#[macro_export] +macro_rules! printk { + ($($arg:tt)*) => ({ + use ::core::fmt::Write; + write!($crate::init::earlyprintk::EARLY_PRINTK_SERIAL.lock().coms[0].as_mut().unwrap(), $($arg)*) + }); +} + +#[macro_export] +macro_rules! printkln { + ($($arg:tt)*) => ({ + use ::core::fmt::Write; + writeln!($crate::init::earlyprintk::EARLY_PRINTK_SERIAL.lock().coms[0].as_mut().unwrap(), $($arg)*) + }); +} diff --git a/kernel/src/io/output/serial/uart_16550.rs b/kernel/src/io/output/serial/uart_16550.rs index 984854a..65ba4e9 100644 --- a/kernel/src/io/output/serial/uart_16550.rs +++ b/kernel/src/io/output/serial/uart_16550.rs @@ -1,15 +1,87 @@ +use bitflags::bitflags; +use uart_16550::{ + Config, Uart16550Tty, Uart16550TtyError, + backend::{PioBackend, PortIoAddress}, +}; + +#[repr(u16)] +// TODO: parse & validate via acpi alors scratch pub enum SerialPortAddress { - Com1 = 0x3F8, + COM1 = 0x3F8, Com2 = 0x2F8, Com3 = 0x3E8, Com4 = 0x2E8, } -#[derive(Default)] -pub struct Uart16550 {} +bitflags! { + pub struct SerialPortBitMask: u8 { + const COM1 = 1 << 0; + const COM2 = 1 << 1; + const COM3 = 1 << 2; + const COM4 = 1 << 3; + } +} + +impl From for u16 { + fn from(value: SerialPortAddress) -> Self { + value as u16 + } +} + +pub struct Uart16550 { + pub coms: [Option>; 4], +} impl Uart16550 { - pub fn new() -> Self { - Self {} + /// # Safety + /// + /// Callers must ensure that the base port is valid and safe to use + /// for the **whole lifetime** of the device(exclusively). Further, all + /// [`NUM_REGISTERS`] registers must be safely reachable from the base + /// address. + /// + /// [`NUM_REGISTERS`]: crate::spec::NUM_REGISTERS + pub unsafe fn init( + coms_enabled: SerialPortBitMask, + mut config: [Option; 4], + ) -> Result> { + unsafe { + Ok(Self { + coms: [ + if coms_enabled.contains(SerialPortBitMask::COM1) { + Some(Uart16550Tty::new_port( + SerialPortAddress::COM1.into(), + config[0].take().unwrap_or_default(), + )?) + } else { + None + }, + if coms_enabled.contains(SerialPortBitMask::COM2) { + Some(Uart16550Tty::new_port( + SerialPortAddress::Com2.into(), + config[1].take().unwrap_or_default(), + )?) + } else { + None + }, + if coms_enabled.contains(SerialPortBitMask::COM3) { + Some(Uart16550Tty::new_port( + SerialPortAddress::Com3.into(), + config[2].take().unwrap_or_default(), + )?) + } else { + None + }, + if coms_enabled.contains(SerialPortBitMask::COM4) { + Some(Uart16550Tty::new_port( + SerialPortAddress::Com4.into(), + config[3].take().unwrap_or_default(), + )?) + } else { + None + }, + ], + }) + } } } diff --git a/kernel/src/main.rs b/kernel/src/main.rs index bfa20e6..87f590d 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -5,11 +5,23 @@ // extern crate alloc; use bootloader_api::{BootInfo, BootloaderConfig, entry_point}; -use kernel::pm::hcf; +use core::fmt::Write; +use kernel::{io::output::serial::uart_16550::Uart16550, pm::hcf, printk}; const CONFIG: BootloaderConfig = BootloaderConfig::new_default(); fn kmain(boot_info: &'static mut BootInfo) -> ! { + // let mut a = unsafe { Uart16550::init(Default::default()) }.unwrap().com1; + // write!(a, "test").unwrap(); + printk!("test").unwrap(); + printk!("test").unwrap(); + printk!("test").unwrap(); + printk!("test").unwrap(); + printk!("test").unwrap(); + printk!("test").unwrap(); + printk!("test").unwrap(); + printk!("test").unwrap(); + printk!("test").unwrap(); hcf() } -- cgit v1.2.3