This commit is contained in:
janis 2026-07-17 17:36:54 +02:00
parent 96c2ea2298
commit 932d98af20
Signed by: janis
SSH key fingerprint: SHA256:bB1qbbqmDXZNT0KKD5c2Dfjg53JGhj7B3CFcLIzSqq8
5 changed files with 821 additions and 0 deletions

9
kernel/Cargo.lock generated
View file

@ -2,6 +2,15 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 4 version = 4
[[package]]
name = "bitflags"
version = "2.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da"
[[package]] [[package]]
name = "kernel" name = "kernel"
version = "0.1.0" version = "0.1.0"
dependencies = [
"bitflags",
]

View file

@ -14,3 +14,4 @@ test = false
bench = false bench = false
[dependencies] [dependencies]
bitflags = "2.13.1"

View file

@ -2,6 +2,7 @@
#![feature(const_trait_impl, const_default)] #![feature(const_trait_impl, const_default)]
pub mod limine; pub mod limine;
pub mod serial;
pub mod sync; pub mod sync;
pub mod x86_64; pub mod x86_64;

View file

@ -3,11 +3,13 @@
#[panic_handler] #[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! { fn panic(_info: &core::panic::PanicInfo) -> ! {
kernel::serial_println!("[PANIC] {}", _info);
kernel::x86_64::halt_loop() kernel::x86_64::halt_loop()
} }
#[unsafe(no_mangle)] #[unsafe(no_mangle)]
fn _start() -> ! { fn _start() -> ! {
kernel::serial_println!("Hello, world!");
assert!(limine_requests::LIMINE_BASE_REVISION.is_supported()); assert!(limine_requests::LIMINE_BASE_REVISION.is_supported());
let fb = limine_requests::FRAMEBUFFER_REQUEST let fb = limine_requests::FRAMEBUFFER_REQUEST

808
kernel/src/serial.rs Normal file
View file

@ -0,0 +1,808 @@
pub mod uart_16550 {
#![cfg(target_arch = "x86_64")]
use crate::x86_64::PortU16;
use core::mem::MaybeUninit;
pub struct Uart16550 {
pub base_port: PortU16,
pub baud_rate: BaudRate,
pub parity: Parity,
pub stop_bits: StopBits,
pub data_bits: DataBits,
pub fifo_trigger_level: Option<FifoTriggerLevel>,
pub interrupt_enable: InterruptEnable,
}
impl Uart16550 {
/// Transmitter/Receiver Holding Register offset
pub const DATA: u16 = 0x0;
/// Interrupt Enable Register offset
pub const IER: u16 = 0x1;
/// Interrupt Status Register offset
pub const ISR: u16 = 0x2;
/// FIFO Control Register offset
pub const FCR: u16 = 0x2;
/// Line Control Register offset
pub const LCR: u16 = 0x3;
/// Modem Control Register offset
pub const MCR: u16 = 0x4;
/// Line Status Register offset
pub const LSR: u16 = 0x5;
/// Modem Status Register offset
pub const MSR: u16 = 0x6;
/// Scratch Pad Register offset
pub const SPR: u16 = 0x7;
/// Divisor Latch Low offset
pub const DLL: u16 = 0x0;
/// Divisor Latch High offset
pub const DLM: u16 = 0x1;
/// # Safety
/// This function creates a new instance of Uart16550 with the given base port.
pub unsafe fn with_port(base_port: u16) -> Self {
Self {
base_port: PortU16(base_port),
baud_rate: BaudRate::default(),
parity: Parity::default(),
stop_bits: StopBits::default(),
data_bits: DataBits::default(),
fifo_trigger_level: Some(FifoTriggerLevel::default()),
interrupt_enable: InterruptEnable::default(),
}
}
pub fn init(&mut self) {
unsafe {
self.base_port.offset(Self::IER).write(0);
self.base_port.offset(Self::LCR).write(0);
}
self.set_baud_rate(self.baud_rate);
let lcr = LineControl::new(false, false, self.parity, self.stop_bits, self.data_bits);
unsafe {
self.write_lcr(lcr);
let mut fcr = FifoControl::empty();
if let Some(level) = self.fifo_trigger_level {
fcr.set_fifo_enable(true);
fcr.set_fifo_trigger_level(level);
}
fcr.set_clear_receive_fifo();
fcr.set_clear_transmit_fifo();
self.write_fcr(fcr);
let mut mcr = ModemControl::empty();
mcr.set_data_terminal_ready(true);
mcr.set_request_to_send(true);
mcr.set_auxiliary_output_2(true);
self.write_mcr(mcr);
self.write_ier(self.interrupt_enable);
loop {
let lsr = self.read_lsr();
if lsr.transmitter_holding_register_empty() {
break;
}
core::hint::spin_loop();
}
}
}
pub fn ready_to_receive(&self) -> bool {
let lsr = self.read_lsr();
lsr.data_ready()
}
pub fn ready_to_send(&self) -> bool {
let lsr = self.read_lsr();
let msr = self.read_msr();
let mcr = self.read_mcr();
if !lsr.transmitter_holding_register_empty() {
return false;
}
if !mcr.loopback_mode() && !msr.clear_to_send() {
return false;
}
true
}
pub fn try_receive_byte(&self) -> Option<u8> {
if self.ready_to_receive() {
let data_port = self.base_port.offset(Self::DATA);
let value = unsafe { data_port.read() } as u8;
Some(value)
} else {
None
}
}
pub fn try_send_bytes(&self, bytes: &[u8]) -> Option<usize> {
if bytes.is_empty() {
return Some(0);
}
if !self.ready_to_send() {
return None;
}
let bytes = match self.fifo_trigger_level {
None => &bytes[..1],
Some(level) => {
let end = core::cmp::min(bytes.len(), level.count());
&bytes[..end]
}
};
for &b in bytes {
unsafe {
self.base_port.offset(Self::DATA).write(b as u16);
}
}
Some(bytes.len())
}
pub fn try_send_byte(&self, byte: u8) -> Option<()> {
if self.ready_to_send() {
let data_port = self.base_port.offset(Self::DATA);
unsafe { data_port.write(byte as u16) };
Some(())
} else {
None
}
}
pub fn try_receive_bytes<'a>(
&self,
buffer: &'a mut [MaybeUninit<u8>],
) -> (&'a mut [u8], &'a mut [MaybeUninit<u8>]) {
let len = buffer
.iter_mut()
.map_while(|b: &mut MaybeUninit<u8>| {
self.try_receive_byte().map(|val| b.write(val))
})
.count();
// SAFETY: We have just initialized the first `len` elements of the
// buffer, so it is safe to transmute them to `&mut [u8]`.
unsafe {
let (init, uninit) = buffer.split_at_mut(len);
let init = core::mem::transmute::<&mut [MaybeUninit<u8>], &mut [u8]>(init);
(init, uninit)
}
}
pub fn receive_bytes_exact<'a>(&self, buffer: &'a mut [MaybeUninit<u8>]) -> &'a mut [u8] {
let (ptr, len) = (buffer.as_mut_ptr(), buffer.len());
let mut rest = buffer;
loop {
rest = self.try_receive_bytes(rest).1;
if rest.is_empty() {
break;
}
}
unsafe {
// SAFETY: We have just initialized the entire buffer, so it is safe to transmute it to `&mut [u8]`.
core::slice::from_raw_parts_mut(ptr as *mut u8, len)
}
}
pub fn send_bytes_exact(&self, bytes: &[u8]) {
let mut rest = bytes;
loop {
let sent = self.try_send_bytes(rest).unwrap_or(0);
rest = &rest[sent..];
if rest.is_empty() {
break;
}
}
}
pub fn read_lcr(&self) -> LineControl {
let lcr_port = self.base_port.offset(3);
let value = unsafe { lcr_port.read() } as u8;
LineControl(value)
}
/// # Safety
/// This function writes to the Line Control Register (LCR) of the UART.
pub unsafe fn write_lcr(&self, lcr: LineControl) {
let lcr_port = self.base_port.offset(Self::LCR);
unsafe { lcr_port.write(lcr.0 as u16) };
}
pub fn read_msr(&self) -> ModemStatus {
let msr_port = self.base_port.offset(Self::MSR);
let value = unsafe { msr_port.read() } as u8;
ModemStatus(value)
}
pub fn read_lsr(&self) -> LineStatus {
let lsr_port = self.base_port.offset(Self::LSR);
let value = unsafe { lsr_port.read() } as u8;
LineStatus(value)
}
pub fn read_ier(&self) -> InterruptEnable {
let ier_port = self.base_port.offset(Self::IER);
let value = unsafe { ier_port.read() } as u8;
InterruptEnable(value)
}
/// # Safety
/// This function writes to the Interrupt Enable Register (IER) of the UART.
pub unsafe fn write_ier(&self, ier: InterruptEnable) {
let ier_port = self.base_port.offset(Self::IER);
unsafe { ier_port.write(ier.0 as u16) };
}
pub fn read_isr(&self) -> InterruptStatus {
let isr_port = self.base_port.offset(Self::ISR);
let value = unsafe { isr_port.read() } as u8;
InterruptStatus(value)
}
pub fn read_fcr(&self) -> FifoControl {
let fcr_port = self.base_port.offset(Self::FCR);
let value = unsafe { fcr_port.read() } as u8;
FifoControl(value)
}
pub fn read_mcr(&self) -> ModemControl {
let mcr_port = self.base_port.offset(Self::MCR);
let value = unsafe { mcr_port.read() } as u8;
ModemControl(value)
}
/// # Safety
/// This function writes to the Modem Control Register (MCR) of the UART.
pub unsafe fn write_mcr(&self, mcr: ModemControl) {
let mcr_port = self.base_port.offset(Self::MCR);
unsafe { mcr_port.write(mcr.0 as u16) };
}
/// # Safety
/// This function writes to the FIFO Control Register (FCR) of the UART.
pub unsafe fn write_fcr(&self, fcr: FifoControl) {
let fcr_port = self.base_port.offset(Self::FCR);
unsafe { fcr_port.write(fcr.0 as u16) };
}
pub fn set_baud_rate(&self, baud_rate: BaudRate) {
let divisor = baud_rate.divisor();
let mut lcr = self.read_lcr();
lcr.set_dlab(true);
let [low_byte, high_byte] = divisor.to_le_bytes();
unsafe {
self.write_lcr(lcr);
self.base_port.offset(Self::DLL).write(low_byte as u16);
self.base_port.offset(Self::DLM).write(high_byte as u16);
lcr.set_dlab(false);
self.write_lcr(lcr);
}
}
}
const BASE_RATE: u32 = 115200;
#[derive(Debug, Clone, Copy, Default)]
pub enum BaudRate {
Baud115200,
Baud57600,
Baud38400,
Baud19200,
#[default]
Baud9600,
}
impl BaudRate {
pub fn divisor(&self) -> u16 {
let rate = match self {
BaudRate::Baud115200 => 115200,
BaudRate::Baud57600 => 57600,
BaudRate::Baud38400 => 38400,
BaudRate::Baud19200 => 19200,
BaudRate::Baud9600 => 9600,
};
assert!(BASE_RATE.is_multiple_of(rate), "Invalid baud rate");
(BASE_RATE / rate) as u16
}
}
#[derive(Debug, Clone, Copy)]
#[repr(transparent)]
pub struct LineControl(pub u8);
#[derive(Debug, Clone, Copy, Default)]
#[repr(u8)]
pub enum DataBits {
Five = 0b00,
Six = 0b01,
Seven = 0b10,
#[default]
Eight = 0b11,
}
#[derive(Debug, Clone, Copy, Default)]
#[repr(u8)]
pub enum StopBits {
#[default]
One = 0b0,
Two = 0b1,
}
#[derive(Debug, Clone, Copy, Default)]
#[repr(u8)]
pub enum Parity {
#[default]
None = 0b00,
Odd = 0b01,
Even = 0b11,
Mark = 0b101,
Space = 0b111,
}
impl LineControl {
pub const fn empty() -> Self {
Self(0)
}
pub fn dlab(&self) -> bool {
(self.0 & (1 << 7)) != 0
}
pub fn set_dlab(&mut self, dlab: bool) {
if dlab {
self.0 |= 1 << 7;
} else {
self.0 &= !(1 << 7);
}
}
pub fn set_break_signal(&mut self, break_signal: bool) {
if break_signal {
self.0 |= 1 << 6;
} else {
self.0 &= !(1 << 6);
}
}
pub fn break_signal(&self) -> bool {
(self.0 & (1 << 6)) != 0
}
pub fn set_parity(&mut self, parity: Parity) {
self.0 &= !(0b111 << 3);
self.0 |= (parity as u8) << 3;
}
pub fn parity(&self) -> Parity {
match (self.0 >> 3) & 0b111 {
0b000 => Parity::None,
0b001 => Parity::Odd,
0b011 => Parity::Even,
0b101 => Parity::Mark,
0b111 => Parity::Space,
_ => unreachable!(),
}
}
pub fn set_stop_bits(&mut self, stop_bits: StopBits) {
self.0 &= !(1 << 2);
self.0 |= (stop_bits as u8) << 2;
}
pub fn stop_bits(&self) -> StopBits {
match (self.0 >> 2) & 0b1 {
0b0 => StopBits::One,
0b1 => StopBits::Two,
_ => unreachable!(),
}
}
pub fn set_data_bits(&mut self, data_bits: DataBits) {
self.0 &= !(0b11);
self.0 |= data_bits as u8;
}
pub fn data_bits(&self) -> DataBits {
match self.0 & 0b11 {
0b00 => DataBits::Five,
0b01 => DataBits::Six,
0b10 => DataBits::Seven,
0b11 => DataBits::Eight,
_ => unreachable!(),
}
}
pub const fn new(
dlab: bool,
break_signal: bool,
parity: Parity,
stop_bits: StopBits,
data_bits: DataBits,
) -> Self {
let mut value = 0u8;
if dlab {
value |= 1 << 7;
}
if break_signal {
value |= 1 << 6;
}
value |= (parity as u8) << 3;
value |= (stop_bits as u8) << 2;
value |= data_bits as u8;
Self(value)
}
}
#[derive(Debug, Clone, Copy)]
#[repr(transparent)]
pub struct InterruptEnable(pub u8);
impl Default for InterruptEnable {
fn default() -> Self {
let mut empty = Self(0);
empty.set_received_data_available(true);
empty
}
}
impl InterruptEnable {
pub const fn empty() -> Self {
Self(0)
}
pub fn set_received_data_available(&mut self, enable: bool) {
if enable {
self.0 |= 1 << 0;
} else {
self.0 &= !(1 << 0);
}
}
pub fn received_data_available(&self) -> bool {
(self.0 & (1 << 0)) != 0
}
pub fn set_transmitter_holding_register_empty(&mut self, enable: bool) {
if enable {
self.0 |= 1 << 1;
} else {
self.0 &= !(1 << 1);
}
}
pub fn transmitter_holding_register_empty(&self) -> bool {
(self.0 & (1 << 1)) != 0
}
pub fn set_receiver_line_status(&mut self, enable: bool) {
if enable {
self.0 |= 1 << 2;
} else {
self.0 &= !(1 << 2);
}
}
pub fn receiver_line_status(&self) -> bool {
(self.0 & (1 << 2)) != 0
}
pub fn set_modem_status(&mut self, enable: bool) {
if enable {
self.0 |= 1 << 3;
} else {
self.0 &= !(1 << 3);
}
}
pub fn modem_status(&self) -> bool {
(self.0 & (1 << 3)) != 0
}
}
pub struct FifoControl(pub u8);
impl FifoControl {
pub const fn empty() -> Self {
Self(0)
}
pub fn set_fifo_enable(&mut self, enable: bool) {
if enable {
self.0 |= 1 << 0;
} else {
self.0 &= !(1 << 0);
}
}
pub fn fifo_enable(&self) -> bool {
(self.0 & (1 << 0)) != 0
}
pub fn set_fifo_trigger_level(&mut self, level: FifoTriggerLevel) {
self.0 &= !(0b11 << 6);
self.0 |= (level as u8) << 6;
}
pub fn fifo_trigger_level(&self) -> FifoTriggerLevel {
match (self.0 >> 6) & 0b11 {
0b00 => FifoTriggerLevel::Level1Byte,
0b01 => FifoTriggerLevel::Level4Bytes,
0b10 => FifoTriggerLevel::Level8Bytes,
0b11 => FifoTriggerLevel::Level14Bytes,
_ => unreachable!(),
}
}
pub fn set_clear_receive_fifo(&mut self) {
self.0 |= 1 << 1;
}
pub fn set_clear_transmit_fifo(&mut self) {
self.0 |= 1 << 2;
}
pub fn set_dma_mode(&mut self, enable: bool) {
if enable {
self.0 |= 1 << 3;
} else {
self.0 &= !(1 << 3);
}
}
}
#[repr(u8)]
pub enum InterruptState {
ModemStatus = 0,
TransmitterHoldingRegisterEmpty = 1,
ReceivedDataAvailable = 2,
ReceiverLineStatus = 3,
}
#[repr(u8)]
pub enum FIFOBufferState {
Disabled = 0,
Unusable = 1,
Enabled = 2,
}
pub struct InterruptStatus(pub u8);
impl InterruptStatus {
pub fn interrupt_pending(&self) -> bool {
(self.0 & (1 << 0)) == 0
}
pub fn timeout_interrupt_pending(&self) -> bool {
(self.0 & (1 << 4)) != 0
}
pub fn interrupt_state(&self) -> InterruptState {
match (self.0 >> 1) & 0b111 {
0b000 => InterruptState::ModemStatus,
0b001 => InterruptState::TransmitterHoldingRegisterEmpty,
0b010 => InterruptState::ReceivedDataAvailable,
0b011 => InterruptState::ReceiverLineStatus,
_ => unreachable!(),
}
}
pub fn fifo_buffer_state(&self) -> FIFOBufferState {
match (self.0 >> 6) & 0b11 {
0b00 => FIFOBufferState::Disabled,
0b01 => FIFOBufferState::Unusable,
0b10 => FIFOBufferState::Enabled,
_ => unreachable!(),
}
}
}
pub struct ModemControl(pub u8);
impl ModemControl {
pub const fn empty() -> Self {
Self(0)
}
pub fn set_data_terminal_ready(&mut self, enable: bool) {
if enable {
self.0 |= 1 << 0;
} else {
self.0 &= !(1 << 0);
}
}
pub fn set_request_to_send(&mut self, enable: bool) {
if enable {
self.0 |= 1 << 1;
} else {
self.0 &= !(1 << 1);
}
}
pub fn set_auxiliary_output_1(&mut self, enable: bool) {
if enable {
self.0 |= 1 << 2;
} else {
self.0 &= !(1 << 2);
}
}
pub fn set_auxiliary_output_2(&mut self, enable: bool) {
if enable {
self.0 |= 1 << 3;
} else {
self.0 &= !(1 << 3);
}
}
pub fn set_loopback_mode(&mut self, enable: bool) {
if enable {
self.0 |= 1 << 4;
} else {
self.0 &= !(1 << 4);
}
}
pub fn loopback_mode(&self) -> bool {
(self.0 & (1 << 4)) != 0
}
}
pub struct LineStatus(pub u8);
impl LineStatus {
pub fn data_ready(&self) -> bool {
(self.0 & (1 << 0)) != 0
}
pub fn overrun_error(&self) -> bool {
(self.0 & (1 << 1)) != 0
}
pub fn parity_error(&self) -> bool {
(self.0 & (1 << 2)) != 0
}
pub fn framing_error(&self) -> bool {
(self.0 & (1 << 3)) != 0
}
pub fn break_interrupt(&self) -> bool {
(self.0 & (1 << 4)) != 0
}
pub fn transmitter_holding_register_empty(&self) -> bool {
(self.0 & (1 << 5)) != 0
}
pub fn transmitter_empty(&self) -> bool {
(self.0 & (1 << 6)) != 0
}
pub fn impending_error(&self) -> bool {
(self.0 & (1 << 7)) != 0
}
}
pub struct ModemStatus(pub u8);
impl ModemStatus {
pub fn delta_clear_to_send(&self) -> bool {
(self.0 & (1 << 0)) != 0
}
pub fn delta_data_set_ready(&self) -> bool {
(self.0 & (1 << 1)) != 0
}
pub fn trailing_edge_ring_indicator(&self) -> bool {
(self.0 & (1 << 2)) != 0
}
pub fn delta_data_carrier_detect(&self) -> bool {
(self.0 & (1 << 3)) != 0
}
pub fn clear_to_send(&self) -> bool {
(self.0 & (1 << 4)) != 0
}
pub fn data_set_ready(&self) -> bool {
(self.0 & (1 << 5)) != 0
}
pub fn ring_indicator(&self) -> bool {
(self.0 & (1 << 6)) != 0
}
pub fn data_carrier_detect(&self) -> bool {
(self.0 & (1 << 7)) != 0
}
}
#[derive(Debug, Clone, Copy, Default)]
#[repr(u8)]
pub enum FifoTriggerLevel {
Level1Byte = 0b00,
Level4Bytes = 0b01,
Level8Bytes = 0b10,
#[default]
Level14Bytes = 0b11,
}
impl FifoTriggerLevel {
pub fn count(&self) -> usize {
match self {
FifoTriggerLevel::Level1Byte => 1,
FifoTriggerLevel::Level4Bytes => 4,
FifoTriggerLevel::Level8Bytes => 8,
FifoTriggerLevel::Level14Bytes => 14,
}
}
}
pub struct Uart16550Writer {
uart: Uart16550,
}
impl Uart16550Writer {
pub fn from_port(base_port: u16) -> Self {
let mut uart = unsafe { Uart16550::with_port(base_port) };
uart.init();
Self { uart }
}
}
impl core::fmt::Write for Uart16550Writer {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
let bytes = s.as_bytes();
const SPECIAL_BYTES: &[u8] = &[b'\n', 8, 0x7f];
bytes
.split_inclusive(|b| SPECIAL_BYTES.contains(b))
.for_each(|chunk| {
if let Some((special, rest)) = chunk.split_last() {
self.uart.send_bytes_exact(rest);
match special {
b'\n' => {
self.uart.send_bytes_exact(b"\r\n");
}
8 | 0x7f => {
self.uart.send_bytes_exact(&[8, b' ', 8]);
}
_ => {}
}
}
});
Ok(())
}
}
pub static SERIAL1: crate::sync::LazyLock<crate::sync::SpinMutex<Uart16550Writer>> =
crate::sync::LazyLock::new(|| {
crate::sync::SpinMutex::new(Uart16550Writer::from_port(0x3f8))
});
}
#[doc(hidden)]
pub fn _print(args: core::fmt::Arguments) {
#[cfg(target_arch = "x86_64")]
{
use core::fmt::Write;
struct Writer<'a>(&'a crate::sync::SpinMutex<uart_16550::Uart16550Writer>);
impl core::fmt::Write for Writer<'_> {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
let mut writer = self.0.lock();
writer.write_str(s)
}
}
Writer(&uart_16550::SERIAL1).write_fmt(args).unwrap();
}
}
#[macro_export]
macro_rules! serial_print {
($($arg:tt)*) => {
$crate::serial::_print(format_args!($($arg)*));
};
}
#[macro_export]
macro_rules! serial_println {
() => {
$crate::serial_print!("\n");
};
($fmt:expr) => {
$crate::serial_print!(concat!($fmt, "\n"));
};
($fmt:expr, $($arg:tt)*) => {
$crate::serial_print!(
concat!($fmt, "\n"), $($arg)*
);
};
}