diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 72c04b85a3..3c767fe401 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -44,7 +44,6 @@ set(KERNEL_SOURCES kernel/Process.cpp kernel/Scheduler.cpp kernel/Semaphore.cpp - kernel/Serial.cpp kernel/SpinLock.cpp kernel/SSP.cpp kernel/Storage/ATABus.cpp @@ -54,8 +53,10 @@ set(KERNEL_SOURCES kernel/Storage/StorageDevice.cpp kernel/Syscall.cpp kernel/Syscall.S + kernel/Terminal/Serial.cpp kernel/Terminal/TTY.cpp kernel/Terminal/VesaTerminalDriver.cpp + kernel/Terminal/VirtualTTY.cpp kernel/Thread.cpp kernel/Timer/HPET.cpp kernel/Timer/PIT.cpp diff --git a/kernel/include/kernel/FS/DevFS/FileSystem.h b/kernel/include/kernel/FS/DevFS/FileSystem.h index 97ec1fa1de..f6c6955da6 100644 --- a/kernel/include/kernel/FS/DevFS/FileSystem.h +++ b/kernel/include/kernel/FS/DevFS/FileSystem.h @@ -16,7 +16,7 @@ namespace Kernel void add_device(BAN::StringView path, BAN::RefPtr); - dev_t get_next_rdev(); + dev_t get_next_dev(); private: DevFileSystem(size_t size) diff --git a/kernel/include/kernel/Serial.h b/kernel/include/kernel/Serial.h deleted file mode 100644 index 2b1afe8b8c..0000000000 --- a/kernel/include/kernel/Serial.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include - -namespace Kernel -{ - - class Serial - { - public: - static void initialize(); - static bool has_devices(); - static void putchar_any(char); - - void putchar(char); - - private: - static bool port_has_device(uint16_t); - - bool is_transmit_empty() const; - - bool is_valid() const { return m_port != 0; } - - private: - uint16_t m_port { 0 }; - }; - -} \ No newline at end of file diff --git a/kernel/include/kernel/Terminal/Serial.h b/kernel/include/kernel/Terminal/Serial.h new file mode 100644 index 0000000000..8473ebf339 --- /dev/null +++ b/kernel/include/kernel/Terminal/Serial.h @@ -0,0 +1,58 @@ +#pragma once + +#include +#include + +namespace Kernel +{ + + class Serial + { + public: + static void initialize(); + static bool has_devices(); + static void putchar_any(char); + + static void initialize_devices(); + + void putchar(char); + char getchar(); + + uint16_t port() const { return m_port; } + uint32_t width() const { return m_width; } + uint32_t height() const { return m_height; } + + private: + static bool port_has_device(uint16_t); + bool initialize_size(); + bool is_valid() const { return m_port != 0; } + + private: + uint16_t m_port { 0 }; + uint32_t m_width { 0 }; + uint32_t m_height { 0 }; + }; + + class SerialTTY final : public TTY + { + public: + static BAN::ErrorOr> create(Serial); + + virtual uint32_t width() const override; + virtual uint32_t height() const override; + virtual void putchar(uint8_t) override; + + private: + SerialTTY(Serial); + bool initialize(); + + private: + Serial m_serial; + + public: + virtual dev_t rdev() const override { return m_rdev; } + private: + const dev_t m_rdev; + }; + +} \ No newline at end of file diff --git a/kernel/include/kernel/Terminal/TTY.h b/kernel/include/kernel/Terminal/TTY.h index b422f13bea..0a37f04bab 100644 --- a/kernel/include/kernel/Terminal/TTY.h +++ b/kernel/include/kernel/Terminal/TTY.h @@ -10,18 +10,13 @@ namespace Kernel { - + class TTY : public CharacterDevice { public: - TTY(TerminalDriver*); - void set_termios(const termios& termios) { m_termios = termios; } termios get_termios() const { return m_termios; } - void set_font(const Kernel::Font&); - - uint32_t height() const { return m_height; } - uint32_t width() const { return m_width; } + virtual void set_font(const Font&) {}; void set_foreground_pgrp(pid_t pgrp) { m_foreground_pgrp = pgrp; } pid_t foreground_pgrp() const { return m_foreground_pgrp; } @@ -30,80 +25,40 @@ namespace Kernel static void putchar_current(uint8_t ch); static bool is_initialized(); static BAN::RefPtr current(); + void set_as_current(); - void initialize_device(); + static void initialize_devices(); + void on_key_event(Input::KeyEvent); + + virtual bool is_tty() const override { return true; } virtual BAN::ErrorOr read(size_t, void*, size_t) override; virtual BAN::ErrorOr write(size_t, const void*, size_t) override; - virtual bool has_data() const override; + + virtual uint32_t height() const = 0; + virtual uint32_t width() const = 0; + virtual void putchar(uint8_t ch) = 0; + + bool has_data() const; + + protected: + TTY(mode_t mode, uid_t uid, gid_t gid) + : CharacterDevice(mode, uid, gid) + { } private: - void clear(); - void putchar(uint8_t ch); - void reset_ansi(); - void handle_ansi_csi(uint8_t ch); - void handle_ansi_csi_color(); - void putchar_at(uint32_t codepoint, uint32_t x, uint32_t y); - void render_from_buffer(uint32_t x, uint32_t y); - void set_cursor_position(uint32_t x, uint32_t y); - - void on_key(Input::KeyEvent); void do_backspace(); - private: - enum class State - { - Normal, - WaitingAnsiEscape, - WaitingAnsiCSI, - WaitingUTF8, - }; - - struct AnsiState - { - int32_t nums[2] { -1, -1 }; - int32_t index { 0 }; - bool question { false }; - }; - - struct UTF8State - { - uint32_t codepoint { 0 }; - uint8_t bytes_missing { 0 }; - }; - - struct Cell - { - TerminalDriver::Color foreground { TerminalColor::BRIGHT_WHITE }; - TerminalDriver::Color background { TerminalColor::BLACK }; - uint32_t codepoint { ' ' }; - }; - - private: + protected: mutable Kernel::SpinLock m_lock; - State m_state { State::Normal }; - AnsiState m_ansi_state { }; - UTF8State m_utf8_state { }; - - uint32_t m_width { 0 }; - uint32_t m_height { 0 }; - - uint32_t m_saved_row { 0 }; - uint32_t m_saved_column { 0 }; - - uint32_t m_row { 0 }; - uint32_t m_column { 0 }; - Cell* m_buffer { nullptr }; - bool m_show_cursor { true }; - TerminalDriver::Color m_foreground { TerminalColor::BRIGHT_WHITE }; TerminalDriver::Color m_background { TerminalColor::BLACK }; - - pid_t m_foreground_pgrp { 0 }; - termios m_termios; + private: + pid_t m_foreground_pgrp { 0 }; + struct Buffer { BAN::Array buffer; @@ -112,15 +67,6 @@ namespace Kernel Semaphore semaphore; }; Buffer m_output; - - TerminalDriver* m_terminal_driver { nullptr }; - - public: - virtual dev_t rdev() const override { return m_rdev; } - virtual bool is_tty() const override { return true; } - - private: - dev_t m_rdev; }; } diff --git a/kernel/include/kernel/Terminal/VirtualTTY.h b/kernel/include/kernel/Terminal/VirtualTTY.h new file mode 100644 index 0000000000..9d391f9491 --- /dev/null +++ b/kernel/include/kernel/Terminal/VirtualTTY.h @@ -0,0 +1,90 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Kernel +{ + + class VirtualTTY : public TTY + { + public: + static BAN::ErrorOr> create(TerminalDriver*); + + virtual void set_font(const Font&) override; + + virtual uint32_t height() const override { return m_height; } + virtual uint32_t width() const override { return m_width; } + virtual void putchar(uint8_t ch) override; + + private: + VirtualTTY(TerminalDriver*); + + void clear(); + void reset_ansi(); + void handle_ansi_csi(uint8_t ch); + void handle_ansi_csi_color(); + void putchar_at(uint32_t codepoint, uint32_t x, uint32_t y); + void render_from_buffer(uint32_t x, uint32_t y); + void set_cursor_position(uint32_t x, uint32_t y); + + private: + enum class State + { + Normal, + WaitingAnsiEscape, + WaitingAnsiCSI, + WaitingUTF8, + }; + + struct AnsiState + { + int32_t nums[2] { -1, -1 }; + int32_t index { 0 }; + bool question { false }; + }; + + struct UTF8State + { + uint32_t codepoint { 0 }; + uint8_t bytes_missing { 0 }; + }; + + struct Cell + { + TerminalDriver::Color foreground { TerminalColor::BRIGHT_WHITE }; + TerminalDriver::Color background { TerminalColor::BLACK }; + uint32_t codepoint { ' ' }; + }; + + private: + State m_state { State::Normal }; + AnsiState m_ansi_state { }; + UTF8State m_utf8_state { }; + + uint32_t m_width { 0 }; + uint32_t m_height { 0 }; + + uint32_t m_saved_row { 0 }; + uint32_t m_saved_column { 0 }; + + uint32_t m_row { 0 }; + uint32_t m_column { 0 }; + Cell* m_buffer { nullptr }; + bool m_show_cursor { true }; + + TerminalDriver* m_terminal_driver { nullptr }; + + public: + virtual dev_t rdev() const override { return m_rdev; } + private: + const dev_t m_rdev; + }; + +} diff --git a/kernel/kernel/Debug.cpp b/kernel/kernel/Debug.cpp index a965db645c..25e125d782 100644 --- a/kernel/kernel/Debug.cpp +++ b/kernel/kernel/Debug.cpp @@ -1,8 +1,8 @@ #include #include #include -#include #include +#include #include #include diff --git a/kernel/kernel/Device/NullDevice.cpp b/kernel/kernel/Device/NullDevice.cpp index a31d2777cc..bcb19aa788 100644 --- a/kernel/kernel/Device/NullDevice.cpp +++ b/kernel/kernel/Device/NullDevice.cpp @@ -6,7 +6,7 @@ namespace Kernel BAN::ErrorOr> NullDevice::create(mode_t mode, uid_t uid, gid_t gid) { - auto* result = new NullDevice(mode, uid, gid, DevFileSystem::get().get_next_rdev()); + auto* result = new NullDevice(mode, uid, gid, DevFileSystem::get().get_next_dev()); if (result == nullptr) return BAN::Error::from_errno(ENOMEM); return BAN::RefPtr::adopt(result); diff --git a/kernel/kernel/FS/DevFS/FileSystem.cpp b/kernel/kernel/FS/DevFS/FileSystem.cpp index 95c5ce358a..9d12384693 100644 --- a/kernel/kernel/FS/DevFS/FileSystem.cpp +++ b/kernel/kernel/FS/DevFS/FileSystem.cpp @@ -58,10 +58,10 @@ namespace Kernel MUST(reinterpret_cast(root_inode().ptr())->add_inode(path, device)); } - dev_t DevFileSystem::get_next_rdev() + dev_t DevFileSystem::get_next_dev() { - static dev_t next_rdev = 1; - return next_rdev++; + static dev_t next_dev = 1; + return next_dev++; } } \ No newline at end of file diff --git a/kernel/kernel/Input/PS2Keyboard.cpp b/kernel/kernel/Input/PS2Keyboard.cpp index 1e1e208574..566e0ffbd9 100644 --- a/kernel/kernel/Input/PS2Keyboard.cpp +++ b/kernel/kernel/Input/PS2Keyboard.cpp @@ -54,7 +54,7 @@ namespace Kernel::Input PS2Keyboard::PS2Keyboard(PS2Controller& controller) : m_controller(controller) - , m_rdev(makedev(DevFileSystem::get().get_next_rdev(), 0)) + , m_rdev(makedev(DevFileSystem::get().get_next_dev(), 0)) { } void PS2Keyboard::on_byte(uint8_t byte) diff --git a/kernel/kernel/Serial.cpp b/kernel/kernel/Serial.cpp deleted file mode 100644 index 87491202d4..0000000000 --- a/kernel/kernel/Serial.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include -#include -#include - -#define COM1_PORT 0x3f8 - -namespace Kernel -{ - - static constexpr uint16_t s_serial_ports[] = { 0x3F8, 0x2F8, 0x3E8, 0x2E8, 0x5F8, 0x4F8, 0x5E8, 0x4E8 }; - static BAN::Array s_serial_devices; - static bool s_has_devices { false }; - - void Serial::initialize() - { - int count = 0; - for (size_t i = 0; i < s_serial_devices.size(); i++) - { - if (port_has_device(s_serial_ports[i])) - { - s_serial_devices[i].m_port = s_serial_ports[i]; - count++; - } - } - s_has_devices = !!count; - dprintln("Initialized {} serial devices", count); - } - - bool Serial::port_has_device(uint16_t port) - { - IO::outb(port + 1, 0x00); // Disable all interrupts - IO::outb(port + 3, 0x80); // Enable DLAB (set baud rate divisor) - IO::outb(port + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud - IO::outb(port + 1, 0x00); // (hi byte) - IO::outb(port + 3, 0x03); // 8 bits, no parity, one stop bit - IO::outb(port + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold - IO::outb(port + 4, 0x0B); // IRQs enabled, RTS/DSR set - IO::outb(port + 4, 0x1E); // Set in loopback mode, test the serial chip - IO::outb(port + 0, 0xAE); // Test serial chip (send byte 0xAE and check if serial returns same byte) - - // Check if serial is faulty (i.e: not same byte as sent) - if(IO::inb(COM1_PORT + 0) != 0xAE) - return false; - - // If serial is not faulty set it in normal operation mode - // (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled) - IO::outb(port + 4, 0x0F); - - return true; - } - - bool Serial::has_devices() - { - return s_has_devices; - } - - bool Serial::is_transmit_empty() const - { - return !(IO::inb(m_port + 5) & 0x20); - } - - void Serial::putchar(char c) - { - while (is_transmit_empty()) - continue; - IO::outb(m_port, c); - } - - void Serial::putchar_any(char c) - { - for (auto& device : s_serial_devices) - if (device.is_valid()) - device.putchar(c); - } - -} \ No newline at end of file diff --git a/kernel/kernel/Storage/ATAController.cpp b/kernel/kernel/Storage/ATAController.cpp index 0033ef022e..2b7d4ed27d 100644 --- a/kernel/kernel/Storage/ATAController.cpp +++ b/kernel/kernel/Storage/ATAController.cpp @@ -47,7 +47,7 @@ namespace Kernel } ATAController::ATAController() - : m_rdev(makedev(DevFileSystem::get().get_next_rdev(), 0)) + : m_rdev(makedev(DevFileSystem::get().get_next_dev(), 0)) { } BAN::ErrorOr ATAController::initialize(const PCIDevice& pci_device) diff --git a/kernel/kernel/Storage/ATADevice.cpp b/kernel/kernel/Storage/ATADevice.cpp index 70e5c957aa..1186e8955e 100644 --- a/kernel/kernel/Storage/ATADevice.cpp +++ b/kernel/kernel/Storage/ATADevice.cpp @@ -11,7 +11,7 @@ namespace Kernel ATADevice::ATADevice(ATABus& bus) : m_bus(bus) - , m_rdev(makedev(DevFileSystem::get().get_next_rdev(), 0)) + , m_rdev(makedev(DevFileSystem::get().get_next_dev(), 0)) { } BAN::ErrorOr ATADevice::initialize(ATABus::DeviceType type, const uint16_t* identify_buffer) diff --git a/kernel/kernel/Terminal/Serial.cpp b/kernel/kernel/Terminal/Serial.cpp new file mode 100644 index 0000000000..131a2bf6b0 --- /dev/null +++ b/kernel/kernel/Terminal/Serial.cpp @@ -0,0 +1,180 @@ +#include +#include +#include +#include + +#include +#include + +namespace Kernel +{ + + static constexpr uint16_t s_serial_ports[] = { 0x3F8, 0x2F8, 0x3E8, 0x2E8, 0x5F8, 0x4F8, 0x5E8, 0x4E8 }; + static BAN::Array s_serial_drivers; + static bool s_has_devices { false }; + + + static dev_t next_rdev() + { + static dev_t major = DevFileSystem::get().get_next_dev(); + static dev_t minor = 0; + return makedev(major, minor++); + } + + void Serial::initialize() + { + int count = 0; + for (size_t i = 0; i < s_serial_drivers.size(); i++) + { + if (port_has_device(s_serial_ports[i])) + { + auto& driver = s_serial_drivers[i]; + driver.m_port = s_serial_ports[i]; + if (!driver.initialize_size()) + continue; + count++; + } + } + s_has_devices = !!count; + + for (auto& driver : s_serial_drivers) + dprintln("{}x{} serial device at 0x{H}", driver.width(), driver.height(), driver.port()); + } + + void Serial::initialize_devices() + { + for (auto& serial : s_serial_drivers) + if (serial.is_valid()) + MUST(SerialTTY::create(serial)); + } + + bool Serial::port_has_device(uint16_t port) + { + IO::outb(port + 1, 0x00); // Disable all interrupts + IO::outb(port + 3, 0x80); // Enable DLAB (set baud rate divisor) + IO::outb(port + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud + IO::outb(port + 1, 0x00); // (hi byte) + IO::outb(port + 3, 0x03); // 8 bits, no parity, one stop bit + IO::outb(port + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold + IO::outb(port + 4, 0x0B); // IRQs enabled, RTS/DSR set + IO::outb(port + 4, 0x1E); // Set in loopback mode, test the serial chip + IO::outb(port + 0, 0xAE); // Test serial chip (send byte 0xAE and check if serial returns same byte) + + // Check if serial is faulty (i.e: not same byte as sent) + if(IO::inb(port + 0) != 0xAE) + return false; + + // If serial is not faulty set it in normal operation mode + // (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled) + IO::outb(port + 4, 0x0F); + + return true; + } + + bool Serial::initialize_size() + { + const char* query = "\e[999;999H\e[6n\e[H\e[J"; + + const char* ptr = query; + while (*ptr) + putchar(*ptr++); + + if (getchar() != '\033') + return false; + if (getchar() != '[') + return false; + + auto read_number = + [&](char end) + { + uint32_t number = 0; + while (true) + { + char c = getchar(); + if (c == end) + break; + if (!isdigit(c)) + return UINT32_MAX; + number = (number * 10) + (c - '0'); + } + return number; + }; + + m_height = read_number(';'); + if (m_height == UINT32_MAX) + { + m_port = 0; + return false; + } + + m_width = read_number('R'); + if (m_width == UINT32_MAX) + { + m_port = 0; + return false; + } + + return true; + } + + bool Serial::has_devices() + { + return s_has_devices; + } + + void Serial::putchar(char c) + { + while (!(IO::inb(m_port + 5) & 0x20)) + continue; + IO::outb(m_port, c); + } + + char Serial::getchar() + { + while (!(IO::inb(m_port + 5) & 0x01)) + continue; + return IO::inb(m_port); + } + + void Serial::putchar_any(char c) + { + for (auto& device : s_serial_drivers) + if (device.is_valid()) + device.putchar(c); + } + + SerialTTY::SerialTTY(Serial serial) + : TTY(0660, 0, 0) + , m_serial(serial) + , m_rdev(next_rdev()) + {} + + BAN::ErrorOr> SerialTTY::create(Serial serial) + { + auto* tty = new SerialTTY(serial); + ASSERT(tty); + + ASSERT(minor(tty->rdev()) < 10); + char name[] = { 't', 't', 'y', 'S', (char)('0' + minor(tty->rdev())), '\0' }; + + auto ref_ptr = BAN::RefPtr::adopt(tty); + DevFileSystem::get().add_device(name, ref_ptr); + return ref_ptr; + } + + uint32_t SerialTTY::width() const + { + return m_serial.width(); + } + + uint32_t SerialTTY::height() const + { + return m_serial.height(); + } + + void SerialTTY::putchar(uint8_t ch) + { + m_serial.putchar(ch); + } + +} \ No newline at end of file diff --git a/kernel/kernel/Terminal/TTY.cpp b/kernel/kernel/Terminal/TTY.cpp index c9c2b6a20d..879de51a78 100644 --- a/kernel/kernel/Terminal/TTY.cpp +++ b/kernel/kernel/Terminal/TTY.cpp @@ -11,61 +11,28 @@ #include #include -#define BEL 0x07 -#define BS 0x08 -#define HT 0x09 -#define LF 0x0A -#define FF 0x0C -#define CR 0x0D -#define ESC 0x1B - -#define CSI '[' - namespace Kernel { - static Process* s_input_process = nullptr; - - static dev_t next_tty_rdev() - { - static dev_t major = DevFileSystem::get().get_next_rdev(); - static dev_t minor = 0; - return makedev(major, minor++); - } - static BAN::RefPtr s_tty; - TTY::TTY(TerminalDriver* driver) - : CharacterDevice(0666, 0, 0) - , m_terminal_driver(driver) - { - m_width = m_terminal_driver->width(); - m_height = m_terminal_driver->height(); - - m_buffer = new Cell[m_width * m_height]; - ASSERT(m_buffer); - - if (!s_tty) - s_tty = this; - } - BAN::RefPtr TTY::current() { + ASSERT(s_tty); return s_tty; } - void TTY::initialize_device() + void TTY::set_as_current() { - m_rdev = next_tty_rdev(); + s_tty = this; + } - ASSERT(minor(m_rdev) < 10); - char name[5] { 't', 't', 'y', (char)('0' + minor(m_rdev)), '\0' }; + void TTY::initialize_devices() + { + static bool initialized = false; + ASSERT(!initialized); - DevFileSystem::get().add_device(name, BAN::RefPtr::adopt(this)); - - if (s_input_process) - return; - s_input_process = Process::create_kernel( + Process::create_kernel( [](void*) { int fd = MUST(Process::current().sys_open("/dev/input0"sv, O_RDONLY)); @@ -86,13 +53,15 @@ namespace Kernel dwarnln("TTY: {}", ret.error()); } else - current_tty.on_key(event); + current_tty.on_key_event(event); } }, nullptr ); + + initialized = true; } - void TTY::on_key(Input::KeyEvent event) + void TTY::on_key_event(Input::KeyEvent event) { LockGuard _(m_lock); @@ -249,24 +218,14 @@ flush: } } - void TTY::clear() - { - for (uint32_t i = 0; i < m_width * m_height; i++) - m_buffer[i] = { .foreground = m_foreground, .background = m_background, .codepoint = ' ' }; - m_terminal_driver->clear(m_background); - } - void TTY::do_backspace() { auto print_backspace = [this] { - if (m_termios.echo && m_column > 0) - { - m_column--; - putchar_at(' ', m_column, m_row); - set_cursor_position(m_column, m_row); - } + putchar('\b'); + putchar(' '); + putchar('\b'); }; if (m_output.bytes > 0) @@ -302,369 +261,6 @@ flush: } } - void TTY::set_cursor_position(uint32_t x, uint32_t y) - { - static uint32_t last_x = -1; - static uint32_t last_y = -1; - if (last_x != uint32_t(-1) && last_y != uint32_t(-1)) - render_from_buffer(last_x, last_y); - if (m_show_cursor) - m_terminal_driver->set_cursor_position(x, y); - last_x = m_column = x; - last_y = m_row = y; - } - - void TTY::set_font(const Kernel::Font& font) - { - m_terminal_driver->set_font(font); - - uint32_t new_width = m_terminal_driver->width(); - uint32_t new_height = m_terminal_driver->height(); - - if (m_width != new_width || m_height != new_height) - { - Cell* new_buffer = new Cell[new_width * new_height]; - ASSERT(new_buffer); - - for (uint32_t i = 0; i < new_width * m_height; i++) - new_buffer[i] = { .foreground = m_foreground, .background = m_background, .codepoint = ' ' }; - - for (uint32_t y = 0; y < BAN::Math::min(m_height, new_height); y++) - for (uint32_t x = 0; x < BAN::Math::min(m_width, new_width); x++) - new_buffer[y * new_width + x] = m_buffer[y * m_width + x]; - - delete[] m_buffer; - m_buffer = new_buffer; - m_width = new_width; - m_height = new_height; - } - - for (uint32_t y = 0; y < m_height; y++) - for (uint32_t x = 0; x < m_width; x++) - render_from_buffer(x, y); - } - - void TTY::reset_ansi() - { - m_ansi_state.index = 0; - m_ansi_state.nums[0] = -1; - m_ansi_state.nums[1] = -1; - m_ansi_state.question = false; - m_state = State::Normal; - } - - void TTY::handle_ansi_csi_color() - { - switch (m_ansi_state.nums[0]) - { - case -1: - case 0: - m_foreground = TerminalColor::BRIGHT_WHITE; - m_background = TerminalColor::BLACK; - break; - - case 30: m_foreground = TerminalColor::BRIGHT_BLACK; break; - case 31: m_foreground = TerminalColor::BRIGHT_RED; break; - case 32: m_foreground = TerminalColor::BRIGHT_GREEN; break; - case 33: m_foreground = TerminalColor::BRIGHT_YELLOW; break; - case 34: m_foreground = TerminalColor::BRIGHT_BLUE; break; - case 35: m_foreground = TerminalColor::BRIGHT_MAGENTA; break; - case 36: m_foreground = TerminalColor::BRIGHT_CYAN; break; - case 37: m_foreground = TerminalColor::BRIGHT_WHITE; break; - - case 40: m_background = TerminalColor::BRIGHT_BLACK; break; - case 41: m_background = TerminalColor::BRIGHT_RED; break; - case 42: m_background = TerminalColor::BRIGHT_GREEN; break; - case 43: m_background = TerminalColor::BRIGHT_YELLOW; break; - case 44: m_background = TerminalColor::BRIGHT_BLUE; break; - case 45: m_background = TerminalColor::BRIGHT_MAGENTA; break; - case 46: m_background = TerminalColor::BRIGHT_CYAN; break; - case 47: m_background = TerminalColor::BRIGHT_WHITE; break; - } - } - - void TTY::handle_ansi_csi(uint8_t ch) - { - switch (ch) - { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - { - int32_t& val = m_ansi_state.nums[m_ansi_state.index]; - val = (val == -1) ? (ch - '0') : (val * 10 + ch - '0'); - return; - } - case ';': - m_ansi_state.index++; - return; - case 'A': // Cursor Up - if (m_ansi_state.nums[0] == -1) - m_ansi_state.nums[0] = 1; - m_row = BAN::Math::max(m_row - m_ansi_state.nums[0], 0); - return reset_ansi(); - case 'B': // Curson Down - if (m_ansi_state.nums[0] == -1) - m_ansi_state.nums[0] = 1; - m_row = BAN::Math::min(m_row + m_ansi_state.nums[0], m_height - 1); - return reset_ansi(); - case 'C': // Cursor Forward - if (m_ansi_state.nums[0] == -1) - m_ansi_state.nums[0] = 1; - m_column = BAN::Math::min(m_column + m_ansi_state.nums[0], m_width - 1); - return reset_ansi(); - case 'D': // Cursor Back - if (m_ansi_state.nums[0] == -1) - m_ansi_state.nums[0] = 1; - m_column = BAN::Math::max(m_column - m_ansi_state.nums[0], 0); - return reset_ansi(); - case 'E': // Cursor Next Line - if (m_ansi_state.nums[0] == -1) - m_ansi_state.nums[0] = 1; - m_row = BAN::Math::min(m_row + m_ansi_state.nums[0], m_height - 1); - m_column = 0; - return reset_ansi(); - case 'F': // Cursor Previous Line - if (m_ansi_state.nums[0] == -1) - m_ansi_state.nums[0] = 1; - m_row = BAN::Math::max(m_row - m_ansi_state.nums[0], 0); - m_column = 0; - return reset_ansi(); - case 'G': // Cursor Horizontal Absolute - if (m_ansi_state.nums[0] == -1) - m_ansi_state.nums[0] = 1; - m_column = BAN::Math::clamp(m_ansi_state.nums[0] - 1, 0, m_width - 1); - return reset_ansi(); - case 'H': // Cursor Position - if (m_ansi_state.nums[0] == -1) - m_ansi_state.nums[0] = 1; - if (m_ansi_state.nums[1] == -1) - m_ansi_state.nums[1] = 1; - m_row = BAN::Math::clamp(m_ansi_state.nums[0] - 1, 0, m_height - 1); - m_column = BAN::Math::clamp(m_ansi_state.nums[1] - 1, 0, m_width - 1); - return reset_ansi(); - case 'J': // Erase in Display - if (m_ansi_state.nums[0] == -1 || m_ansi_state.nums[0] == 0) - { - // Clear from cursor to the end of screen - for (uint32_t i = m_column; i < m_width; i++) - putchar_at(' ', i, m_row); - for (uint32_t row = 0; row < m_height; row++) - for (uint32_t col = 0; col < m_width; col++) - putchar_at(' ', col, row); - } - else if (m_ansi_state.nums[0] == 1) - { - // Clear from cursor to the beginning of screen - for (uint32_t row = 0; row < m_row; row++) - for (uint32_t col = 0; col < m_width; col++) - putchar_at(' ', col, row); - for (uint32_t i = 0; i <= m_column; i++) - putchar_at(' ', i, m_row); - } - else if (m_ansi_state.nums[0] == 2 || m_ansi_state.nums[0] == 3) - { - // Clean entire screen - clear(); - } - else - { - dprintln("Unsupported ANSI CSI character J"); - } - - if (m_ansi_state.nums[0] == 3) - { - // FIXME: Clear scroll backbuffer if/when added - } - return reset_ansi(); - case 'K': // Erase in Line - if (m_ansi_state.nums[0] == -1 || m_ansi_state.nums[0] == 0) - for (uint32_t i = m_column; i < m_width; i++) - putchar_at(' ', i, m_row); - else - dprintln("Unsupported ANSI CSI character K"); - return reset_ansi(); - case 'S': // Scroll Up - dprintln("Unsupported ANSI CSI character S"); - return reset_ansi(); - case 'T': // Scroll Down - dprintln("Unsupported ANSI CSI character T"); - return reset_ansi(); - case 'f': // Horizontal Vertical Position - dprintln("Unsupported ANSI CSI character f"); - return reset_ansi(); - case 'm': - handle_ansi_csi_color(); - return reset_ansi(); - case 's': - m_saved_row = m_row; - m_saved_column = m_column; - return reset_ansi(); - case 'u': - m_row = m_saved_row; - m_column = m_saved_column; - return reset_ansi(); - - case '?': - if (m_ansi_state.index != 0 || m_ansi_state.nums[0] != -1) - { - dprintln("invalid ANSI CSI ?"); - return reset_ansi(); - } - m_ansi_state.question = true; - return; - case 'h': - case 'l': - if (!m_ansi_state.question || m_ansi_state.nums[0] != 25) - { - dprintln("invalid ANSI CSI ?{}{}", m_ansi_state.nums[0], (char)ch); - return reset_ansi(); - } - m_show_cursor = (ch == 'h'); - return reset_ansi(); - default: - dprintln("Unsupported ANSI CSI character {}", ch); - return reset_ansi(); - } - } - - void TTY::render_from_buffer(uint32_t x, uint32_t y) - { - ASSERT(x < m_width && y < m_height); - const auto& cell = m_buffer[y * m_width + x]; - m_terminal_driver->putchar_at(cell.codepoint, x, y, cell.foreground, cell.background); - } - - void TTY::putchar_at(uint32_t codepoint, uint32_t x, uint32_t y) - { - ASSERT(x < m_width && y < m_height); - auto& cell = m_buffer[y * m_width + x]; - cell.codepoint = codepoint; - cell.foreground = m_foreground; - cell.background = m_background; - m_terminal_driver->putchar_at(codepoint, x, y, m_foreground, m_background); - } - - void TTY::putchar(uint8_t ch) - { - ASSERT(m_lock.is_locked()); - - uint32_t codepoint = ch; - - switch (m_state) - { - case State::Normal: - if ((ch & 0x80) == 0) - break; - if ((ch & 0xE0) == 0xC0) - { - m_utf8_state.codepoint = ch & 0x1F; - m_utf8_state.bytes_missing = 1; - } - else if ((ch & 0xF0) == 0xE0) - { - m_utf8_state.codepoint = ch & 0x0F; - m_utf8_state.bytes_missing = 2; - } - else if ((ch & 0xF8) == 0xF0) - { - m_utf8_state.codepoint = ch & 0x07; - m_utf8_state.bytes_missing = 3; - } - else - { - dprintln("invalid utf8"); - } - m_state = State::WaitingUTF8; - return; - case State::WaitingAnsiEscape: - if (ch == CSI) - m_state = State::WaitingAnsiCSI; - else - { - dprintln("unsupported byte after ansi escape {2H}", (uint8_t)ch); - reset_ansi(); - } - return; - case State::WaitingAnsiCSI: - handle_ansi_csi(ch); - set_cursor_position(m_column, m_row); - return; - case State::WaitingUTF8: - if ((ch & 0xC0) != 0x80) - { - dprintln("invalid utf8"); - m_state = State::Normal; - return; - } - m_utf8_state.codepoint = (m_utf8_state.codepoint << 6) | (ch & 0x3F); - m_utf8_state.bytes_missing--; - if (m_utf8_state.bytes_missing) - return; - m_state = State::Normal; - codepoint = m_utf8_state.codepoint; - break; - default: - ASSERT_NOT_REACHED(); - } - - switch (codepoint) - { - case BEL: // TODO - break; - case BS: - if (m_column > 0) - m_column--; - break; - case HT: - m_column++; - while (m_column % 8) - m_column++; - break; - case LF: - m_column = 0; - m_row++; - break; - case FF: - m_row++; - break; - case CR: - m_column = 0; - break; - case ESC: - m_state = State::WaitingAnsiEscape; - break;; - default: - putchar_at(codepoint, m_column, m_row); - m_column++; - break; - } - - if (m_column >= m_width) - { - m_column = 0; - m_row++; - } - - while (m_row >= m_height) - { - memmove(m_buffer, m_buffer + m_width, m_width * (m_height - 1) * sizeof(Cell)); - - // Clear last line in buffer - for (uint32_t x = 0; x < m_width; x++) - m_buffer[(m_height - 1) * m_width + x] = { .foreground = m_foreground, .background = m_background, .codepoint = ' ' }; - - // Render the whole buffer to the screen - for (uint32_t y = 0; y < m_height; y++) - for (uint32_t x = 0; x < m_width; x++) - render_from_buffer(x, y); - - m_column = 0; - m_row--; - } - - set_cursor_position(m_column, m_row); - } - BAN::ErrorOr TTY::read(size_t, void* buffer, size_t count) { m_lock.lock(); diff --git a/kernel/kernel/Terminal/VirtualTTY.cpp b/kernel/kernel/Terminal/VirtualTTY.cpp new file mode 100644 index 0000000000..4bed338468 --- /dev/null +++ b/kernel/kernel/Terminal/VirtualTTY.cpp @@ -0,0 +1,429 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define BEL 0x07 +#define BS 0x08 +#define HT 0x09 +#define LF 0x0A +#define FF 0x0C +#define CR 0x0D +#define ESC 0x1B + +#define CSI '[' + +namespace Kernel +{ + + static dev_t next_rdev() + { + static dev_t major = DevFileSystem::get().get_next_dev(); + static dev_t minor = 0; + return makedev(major, minor++); + } + + BAN::ErrorOr> VirtualTTY::create(TerminalDriver* driver) + { + auto* tty = new VirtualTTY(driver); + ASSERT(tty); + + ASSERT(minor(tty->rdev()) < 10); + char name[5] { 't', 't', 'y', (char)('0' + minor(tty->rdev())), '\0' }; + + auto ref_ptr = BAN::RefPtr::adopt(tty); + DevFileSystem::get().add_device(name, ref_ptr); + return ref_ptr; + } + + VirtualTTY::VirtualTTY(TerminalDriver* driver) + : TTY(0666, 0, 0) + , m_terminal_driver(driver) + , m_rdev(next_rdev()) + { + m_width = m_terminal_driver->width(); + m_height = m_terminal_driver->height(); + + m_buffer = new Cell[m_width * m_height]; + ASSERT(m_buffer); + } + + void VirtualTTY::clear() + { + for (uint32_t i = 0; i < m_width * m_height; i++) + m_buffer[i] = { .foreground = m_foreground, .background = m_background, .codepoint = ' ' }; + m_terminal_driver->clear(m_background); + } + + void VirtualTTY::set_font(const Kernel::Font& font) + { + m_terminal_driver->set_font(font); + + uint32_t new_width = m_terminal_driver->width(); + uint32_t new_height = m_terminal_driver->height(); + + if (m_width != new_width || m_height != new_height) + { + Cell* new_buffer = new Cell[new_width * new_height]; + ASSERT(new_buffer); + + for (uint32_t i = 0; i < new_width * m_height; i++) + new_buffer[i] = { .foreground = m_foreground, .background = m_background, .codepoint = ' ' }; + + for (uint32_t y = 0; y < BAN::Math::min(m_height, new_height); y++) + for (uint32_t x = 0; x < BAN::Math::min(m_width, new_width); x++) + new_buffer[y * new_width + x] = m_buffer[y * m_width + x]; + + delete[] m_buffer; + m_buffer = new_buffer; + m_width = new_width; + m_height = new_height; + } + + for (uint32_t y = 0; y < m_height; y++) + for (uint32_t x = 0; x < m_width; x++) + render_from_buffer(x, y); + } + + void VirtualTTY::set_cursor_position(uint32_t x, uint32_t y) + { + static uint32_t last_x = -1; + static uint32_t last_y = -1; + if (last_x != uint32_t(-1) && last_y != uint32_t(-1)) + render_from_buffer(last_x, last_y); + if (m_show_cursor) + m_terminal_driver->set_cursor_position(x, y); + last_x = m_column = x; + last_y = m_row = y; + } + + void VirtualTTY::reset_ansi() + { + m_ansi_state.index = 0; + m_ansi_state.nums[0] = -1; + m_ansi_state.nums[1] = -1; + m_ansi_state.question = false; + m_state = State::Normal; + } + + void VirtualTTY::handle_ansi_csi_color() + { + switch (m_ansi_state.nums[0]) + { + case -1: + case 0: + m_foreground = TerminalColor::BRIGHT_WHITE; + m_background = TerminalColor::BLACK; + break; + + case 30: m_foreground = TerminalColor::BRIGHT_BLACK; break; + case 31: m_foreground = TerminalColor::BRIGHT_RED; break; + case 32: m_foreground = TerminalColor::BRIGHT_GREEN; break; + case 33: m_foreground = TerminalColor::BRIGHT_YELLOW; break; + case 34: m_foreground = TerminalColor::BRIGHT_BLUE; break; + case 35: m_foreground = TerminalColor::BRIGHT_MAGENTA; break; + case 36: m_foreground = TerminalColor::BRIGHT_CYAN; break; + case 37: m_foreground = TerminalColor::BRIGHT_WHITE; break; + + case 40: m_background = TerminalColor::BRIGHT_BLACK; break; + case 41: m_background = TerminalColor::BRIGHT_RED; break; + case 42: m_background = TerminalColor::BRIGHT_GREEN; break; + case 43: m_background = TerminalColor::BRIGHT_YELLOW; break; + case 44: m_background = TerminalColor::BRIGHT_BLUE; break; + case 45: m_background = TerminalColor::BRIGHT_MAGENTA; break; + case 46: m_background = TerminalColor::BRIGHT_CYAN; break; + case 47: m_background = TerminalColor::BRIGHT_WHITE; break; + } + } + + void VirtualTTY::handle_ansi_csi(uint8_t ch) + { + switch (ch) + { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + int32_t& val = m_ansi_state.nums[m_ansi_state.index]; + val = (val == -1) ? (ch - '0') : (val * 10 + ch - '0'); + return; + } + case ';': + m_ansi_state.index++; + return; + case 'A': // Cursor Up + if (m_ansi_state.nums[0] == -1) + m_ansi_state.nums[0] = 1; + m_row = BAN::Math::max(m_row - m_ansi_state.nums[0], 0); + return reset_ansi(); + case 'B': // Curson Down + if (m_ansi_state.nums[0] == -1) + m_ansi_state.nums[0] = 1; + m_row = BAN::Math::min(m_row + m_ansi_state.nums[0], m_height - 1); + return reset_ansi(); + case 'C': // Cursor Forward + if (m_ansi_state.nums[0] == -1) + m_ansi_state.nums[0] = 1; + m_column = BAN::Math::min(m_column + m_ansi_state.nums[0], m_width - 1); + return reset_ansi(); + case 'D': // Cursor Back + if (m_ansi_state.nums[0] == -1) + m_ansi_state.nums[0] = 1; + m_column = BAN::Math::max(m_column - m_ansi_state.nums[0], 0); + return reset_ansi(); + case 'E': // Cursor Next Line + if (m_ansi_state.nums[0] == -1) + m_ansi_state.nums[0] = 1; + m_row = BAN::Math::min(m_row + m_ansi_state.nums[0], m_height - 1); + m_column = 0; + return reset_ansi(); + case 'F': // Cursor Previous Line + if (m_ansi_state.nums[0] == -1) + m_ansi_state.nums[0] = 1; + m_row = BAN::Math::max(m_row - m_ansi_state.nums[0], 0); + m_column = 0; + return reset_ansi(); + case 'G': // Cursor Horizontal Absolute + if (m_ansi_state.nums[0] == -1) + m_ansi_state.nums[0] = 1; + m_column = BAN::Math::clamp(m_ansi_state.nums[0] - 1, 0, m_width - 1); + return reset_ansi(); + case 'H': // Cursor Position + if (m_ansi_state.nums[0] == -1) + m_ansi_state.nums[0] = 1; + if (m_ansi_state.nums[1] == -1) + m_ansi_state.nums[1] = 1; + m_row = BAN::Math::clamp(m_ansi_state.nums[0] - 1, 0, m_height - 1); + m_column = BAN::Math::clamp(m_ansi_state.nums[1] - 1, 0, m_width - 1); + return reset_ansi(); + case 'J': // Erase in Display + if (m_ansi_state.nums[0] == -1 || m_ansi_state.nums[0] == 0) + { + // Clear from cursor to the end of screen + for (uint32_t i = m_column; i < m_width; i++) + putchar_at(' ', i, m_row); + for (uint32_t row = 0; row < m_height; row++) + for (uint32_t col = 0; col < m_width; col++) + putchar_at(' ', col, row); + } + else if (m_ansi_state.nums[0] == 1) + { + // Clear from cursor to the beginning of screen + for (uint32_t row = 0; row < m_row; row++) + for (uint32_t col = 0; col < m_width; col++) + putchar_at(' ', col, row); + for (uint32_t i = 0; i <= m_column; i++) + putchar_at(' ', i, m_row); + } + else if (m_ansi_state.nums[0] == 2 || m_ansi_state.nums[0] == 3) + { + // Clean entire screen + clear(); + } + else + { + dprintln("Unsupported ANSI CSI character J"); + } + + if (m_ansi_state.nums[0] == 3) + { + // FIXME: Clear scroll backbuffer if/when added + } + return reset_ansi(); + case 'K': // Erase in Line + if (m_ansi_state.nums[0] == -1 || m_ansi_state.nums[0] == 0) + for (uint32_t i = m_column; i < m_width; i++) + putchar_at(' ', i, m_row); + else + dprintln("Unsupported ANSI CSI character K"); + return reset_ansi(); + case 'S': // Scroll Up + dprintln("Unsupported ANSI CSI character S"); + return reset_ansi(); + case 'T': // Scroll Down + dprintln("Unsupported ANSI CSI character T"); + return reset_ansi(); + case 'f': // Horizontal Vertical Position + dprintln("Unsupported ANSI CSI character f"); + return reset_ansi(); + case 'm': + handle_ansi_csi_color(); + return reset_ansi(); + case 's': + m_saved_row = m_row; + m_saved_column = m_column; + return reset_ansi(); + case 'u': + m_row = m_saved_row; + m_column = m_saved_column; + return reset_ansi(); + + case '?': + if (m_ansi_state.index != 0 || m_ansi_state.nums[0] != -1) + { + dprintln("invalid ANSI CSI ?"); + return reset_ansi(); + } + m_ansi_state.question = true; + return; + case 'h': + case 'l': + if (!m_ansi_state.question || m_ansi_state.nums[0] != 25) + { + dprintln("invalid ANSI CSI ?{}{}", m_ansi_state.nums[0], (char)ch); + return reset_ansi(); + } + m_show_cursor = (ch == 'h'); + return reset_ansi(); + default: + dprintln("Unsupported ANSI CSI character {}", ch); + return reset_ansi(); + } + } + + void VirtualTTY::render_from_buffer(uint32_t x, uint32_t y) + { + ASSERT(x < m_width && y < m_height); + const auto& cell = m_buffer[y * m_width + x]; + m_terminal_driver->putchar_at(cell.codepoint, x, y, cell.foreground, cell.background); + } + + void VirtualTTY::putchar_at(uint32_t codepoint, uint32_t x, uint32_t y) + { + ASSERT(x < m_width && y < m_height); + auto& cell = m_buffer[y * m_width + x]; + cell.codepoint = codepoint; + cell.foreground = m_foreground; + cell.background = m_background; + m_terminal_driver->putchar_at(codepoint, x, y, m_foreground, m_background); + } + + void VirtualTTY::putchar(uint8_t ch) + { + ASSERT(m_lock.is_locked()); + + uint32_t codepoint = ch; + + switch (m_state) + { + case State::Normal: + if ((ch & 0x80) == 0) + break; + if ((ch & 0xE0) == 0xC0) + { + m_utf8_state.codepoint = ch & 0x1F; + m_utf8_state.bytes_missing = 1; + } + else if ((ch & 0xF0) == 0xE0) + { + m_utf8_state.codepoint = ch & 0x0F; + m_utf8_state.bytes_missing = 2; + } + else if ((ch & 0xF8) == 0xF0) + { + m_utf8_state.codepoint = ch & 0x07; + m_utf8_state.bytes_missing = 3; + } + else + { + dprintln("invalid utf8"); + } + m_state = State::WaitingUTF8; + return; + case State::WaitingAnsiEscape: + if (ch == CSI) + m_state = State::WaitingAnsiCSI; + else + { + dprintln("unsupported byte after ansi escape {2H}", (uint8_t)ch); + reset_ansi(); + } + return; + case State::WaitingAnsiCSI: + handle_ansi_csi(ch); + set_cursor_position(m_column, m_row); + return; + case State::WaitingUTF8: + if ((ch & 0xC0) != 0x80) + { + dprintln("invalid utf8"); + m_state = State::Normal; + return; + } + m_utf8_state.codepoint = (m_utf8_state.codepoint << 6) | (ch & 0x3F); + m_utf8_state.bytes_missing--; + if (m_utf8_state.bytes_missing) + return; + m_state = State::Normal; + codepoint = m_utf8_state.codepoint; + break; + default: + ASSERT_NOT_REACHED(); + } + + switch (codepoint) + { + case BEL: // TODO + break; + case BS: + if (m_column > 0) + m_column--; + break; + case HT: + m_column++; + while (m_column % 8) + m_column++; + break; + case LF: + m_column = 0; + m_row++; + break; + case FF: + m_row++; + break; + case CR: + m_column = 0; + break; + case ESC: + m_state = State::WaitingAnsiEscape; + break;; + default: + putchar_at(codepoint, m_column, m_row); + m_column++; + break; + } + + if (m_column >= m_width) + { + m_column = 0; + m_row++; + } + + while (m_row >= m_height) + { + memmove(m_buffer, m_buffer + m_width, m_width * (m_height - 1) * sizeof(Cell)); + + // Clear last line in buffer + for (uint32_t x = 0; x < m_width; x++) + m_buffer[(m_height - 1) * m_width + x] = { .foreground = m_foreground, .background = m_background, .codepoint = ' ' }; + + // Render the whole buffer to the screen + for (uint32_t y = 0; y < m_height; y++) + for (uint32_t x = 0; x < m_width; x++) + render_from_buffer(x, y); + + m_column = 0; + m_row--; + } + + set_cursor_position(m_column, m_row); + } + +} \ No newline at end of file diff --git a/kernel/kernel/kernel.cpp b/kernel/kernel/kernel.cpp index f85ab2341c..35840d7a13 100644 --- a/kernel/kernel/kernel.cpp +++ b/kernel/kernel/kernel.cpp @@ -16,9 +16,9 @@ #include #include #include -#include #include -#include +#include +#include #include #include @@ -28,6 +28,7 @@ struct ParsedCommandLine { bool force_pic = false; bool disable_serial = false; + BAN::StringView console = "tty0"sv; BAN::StringView root; }; @@ -72,30 +73,11 @@ static void parse_command_line() cmdline.disable_serial = true; else if (argument.size() > 5 && argument.substring(0, 5) == "root=") cmdline.root = argument.substring(5); + else if (argument.size() > 8 && argument.substring(0, 8) == "console=") + cmdline.console = argument.substring(8); } } -struct Test -{ - Test() { dprintln("construct (default)"); } - Test(const Test&) { dprintln("construct (copy)"); } - Test(Test&&) { dprintln("construct (move)"); } - ~Test() { dprintln("destruct"); } - Test& operator=(const Test&) { dprintln("assign (copy)"); return *this; } - Test& operator=(Test&&) { dprintln("assign (move)"); return *this; } -}; - -namespace BAN::Formatter -{ - - template - void print_argument(F putc, const Test& test, const ValueFormat& format) - { - print_argument(putc, &test, format); - } - -} - extern "C" uint8_t g_userspace_start[]; extern "C" uint8_t g_userspace_end[]; @@ -112,7 +94,7 @@ extern "C" void kernel_main() Serial::initialize(); dprintln("Serial output initialized"); } - + if (g_multiboot_magic != 0x2BADB002) { dprintln("Invalid multiboot magic number"); @@ -134,16 +116,12 @@ extern "C" void kernel_main() Heap::initialize(); dprintln("Heap initialzed"); - TerminalDriver* terminal_driver = VesaTerminalDriver::create(); - ASSERT(terminal_driver); - dprintln("VESA initialized"); + parse_command_line(); + dprintln("command line parsed, root='{}', console='{}'", cmdline.root, cmdline.console); MUST(ACPI::initialize()); dprintln("ACPI initialized"); - parse_command_line(); - dprintln("command line parsed, root='{}'", cmdline.root); - InterruptController::initialize(cmdline.force_pic); dprintln("Interrupt controller initialized"); @@ -153,21 +131,34 @@ extern "C" void kernel_main() DevFileSystem::initialize(); dprintln("devfs initialized"); - TTY* tty1 = new TTY(terminal_driver); - ASSERT(tty1); - dprintln("TTY initialized"); + if (Serial::has_devices()) + { + Serial::initialize_devices(); + dprintln("Serial devices initialized"); + } + + TerminalDriver* terminal_driver = VesaTerminalDriver::create(); + ASSERT(terminal_driver); + dprintln("VESA initialized"); + + auto vtty = MUST(VirtualTTY::create(terminal_driver)); + dprintln("Virtual TTY initialized"); + + auto console = MUST(DevFileSystem::get().root_inode()->directory_find_inode(cmdline.console)); + ASSERT(console->is_tty()); + ((TTY*)console.ptr())->set_as_current(); MUST(Scheduler::initialize()); dprintln("Scheduler initialized"); Scheduler& scheduler = Scheduler::get(); - Process::create_kernel(init2, tty1); + Process::create_kernel(init2, nullptr); scheduler.start(); ASSERT_NOT_REACHED(); } -static void init2(void* tty1) +static void init2(void*) { using namespace Kernel; using namespace Kernel::Input; @@ -184,7 +175,7 @@ static void init2(void* tty1) if (auto res = PS2Controller::initialize(); res.is_error()) dprintln("{}", res.error()); - ((TTY*)tty1)->initialize_device(); + TTY::initialize_devices(); MUST(Process::create_userspace({ 0, 0, 0, 0 }, "/usr/bin/init"sv)); }