terminal.rs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673
  1. use alloc::{
  2. collections::vec_deque::VecDeque,
  3. sync::{Arc, Weak},
  4. };
  5. use bindings::{EINTR, ENOTTY, EPERM};
  6. use bitflags::bitflags;
  7. use crate::{
  8. io::Buffer,
  9. prelude::*,
  10. sync::{AsRefPosition as _, CondVar},
  11. };
  12. use super::{
  13. task::{ProcessList, Session, Signal, Thread},
  14. user::{UserPointer, UserPointerMut},
  15. };
  16. const BUFFER_SIZE: usize = 4096;
  17. const NCCS: usize = 32;
  18. // taken from linux kernel code
  19. /* c_cc characters */
  20. const VINTR: usize = 0;
  21. const VQUIT: usize = 1;
  22. const VERASE: usize = 2;
  23. const VKILL: usize = 3;
  24. const VEOF: usize = 4;
  25. const VTIME: usize = 5;
  26. const VMIN: usize = 6;
  27. const VSWTC: usize = 7;
  28. const VSTART: usize = 8;
  29. const VSTOP: usize = 9;
  30. const VSUSP: usize = 10;
  31. const VEOL: usize = 11;
  32. const VREPRINT: usize = 12;
  33. const VDISCARD: usize = 13;
  34. const VWERASE: usize = 14;
  35. const VLNEXT: usize = 15;
  36. const VEOL2: usize = 16;
  37. /* c_iflag bits */
  38. bitflags! {
  39. #[derive(Debug)]
  40. pub struct TermioIFlags: u16 {
  41. /// Ignore break condition
  42. const IGNBRK = 0x0001;
  43. /// Signal interrupt on break
  44. const BRKINT = 0x0002;
  45. /// Ignore characters with parity errors
  46. const IGNPAR = 0x0004;
  47. /// Mark parity and framing errors
  48. const PARMRK = 0x0008;
  49. /// Enable input parity check
  50. const INPCK = 0x0010;
  51. /// Strip 8th bit off characters
  52. const ISTRIP = 0x0020;
  53. /// Map NL to CR on input
  54. const INLCR = 0x0040;
  55. /// Ignore CR
  56. const IGNCR = 0x0080;
  57. /// Map CR to NL on input
  58. const ICRNL = 0x0100;
  59. const IUCLC = 0x0200;
  60. const IXON = 0x0400;
  61. /// Any character will restart after stop
  62. const IXANY = 0x0800;
  63. const IXOFF = 0x1000;
  64. const IMAXBEL = 0x2000;
  65. const IUTF8 = 0x4000;
  66. }
  67. #[derive(Debug)]
  68. pub struct TermioOFlags: u16 {
  69. /// Perform output processing
  70. const OPOST = 0x0001;
  71. const OLCUC = 0x0002;
  72. const ONLCR = 0x0004;
  73. const OCRNL = 0x0008;
  74. const ONOCR = 0x0010;
  75. const ONLRET = 0x0020;
  76. const OFILL = 0x0040;
  77. const OFDEL = 0x0080;
  78. }
  79. }
  80. bitflags! {
  81. #[derive(Debug)]
  82. pub struct TermioLFlags: u16 {
  83. const ISIG = 0x0001;
  84. const ICANON = 0x0002;
  85. const XCASE = 0x0004;
  86. const ECHO = 0x0008;
  87. const ECHOE = 0x0010;
  88. const ECHOK = 0x0020;
  89. const ECHONL = 0x0040;
  90. const NOFLSH = 0x0080;
  91. const TOSTOP = 0x0100;
  92. const ECHOCTL = 0x0200;
  93. const ECHOPRT = 0x0400;
  94. const ECHOKE = 0x0800;
  95. const FLUSHO = 0x1000;
  96. const PENDIN = 0x4000;
  97. const IEXTEN = 0x8000;
  98. }
  99. }
  100. /* c_cflag bit meaning */
  101. const B38400: u32 = 0x0000000f;
  102. const CS8: u32 = 0x00000030;
  103. const CREAD: u32 = 0x00000080;
  104. const HUPCL: u32 = 0x00000400;
  105. // line disciplines
  106. const N_TTY: u8 = 0;
  107. #[derive(Debug)]
  108. pub struct Termios {
  109. iflag: TermioIFlags,
  110. oflag: TermioOFlags,
  111. cflag: u32,
  112. lflag: TermioLFlags,
  113. line: u8,
  114. cc: [u8; NCCS],
  115. }
  116. macro_rules! CTRL {
  117. ('A') => {
  118. 0x01
  119. };
  120. ('B') => {
  121. 0x02
  122. };
  123. ('C') => {
  124. 0x03
  125. };
  126. ('D') => {
  127. 0x04
  128. };
  129. ('E') => {
  130. 0x05
  131. };
  132. ('F') => {
  133. 0x06
  134. };
  135. ('G') => {
  136. 0x07
  137. };
  138. ('H') => {
  139. 0x08
  140. };
  141. ('I') => {
  142. 0x09
  143. };
  144. ('J') => {
  145. 0x0A
  146. };
  147. ('K') => {
  148. 0x0B
  149. };
  150. ('L') => {
  151. 0x0C
  152. };
  153. ('M') => {
  154. 0x0D
  155. };
  156. ('N') => {
  157. 0x0E
  158. };
  159. ('O') => {
  160. 0x0F
  161. };
  162. ('P') => {
  163. 0x10
  164. };
  165. ('Q') => {
  166. 0x11
  167. };
  168. ('R') => {
  169. 0x12
  170. };
  171. ('S') => {
  172. 0x13
  173. };
  174. ('T') => {
  175. 0x14
  176. };
  177. ('U') => {
  178. 0x15
  179. };
  180. ('V') => {
  181. 0x16
  182. };
  183. ('W') => {
  184. 0x17
  185. };
  186. ('X') => {
  187. 0x18
  188. };
  189. ('Y') => {
  190. 0x19
  191. };
  192. ('Z') => {
  193. 0x1A
  194. };
  195. ('\\') => {
  196. 0x1c
  197. };
  198. }
  199. impl Termios {
  200. pub fn veof(&self) -> u8 {
  201. self.cc[VEOF]
  202. }
  203. pub fn veol(&self) -> u8 {
  204. self.cc[VEOL]
  205. }
  206. pub fn veol2(&self) -> u8 {
  207. self.cc[VEOL2]
  208. }
  209. pub fn vintr(&self) -> u8 {
  210. self.cc[VINTR]
  211. }
  212. pub fn vquit(&self) -> u8 {
  213. self.cc[VQUIT]
  214. }
  215. pub fn vsusp(&self) -> u8 {
  216. self.cc[VSUSP]
  217. }
  218. pub fn verase(&self) -> u8 {
  219. self.cc[VERASE]
  220. }
  221. pub fn vkill(&self) -> u8 {
  222. self.cc[VKILL]
  223. }
  224. pub fn echo(&self) -> bool {
  225. self.lflag.contains(TermioLFlags::ECHO)
  226. }
  227. pub fn echoe(&self) -> bool {
  228. self.lflag.contains(TermioLFlags::ECHOE)
  229. }
  230. pub fn echoctl(&self) -> bool {
  231. self.lflag.contains(TermioLFlags::ECHOCTL)
  232. }
  233. pub fn echoke(&self) -> bool {
  234. self.lflag.contains(TermioLFlags::ECHOKE)
  235. }
  236. pub fn echok(&self) -> bool {
  237. self.lflag.contains(TermioLFlags::ECHOK)
  238. }
  239. pub fn echonl(&self) -> bool {
  240. self.lflag.contains(TermioLFlags::ECHONL)
  241. }
  242. pub fn isig(&self) -> bool {
  243. self.lflag.contains(TermioLFlags::ISIG)
  244. }
  245. pub fn icanon(&self) -> bool {
  246. self.lflag.contains(TermioLFlags::ICANON)
  247. }
  248. pub fn iexten(&self) -> bool {
  249. self.lflag.contains(TermioLFlags::IEXTEN)
  250. }
  251. pub fn igncr(&self) -> bool {
  252. self.iflag.contains(TermioIFlags::IGNCR)
  253. }
  254. pub fn icrnl(&self) -> bool {
  255. self.iflag.contains(TermioIFlags::ICRNL)
  256. }
  257. pub fn inlcr(&self) -> bool {
  258. self.iflag.contains(TermioIFlags::INLCR)
  259. }
  260. pub fn noflsh(&self) -> bool {
  261. self.lflag.contains(TermioLFlags::NOFLSH)
  262. }
  263. pub fn new_standard() -> Self {
  264. let cc = core::array::from_fn(|idx| match idx {
  265. VINTR => CTRL!('C'),
  266. VQUIT => CTRL!('\\'),
  267. VERASE => 0x7f,
  268. VKILL => CTRL!('U'),
  269. VEOF => CTRL!('D'),
  270. VSUSP => CTRL!('Z'),
  271. VMIN => 1,
  272. _ => 0,
  273. });
  274. Self {
  275. iflag: TermioIFlags::ICRNL | TermioIFlags::IXOFF,
  276. oflag: TermioOFlags::OPOST | TermioOFlags::ONLCR,
  277. cflag: B38400 | CS8 | CREAD | HUPCL,
  278. lflag: TermioLFlags::ISIG
  279. | TermioLFlags::ICANON
  280. | TermioLFlags::ECHO
  281. | TermioLFlags::ECHOE
  282. | TermioLFlags::ECHOK
  283. | TermioLFlags::ECHOCTL
  284. | TermioLFlags::ECHOKE
  285. | TermioLFlags::IEXTEN,
  286. line: N_TTY,
  287. cc,
  288. }
  289. }
  290. fn get_user(&self) -> UserTermios {
  291. UserTermios {
  292. iflag: self.iflag.bits() as u32,
  293. oflag: self.oflag.bits() as u32,
  294. cflag: self.cflag,
  295. lflag: self.lflag.bits() as u32,
  296. line: self.line,
  297. cc: self.cc,
  298. }
  299. }
  300. }
  301. pub trait TerminalDevice: Send + Sync {
  302. fn putchar(&self, ch: u8);
  303. }
  304. struct TerminalInner {
  305. termio: Termios,
  306. session: Weak<Session>,
  307. buffer: VecDeque<u8>,
  308. }
  309. pub struct Terminal {
  310. /// Lock with IRQ disabled. We might use this in IRQ context.
  311. inner: Spin<TerminalInner>,
  312. device: Arc<dyn TerminalDevice>,
  313. cv: CondVar,
  314. }
  315. #[repr(C)]
  316. #[derive(Debug, Clone, Copy)]
  317. pub struct UserWindowSize {
  318. row: u16,
  319. col: u16,
  320. xpixel: u16,
  321. ypixel: u16,
  322. }
  323. #[repr(C)]
  324. #[derive(Debug, Clone, Copy)]
  325. pub struct UserTermios {
  326. iflag: u32,
  327. oflag: u32,
  328. cflag: u32,
  329. lflag: u32,
  330. line: u8,
  331. cc: [u8; NCCS],
  332. }
  333. pub enum TerminalIORequest<'a> {
  334. GetProcessGroup(UserPointerMut<'a, u32>),
  335. SetProcessGroup(UserPointer<'a, u32>),
  336. GetWindowSize(UserPointerMut<'a, UserWindowSize>),
  337. GetTermios(UserPointerMut<'a, UserTermios>),
  338. SetTermios(UserPointer<'a, UserTermios>),
  339. }
  340. impl core::fmt::Debug for Terminal {
  341. fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
  342. f.debug_struct("Terminal").finish()
  343. }
  344. }
  345. impl Terminal {
  346. pub fn new(device: Arc<dyn TerminalDevice>) -> Arc<Self> {
  347. Arc::new(Self {
  348. inner: Spin::new(TerminalInner {
  349. termio: Termios::new_standard(),
  350. session: Weak::new(),
  351. buffer: VecDeque::with_capacity(BUFFER_SIZE),
  352. }),
  353. cv: CondVar::new(),
  354. device,
  355. })
  356. }
  357. /// Clear the read buffer.
  358. fn clear_read_buffer(&self, inner: &mut TerminalInner) {
  359. inner.buffer.clear();
  360. }
  361. // TODO: Buffer terminal writes.
  362. pub fn show_char(&self, ch: u8) {
  363. self.device.putchar(ch)
  364. }
  365. fn erase(&self, inner: &mut TerminalInner, echo: bool) -> Option<u8> {
  366. let back = inner.buffer.back().copied();
  367. match back {
  368. None => return None,
  369. Some(b'\n') => return None,
  370. Some(back) if back == inner.termio.veof() => return None,
  371. Some(back) if back == inner.termio.veol() => return None,
  372. Some(back) if back == inner.termio.veol2() => return None,
  373. _ => {}
  374. }
  375. let back = inner.buffer.pop_back();
  376. if echo && inner.termio.echo() && inner.termio.echoe() {
  377. self.show_char(CTRL!('H')); // Backspace
  378. self.show_char(b' '); // Space
  379. self.show_char(CTRL!('H')); // Backspace
  380. }
  381. return back;
  382. }
  383. fn echo_char(&self, inner: &mut TerminalInner, ch: u8) {
  384. match ch {
  385. b'\t' | b'\n' | CTRL!('Q') | CTRL!('S') => self.show_char(ch),
  386. c if c >= 32 => self.show_char(ch),
  387. _ if !inner.termio.echo() => self.show_char(ch),
  388. _ if !inner.termio.echoctl() => self.show_char(ch),
  389. _ if !inner.termio.iexten() => self.show_char(ch),
  390. _ => {
  391. self.show_char(b'^');
  392. self.show_char(ch + 0x40);
  393. }
  394. }
  395. }
  396. fn signal(&self, inner: &mut TerminalInner, signal: Signal) {
  397. if let Some(session) = inner.session.upgrade() {
  398. session.raise_foreground(signal);
  399. }
  400. if !inner.termio.noflsh() {
  401. self.clear_read_buffer(inner);
  402. }
  403. }
  404. fn echo_and_signal(&self, inner: &mut TerminalInner, ch: u8, signal: Signal) {
  405. self.echo_char(inner, ch);
  406. self.signal(inner, signal);
  407. }
  408. fn do_commit_char(&self, inner: &mut TerminalInner, ch: u8) {
  409. inner.buffer.push_back(ch);
  410. if inner.termio.echo() || (ch == b'\n' && inner.termio.echonl()) {
  411. self.echo_char(inner, ch);
  412. }
  413. // If ICANON is not set, we notify all waiting processes.
  414. // If ICANON is set but we have a new line, there are data ready, we notify as well.
  415. if ch == b'\n' || !inner.termio.icanon() {
  416. self.cv.notify_all();
  417. }
  418. }
  419. // TODO: Find a better way to handle this.
  420. pub fn commit_char(&self, ch: u8) {
  421. let mut inner = self.inner.lock_irq();
  422. if inner.termio.isig() {
  423. match ch {
  424. 0xff => {}
  425. ch if ch == inner.termio.vintr() => {
  426. return self.echo_and_signal(&mut inner, ch, Signal::SIGINT)
  427. }
  428. ch if ch == inner.termio.vquit() => {
  429. return self.echo_and_signal(&mut inner, ch, Signal::SIGQUIT)
  430. }
  431. ch if ch == inner.termio.vsusp() => {
  432. return self.echo_and_signal(&mut inner, ch, Signal::SIGTSTP)
  433. }
  434. _ => {}
  435. }
  436. }
  437. // If handled, the character is discarded.
  438. if inner.termio.icanon() {
  439. match ch {
  440. 0xff => {}
  441. ch if ch == inner.termio.veof() => return self.cv.notify_all(),
  442. ch if ch == inner.termio.verase() => {
  443. self.erase(&mut inner, true);
  444. return;
  445. }
  446. ch if ch == inner.termio.vkill() => {
  447. if inner.termio.echok() {
  448. while self.erase(&mut inner, false).is_some() {}
  449. self.show_char(b'\n');
  450. } else if inner.termio.echoke() && inner.termio.iexten() {
  451. while self.erase(&mut inner, true).is_some() {}
  452. }
  453. return;
  454. }
  455. _ => {}
  456. }
  457. }
  458. match ch {
  459. b'\r' if inner.termio.igncr() => {}
  460. b'\r' if inner.termio.icrnl() => return self.do_commit_char(&mut inner, b'\n'),
  461. b'\n' if inner.termio.inlcr() => return self.do_commit_char(&mut inner, b'\r'),
  462. _ => self.do_commit_char(&mut inner, ch),
  463. }
  464. }
  465. pub fn poll_in(&self) -> KResult<()> {
  466. let mut inner = self.inner.lock_irq();
  467. if inner.buffer.is_empty() {
  468. self.cv.wait(&mut inner);
  469. if Thread::current().signal_list.has_pending_signal() {
  470. return Err(EINTR);
  471. }
  472. }
  473. Ok(())
  474. }
  475. pub fn read(&self, buffer: &mut dyn Buffer) -> KResult<usize> {
  476. let mut tmp_buffer = [0u8; 32];
  477. let data = 'block: {
  478. if buffer.available() == 0 {
  479. break 'block &tmp_buffer[..0];
  480. }
  481. let mut inner = self.inner.lock_irq();
  482. if inner.buffer.is_empty() {
  483. self.cv.wait(&mut inner);
  484. if Thread::current().signal_list.has_pending_signal() {
  485. return Err(EINTR);
  486. }
  487. }
  488. if inner.buffer.is_empty() {
  489. break 'block &tmp_buffer[..0];
  490. }
  491. let length = if inner.termio.icanon() {
  492. // Canonical mode, return data until we see a newline.
  493. // TODO!!: We should wait if we don't see one.
  494. inner
  495. .buffer
  496. .iter()
  497. .position(|&ch| ch == b'\n')
  498. .map(|pos| pos + 1)
  499. .unwrap_or(inner.buffer.len())
  500. } else {
  501. buffer.available().min(inner.buffer.len())
  502. };
  503. // TODO!!!!!!: Change this. We need to loop until we've got enough data.
  504. let length = length.min(tmp_buffer.len());
  505. for (ch, r) in inner
  506. .buffer
  507. .drain(..length)
  508. .zip(tmp_buffer.iter_mut().take(length))
  509. {
  510. *r = ch;
  511. }
  512. &tmp_buffer[..length]
  513. };
  514. buffer.fill(data).map(|result| result.allow_partial())
  515. }
  516. pub fn ioctl(&self, request: TerminalIORequest) -> KResult<()> {
  517. match request {
  518. TerminalIORequest::GetProcessGroup(pgid_pointer) => {
  519. let session = self.inner.lock().session.upgrade();
  520. let pgroup = session.map(|session| session.foreground()).flatten();
  521. if let Some(pgroup) = pgroup {
  522. pgid_pointer.write(pgroup.pgid)
  523. } else {
  524. Err(ENOTTY)
  525. }
  526. }
  527. TerminalIORequest::SetProcessGroup(pgid) => {
  528. let pgid = pgid.read()?;
  529. let procs = ProcessList::get().lock_shared();
  530. let inner = self.inner.lock();
  531. let session = inner.session.upgrade();
  532. if let Some(session) = session {
  533. session.set_foreground_pgid(pgid, procs.as_pos())
  534. } else {
  535. Err(ENOTTY)
  536. }
  537. }
  538. TerminalIORequest::GetWindowSize(ptr) => {
  539. // TODO: Get the actual window size
  540. let window_size = UserWindowSize {
  541. row: 40,
  542. col: 80,
  543. xpixel: 0,
  544. ypixel: 0,
  545. };
  546. ptr.write(window_size)
  547. }
  548. TerminalIORequest::GetTermios(ptr) => {
  549. let termios = self.inner.lock().termio.get_user();
  550. ptr.write(termios)
  551. }
  552. TerminalIORequest::SetTermios(ptr) => {
  553. let user_termios = ptr.read()?;
  554. let mut inner = self.inner.lock();
  555. // TODO: We ignore unknown bits for now.
  556. inner.termio.iflag = TermioIFlags::from_bits_truncate(user_termios.iflag as u16);
  557. inner.termio.oflag = TermioOFlags::from_bits_truncate(user_termios.oflag as u16);
  558. inner.termio.lflag = TermioLFlags::from_bits_truncate(user_termios.lflag as u16);
  559. inner.termio.cflag = user_termios.cflag;
  560. inner.termio.line = user_termios.line;
  561. inner.termio.cc = user_termios.cc;
  562. Ok(())
  563. }
  564. }
  565. }
  566. /// Assign the `session` to this terminal. Drop the previous session if `forced` is true.
  567. pub fn set_session(&self, session: &Arc<Session>, forced: bool) -> KResult<()> {
  568. let mut inner = self.inner.lock();
  569. if let Some(session) = inner.session.upgrade() {
  570. if !forced {
  571. Err(EPERM)
  572. } else {
  573. session.drop_control_terminal();
  574. inner.session = Arc::downgrade(&session);
  575. Ok(())
  576. }
  577. } else {
  578. // Sessions should set their `control_terminal` field.
  579. inner.session = Arc::downgrade(&session);
  580. Ok(())
  581. }
  582. }
  583. pub fn drop_session(&self) {
  584. self.inner.lock().session = Weak::new();
  585. }
  586. pub fn session(&self) -> Option<Arc<Session>> {
  587. self.inner.lock().session.upgrade()
  588. }
  589. }