kernel/
uart.rs

1use core::ptr;
2use core::sync::atomic::Ordering;
3
4use crate::memlayout::UART0;
5use crate::printf::PRINTF;
6use crate::proc::Cpus;
7use crate::spinlock::Mutex;
8
9const fn offset(base_address: usize, reg: usize) -> *mut u8 {
10    unsafe { (base_address as *mut u8).add(reg) }
11}
12
13const RHR: usize = 0;
14const THR: usize = 0;
15const IER: usize = 1;
16const IER_RX_ENABLE: u8 = 1 << 0;
17const IER_TX_ENABLE: u8 = 1 << 0;
18const FCR: usize = 2;
19const FCR_FIFO_ENABLE: u8 = 1 << 0;
20const FCR_FIFO_CLEAR: u8 = 3 << 1;
21const _ISR: usize = 2;
22const LCR: usize = 3;
23const LCR_EIGHT_BITS: u8 = 3 << 0;
24const LCR_BAUD_LATCH: u8 = 1 << 7;
25const LSR: usize = 5;
26const _LSR_RX_READY: u8 = 1 << 0;
27const LSR_TX_IDLE: u8 = 1 << 5;
28
29pub static UART: Mutex<Uart> = Mutex::new(Uart::new(UART0), "uart");
30
31const UART_TX_BUF_SIZE: usize = 32;
32
33pub struct Uart {
34    base_address: usize,
35    tx_buf: [u8; UART_TX_BUF_SIZE],
36    tx_w: usize,
37    tx_r: usize,
38}
39
40impl Uart {
41    pub const fn new(base_address: usize) -> Self {
42        Self {
43            base_address,
44            tx_buf: [0; UART_TX_BUF_SIZE],
45            tx_w: 0,
46            tx_r: 0,
47        }
48    }
49
50    fn read(&self, reg: usize) -> u8 {
51        unsafe { ptr::read_volatile(offset(self.base_address, reg)) }
52    }
53
54    fn write(&mut self, reg: usize, value: u8) {
55        unsafe { ptr::write_volatile(offset(self.base_address, reg), value) }
56    }
57
58    pub fn init(&mut self) {
59        // Disable interrupts
60        self.write(IER, 0x00);
61
62        // Special mode to set baud rate
63        self.write(LCR, LCR_BAUD_LATCH);
64
65        // LSB for baud rate of 38.4K
66        self.write(0, 0x03);
67
68        // MSB for baud rate of 38.4K
69        self.write(1, 0x00);
70
71        // Leave set-baud mode
72        self.write(LCR, LCR_EIGHT_BITS);
73
74        // reset and enable FIFOs
75        self.write(FCR, FCR_FIFO_ENABLE | FCR_FIFO_CLEAR);
76
77        // enable transmit and receive interrupts
78        self.write(IER, IER_TX_ENABLE | IER_RX_ENABLE);
79    }
80
81    fn start(&mut self) {
82        loop {
83            if self.tx_w == self.tx_r {
84                return;
85            }
86
87            if (self.read(LSR) & LSR_TX_IDLE) == 0 {
88                return;
89            }
90
91            let c = self.tx_buf[self.tx_r % UART_TX_BUF_SIZE];
92            self.tx_r += 1;
93
94            // TODO: Wakeup
95
96            self.write(THR, c);
97        }
98    }
99}
100
101impl Mutex<Uart> {
102    pub fn putc(&self, c: u8) {
103        let mut guard = self.lock();
104
105        if PRINTF.is_panicked().load(Ordering::Relaxed) {
106            loop {}
107        }
108
109        while guard.tx_w == guard.tx_r + UART_TX_BUF_SIZE {
110            // TODO: sleep
111        }
112
113        let index = guard.tx_w % UART_TX_BUF_SIZE;
114        *guard.tx_buf.get_mut(index).unwrap() = c;
115        guard.tx_w += 1;
116
117        guard.start();
118    }
119
120    pub fn getc(&self) -> Option<u8> {
121        // Safety: we are only reading from uart
122        let uart = unsafe { self.get_mut_unchecked() };
123        if uart.read(LSR) & 0x01 != 0 {
124            Some(uart.read(RHR))
125        } else {
126            None
127        }
128    }
129
130    pub fn handle_interrupt(&self) {
131        while let Some(c) = self.getc() {
132            // TODO: console interrupt with c
133        }
134
135        self.lock().start();
136    }
137}
138
139pub fn putc_sync(c: u8) {
140    let _intr_lock = Cpus::lock_mycpu();
141
142    // Safety: locked interrupts
143    let uart = unsafe { UART.get_mut_unchecked() };
144
145    if PRINTF.is_panicked().load(Ordering::Relaxed) {
146        loop {}
147    }
148
149    while (uart.read(LSR) & LSR_TX_IDLE) == 0 {}
150
151    uart.write(THR, c);
152}
153
154pub unsafe fn init() {
155    UART.get_mut_unchecked().init()
156}