diff --git a/kernel/include/kernel/Terminal/TTY.h b/kernel/include/kernel/Terminal/TTY.h index 77ba288c..1244132e 100644 --- a/kernel/include/kernel/Terminal/TTY.h +++ b/kernel/include/kernel/Terminal/TTY.h @@ -12,6 +12,20 @@ namespace Kernel { +#define TTY_DEFAULT_TERMIOS_CC { \ + [VEOF] = '\x04', /* ctrl+D */ \ + [VEOL] = '\0', \ + [VERASE] = '\b', \ + [VINTR] = '\x03', /* ctrl+C */ \ + [VKILL] = '\x15', /* ctrl+U */ \ + [VMIN] = 0, \ + [VQUIT] = '\x1c', /* ctrl+\ */ \ + [VSTART] = '\x11', /* ctrl+Q */ \ + [VSTOP] = '\x13', /* ctrl+S */ \ + [VSUSP] = '\x1a', /* ctrl+Z */ \ + [VTIME] = 0 \ + } + class TTY : public CharacterDevice { public: diff --git a/kernel/kernel/Terminal/PseudoTerminal.cpp b/kernel/kernel/Terminal/PseudoTerminal.cpp index 79f71c17..167ca646 100644 --- a/kernel/kernel/Terminal/PseudoTerminal.cpp +++ b/kernel/kernel/Terminal/PseudoTerminal.cpp @@ -162,8 +162,8 @@ namespace Kernel .c_iflag = 0, .c_oflag = 0, .c_cflag = CS8, - .c_lflag = ECHO | ICANON, - .c_cc = {}, + .c_lflag = ECHO | ICANON | ISIG, + .c_cc = TTY_DEFAULT_TERMIOS_CC, .c_ospeed = B38400, .c_ispeed = B38400, }, mode, uid, gid) diff --git a/kernel/kernel/Terminal/Serial.cpp b/kernel/kernel/Terminal/Serial.cpp index b6bec3d9..82e62333 100644 --- a/kernel/kernel/Terminal/Serial.cpp +++ b/kernel/kernel/Terminal/Serial.cpp @@ -174,8 +174,8 @@ namespace Kernel .c_iflag = ICRNL, .c_oflag = OPOST | ONLCR, .c_cflag = CS8, - .c_lflag = ECHO | ICANON, - .c_cc = {}, + .c_lflag = ECHO | ICANON | ISIG, + .c_cc = TTY_DEFAULT_TERMIOS_CC, .c_ospeed = B38400, .c_ispeed = B38400, }, 0600, 0, 0) diff --git a/kernel/kernel/Terminal/TTY.cpp b/kernel/kernel/Terminal/TTY.cpp index 33f7c948..03af9d48 100644 --- a/kernel/kernel/Terminal/TTY.cpp +++ b/kernel/kernel/Terminal/TTY.cpp @@ -18,6 +18,9 @@ #include #include +#define NL '\n' +#define CR '\r' + namespace Kernel { @@ -216,53 +219,85 @@ namespace Kernel void TTY::handle_input_byte(uint8_t ch) { - if (ch == 0) + if (ch == _POSIX_VDISABLE) return; LockGuard _(m_mutex); - if ((m_termios.c_iflag & ISTRIP)) - ch &= 0x7F; - if ((m_termios.c_iflag & IGNCR) && ch == '\r') - return; - uint8_t conv = ch; - if ((m_termios.c_iflag & ICRNL) && ch == '\r') - conv = '\n'; - if ((m_termios.c_iflag & INLCR) && ch == '\n') - conv = '\r'; - ch = conv; - - // ^C - if (ch == '\x03') + if (m_termios.c_lflag & ICANON) { - if (auto ret = Process::kill(-m_foreground_pgrp, SIGINT); ret.is_error()) - dwarnln("TTY: {}", ret.error()); - return; + if ((m_termios.c_iflag & ISTRIP)) + ch &= 0x7F; + if ((m_termios.c_iflag & IGNCR) && ch == CR) + return; + uint8_t conv = ch; + if ((m_termios.c_iflag & ICRNL) && ch == CR) + conv = NL; + if ((m_termios.c_iflag & INLCR) && ch == NL) + conv = CR; + ch = conv; } - // ^D + canonical - if (ch == '\x04' && (m_termios.c_lflag & ICANON)) + if (m_termios.c_lflag & ISIG) { - m_output.flush = true; - epoll_notify(EPOLLIN); - m_output.thread_blocker.unblock(); - return; + int sig = -1; + if (ch == m_termios.c_cc[VINTR]) + sig = SIGINT; + if (ch == m_termios.c_cc[VQUIT]) + sig = SIGQUIT; + if (ch == m_termios.c_cc[VSUSP]) + sig = SIGTSTP; + if (sig != -1) + { + if (auto ret = Process::kill(-m_foreground_pgrp, sig); ret.is_error()) + dwarnln("TTY: {}", ret.error()); + return; + } } - // backspace + canonical - if (ch == '\b' && (m_termios.c_lflag & ICANON)) + bool should_append = true; + bool should_flush = false; + bool force_echo = false; + + if (!(m_termios.c_lflag & ICANON)) + should_flush = true; + else { - do_backspace(); - return; + if (ch == m_termios.c_cc[VERASE] && (m_termios.c_lflag & ECHOE)) + return do_backspace(); + + //if (ch == m_termios.c_cc[VKILL] && (m_termios.c_lflag & ECHOK)) + // ; + + if (ch == m_termios.c_cc[VEOF]) + { + should_append = false; + should_flush = true; + } + + if (ch == NL || ch == m_termios.c_cc[VEOL]) + { + should_append = true; + should_flush = true; + force_echo = !!(m_termios.c_lflag & ECHONL); + ch = NL; + } } - // FIXME: don't ignore these bytes - if (m_output.bytes >= m_output.buffer.size()) - return; + // TODO: terminal suspension with VSTOP/VSTART - m_output.buffer[m_output.bytes++] = ch; + if (should_append) + { + // FIXME: don't ignore these bytes + if (m_output.bytes >= m_output.buffer.size()) + { + dwarnln("TTY input full"); + return; + } + m_output.buffer[m_output.bytes++] = ch; + } - if (m_termios.c_lflag & ECHO) + if (force_echo || (m_termios.c_lflag & ECHO)) { if ((ch <= 31 || ch == 127) && ch != '\n') { @@ -288,7 +323,7 @@ namespace Kernel } } - if (ch == '\n' || !(m_termios.c_lflag & ICANON) || m_output.bytes == m_output.buffer.size()) + if (should_flush) { m_output.flush = true; epoll_notify(EPOLLIN); @@ -346,10 +381,10 @@ namespace Kernel return true; if (m_termios.c_oflag & OPOST) { - if ((m_termios.c_oflag & ONLCR) && ch == '\n') - return putchar_impl('\r') && putchar_impl('\n'); - if ((m_termios.c_oflag & OCRNL) && ch == '\r') - return putchar_impl('\n'); + if ((m_termios.c_oflag & ONLCR) && ch == NL) + return putchar_impl(CR) && putchar_impl(NL); + if ((m_termios.c_oflag & OCRNL) && ch == CR) + return putchar_impl(NL); } return putchar_impl(ch); } @@ -372,7 +407,7 @@ namespace Kernel size_t to_copy = max_to_copy; if (m_termios.c_lflag & ICANON) for (to_copy = 1; to_copy < max_to_copy; to_copy++) - if (m_output.buffer[to_copy - 1] == '\n') + if (m_output.buffer[to_copy - 1] == NL) break; memcpy(buffer.data(), m_output.buffer.data(), to_copy); diff --git a/kernel/kernel/Terminal/VirtualTTY.cpp b/kernel/kernel/Terminal/VirtualTTY.cpp index 8bf3a572..7cbaebcd 100644 --- a/kernel/kernel/Terminal/VirtualTTY.cpp +++ b/kernel/kernel/Terminal/VirtualTTY.cpp @@ -40,8 +40,8 @@ namespace Kernel .c_iflag = 0, .c_oflag = 0, .c_cflag = CS8, - .c_lflag = ECHO | ICANON, - .c_cc = {}, + .c_lflag = ECHO | ICANON | ISIG, + .c_cc = TTY_DEFAULT_TERMIOS_CC, .c_ospeed = B38400, .c_ispeed = B38400, }, 0600, 0, 0)