summaryrefslogtreecommitdiffstats
path: root/rsnix/src/serial.rs
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-07-31 02:58:31 +0200
committersalmonik <salmonik@tuta.io>2026-07-31 02:58:31 +0200
commit6a5c32fa6ae8ec34e3e5b44d7e5a78ded8fe729b (patch)
treeed59a5bd59a94b3a731b28c68c507f18afc44b0b /rsnix/src/serial.rs
parentauto-version all strings from Cargo.toml via env!("CARGO_PKG_VERSION") (diff)
downloadrs-dos-6a5c32fa6ae8ec34e3e5b44d7e5a78ded8fe729b.tar.gz
rs-dos-6a5c32fa6ae8ec34e3e5b44d7e5a78ded8fe729b.zip
restructure: rsnix kernel + shell crate + rsdos entry point
Architecture: rs-dos/ (workspace root, was raisernics/) ├── rsnix/ — kernel lib crate (uefi, serial, gop, ps2, interrupts, memory) ├── shell/ — shell lib crate (prompt, commands, line input) ├── rsdos/ — binary crate (efi_main, init, panic handler) └── rsboot/ — future git submodule No functional changes — boots to shell prompt identically. Version auto-pulled from Cargo.toml via env!("CARGO_PKG_VERSION").
Diffstat (limited to 'rsnix/src/serial.rs')
-rw-r--r--rsnix/src/serial.rs118
1 files changed, 118 insertions, 0 deletions
diff --git a/rsnix/src/serial.rs b/rsnix/src/serial.rs
new file mode 100644
index 0000000..03fa570
--- /dev/null
+++ b/rsnix/src/serial.rs
@@ -0,0 +1,118 @@
1/// UART 16550 serial driver — port-mapped I/O on COM1 (0x3F8)
2use core::fmt;
3
4const COM1: u16 = 0x3F8;
5
6const DATA_REG: u16 = COM1;
7const INTR_ENABLE: u16 = COM1 + 1;
8const FIFO_CONTROL: u16 = COM1 + 2;
9const LINE_CONTROL: u16 = COM1 + 3;
10const MODEM_CONTROL: u16 = COM1 + 4;
11const LINE_STATUS: u16 = COM1 + 5;
12
13const LSR_TX_EMPTY: u8 = 0x20;
14const LSR_DATA_READY: u8 = 0x01;
15
16/// Initialise the UART with 115200 baud, 8N1.
17pub fn init() {
18 unsafe {
19 // Disable interrupts
20 port_out(INTR_ENABLE, 0x00);
21 // Set DLAB=1 (baud rate divisor)
22 port_out(LINE_CONTROL, 0x80);
23 // Divisor = 1 → 115200 baud (with 1.8432 MHz clock)
24 port_out(DATA_REG, 0x01);
25 port_out(INTR_ENABLE, 0x00);
26 // 8-bit, 1 stop, no parity, DLAB=0
27 port_out(LINE_CONTROL, 0x03);
28 // Enable FIFO, clear, 14-byte threshold
29 port_out(FIFO_CONTROL, 0xC7);
30 // RTS/DSR set
31 port_out(MODEM_CONTROL, 0x0B);
32 }
33}
34
35/// Write a single byte to the serial port (blocking poll).
36pub fn put_byte(b: u8) {
37 unsafe {
38 // Wait for transmitter holding register empty
39 while port_in(LINE_STATUS) & LSR_TX_EMPTY == 0 {}
40 port_out(DATA_REG, b);
41 }
42}
43
44/// Read a single byte from the serial port (blocking poll).
45pub fn get_byte() -> u8 {
46 unsafe {
47 while port_in(LINE_STATUS) & LSR_DATA_READY == 0 {}
48 port_in(DATA_REG)
49 }
50}
51
52/// Non-blocking read: returns Some(byte) if data ready, None otherwise.
53pub fn try_get_byte() -> Option<u8> {
54 unsafe {
55 if port_in(LINE_STATUS) & LSR_DATA_READY != 0 {
56 Some(port_in(DATA_REG))
57 } else {
58 None
59 }
60 }
61}
62
63/// Write a string to serial.
64pub fn write_str(s: &str) {
65 for &b in s.as_bytes() {
66 if b == b'\n' {
67 put_byte(b'\r');
68 }
69 put_byte(b);
70 }
71}
72
73// ---------------------------------------------------------------------------
74// fmt::Write implementation
75// ---------------------------------------------------------------------------
76pub struct SerialWriter;
77
78impl fmt::Write for SerialWriter {
79 fn write_str(&mut self, s: &str) -> fmt::Result {
80 write_str(s);
81 Ok(())
82 }
83}
84
85/// Helper macro — prints to serial via format_args!.
86#[macro_export]
87macro_rules! serial_print {
88 ($($arg:tt)*) => {{
89 use core::fmt::Write;
90 let _ = write!(&mut $crate::serial::SerialWriter, $($arg)*);
91 }};
92}
93
94#[macro_export]
95macro_rules! serial_println {
96 () => { $crate::serial::write_str("\r\n"); };
97 ($($arg:tt)*) => {{
98 $crate::serial_print!($($arg)*);
99 $crate::serial::write_str("\r\n");
100 }};
101}
102
103// ---------------------------------------------------------------------------
104// Port I/O helpers
105// ---------------------------------------------------------------------------
106unsafe fn port_in(port: u16) -> u8 {
107 let val: u8;
108 unsafe {
109 core::arch::asm!("in al, dx", out("al") val, in("dx") port, options(nostack, preserves_flags));
110 }
111 val
112}
113
114unsafe fn port_out(port: u16, val: u8) {
115 unsafe {
116 core::arch::asm!("out dx, al", in("al") val, in("dx") port, options(nostack, preserves_flags));
117 }
118}