From 4a0652684c053da1cb1ad435d71ad272c6330dad Mon Sep 17 00:00:00 2001 From: Bananymous Date: Tue, 5 Sep 2023 00:05:49 +0300 Subject: [PATCH] Kernel: You can now read serial output from the /dev/ttyS* --- kernel/include/kernel/Terminal/Serial.h | 2 + kernel/include/kernel/Terminal/TTY.h | 3 +- kernel/kernel/Terminal/Serial.cpp | 86 +++++++++++++++++++++---- kernel/kernel/Terminal/TTY.cpp | 11 +++- 4 files changed, 85 insertions(+), 17 deletions(-) diff --git a/kernel/include/kernel/Terminal/Serial.h b/kernel/include/kernel/Terminal/Serial.h index 64944310..4ddd28fb 100644 --- a/kernel/include/kernel/Terminal/Serial.h +++ b/kernel/include/kernel/Terminal/Serial.h @@ -43,6 +43,8 @@ namespace Kernel virtual uint32_t height() const override; virtual void putchar(uint8_t) override; + virtual void update() override; + private: SerialTTY(Serial); bool initialize(); diff --git a/kernel/include/kernel/Terminal/TTY.h b/kernel/include/kernel/Terminal/TTY.h index 0a37f04b..f3261953 100644 --- a/kernel/include/kernel/Terminal/TTY.h +++ b/kernel/include/kernel/Terminal/TTY.h @@ -29,6 +29,7 @@ namespace Kernel static void initialize_devices(); void on_key_event(Input::KeyEvent); + void handle_input(const uint8_t* ch); virtual bool is_tty() const override { return true; } @@ -50,7 +51,7 @@ namespace Kernel void do_backspace(); protected: - mutable Kernel::SpinLock m_lock; + mutable Kernel::RecursiveSpinLock m_lock; TerminalDriver::Color m_foreground { TerminalColor::BRIGHT_WHITE }; TerminalDriver::Color m_background { TerminalColor::BLACK }; diff --git a/kernel/kernel/Terminal/Serial.cpp b/kernel/kernel/Terminal/Serial.cpp index a08d1622..c97132f0 100644 --- a/kernel/kernel/Terminal/Serial.cpp +++ b/kernel/kernel/Terminal/Serial.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include #include #include @@ -24,6 +26,11 @@ #define PARITY_MARK (0b101 << 3) #define PARITY_SPACE (0b111 << 3) +#define COM1_PORT 0x3F8 +#define COM2_PORT 0x2F8 +#define COM1_IRQ 4 +#define COM2_IRQ 3 + namespace Kernel { @@ -31,20 +38,35 @@ namespace Kernel static BAN::Array s_serial_drivers; static bool s_has_devices { false }; + static BAN::CircularQueue s_com1_input; + static BAN::CircularQueue s_com2_input; + static BAN::RefPtr s_com1; + static BAN::RefPtr s_com2; + static void irq3_handler() { if (!s_serial_drivers[1].is_valid()) return; - uint8_t ch = IO::inb(s_serial_drivers[1].port()); - Debug::putchar(ch); + uint8_t ch = IO::inb(COM2_PORT); + if (s_com2_input.full()) + { + dwarnln("COM2 buffer full"); + s_com2_input.pop(); + } + s_com2_input.push(ch); } static void irq4_handler() { if (!s_serial_drivers[0].is_valid()) return; - uint8_t ch = IO::inb(s_serial_drivers[0].port()); - Debug::putchar(ch); + uint8_t ch = IO::inb(COM1_PORT); + if (s_com1_input.full()) + { + dwarnln("COM1 buffer full"); + s_com1_input.pop(); + } + s_com1_input.push(ch); } static dev_t next_rdev() @@ -71,7 +93,8 @@ namespace Kernel s_has_devices = !!count; for (auto& driver : s_serial_drivers) - dprintln("{}x{} serial device at 0x{H}", driver.width(), driver.height(), driver.port()); + if (driver.is_valid()) + dprintln("{}x{} serial device at 0x{H}", driver.width(), driver.height(), driver.port()); } void Serial::initialize_devices() @@ -192,17 +215,17 @@ namespace Kernel ASSERT(tty); // Enable interrupts for COM1 and COM2 - if (serial.port() == s_serial_ports[0]) + if (serial.port() == COM1_PORT) { - IO::outb(serial.port() + 1, 1); - InterruptController::get().enable_irq(4); - IDT::register_irq_handler(4, irq4_handler); + IO::outb(COM1_PORT + 1, 1); + InterruptController::get().enable_irq(COM1_IRQ); + IDT::register_irq_handler(COM1_IRQ, irq4_handler); } - else if (serial.port() == s_serial_ports[1]) + else if (serial.port() == COM2_PORT) { - IO::outb(serial.port() + 1, 1); - InterruptController::get().enable_irq(3); - IDT::register_irq_handler(3, irq3_handler); + IO::outb(COM2_PORT + 1, 1); + InterruptController::get().enable_irq(COM2_IRQ); + IDT::register_irq_handler(COM2_IRQ, irq3_handler); } ASSERT(minor(tty->rdev()) < 10); @@ -210,8 +233,45 @@ namespace Kernel auto ref_ptr = BAN::RefPtr::adopt(tty); DevFileSystem::get().add_device(name, ref_ptr); + if (serial.port() == COM1_PORT) + s_com1 = ref_ptr; + if (serial.port() == COM2_PORT) + s_com2 = ref_ptr; return ref_ptr; } + + void SerialTTY::update() + { + if (m_serial.port() != COM1_PORT && m_serial.port() != COM2_PORT) + return; + + auto update_com = + [&](auto& device, auto& input_queue) + { + if (input_queue.empty()) + return; + uint8_t buffer[128]; + uint8_t* ptr = buffer; + while (!input_queue.empty()) + { + *ptr = input_queue.front(); + if (*ptr == '\r') + *ptr = '\n'; + if (*ptr == 127) + *ptr++ = '\b', *ptr++ = ' ', *ptr = '\b'; + input_queue.pop(); + ptr++; + } + *ptr = '\0'; + device->handle_input(buffer); + }; + + CriticalScope _; + if (m_serial.port() == COM1_PORT) + update_com(s_com1, s_com1_input); + if (m_serial.port() == COM2_PORT) + update_com(s_com2, s_com2_input); + } uint32_t SerialTTY::width() const { diff --git a/kernel/kernel/Terminal/TTY.cpp b/kernel/kernel/Terminal/TTY.cpp index 879de51a..28fd2d8d 100644 --- a/kernel/kernel/Terminal/TTY.cpp +++ b/kernel/kernel/Terminal/TTY.cpp @@ -132,11 +132,16 @@ namespace Kernel } } - const uint8_t* ansi = (const uint8_t*)ansi_c_str; + handle_input((const uint8_t*)ansi_c_str); + } + + void TTY::handle_input(const uint8_t* ansi) + { + LockGuard _(m_lock); bool eof = ansi && ( - ansi[0] == '\x04' || // ^D - ansi[0] == '\n' // \n + ansi[0] == '\x04' || // ^D + ansi[0] == '\n' // \n ); if (ansi && m_termios.canonical)