From d9fe457b44f17eee97ae35ea8591483c19e3259d Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Thu, 3 May 2018 00:08:22 -0700 Subject: [PATCH] Add beginning basic serial driver --- src/kernel/console.cpp | 83 ++++++++++++++++++++++----------------- src/kernel/console.h | 6 +++ src/kernel/interrupts.cpp | 15 ++++++- src/kernel/main.cpp | 6 ++- src/kernel/serial.cpp | 31 +++++++++++++++ src/kernel/serial.h | 25 ++++++++++++ 6 files changed, 128 insertions(+), 38 deletions(-) create mode 100644 src/kernel/serial.cpp create mode 100644 src/kernel/serial.h diff --git a/src/kernel/console.cpp b/src/kernel/console.cpp index 039374b..03131dd 100644 --- a/src/kernel/console.cpp +++ b/src/kernel/console.cpp @@ -1,5 +1,5 @@ #include "console.h" -#include "io.h" +#include "serial.h" const char digits[] = "0123456789abcdef"; console g_console; @@ -212,25 +212,28 @@ console_get_screen_out(const font &f, const screen &s, void *scratch, size_t len } -static bool -serial_ready() -{ - return (inb(COM1 + 5) & 0x20) != 0; -} - -static void -serial_write(char c) { - while (!serial_ready()); - outb(COM1, c); -} - console::console() : - m_screen(nullptr) + m_screen(nullptr), + m_serial(nullptr) { - const char *fgseq = "\x1b[2J"; - while (*fgseq) - serial_write(*fgseq++); +} + +console::console(serial_port *serial) : + m_screen(nullptr), + m_serial(serial) +{ + if (m_serial) { + const char *fgseq = "\x1b[2J"; + while (*fgseq) + m_serial->write(*fgseq++); + } +} + +void +console::echo() +{ + putc(m_serial->read()); } void @@ -239,32 +242,40 @@ console::set_color(uint8_t fg, uint8_t bg) if (m_screen) m_screen->set_color(fg, bg); - const char *fgseq = "\x1b[38;5;"; - while (*fgseq) - serial_write(*fgseq++); - if (fg >= 100) serial_write('0' + (fg/100)); - if (fg >= 10) serial_write('0' + (fg/10) % 10); - serial_write('0' + fg % 10); - serial_write('m'); + if (m_serial) { + const char *fgseq = "\x1b[38;5;"; + while (*fgseq) + m_serial->write(*fgseq++); + if (fg >= 100) m_serial->write('0' + (fg/100)); + if (fg >= 10) m_serial->write('0' + (fg/10) % 10); + m_serial->write('0' + fg % 10); + m_serial->write('m'); - const char *bgseq = "\x1b[48;5;"; - while (*bgseq) - serial_write(*bgseq++); - if (bg >= 100) serial_write('0' + (bg/100)); - if (bg >= 10) serial_write('0' + (bg/10) % 10); - serial_write('0' + bg % 10); - serial_write('m'); + const char *bgseq = "\x1b[48;5;"; + while (*bgseq) + m_serial->write(*bgseq++); + if (bg >= 100) m_serial->write('0' + (bg/100)); + if (bg >= 10) m_serial->write('0' + (bg/10) % 10); + m_serial->write('0' + bg % 10); + m_serial->write('m'); + } } void console::puts(const char *message) { - while (message && *message) { - char c = *message++; - if (m_screen) m_screen->putc(c); + while (message && *message) + putc(*message++); +} - serial_write(c); - if (c == '\n') serial_write('\r'); +void +console::putc(char c) +{ + if (m_screen) m_screen->putc(c); + + if (m_serial) { + m_serial->write(c); + if (c == '\r') m_serial->write('\n'); } } diff --git a/src/kernel/console.h b/src/kernel/console.h index 945fb6a..d5459a9 100644 --- a/src/kernel/console.h +++ b/src/kernel/console.h @@ -6,14 +6,17 @@ #include "screen.h" class console_out_screen; +class serial_port; class console { public: console(); + console(serial_port *serial); void set_color(uint8_t fg = 7, uint8_t bg = 0); + void putc(char c); void puts(const char *message); void vprintf(const char *fmt, va_list args); @@ -33,10 +36,13 @@ public: void set_screen(console_out_screen *out) { m_screen = out; } + void echo(); + static console * get(); private: console_out_screen *m_screen; + serial_port *m_serial; }; extern console g_console; diff --git a/src/kernel/interrupts.cpp b/src/kernel/interrupts.cpp index d1ae33c..63a5620 100644 --- a/src/kernel/interrupts.cpp +++ b/src/kernel/interrupts.cpp @@ -130,7 +130,7 @@ set_idt_entry(uint8_t i, uint64_t addr, uint16_t selector, uint8_t flags) g_idt_table[i].reserved = 0; } -void +static void disable_legacy_pic() { @@ -154,6 +154,13 @@ disable_legacy_pic() outb(PIC2+1, 0x02); io_wait(); } +static void +enable_serial_interrupts() +{ + uint8_t ier = inb(COM1+1); + outb(COM1+1, ier | 0x1); +} + void interrupts_init() { @@ -186,6 +193,7 @@ interrupts_init() idt_write(); disable_legacy_pic(); + enable_serial_interrupts(); log::info(logs::interrupt, "Interrupts enabled."); } @@ -288,6 +296,11 @@ irq_handler(registers regs) cons->set_color(); break; + case 4: + // TODO: move this to a real serial driver + cons->echo(); + break; + default: cons->set_color(11); cons->printf("\nReceived IRQ interrupt: %d (vec %d)\n", diff --git a/src/kernel/main.cpp b/src/kernel/main.cpp index d4a36cd..2200eb2 100644 --- a/src/kernel/main.cpp +++ b/src/kernel/main.cpp @@ -7,11 +7,13 @@ #include "device_manager.h" #include "font.h" #include "interrupts.h" +#include "io.h" #include "kernel_data.h" #include "log.h" #include "memory.h" #include "memory_pages.h" #include "screen.h" +#include "serial.h" extern "C" { void do_the_set_registers(popcorn_data *header); @@ -41,7 +43,9 @@ load_console(const popcorn_data *header) void kernel_main(popcorn_data *header) { - console *cons = new (&g_console) console(); + serial_port *com1 = new (&g_com1) serial_port(COM1); + console *cons = new (&g_console) console(com1); + cons->set_color(0x21, 0x00); cons->puts("Popcorn OS "); cons->set_color(0x08, 0x00); diff --git a/src/kernel/serial.cpp b/src/kernel/serial.cpp new file mode 100644 index 0000000..d12e449 --- /dev/null +++ b/src/kernel/serial.cpp @@ -0,0 +1,31 @@ +#include "io.h" +#include "serial.h" + +serial_port g_com1; + + +serial_port::serial_port() : + m_port(0) +{ +} + +serial_port::serial_port(uint16_t port) : + m_port(port) +{ +} + +bool serial_port::read_ready() { return (inb(m_port + 5) & 0x01) != 0; } +bool serial_port::write_ready() { return (inb(m_port + 5) & 0x20) != 0; } + +char +serial_port::read() { + while (!read_ready()); + return inb(m_port); +} + +void +serial_port::write(char c) { + while (!write_ready()); + outb(m_port, c); +} + diff --git a/src/kernel/serial.h b/src/kernel/serial.h new file mode 100644 index 0000000..25f8f52 --- /dev/null +++ b/src/kernel/serial.h @@ -0,0 +1,25 @@ +#pragma once +/// \file serial.h +/// Declarations related to serial ports. +#include + +class serial_port +{ +public: + /// Constructor. + /// \arg port The IO address of the serial port + serial_port(uint16_t port); + + serial_port(); + + void write(char c); + char read(); + +private: + uint16_t m_port; + + bool read_ready(); + bool write_ready(); +}; + +extern serial_port g_com1;