From e477dea5c79c9982c95bcdb0883055f2e7b312f4 Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Sun, 3 Jan 2021 18:13:41 -0800 Subject: [PATCH] [fb] Output klog to fb if video exists If there's no video, do as we did before, otherwise route logs to the fb driver instead. (Need to clean this up to just have a log consumer general interface?) Also added a "scrollback" class to fb driver and updated the system_get_log syscall. --- modules.yaml | 1 + qemu.sh | 4 ++- src/boot/console.cpp | 11 ++++-- src/drivers/fb/main.cpp | 55 ++++++++++++++++++++++++------ src/drivers/fb/scrollback.cpp | 61 ++++++++++++++++++++++++++++++++++ src/drivers/fb/scrollback.h | 26 +++++++++++++++ src/include/syscalls.inc | 2 +- src/kernel/log.cpp | 7 +++- src/kernel/log.h | 1 + src/kernel/main.cpp | 10 ++++-- src/kernel/scheduler.cpp | 25 ++++++++++---- src/kernel/syscalls/system.cpp | 7 ++-- 12 files changed, 181 insertions(+), 29 deletions(-) create mode 100644 src/drivers/fb/scrollback.cpp create mode 100644 src/drivers/fb/scrollback.h diff --git a/modules.yaml b/modules.yaml index b79a9d9..b37e675 100644 --- a/modules.yaml +++ b/modules.yaml @@ -94,6 +94,7 @@ modules: - src/drivers/fb/font.cpp - src/drivers/fb/main.cpp - src/drivers/fb/screen.cpp + - src/drivers/fb/scrollback.cpp kutil: kind: lib diff --git a/qemu.sh b/qemu.sh index 7b345b6..b349691 100755 --- a/qemu.sh +++ b/qemu.sh @@ -6,6 +6,7 @@ debug="" debugtarget="${build}/jsix.elf" flash_name="ovmf_vars" gfx="-nographic" +vga="-vga none" kvm="" cpu="Broadwell,+pdpe1gb" @@ -22,6 +23,7 @@ for arg in $@; do ;; --gfx) gfx="" + vga="" ;; --kvm) kvm="-enable-kvm" @@ -72,4 +74,4 @@ exec qemu-system-x86_64 \ -cpu "${cpu}" \ -M q35 \ -no-reboot \ - $gfx $kvm $debug + $gfx $vga $kvm $debug diff --git a/src/boot/console.cpp b/src/boot/console.cpp index b820a3e..a9179ae 100644 --- a/src/boot/console.cpp +++ b/src/boot/console.cpp @@ -83,9 +83,14 @@ console::pick_mode(uefi::boot_services *bs) uefi::protos::graphics_output *gfx_out_proto; uefi::guid guid = uefi::protos::graphics_output::guid; - try_or_raise( - bs->locate_protocol(&guid, nullptr, (void **)&gfx_out_proto), - L"Failed to find a Graphics Output Protocol handle"); + m_fb.type = kernel::args::fb_type::none; + + uefi::status has_gop = bs->locate_protocol(&guid, nullptr, + (void **)&gfx_out_proto); + + if (has_gop != uefi::status::success) + // No video output found, skip it + return; const uint32_t modes = gfx_out_proto->mode->max_mode; uint32_t best = gfx_out_proto->mode->mode; diff --git a/src/drivers/fb/main.cpp b/src/drivers/fb/main.cpp index 9a58193..2f02053 100644 --- a/src/drivers/fb/main.cpp +++ b/src/drivers/fb/main.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "j6/init.h" #include "j6/errors.h" @@ -10,12 +11,24 @@ #include "font.h" #include "screen.h" +#include "scrollback.h" extern "C" { int main(int, const char **); void _get_init(size_t *initc, struct j6_init_value **initv); } +extern j6_handle_t __handle_sys; + +struct entry +{ + uint8_t bytes; + uint8_t area; + uint8_t severity; + uint8_t sequence; + char message[0]; +}; + int main(int argc, const char **argv) { @@ -44,25 +57,45 @@ main(int argc, const char **argv) screen scr(fb->addr, fb->horizontal, fb->vertical, order); font fnt; - screen::pixel_t fg = scr.color(255, 255, 255); + screen::pixel_t fg = scr.color(0xb0, 0xb0, 0xb0); screen::pixel_t bg = scr.color(49, 79, 128); scr.fill(bg); - constexpr int margin = 4; + constexpr int margin = 2; + const unsigned xstride = (margin + fnt.width()); + const unsigned ystride = (margin + fnt.height()); + const unsigned rows = (scr.height() - margin) / ystride; + const unsigned cols = (scr.width() - margin) / xstride; - int y = margin; - char g = 0; + scrollback scroll(rows, cols); - while (y < scr.height() - margin - fnt.height()) { - int x = margin; - while (x < scr.width() - margin - fnt.width()) { - fnt.draw_glyph(scr, g+' ', fg, bg, x, y); - x += fnt.width() + fnt.width() / 4; - g = ++g % ('~' - ' ' + 1); + int pending = 0; + constexpr int pending_threshold = 10; + + char message_buffer[256]; + while (true) { + size_t size = sizeof(message_buffer); + _syscall_system_get_log(__handle_sys, message_buffer, &size); + if (size != 0) { + entry *e = reinterpret_cast(&message_buffer); + + size_t eom = e->bytes - sizeof(entry); + e->message[eom] = 0; + + scroll.add_line(e->message, eom); + if (++pending > pending_threshold) { + scroll.render(scr, fnt); + pending = 0; + } + } else { + if (pending) { + scroll.render(scr, fnt); + pending = 0; + } } - y += fnt.height() + fnt.height() / 4; } + _syscall_system_log("fb driver done, exiting"); return 0; } diff --git a/src/drivers/fb/scrollback.cpp b/src/drivers/fb/scrollback.cpp new file mode 100644 index 0000000..170dd09 --- /dev/null +++ b/src/drivers/fb/scrollback.cpp @@ -0,0 +1,61 @@ +#include +#include + +#include "font.h" +#include "screen.h" +#include "scrollback.h" + +scrollback::scrollback(unsigned lines, unsigned cols, unsigned margin) : + m_rows {lines}, + m_cols {cols}, + m_start {0}, + m_count {0}, + m_margin {margin} +{ + m_data = reinterpret_cast(malloc(lines*cols)); + m_lines = reinterpret_cast(malloc(lines*sizeof(char*))); + for (unsigned i = 0; i < lines; ++i) + m_lines[i] = &m_data[i*cols]; + + memset(m_data, ' ', lines*cols); +} + +void +scrollback::add_line(const char *line, size_t len) +{ + unsigned i = 0; + if (m_count < m_rows) + i = m_count++; + else + i = m_start++; + + if (len > m_cols) + len = m_cols; + + memcpy(m_lines[i % m_rows], line, len); + if (len < m_cols) + memset(m_lines[i % m_rows]+len, ' ', m_cols - len); +} + +char * +scrollback::get_line(unsigned i) +{ + return m_lines[(i+m_start)%m_rows]; +} + +void +scrollback::render(screen &scr, font &fnt) +{ + screen::pixel_t fg = scr.color(0xb0, 0xb0, 0xb0); + screen::pixel_t bg = scr.color(49, 79, 128); + + const unsigned xstride = (m_margin + fnt.width()); + const unsigned ystride = (m_margin + fnt.height()); + + for (unsigned y = 0; y < m_rows; ++y) { + char *line = get_line(y); + for (unsigned x = 0; x < m_cols; ++x) { + fnt.draw_glyph(scr, line[x], fg, bg, m_margin+x*xstride, m_margin+y*ystride); + } + } +} diff --git a/src/drivers/fb/scrollback.h b/src/drivers/fb/scrollback.h new file mode 100644 index 0000000..56bfef9 --- /dev/null +++ b/src/drivers/fb/scrollback.h @@ -0,0 +1,26 @@ +#pragma once +/// \file scrollback.h + +class screen; +class font; + +class scrollback +{ +public: + scrollback(unsigned lines, unsigned cols, unsigned margin = 2); + + void add_line(const char *line, size_t len); + + char * get_line(unsigned i); + + void render(screen &scr, font &fnt); + +private: + char *m_data; + char **m_lines; + unsigned m_rows, m_cols; + unsigned m_start; + unsigned m_count; + unsigned m_margin; +}; + diff --git a/src/include/syscalls.inc b/src/include/syscalls.inc index 4cd636f..4c2ddc5 100644 --- a/src/include/syscalls.inc +++ b/src/include/syscalls.inc @@ -1,6 +1,6 @@ SYSCALL(0x00, system_log, const char *) SYSCALL(0x01, system_noop, void) -SYSCALL(0x02, system_get_log, j6_handle_t, j6_handle_t *) +SYSCALL(0x02, system_get_log, j6_handle_t, char *, size_t *) SYSCALL(0x03, system_bind_irq, j6_handle_t, j6_handle_t, unsigned) SYSCALL(0x08, object_koid, j6_handle_t, j6_koid_t *) diff --git a/src/kernel/log.cpp b/src/kernel/log.cpp index 3ef7bb5..dc9e68b 100644 --- a/src/kernel/log.cpp +++ b/src/kernel/log.cpp @@ -10,7 +10,7 @@ static uint8_t log_buffer[0x10000]; // so that we can start log output immediately. Keep its constructor // from being called here so as to not overwrite the previous initialization. static kutil::no_construct __g_logger_storage; -static log::logger &g_logger = __g_logger_storage.value; +log::logger &g_logger = __g_logger_storage.value; static const uint8_t level_colors[] = {0x07, 0x07, 0x0f, 0x0b, 0x09}; @@ -57,3 +57,8 @@ 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 index d3b10b2..c60c436 100644 --- a/src/kernel/log.h +++ b/src/kernel/log.h @@ -6,4 +6,5 @@ namespace log = kutil::log; namespace logs = kutil::logs; void logger_init(); +void logger_clear_immediate(); void logger_task(); diff --git a/src/kernel/main.cpp b/src/kernel/main.cpp index def6202..6cd52f2 100644 --- a/src/kernel/main.cpp +++ b/src/kernel/main.cpp @@ -64,7 +64,6 @@ init_console() cons->puts("jsix OS "); cons->set_color(0x08, 0x00); cons->puts(GIT_VERSION " booting...\n"); - logger_init(); } channel *std_out = nullptr; @@ -112,6 +111,7 @@ kernel_main(args::header *header) { kutil::assert_set_callback(__kernel_assert); init_console(); + logger_init(); gdt_init(); interrupts_init(); @@ -135,8 +135,11 @@ kernel_main(args::header *header) } } + bool has_video = false; if (header->video.size > 0) { fb = memory::to_virtual(reinterpret_cast(&header->video)); + has_video = true; + logger_clear_immediate(); } log::debug(logs::boot, " jsix header is at: %016lx", header); @@ -186,11 +189,12 @@ kernel_main(args::header *header) args::program &prog = header->programs[i]; thread *th = sched->load_process(prog.phys_addr, prog.virt_addr, prog.size, prog.entrypoint); if (i == 2) { - th->set_state(thread::state::constant); + //th->set_state(thread::state::constant); } } - sched->create_kernel_task(logger_task, scheduler::max_priority-1, true); + if (!has_video) + sched->create_kernel_task(logger_task, scheduler::max_priority-1, true); sched->create_kernel_task(stdout_task, scheduler::max_priority-1, true); const char stdout_message[] = "Hello on the fake stdout channel\n"; diff --git a/src/kernel/scheduler.cpp b/src/kernel/scheduler.cpp index e27c9c3..5f89f25 100644 --- a/src/kernel/scheduler.cpp +++ b/src/kernel/scheduler.cpp @@ -19,13 +19,15 @@ #include "objects/vm_area.h" #include "scheduler.h" +// here for the framebuffer hack +#include "kernel_args.h" + #include "kutil/assert.h" scheduler *scheduler::s_instance = nullptr; -extern uintptr_t fb_loc; -extern size_t fb_size; +extern kernel::args::framebuffer *fb; const uint64_t rflags_noint = 0x002; const uint64_t rflags_int = 0x202; @@ -98,8 +100,15 @@ load_process_image(uintptr_t phys, uintptr_t virt, size_t bytes, TCB *tcb) kutil::memcpy(message_arg, message, sizeof(message)); j6_init_framebuffer *fb_desc = push(tcb->rsp3); - fb_desc->addr = reinterpret_cast(0x100000000); - fb_desc->size = fb_size; + fb_desc->addr = fb ? reinterpret_cast(0x100000000) : nullptr; + fb_desc->size = fb ? fb->size : 0; + fb_desc->vertical = fb ? fb->vertical : 0; + fb_desc->horizontal = fb ? fb->horizontal : 0; + fb_desc->scanline = fb ? fb->scanline : 0; + fb_desc->flags = 0; + + if (fb && fb->type == kernel::args::fb_type::bgr8) + fb_desc->flags |= 1; j6_init_value *initv = push(tcb->rsp3); initv->type = j6_init_handle_system; @@ -131,9 +140,11 @@ load_process_image(uintptr_t phys, uintptr_t virt, size_t bytes, TCB *tcb) *argc = 1; // Crazypants framebuffer part - vma = new vm_area_open(fb_size, space, vm_flags::write|vm_flags::mmio); - space.add(0x100000000, vma); - vma->commit(fb_loc, 0, memory::page_count(fb_size)); + if (fb) { + vma = new vm_area_open(fb->size, space, vm_flags::write|vm_flags::mmio); + space.add(0x100000000, vma); + vma->commit(fb->phys_addr, 0, memory::page_count(fb->size)); + } th.clear_state(thread::state::loading); return tcb->rsp3; diff --git a/src/kernel/syscalls/system.cpp b/src/kernel/syscalls/system.cpp index 9730121..fa13a96 100644 --- a/src/kernel/syscalls/system.cpp +++ b/src/kernel/syscalls/system.cpp @@ -7,6 +7,8 @@ #include "objects/thread.h" #include "syscalls/helpers.h" +extern log::logger &g_logger; + namespace syscalls { j6_status_t @@ -29,9 +31,10 @@ system_noop() } j6_status_t -system_get_log(j6_handle_t sys, j6_handle_t *log) +system_get_log(j6_handle_t sys, char *buffer, size_t *size) { - return j6_err_nyi; + *size = g_logger.get_entry(buffer, *size); + return j6_status_ok; } j6_status_t