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