serial.rs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. mod io;
  2. use crate::{
  3. kernel::{
  4. block::make_device, console::set_console, constants::EIO, interrupt::register_irq_handler,
  5. task::KernelStack, CharDevice, CharDeviceType, Terminal, TerminalDevice,
  6. },
  7. prelude::*,
  8. };
  9. use alloc::{collections::vec_deque::VecDeque, format, sync::Arc};
  10. use bitflags::bitflags;
  11. use core::pin::pin;
  12. use eonix_runtime::{run::FutureRun, scheduler::Scheduler};
  13. use eonix_sync::{SpinIrq as _, WaitList};
  14. use io::SerialIO;
  15. bitflags! {
  16. struct LineStatus: u8 {
  17. const RX_READY = 0x01;
  18. const TX_READY = 0x20;
  19. }
  20. }
  21. trait SerialRegister {
  22. fn read(&self) -> u8;
  23. fn write(&self, value: u8);
  24. }
  25. #[allow(dead_code)]
  26. struct Serial {
  27. id: u32,
  28. name: Arc<str>,
  29. terminal: Spin<Option<Arc<Terminal>>>,
  30. worker_wait: WaitList,
  31. working: Spin<bool>,
  32. tx_buffer: Spin<VecDeque<u8>>,
  33. ioregs: SerialIO,
  34. }
  35. impl Serial {
  36. fn enable_interrupts(&self) {
  37. // Enable interrupt #0: Received data available
  38. self.ioregs.int_ena().write(0x03);
  39. }
  40. fn disable_interrupts(&self) {
  41. // Disable interrupt #0: Received data available
  42. self.ioregs.int_ena().write(0x02);
  43. }
  44. fn line_status(&self) -> LineStatus {
  45. LineStatus::from_bits_truncate(self.ioregs.line_status().read())
  46. }
  47. async fn wait_for_interrupt(&self) {
  48. let mut wait = pin!(self.worker_wait.prepare_to_wait());
  49. {
  50. let mut working = self.working.lock_irq();
  51. self.enable_interrupts();
  52. wait.as_mut().add_to_wait_list();
  53. *working = false;
  54. };
  55. wait.await;
  56. *self.working.lock_irq() = true;
  57. self.disable_interrupts();
  58. }
  59. async fn worker(port: Arc<Self>) {
  60. let terminal = port.terminal.lock().clone();
  61. loop {
  62. while port.line_status().contains(LineStatus::RX_READY) {
  63. let ch = port.ioregs.tx_rx().read();
  64. if let Some(terminal) = terminal.as_ref() {
  65. terminal.commit_char(ch).await;
  66. }
  67. }
  68. let should_wait = {
  69. let mut tx_buffer = port.tx_buffer.lock();
  70. let mut count = 0;
  71. // Give it a chance to receive data.
  72. for &ch in tx_buffer.iter().take(64) {
  73. if port.line_status().contains(LineStatus::TX_READY) {
  74. port.ioregs.tx_rx().write(ch);
  75. } else {
  76. break;
  77. }
  78. count += 1;
  79. }
  80. tx_buffer.drain(..count);
  81. tx_buffer.is_empty()
  82. };
  83. if should_wait {
  84. port.wait_for_interrupt().await;
  85. }
  86. }
  87. }
  88. pub fn new(id: u32, ioregs: SerialIO) -> KResult<Self> {
  89. ioregs.int_ena().write(0x00); // Disable all interrupts
  90. ioregs.line_control().write(0x80); // Enable DLAB (set baud rate divisor)
  91. ioregs.tx_rx().write(0x00); // Set divisor to 0 (lo byte) 115200 baud rate
  92. ioregs.int_ena().write(0x00); // 0 (hi byte)
  93. ioregs.line_control().write(0x03); // 8 bits, no parity, one stop bit
  94. ioregs.int_ident().write(0xc7); // Enable FIFO, clear them, with 14-byte threshold
  95. ioregs.modem_control().write(0x0b); // IRQs enabled, RTS/DSR set
  96. ioregs.modem_control().write(0x1e); // Set in loopback mode, test the serial chip
  97. ioregs.tx_rx().write(0x19); // Test serial chip (send byte 0x19 and check if serial returns
  98. // same byte)
  99. if ioregs.tx_rx().read() != 0x19 {
  100. return Err(EIO);
  101. }
  102. ioregs.modem_control().write(0x0f); // Return to normal operation mode
  103. Ok(Self {
  104. id,
  105. name: Arc::from(format!("ttyS{id}")),
  106. terminal: Spin::new(None),
  107. worker_wait: WaitList::new(),
  108. working: Spin::new(true),
  109. tx_buffer: Spin::new(VecDeque::new()),
  110. ioregs,
  111. })
  112. }
  113. fn wakeup_worker(&self) {
  114. let working = self.working.lock_irq();
  115. if !*working {
  116. self.worker_wait.notify_one();
  117. }
  118. }
  119. fn irq_handler(&self) {
  120. // Read the interrupt ID register to clear the interrupt.
  121. self.ioregs.int_ident().read();
  122. self.wakeup_worker();
  123. }
  124. fn register_as_char_device(self, irq_no: usize) -> KResult<()> {
  125. let port = Arc::new(self);
  126. let terminal = Terminal::new(port.clone());
  127. port.terminal.lock().replace(terminal.clone());
  128. {
  129. let port = port.clone();
  130. register_irq_handler(irq_no as i32, move || {
  131. port.irq_handler();
  132. })?;
  133. }
  134. Scheduler::get().spawn::<KernelStack, _>(FutureRun::new(Self::worker(port.clone())));
  135. let _ = set_console(terminal.clone());
  136. eonix_log::set_console(terminal.clone());
  137. CharDevice::register(
  138. make_device(4, 64 + port.id),
  139. port.name.clone(),
  140. CharDeviceType::Terminal(terminal),
  141. )?;
  142. Ok(())
  143. }
  144. }
  145. impl TerminalDevice for Serial {
  146. fn write(&self, data: &[u8]) {
  147. let mut tx_buffer = self.tx_buffer.lock();
  148. tx_buffer.extend(data.iter().copied());
  149. self.wakeup_worker();
  150. }
  151. fn write_direct(&self, data: &[u8]) {
  152. for &ch in data {
  153. self.ioregs.tx_rx().write(ch);
  154. }
  155. }
  156. }
  157. pub fn init() -> KResult<()> {
  158. #[cfg(target_arch = "x86_64")]
  159. {
  160. let (com0, com1) = unsafe {
  161. const COM0_BASE: u16 = 0x3f8;
  162. const COM1_BASE: u16 = 0x2f8;
  163. // SAFETY: The COM ports are well-known hardware addresses.
  164. (SerialIO::new(COM0_BASE), SerialIO::new(COM1_BASE))
  165. };
  166. if let Ok(port) = Serial::new(0, com0) {
  167. const COM0_IRQ: usize = 4;
  168. port.register_as_char_device(COM0_IRQ)?;
  169. }
  170. if let Ok(port) = Serial::new(1, com1) {
  171. const COM1_IRQ: usize = 3;
  172. port.register_as_char_device(COM1_IRQ)?;
  173. }
  174. }
  175. #[cfg(target_arch = "riscv64")]
  176. {
  177. use eonix_hal::arch_exported::fdt::FDT;
  178. use eonix_mm::address::PAddr;
  179. if let Some(uart) = FDT.find_compatible(&["ns16550a", "ns16550"]) {
  180. let regs = uart.reg().unwrap();
  181. let base_address = regs
  182. .map(|reg| PAddr::from(reg.starting_address as usize))
  183. .next()
  184. .expect("UART base address not found");
  185. let port = unsafe {
  186. // SAFETY: The base address is provided by the FDT and should be valid.
  187. SerialIO::new(base_address)
  188. };
  189. let serial = Serial::new(0, port)?;
  190. serial.register_as_char_device(
  191. uart.interrupts()
  192. .expect("UART device should have `interrupts` property")
  193. .next()
  194. .expect("UART device should have an interrupt pin"),
  195. )?;
  196. }
  197. }
  198. #[cfg(target_arch = "loongarch64")]
  199. {
  200. use eonix_mm::address::PAddr;
  201. let port = unsafe {
  202. // SAFETY: The base address is provided by the FDT and should be valid.
  203. SerialIO::new(PAddr::from(0x1fe0_01e0))
  204. };
  205. let serial = Serial::new(0, port)?;
  206. serial.register_as_char_device(
  207. // 2 or 4 here, let's try 2 first!
  208. 2,
  209. )?;
  210. }
  211. Ok(())
  212. }