From c631ec5ef50628a2e220ccf1c8cc6f389369bc50 Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Sat, 15 Jan 2022 18:07:25 -0800 Subject: [PATCH] [uart] Add first pass UART driver and logger First attempt at a UART driver. I'm not sure it's the most stable. Now that userspace is handling displaying logs, also removed serial and log output support from the kernel. --- assets/manifests/default.yaml | 2 +- src/kernel/apic.cpp | 2 +- src/kernel/console.cpp | 84 ---------- src/kernel/console.h | 84 ---------- src/kernel/cpu.cpp | 2 +- src/kernel/debug.cpp | 73 --------- src/kernel/debug.h | 8 - src/kernel/device_manager.cpp | 9 +- src/kernel/frame_allocator.cpp | 2 +- src/kernel/gdt.cpp | 5 +- src/kernel/hpet.cpp | 2 +- src/kernel/idt.cpp | 2 +- src/kernel/interrupts.cpp | 2 +- src/kernel/kernel.module | 4 - src/kernel/log.cpp | 88 ---------- src/kernel/log.h | 7 - src/kernel/logger.cpp | 21 ++- src/kernel/logger.h | 2 + src/kernel/main.cpp | 46 +----- src/kernel/memory_bootstrap.cpp | 2 +- src/kernel/objects/thread.cpp | 2 +- src/kernel/page_table.cpp | 3 +- src/kernel/pci.cpp | 5 +- src/kernel/scheduler.cpp | 3 +- src/kernel/syscall.cpp.cog | 13 +- src/kernel/syscalls/endpoint.cpp | 2 +- src/kernel/syscalls/object.cpp | 2 +- src/kernel/syscalls/process.cpp | 2 +- src/kernel/syscalls/system.cpp | 2 +- src/kernel/syscalls/thread.cpp | 2 +- src/kernel/syscalls/vm_area.cpp | 2 +- src/kernel/tss.cpp | 2 +- src/kernel/vm_space.cpp | 2 +- src/user/drv.uart/io.cpp | 22 +++ src/user/drv.uart/io.h | 24 +++ src/user/drv.uart/main.cpp | 196 +++++++++++++++++++++++ src/{kernel => user/drv.uart}/serial.cpp | 75 ++++----- src/{kernel => user/drv.uart}/serial.h | 12 +- src/user/drv.uart/uart.module | 12 ++ src/user/srv.init/loader.cpp | 6 + 40 files changed, 354 insertions(+), 482 deletions(-) delete mode 100644 src/kernel/console.cpp delete mode 100644 src/kernel/console.h delete mode 100644 src/kernel/debug.cpp delete mode 100644 src/kernel/log.cpp delete mode 100644 src/kernel/log.h create mode 100644 src/user/drv.uart/io.cpp create mode 100644 src/user/drv.uart/io.h create mode 100644 src/user/drv.uart/main.cpp rename src/{kernel => user/drv.uart}/serial.cpp (72%) rename src/{kernel => user/drv.uart}/serial.h (66%) create mode 100644 src/user/drv.uart/uart.module diff --git a/assets/manifests/default.yaml b/assets/manifests/default.yaml index d651360..59ab3a3 100644 --- a/assets/manifests/default.yaml +++ b/assets/manifests/default.yaml @@ -6,4 +6,4 @@ programs: flags: panic - name: drv.uefi_fb flags: graphical - - name: testapp + - name: drv.uart diff --git a/src/kernel/apic.cpp b/src/kernel/apic.cpp index 5fab458..effa0c4 100644 --- a/src/kernel/apic.cpp +++ b/src/kernel/apic.cpp @@ -3,7 +3,7 @@ #include "clock.h" #include "interrupts.h" #include "io.h" -#include "log.h" +#include "logger.h" #include "memory.h" uint64_t lapic::s_ticks_per_us = 0; diff --git a/src/kernel/console.cpp b/src/kernel/console.cpp deleted file mode 100644 index 64590ff..0000000 --- a/src/kernel/console.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include - -#include "console.h" -#include "printf/printf.h" -#include "serial.h" - - -const char digits[] = "0123456789abcdef"; - -static util::no_construct __g_console_storage; -console &g_console = __g_console_storage.value; - - -console::console() : - m_serial(nullptr) -{ -} - -console::console(serial_port *serial) : - 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 -console::set_color(uint8_t fg, uint8_t bg) -{ - 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) - 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'); - } -} - -size_t -console::puts(const char *message) -{ - size_t n = 0; - while (message && *message) { - n++; - putc(*message++); - } - - return n; -} - -void -console::putc(char c) -{ - if (m_serial) { - if (c == '\n') m_serial->write('\r'); - m_serial->write(c); - } -} - -void console::vprintf(const char *fmt, va_list args) -{ - static const unsigned buf_size = 256; - char buffer[buf_size]; - vsnprintf(buffer, buf_size, fmt, args); - puts(buffer); -} diff --git a/src/kernel/console.h b/src/kernel/console.h deleted file mode 100644 index df10394..0000000 --- a/src/kernel/console.h +++ /dev/null @@ -1,84 +0,0 @@ -#pragma once -#include -#include - -struct kernel_data; -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); - size_t puts(const char *message); - void vprintf(const char *fmt, va_list args); - - inline void printf(const char *fmt, ...) - { - va_list args; - va_start(args, fmt); - vprintf(fmt, args); - va_end(args); - } - - template - void put_hex(T x, int width = 0, char pad = ' '); - - template - void put_dec(T x, int width = 0, char pad = ' '); - - void echo(); - - static console * get(); - -private: - serial_port *m_serial; -}; - -extern console &g_console; -inline console * console::get() { return &g_console; } - - -extern const char digits[]; - -template -void console::put_hex(T x, int width, char pad) -{ - static const int chars = sizeof(x) * 2; - char message[chars + 1]; - - int len = 1; - for (int i = chars - 1; i >= 0; --i) { - uint8_t nibble = (x >> (i*4)) & 0xf; - if (nibble) len = len > i + 1 ? len : i + 1; - message[chars - i - 1] = digits[nibble]; - } - message[chars] = 0; - - if (width > len) for(int i=0; i<(width-len); ++i) putc(pad); - puts(message + (chars - len)); - if (-width > len) for(int i=0; i<(-width-len); ++i) putc(' '); -} - -template -void console::put_dec(T x, int width, char pad) -{ - static const int chars = sizeof(x) * 3; - char message[chars + 1]; - char *p = message + chars; - int length = 0; - *p-- = 0; - do { - *p-- = digits[x % 10]; - x /= 10; - length += 1; - } while (x != 0); - - if (width > length) for(int i=0; i<(width-length); ++i) putc(pad); - puts(++p); - if (-width > length) for(int i=0; i<(-width-length); ++i) putc(' '); -} diff --git a/src/kernel/cpu.cpp b/src/kernel/cpu.cpp index de8a574..a6badf4 100644 --- a/src/kernel/cpu.cpp +++ b/src/kernel/cpu.cpp @@ -7,7 +7,7 @@ #include "device_manager.h" #include "gdt.h" #include "idt.h" -#include "log.h" +#include "logger.h" #include "msr.h" #include "objects/thread.h" #include "objects/vm_area.h" diff --git a/src/kernel/debug.cpp b/src/kernel/debug.cpp deleted file mode 100644 index bbafcb5..0000000 --- a/src/kernel/debug.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include "console.h" -#include "cpu.h" -#include "debug.h" -#include "gdt.h" -#include "objects/process.h" -#include "objects/thread.h" - -size_t __counter_syscall_enter = 0; -size_t __counter_syscall_sysret = 0; - -void -print_regs(const cpu_state ®s) -{ - console *cons = console::get(); - cpu_data &cpu = current_cpu(); - - uint64_t cr2 = 0; - __asm__ __volatile__ ("mov %%cr2, %0" : "=r"(cr2)); - - uintptr_t cr3 = 0; - __asm__ __volatile__ ( "mov %%cr3, %0" : "=r" (cr3) ); - - cons->printf(" process: %llx", cpu.process->koid()); - cons->printf(" thread: %llx\n", cpu.thread->koid()); - - print_regL("rax", regs.rax); - print_regM("rbx", regs.rbx); - print_regR("rcx", regs.rcx); - print_regL("rdx", regs.rdx); - print_regM("rdi", regs.rdi); - print_regR("rsi", regs.rsi); - - cons->puts("\n"); - print_regL(" r8", regs.r8); - print_regM(" r9", regs.r9); - print_regR("r10", regs.r10); - print_regL("r11", regs.r11); - print_regM("r12", regs.r12); - print_regR("r13", regs.r13); - print_regL("r14", regs.r14); - print_regM("r15", regs.r15); - - cons->puts("\n\n"); - print_regL("rbp", regs.rbp); - print_regM("rsp", regs.rsp); - print_regR("sp0", cpu.rsp0); - - print_regL("rip", regs.rip); - print_regM("cr3", cr3); - print_regR("cr2", cr2); - - cons->puts("\n"); -} - -struct frame -{ - frame *prev; - uintptr_t return_addr; -}; - -void -print_stack(const cpu_state ®s) -{ - console *cons = console::get(); - - cons->puts("\nStack:\n"); - uint64_t sp = regs.rsp; - while (sp <= regs.rbp) { - cons->printf("%016x: %016x\n", sp, *reinterpret_cast(sp)); - sp += sizeof(uint64_t); - } -} - diff --git a/src/kernel/debug.h b/src/kernel/debug.h index 424d56c..3b2af6a 100644 --- a/src/kernel/debug.h +++ b/src/kernel/debug.h @@ -18,11 +18,3 @@ extern "C" { extern size_t __counter_syscall_enter; extern size_t __counter_syscall_sysret; - -void print_regs(const cpu_state ®s); -void print_stack(const cpu_state ®s); - -#define print_regL(name, value) cons->printf(" %s: %016lx", name, (value)); -#define print_regM(name, value) cons->printf(" %s: %016lx", name, (value)); -#define print_regR(name, value) cons->printf(" %s: %016lx\n", name, (value)); - diff --git a/src/kernel/device_manager.cpp b/src/kernel/device_manager.cpp index 0678b5b..a320689 100644 --- a/src/kernel/device_manager.cpp +++ b/src/kernel/device_manager.cpp @@ -7,13 +7,11 @@ #include "acpi_tables.h" #include "apic.h" #include "clock.h" -#include "console.h" #include "device_manager.h" #include "interrupts.h" -#include "log.h" +#include "logger.h" #include "memory.h" #include "objects/endpoint.h" -#include "serial.h" static endpoint * const ignore_endpoint = reinterpret_cast(-1ull); @@ -378,11 +376,6 @@ device_manager::init_drivers() bool device_manager::dispatch_irq(unsigned irq) { - if (irq == 4) { - g_com1.handle_interrupt(); - return true; - } - if (irq >= m_irqs.count()) return false; diff --git a/src/kernel/frame_allocator.cpp b/src/kernel/frame_allocator.cpp index 9152ede..b0822be 100644 --- a/src/kernel/frame_allocator.cpp +++ b/src/kernel/frame_allocator.cpp @@ -2,7 +2,7 @@ #include "assert.h" #include "frame_allocator.h" -#include "log.h" +#include "logger.h" #include "memory.h" using mem::frame_size; diff --git a/src/kernel/gdt.cpp b/src/kernel/gdt.cpp index 88d9bae..1ca20b8 100644 --- a/src/kernel/gdt.cpp +++ b/src/kernel/gdt.cpp @@ -4,10 +4,9 @@ #include #include "assert.h" -#include "console.h" #include "cpu.h" #include "gdt.h" -#include "log.h" +#include "logger.h" #include "tss.h" extern "C" void gdt_write(const void *gdt_ptr, uint16_t cs, uint16_t ds, uint16_t tr); @@ -114,6 +113,7 @@ GDT::set_tss(TSS *tss) memcpy(&m_entries[tss_index], &tssd, sizeof(tss_descriptor)); } +/* void GDT::dump(unsigned index) const { @@ -167,3 +167,4 @@ GDT::dump(unsigned index) const (gdt[i].size & 0x60) == 0x40 ? "32" : "16"); } } +*/ diff --git a/src/kernel/hpet.cpp b/src/kernel/hpet.cpp index bc460ba..08394f2 100644 --- a/src/kernel/hpet.cpp +++ b/src/kernel/hpet.cpp @@ -2,7 +2,7 @@ #include "device_manager.h" #include "hpet.h" #include "io.h" -#include "log.h" +#include "logger.h" namespace { inline uint64_t volatile *capabilities(uint64_t volatile *base) { return base; } diff --git a/src/kernel/idt.cpp b/src/kernel/idt.cpp index 39a6206..3bd0d68 100644 --- a/src/kernel/idt.cpp +++ b/src/kernel/idt.cpp @@ -4,7 +4,7 @@ #include "cpu.h" #include "idt.h" -#include "log.h" +#include "logger.h" extern "C" { void idt_write(const void *idt_ptr); diff --git a/src/kernel/interrupts.cpp b/src/kernel/interrupts.cpp index 4d92220..defc231 100644 --- a/src/kernel/interrupts.cpp +++ b/src/kernel/interrupts.cpp @@ -7,7 +7,7 @@ #include "idt.h" #include "interrupts.h" #include "io.h" -#include "log.h" +#include "logger.h" #include "memory.h" #include "objects/process.h" #include "printf/printf.h" diff --git a/src/kernel/kernel.module b/src/kernel/kernel.module index 6d987ed..8c07876 100644 --- a/src/kernel/kernel.module +++ b/src/kernel/kernel.module @@ -14,10 +14,8 @@ kernel = module("kernel", "assert.cpp", "boot.s", "clock.cpp", - "console.cpp", "cpprt.cpp", "cpu.cpp", - "debug.cpp", "debug.s", "device_manager.cpp", "frame_allocator.cpp", @@ -29,7 +27,6 @@ kernel = module("kernel", "interrupts.cpp", "interrupts.s", "io.cpp", - "log.cpp", "logger.cpp", "main.cpp", "memory.cpp", @@ -48,7 +45,6 @@ kernel = module("kernel", "pci.cpp", "printf/printf.c", "scheduler.cpp", - "serial.cpp", "syscall.cpp.cog", "syscall.h.cog", "syscall.s", diff --git a/src/kernel/log.cpp b/src/kernel/log.cpp deleted file mode 100644 index cbf7616..0000000 --- a/src/kernel/log.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include -#include - -#include "assert.h" -#include "console.h" -#include "log.h" -#include "memory.h" -#include "objects/system.h" -#include "objects/thread.h" - -static uint8_t log_buffer[128 * 1024]; - -// The logger is initialized _before_ global constructors are called, -// so that we can start log output immediately. Keep its constructor -// from being called here so as to not overwrite the previous initialization. -static util::no_construct __g_logger_storage; -log::logger &g_logger = __g_logger_storage.value; - -static const uint8_t level_colors[] = {0x07, 0x07, 0x0f, 0x0b, 0x09}; - -static void -output_log(logs area, log::level severity, const char *message) -{ - auto *cons = console::get(); - cons->set_color(level_colors[static_cast(severity)]); - cons->printf("%7s %5s: %s\n", - g_logger.area_name(area), - g_logger.level_name(severity), - message); - cons->set_color(); -} - -// For printf.c -extern "C" void putchar_(char c) {} - -void -logger_task() -{ - auto *cons = console::get(); - - log::info(logs::task, "Starting kernel logger task"); - g_logger.set_immediate(nullptr); - - thread &self = thread::current(); - system &sys = system::get(); - - size_t buffer_size = 1; - uint8_t *buffer = nullptr; - - while (true) { - size_t size = g_logger.get_entry(buffer, buffer_size); - if (size > buffer_size) { - while (size > buffer_size) buffer_size *= 2; - kfree(buffer); - buffer = reinterpret_cast(kalloc(buffer_size)); - kassert(buffer, "Could not allocate logger task buffer"); - continue; - } - - if(size) { - auto *ent = reinterpret_cast(buffer); - buffer[ent->bytes] = 0; - - cons->set_color(level_colors[static_cast(ent->severity)]); - cons->printf("%7s %5s: %s\n", - g_logger.area_name(ent->area), - g_logger.level_name(ent->severity), - ent->message); - cons->set_color(); - } - - if (!g_logger.has_log()) { - sys.deassert_signal(j6_signal_system_has_log); - sys.add_blocked_thread(&self); - self.wait_on_signals(j6_signal_system_has_log); - } - } -} - -void logger_init() -{ - new (&g_logger) log::logger(log_buffer, sizeof(log_buffer), output_log); -} - -void logger_clear_immediate() -{ - g_logger.set_immediate(nullptr); -} diff --git a/src/kernel/log.h b/src/kernel/log.h deleted file mode 100644 index 5120af6..0000000 --- a/src/kernel/log.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include "logger.h" - -void logger_init(); -void logger_clear_immediate(); -void logger_task(); diff --git a/src/kernel/logger.cpp b/src/kernel/logger.cpp index 1edcd37..562d27f 100644 --- a/src/kernel/logger.cpp +++ b/src/kernel/logger.cpp @@ -1,12 +1,25 @@ #include -#include +#include #include "assert.h" #include "logger.h" +#include "memory.h" #include "objects/system.h" #include "printf/printf.h" +static uint8_t log_buffer[128 * 1024]; + +// The logger is initialized _before_ global constructors are called, +// so that we can start log output immediately. Keep its constructor +// from being called here so as to not overwrite the previous initialization. +static util::no_construct __g_logger_storage; +log::logger &g_logger = __g_logger_storage.value; + +// For printf.c +extern "C" void putchar_(char c) {} + + namespace log { logger *logger::s_log = nullptr; @@ -131,3 +144,9 @@ void fatal(logs area, const char *fmt, ...) } } // namespace log + + +void logger_init() +{ + new (&g_logger) log::logger(log_buffer, sizeof(log_buffer), nullptr); +} diff --git a/src/kernel/logger.h b/src/kernel/logger.h index 7c92411..f7466f5 100644 --- a/src/kernel/logger.h +++ b/src/kernel/logger.h @@ -129,3 +129,5 @@ void fatal(logs area, const char *fmt, ...); extern log::logger &g_logger; } // namespace log + +void logger_init(); diff --git a/src/kernel/main.cpp b/src/kernel/main.cpp index 78b21f1..4f18ec0 100644 --- a/src/kernel/main.cpp +++ b/src/kernel/main.cpp @@ -10,22 +10,19 @@ #include "assert.h" #include "block_device.h" #include "clock.h" -#include "console.h" #include "cpu.h" #include "device_manager.h" #include "gdt.h" #include "idt.h" #include "interrupts.h" #include "io.h" -#include "log.h" +#include "logger.h" #include "memory.h" #include "msr.h" #include "objects/channel.h" #include "objects/event.h" -#include "objects/thread.h" #include "objects/vm_area.h" #include "scheduler.h" -#include "serial.h" #include "syscall.h" #include "sysconf.h" #include "tss.h" @@ -56,18 +53,6 @@ void load_init_server(bootproto::program &program, uintptr_t modules_address); unsigned start_aps(lapic &apic, const util::vector &ids, void *kpml4); -void -init_console() -{ - serial_port *com1 = new (&g_com1) serial_port(COM1); - console *cons = new (&g_console) console(com1); - - cons->set_color(0x21, 0x00); - cons->puts("jsix OS "); - cons->set_color(0x08, 0x00); - cons->puts(GIT_VERSION " booting...\n"); -} - void run_constructors() { @@ -86,9 +71,7 @@ kernel_main(bootproto::args *args) panic::symbol_table = util::offset_pointer(args->symbol_table, mem::linear_offset); } - init_console(); logger_init(); - cpu_validate(); extern IDT &g_bsp_idt; @@ -154,31 +137,7 @@ kernel_main(bootproto::args *args) sysconf_create(); interrupts_enable(); - g_com1.handle_interrupt(); - - /* - block_device *disk = devices->get_block_device(0); - if (disk) { - for (int i=0; i<1; ++i) { - uint8_t buf[512]; - memset(buf, 0, 512); - - kassert(disk->read(0x200, sizeof(buf), buf), - "Disk read returned 0"); - - console *cons = console::get(); - uint8_t *p = &buf[0]; - for (int i = 0; i < 8; ++i) { - for (int j = 0; j < 16; ++j) { - cons->printf(" %02x", *p++); - } - cons->putc('\n'); - } - } - } else { - log::warn(logs::boot, "No block devices present."); - } - */ + //g_com1.handle_interrupt(); scheduler *sched = new scheduler {g_num_cpus}; scheduler_ready = true; @@ -186,7 +145,6 @@ kernel_main(bootproto::args *args) // Load the init server load_init_server(*args->init, args->modules); - sched->create_kernel_task(logger_task, scheduler::max_priority/4, true); sched->start(); } diff --git a/src/kernel/memory_bootstrap.cpp b/src/kernel/memory_bootstrap.cpp index 1e43d4d..a80b8db 100644 --- a/src/kernel/memory_bootstrap.cpp +++ b/src/kernel/memory_bootstrap.cpp @@ -10,7 +10,7 @@ #include "gdt.h" #include "heap_allocator.h" #include "io.h" -#include "log.h" +#include "logger.h" #include "memory.h" #include "msr.h" #include "objects/process.h" diff --git a/src/kernel/objects/thread.cpp b/src/kernel/objects/thread.cpp index e5fb81e..f60954b 100644 --- a/src/kernel/objects/thread.cpp +++ b/src/kernel/objects/thread.cpp @@ -2,7 +2,7 @@ #include #include "cpu.h" -#include "log.h" +#include "logger.h" #include "memory.h" #include "objects/thread.h" #include "objects/process.h" diff --git a/src/kernel/page_table.cpp b/src/kernel/page_table.cpp index c969b96..abd788a 100644 --- a/src/kernel/page_table.cpp +++ b/src/kernel/page_table.cpp @@ -2,7 +2,6 @@ #include #include "assert.h" -#include "console.h" #include "memory.h" #include "frame_allocator.h" #include "page_table.h" @@ -259,6 +258,7 @@ page_table::free(page_table::level l) void page_table::dump(page_table::level lvl, bool recurse) { + /* console *cons = console::get(); cons->printf("\nLevel %d page table @ %lx:\n", lvl, this); @@ -289,4 +289,5 @@ page_table::dump(page_table::level lvl, bool recurse) next->dump(deeper(lvl), true); } } + */ } diff --git a/src/kernel/pci.cpp b/src/kernel/pci.cpp index 964dbc0..7856bad 100644 --- a/src/kernel/pci.cpp +++ b/src/kernel/pci.cpp @@ -1,6 +1,5 @@ #include "assert.h" -#include "console.h" -#include "log.h" +#include "logger.h" #include "interrupts.h" #include "pci.h" @@ -36,6 +35,7 @@ struct pci_cap_msi64 } __attribute__ ((packed)); +/* void dump_msi(pci_cap_msi *cap) { auto cons = console::get(); @@ -62,6 +62,7 @@ void dump_msi(pci_cap_msi *cap) } cons->putc('\n'); }; +*/ pci_device::pci_device() : m_base(nullptr), diff --git a/src/kernel/scheduler.cpp b/src/kernel/scheduler.cpp index 0d7e43a..99fcd46 100644 --- a/src/kernel/scheduler.cpp +++ b/src/kernel/scheduler.cpp @@ -5,14 +5,13 @@ #include "apic.h" #include "assert.h" #include "clock.h" -#include "console.h" #include "cpu.h" #include "debug.h" #include "device_manager.h" #include "gdt.h" #include "interrupts.h" #include "io.h" -#include "log.h" +#include "logger.h" #include "msr.h" #include "objects/channel.h" #include "objects/process.h" diff --git a/src/kernel/syscall.cpp.cog b/src/kernel/syscall.cpp.cog index a061897..3df6bbd 100644 --- a/src/kernel/syscall.cpp.cog +++ b/src/kernel/syscall.cpp.cog @@ -3,15 +3,17 @@ #include -#include "console.h" #include "debug.h" -#include "log.h" +#include "logger.h" #include "syscall.h" extern "C" { void syscall_invalid(uint64_t call); } +size_t __counter_syscall_enter = 0; +size_t __counter_syscall_sysret = 0; + /*[[[cog code generation from definitions.context import Context @@ -27,12 +29,7 @@ uintptr_t syscall_registry[num_syscalls] __attribute__((section(".syscall_regist void syscall_invalid(uint64_t call) { - console *cons = console::get(); - cons->set_color(9); - cons->printf("\nReceived unknown syscall: %02x\n", call); - - cons->set_color(); - _halt(); + log::warn(logs::syscall, "Received unknown syscall: %02x\n", call); } void diff --git a/src/kernel/syscalls/endpoint.cpp b/src/kernel/syscalls/endpoint.cpp index c9c6050..d163e08 100644 --- a/src/kernel/syscalls/endpoint.cpp +++ b/src/kernel/syscalls/endpoint.cpp @@ -1,7 +1,7 @@ #include #include -#include "log.h" +#include "logger.h" #include "objects/endpoint.h" #include "syscalls/helpers.h" diff --git a/src/kernel/syscalls/object.cpp b/src/kernel/syscalls/object.cpp index 42c5e36..5b07583 100644 --- a/src/kernel/syscalls/object.cpp +++ b/src/kernel/syscalls/object.cpp @@ -4,7 +4,7 @@ #include #include "assert.h" -#include "log.h" +#include "logger.h" #include "objects/thread.h" #include "syscalls/helpers.h" diff --git a/src/kernel/syscalls/process.cpp b/src/kernel/syscalls/process.cpp index d046e50..e48af1c 100644 --- a/src/kernel/syscalls/process.cpp +++ b/src/kernel/syscalls/process.cpp @@ -1,7 +1,7 @@ #include #include -#include "log.h" +#include "logger.h" #include "objects/process.h" #include "syscalls/helpers.h" diff --git a/src/kernel/syscalls/system.cpp b/src/kernel/syscalls/system.cpp index 60cfbf5..4999f1e 100644 --- a/src/kernel/syscalls/system.cpp +++ b/src/kernel/syscalls/system.cpp @@ -4,7 +4,7 @@ #include "cpu.h" #include "device_manager.h" #include "frame_allocator.h" -#include "log.h" +#include "logger.h" #include "memory.h" #include "objects/endpoint.h" #include "objects/thread.h" diff --git a/src/kernel/syscalls/thread.cpp b/src/kernel/syscalls/thread.cpp index a844e26..7512118 100644 --- a/src/kernel/syscalls/thread.cpp +++ b/src/kernel/syscalls/thread.cpp @@ -1,7 +1,7 @@ #include #include -#include "log.h" +#include "logger.h" #include "objects/process.h" #include "objects/thread.h" #include "syscalls/helpers.h" diff --git a/src/kernel/syscalls/vm_area.cpp b/src/kernel/syscalls/vm_area.cpp index 8c56cbd..fb9dd02 100644 --- a/src/kernel/syscalls/vm_area.cpp +++ b/src/kernel/syscalls/vm_area.cpp @@ -2,7 +2,7 @@ #include #include -#include "log.h" +#include "logger.h" #include "objects/process.h" #include "objects/vm_area.h" #include "syscalls/helpers.h" diff --git a/src/kernel/tss.cpp b/src/kernel/tss.cpp index d472ebf..8e404e1 100644 --- a/src/kernel/tss.cpp +++ b/src/kernel/tss.cpp @@ -3,7 +3,7 @@ #include "assert.h" #include "cpu.h" -#include "log.h" +#include "logger.h" #include "memory.h" #include "objects/vm_area.h" #include "tss.h" diff --git a/src/kernel/vm_space.cpp b/src/kernel/vm_space.cpp index 072ef37..c39e3a3 100644 --- a/src/kernel/vm_space.cpp +++ b/src/kernel/vm_space.cpp @@ -4,7 +4,7 @@ #include "assert.h" #include "frame_allocator.h" -#include "log.h" +#include "logger.h" #include "memory.h" #include "objects/process.h" #include "objects/thread.h" diff --git a/src/user/drv.uart/io.cpp b/src/user/drv.uart/io.cpp new file mode 100644 index 0000000..f5aa618 --- /dev/null +++ b/src/user/drv.uart/io.cpp @@ -0,0 +1,22 @@ +#include "io.h" + +uint8_t +inb(uint16_t port) +{ + uint8_t val; + __asm__ __volatile__ ( "inb %1, %0" : "=a"(val) : "Nd"(port) ); + return val; +} + +void +outb(uint16_t port, uint8_t val) +{ + __asm__ __volatile__ ( "outb %0, %1" :: "a"(val), "Nd"(port) ); +} + +void +io_wait(unsigned times) +{ + for (unsigned i = 0; i < times; ++i) + outb(0x80, 0); +} diff --git a/src/user/drv.uart/io.h b/src/user/drv.uart/io.h new file mode 100644 index 0000000..ebc7da0 --- /dev/null +++ b/src/user/drv.uart/io.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +extern "C" { + +/// Read a byte from an IO port. +/// \arg port The address of the IO port +/// \returns One byte read from the port +uint8_t inb(uint16_t port); + +/// Write a byte to an IO port. +/// \arg port The addres of the IO port +/// \arg val The byte to write +void outb(uint16_t port, uint8_t val); + +/// Pause briefly by doing IO to port 0x80 +/// \arg times Number of times to delay by writing +void io_wait(unsigned times = 1); + +} + +constexpr uint16_t COM1 = 0x03f8; +constexpr uint16_t COM2 = 0x02f8; diff --git a/src/user/drv.uart/main.cpp b/src/user/drv.uart/main.cpp new file mode 100644 index 0000000..2829dd4 --- /dev/null +++ b/src/user/drv.uart/main.cpp @@ -0,0 +1,196 @@ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "io.h" +#include "serial.h" + +extern "C" { + int main(int, const char **); +} + +constexpr j6_handle_t handle_self = 1; +constexpr j6_handle_t handle_sys = 2; + +struct entry +{ + uint8_t bytes; + uint8_t area; + uint8_t severity; + uint8_t sequence; + char message[0]; +}; + +static const uint8_t level_colors[] = {0x07, 0x07, 0x0f, 0x0b, 0x09}; +const char *level_names[] = {"", "debug", "info", "warn", "error", "fatal"}; +const char *area_names[] = { +#define LOG(name, lvl) #name , +#include +#undef LOG + nullptr +}; + +constexpr size_t in_buf_size = 512; +constexpr size_t out_buf_size = 128 * 1024; + +uint8_t com1_in[in_buf_size]; +uint8_t com2_in[in_buf_size]; +uint8_t com1_out[out_buf_size]; +uint8_t com2_out[out_buf_size]; + +serial_port *g_com1; +serial_port *g_com2; + +constexpr size_t stack_size = 0x10000; +constexpr uintptr_t stack_top = 0xf80000000; + +void +print_header() +{ + char stringbuf[150]; + + unsigned version_major = j6_sysconf(j6sc_version_major); + unsigned version_minor = j6_sysconf(j6sc_version_minor); + unsigned version_patch = j6_sysconf(j6sc_version_patch); + unsigned version_git = j6_sysconf(j6sc_version_gitsha); + + size_t len = snprintf(stringbuf, sizeof(stringbuf), + "\e[38;5;21mjsix OS\e[38;5;8m %d.%d.%d (%07x) booting...\e[0m\r\n", + version_major, version_minor, version_patch, version_git); + g_com1->write(stringbuf, len); +} + +void +log_pump_proc() +{ + size_t buffer_size = 0; + void *message_buffer = nullptr; + char stringbuf[300]; + + j6_status_t result = j6_system_request_iopl(handle_sys, 3); + if (result != j6_status_ok) + return; + + while (true) { + size_t size = buffer_size; + j6_status_t s = j6_system_get_log(handle_sys, message_buffer, &size); + + if (s == j6_err_insufficient) { + free(message_buffer); + buffer_size = size * 2; + message_buffer = malloc(buffer_size); + continue; + } else if (s != j6_status_ok) { + j6_log("uart driver got error from get_log"); + continue; + } + + if (size == 0) { + j6_signal_t sigs = 0; + j6_kobject_wait(handle_sys, j6_signal_system_has_log, &sigs); + continue; + } + + const entry *e = reinterpret_cast(message_buffer); + + const char *area_name = area_names[e->area]; + const char *level_name = level_names[e->severity]; + uint8_t level_color = level_colors[e->severity]; + + size_t len = snprintf(stringbuf, sizeof(stringbuf), + "\e[38;5;%dm%7s %5s: %s\e[38;5;0m\r\n", + level_color, area_name, level_name, e->message); + g_com1->write(stringbuf, len); + } +} + +int +main(int argc, const char **argv) +{ + j6_log("uart driver starting"); + + j6_handle_t endp = j6_handle_invalid; + j6_status_t result = j6_status_ok; + + result = j6_system_request_iopl(handle_sys, 3); + if (result != j6_status_ok) + return result; + + result = j6_endpoint_create(&endp); + if (result != j6_status_ok) + return result; + + result = j6_system_bind_irq(handle_sys, endp, 3); + if (result != j6_status_ok) + return result; + + result = j6_system_bind_irq(handle_sys, endp, 4); + if (result != j6_status_ok) + return result; + + serial_port com1 {COM1, in_buf_size, com1_in, out_buf_size, com1_out}; + serial_port com2 {COM2, in_buf_size, com2_in, out_buf_size, com2_out}; + g_com1 = &com1; + g_com2 = &com2; + + print_header(); + + j6_handle_t child_stack_vma = j6_handle_invalid; + result = j6_vma_create_map(&child_stack_vma, stack_size, stack_top-stack_size, j6_vm_flag_write); + if (result != j6_status_ok) + return result; + + uint64_t *sp = reinterpret_cast(stack_top - 0x10); + sp[0] = sp[1] = 0; + + j6_handle_t child = j6_handle_invalid; + result = j6_thread_create(&child, handle_self, stack_top - 0x10, reinterpret_cast(&log_pump_proc)); + if (result != j6_status_ok) + return result; + + size_t len = 0; + while (true) { + uint64_t tag = 0; + result = j6_endpoint_receive(endp, &tag, nullptr, &len, 10); + if (result == j6_err_timed_out) { + com1.handle_interrupt(); + com2.handle_interrupt(); + continue; + } + + if (result != j6_status_ok) { + j6_log("uart driver got error waiting for irq"); + continue; + } + + if (!j6_tag_is_irq(tag)) { + j6_log("uart driver got non-irq waiting for irq"); + continue; + } + + unsigned irq = j6_tag_to_irq(tag); + switch (irq) { + case 3: + com2.handle_interrupt(); + break; + case 4: + com1.handle_interrupt(); + break; + default: + j6_log("uart driver got unknown irq waiting for irq"); + } + } + + j6_log("uart driver somehow got to the end of main"); + return 0; +} + diff --git a/src/kernel/serial.cpp b/src/user/drv.uart/serial.cpp similarity index 72% rename from src/kernel/serial.cpp rename to src/user/drv.uart/serial.cpp index b1b5bfe..97e9ac5 100644 --- a/src/kernel/serial.cpp +++ b/src/user/drv.uart/serial.cpp @@ -1,17 +1,7 @@ #include -#include - -#include "assert.h" -#include "interrupts.h" #include "io.h" #include "serial.h" -// This object is initialized _before_ global constructors are called, -// so we don't want it to have global constructors at all, lest it -// overwrite the previous initialization. -static util::no_construct __g_com1_storage; -serial_port &g_com1 = __g_com1_storage.value; - constexpr size_t fifo_size = 64; // register offsets @@ -28,20 +18,13 @@ constexpr uint16_t MSR = 6; constexpr uint16_t DLL = 0; // DLAB == 1 constexpr uint16_t DLH = 1; // DLAB == 1 -uint8_t com1_out_buffer[4096*4]; -uint8_t com1_in_buffer[512]; - -serial_port::serial_port() : - m_writing(false), - m_port(0) -{ -} - -serial_port::serial_port(uint16_t port) : +serial_port::serial_port(uint16_t port, + size_t in_buffer_len, uint8_t *in_buffer, + size_t out_buffer_len, uint8_t *out_buffer) : m_writing(false), m_port(port), - m_out_buffer(com1_out_buffer, sizeof(com1_out_buffer)), - m_in_buffer(com1_in_buffer, sizeof(com1_in_buffer)) + m_out_buffer(out_buffer, out_buffer_len), + m_in_buffer(in_buffer, in_buffer_len) { outb(port + IER, 0x00); // Disable all interrupts outb(port + LCR, 0x80); // Enable the Divisor Latch Access Bit @@ -62,7 +45,6 @@ inline bool write_ready(uint16_t port) { return (inb(port + LSR) & 0x20) != 0; } void serial_port::handle_interrupt() { - interrupts_disable(); uint8_t iir = inb(m_port + IIR); while ((iir & 1) == 0) { @@ -74,11 +56,9 @@ serial_port::handle_interrupt() break; case 1: // Transmit buffer empty - do_write(); - break; - case 2: // Received data available - do_read(); + if (read_ready(m_port)) do_read(); + if (write_ready(m_port)) do_write(); break; case 3: // Line status change @@ -89,7 +69,6 @@ serial_port::handle_interrupt() iir = inb(m_port + IIR); } - interrupts_enable(); } void @@ -110,30 +89,39 @@ serial_port::do_read() void serial_port::do_write() { - uint8_t *data = nullptr; - uint8_t tmp[fifo_size]; + // If another thread is writing data, just give up and + // try again later + util::scoped_trylock lock {m_lock}; + if (!lock.locked()) + return; + uint8_t *data = nullptr; size_t n = m_out_buffer.get_block(reinterpret_cast(&data)); m_writing = (n > 0); - if (!m_writing) + if (!m_writing) { + m_out_buffer.consume(0); return; + } if (n > fifo_size) n = fifo_size; - memcpy(tmp, data, n); - m_out_buffer.consume(n); - - for (size_t i = 0; i < n; ++i) + for (size_t i = 0; i < n; ++i) { + if (!write_ready(m_port)) { + n = i; + break; + } outb(m_port, data[i]); + } + m_out_buffer.consume(n); } void serial_port::handle_error(uint16_t reg, uint8_t value) { - kassert(false, "serial line error"); + while (1) asm ("hlt"); } char @@ -147,17 +135,18 @@ serial_port::read() return c; } -void -serial_port::write(char c) +size_t +serial_port::write(const char *c, size_t len) { uint8_t *data = nullptr; - size_t avail = m_out_buffer.reserve(1, reinterpret_cast(&data)); - if (!avail) - return; - *data = c; - m_out_buffer.commit(1); + size_t avail = m_out_buffer.reserve(len, reinterpret_cast(&data)); + + memcpy(data, c, avail); + m_out_buffer.commit(avail); if (!m_writing) do_write(); + + return avail; } diff --git a/src/kernel/serial.h b/src/user/drv.uart/serial.h similarity index 66% rename from src/kernel/serial.h rename to src/user/drv.uart/serial.h index 99e6f27..9a71732 100644 --- a/src/kernel/serial.h +++ b/src/user/drv.uart/serial.h @@ -4,17 +4,18 @@ #include #include +#include class serial_port { public: /// Constructor. /// \arg port The IO address of the serial port - serial_port(uint16_t port); + serial_port(uint16_t port, + size_t in_buffer_len, uint8_t *in_buffer, + size_t out_buffer_len, uint8_t *out_buffer); - serial_port(); - - void write(char c); + size_t write(const char *str, size_t len); char read(); void handle_interrupt(); @@ -24,10 +25,9 @@ private: uint16_t m_port; util::bip_buffer m_out_buffer; util::bip_buffer m_in_buffer; + util::spinlock m_lock; void do_read(); void do_write(); void handle_error(uint16_t reg, uint8_t value); }; - -extern serial_port &g_com1; diff --git a/src/user/drv.uart/uart.module b/src/user/drv.uart/uart.module new file mode 100644 index 0000000..f9fbcb9 --- /dev/null +++ b/src/user/drv.uart/uart.module @@ -0,0 +1,12 @@ +# vim: ft=python + +module("drv.uart", + targets = [ "user" ], + deps = [ "libc", "util" ], + description = "UART driver", + sources = [ + "io.cpp", + "main.cpp", + "serial.cpp", + ]) + diff --git a/src/user/srv.init/loader.cpp b/src/user/srv.init/loader.cpp index 00355b3..ddb1bc9 100644 --- a/src/user/srv.init/loader.cpp +++ b/src/user/srv.init/loader.cpp @@ -55,6 +55,12 @@ load_program(const module_program &prog, char *err_msg) return false; } + res = j6_process_give_handle(proc, handle_system, nullptr); + if (res != j6_status_ok) { + sprintf(err_msg, " ** error loading program '%s': giving system handle: %lx", prog.filename, res); + return false; + } + uintptr_t load_addr = load_addr_base; for (auto &seg : progelf.programs()) {