[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.
This commit is contained in:
Justin C. Miller
2021-01-03 18:13:41 -08:00
parent 4c41205e73
commit 972ef39295
12 changed files with 181 additions and 29 deletions

View File

@@ -94,6 +94,7 @@ modules:
- src/drivers/fb/font.cpp - src/drivers/fb/font.cpp
- src/drivers/fb/main.cpp - src/drivers/fb/main.cpp
- src/drivers/fb/screen.cpp - src/drivers/fb/screen.cpp
- src/drivers/fb/scrollback.cpp
kutil: kutil:
kind: lib kind: lib

View File

@@ -6,6 +6,7 @@ debug=""
debugtarget="${build}/jsix.elf" debugtarget="${build}/jsix.elf"
flash_name="ovmf_vars" flash_name="ovmf_vars"
gfx="-nographic" gfx="-nographic"
vga="-vga none"
kvm="" kvm=""
cpu="Broadwell,+pdpe1gb" cpu="Broadwell,+pdpe1gb"
@@ -22,6 +23,7 @@ for arg in $@; do
;; ;;
--gfx) --gfx)
gfx="" gfx=""
vga=""
;; ;;
--kvm) --kvm)
kvm="-enable-kvm" kvm="-enable-kvm"
@@ -72,4 +74,4 @@ exec qemu-system-x86_64 \
-cpu "${cpu}" \ -cpu "${cpu}" \
-M q35 \ -M q35 \
-no-reboot \ -no-reboot \
$gfx $kvm $debug $gfx $vga $kvm $debug

View File

@@ -83,9 +83,14 @@ console::pick_mode(uefi::boot_services *bs)
uefi::protos::graphics_output *gfx_out_proto; uefi::protos::graphics_output *gfx_out_proto;
uefi::guid guid = uefi::protos::graphics_output::guid; uefi::guid guid = uefi::protos::graphics_output::guid;
try_or_raise( m_fb.type = kernel::args::fb_type::none;
bs->locate_protocol(&guid, nullptr, (void **)&gfx_out_proto),
L"Failed to find a Graphics Output Protocol handle"); 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; const uint32_t modes = gfx_out_proto->mode->max_mode;
uint32_t best = gfx_out_proto->mode->mode; uint32_t best = gfx_out_proto->mode->mode;

View File

@@ -1,5 +1,6 @@
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include "j6/init.h" #include "j6/init.h"
#include "j6/errors.h" #include "j6/errors.h"
@@ -10,12 +11,24 @@
#include "font.h" #include "font.h"
#include "screen.h" #include "screen.h"
#include "scrollback.h"
extern "C" { extern "C" {
int main(int, const char **); int main(int, const char **);
void _get_init(size_t *initc, struct j6_init_value **initv); 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 int
main(int argc, const char **argv) 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); screen scr(fb->addr, fb->horizontal, fb->vertical, order);
font fnt; 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); screen::pixel_t bg = scr.color(49, 79, 128);
scr.fill(bg); 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; scrollback scroll(rows, cols);
char g = 0;
while (y < scr.height() - margin - fnt.height()) { int pending = 0;
int x = margin; constexpr int pending_threshold = 10;
while (x < scr.width() - margin - fnt.width()) {
fnt.draw_glyph(scr, g+' ', fg, bg, x, y); char message_buffer[256];
x += fnt.width() + fnt.width() / 4; while (true) {
g = ++g % ('~' - ' ' + 1); size_t size = sizeof(message_buffer);
_syscall_system_get_log(__handle_sys, message_buffer, &size);
if (size != 0) {
entry *e = reinterpret_cast<entry*>(&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"); _syscall_system_log("fb driver done, exiting");
return 0; return 0;
} }

View File

@@ -0,0 +1,61 @@
#include <stdlib.h>
#include <string.h>
#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<char*>(malloc(lines*cols));
m_lines = reinterpret_cast<char**>(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);
}
}
}

View File

@@ -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;
};

View File

@@ -1,6 +1,6 @@
SYSCALL(0x00, system_log, const char *) SYSCALL(0x00, system_log, const char *)
SYSCALL(0x01, system_noop, void) 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(0x03, system_bind_irq, j6_handle_t, j6_handle_t, unsigned)
SYSCALL(0x08, object_koid, j6_handle_t, j6_koid_t *) SYSCALL(0x08, object_koid, j6_handle_t, j6_koid_t *)

View File

@@ -10,7 +10,7 @@ static uint8_t log_buffer[0x10000];
// so that we can start log output immediately. Keep its constructor // so that we can start log output immediately. Keep its constructor
// from being called here so as to not overwrite the previous initialization. // from being called here so as to not overwrite the previous initialization.
static kutil::no_construct<log::logger> __g_logger_storage; static kutil::no_construct<log::logger> __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}; 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); new (&g_logger) log::logger(log_buffer, sizeof(log_buffer), output_log);
} }
void logger_clear_immediate()
{
g_logger.set_immediate(nullptr);
}

View File

@@ -6,4 +6,5 @@ namespace log = kutil::log;
namespace logs = kutil::logs; namespace logs = kutil::logs;
void logger_init(); void logger_init();
void logger_clear_immediate();
void logger_task(); void logger_task();

View File

@@ -64,7 +64,6 @@ init_console()
cons->puts("jsix OS "); cons->puts("jsix OS ");
cons->set_color(0x08, 0x00); cons->set_color(0x08, 0x00);
cons->puts(GIT_VERSION " booting...\n"); cons->puts(GIT_VERSION " booting...\n");
logger_init();
} }
channel *std_out = nullptr; channel *std_out = nullptr;
@@ -112,6 +111,7 @@ kernel_main(args::header *header)
{ {
kutil::assert_set_callback(__kernel_assert); kutil::assert_set_callback(__kernel_assert);
init_console(); init_console();
logger_init();
gdt_init(); gdt_init();
interrupts_init(); interrupts_init();
@@ -135,8 +135,11 @@ kernel_main(args::header *header)
} }
} }
bool has_video = false;
if (header->video.size > 0) { if (header->video.size > 0) {
fb = memory::to_virtual<args::framebuffer>(reinterpret_cast<uintptr_t>(&header->video)); fb = memory::to_virtual<args::framebuffer>(reinterpret_cast<uintptr_t>(&header->video));
has_video = true;
logger_clear_immediate();
} }
log::debug(logs::boot, " jsix header is at: %016lx", header); 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]; args::program &prog = header->programs[i];
thread *th = sched->load_process(prog.phys_addr, prog.virt_addr, prog.size, prog.entrypoint); thread *th = sched->load_process(prog.phys_addr, prog.virt_addr, prog.size, prog.entrypoint);
if (i == 2) { 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); sched->create_kernel_task(stdout_task, scheduler::max_priority-1, true);
const char stdout_message[] = "Hello on the fake stdout channel\n"; const char stdout_message[] = "Hello on the fake stdout channel\n";

View File

@@ -19,13 +19,15 @@
#include "objects/vm_area.h" #include "objects/vm_area.h"
#include "scheduler.h" #include "scheduler.h"
// here for the framebuffer hack
#include "kernel_args.h"
#include "kutil/assert.h" #include "kutil/assert.h"
scheduler *scheduler::s_instance = nullptr; scheduler *scheduler::s_instance = nullptr;
extern uintptr_t fb_loc; extern kernel::args::framebuffer *fb;
extern size_t fb_size;
const uint64_t rflags_noint = 0x002; const uint64_t rflags_noint = 0x002;
const uint64_t rflags_int = 0x202; 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)); kutil::memcpy(message_arg, message, sizeof(message));
j6_init_framebuffer *fb_desc = push<j6_init_framebuffer>(tcb->rsp3); j6_init_framebuffer *fb_desc = push<j6_init_framebuffer>(tcb->rsp3);
fb_desc->addr = reinterpret_cast<void*>(0x100000000); fb_desc->addr = fb ? reinterpret_cast<void*>(0x100000000) : nullptr;
fb_desc->size = fb_size; 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<j6_init_value>(tcb->rsp3); j6_init_value *initv = push<j6_init_value>(tcb->rsp3);
initv->type = j6_init_handle_system; 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; *argc = 1;
// Crazypants framebuffer part // Crazypants framebuffer part
vma = new vm_area_open(fb_size, space, vm_flags::write|vm_flags::mmio); if (fb) {
space.add(0x100000000, vma); vma = new vm_area_open(fb->size, space, vm_flags::write|vm_flags::mmio);
vma->commit(fb_loc, 0, memory::page_count(fb_size)); space.add(0x100000000, vma);
vma->commit(fb->phys_addr, 0, memory::page_count(fb->size));
}
th.clear_state(thread::state::loading); th.clear_state(thread::state::loading);
return tcb->rsp3; return tcb->rsp3;

View File

@@ -7,6 +7,8 @@
#include "objects/thread.h" #include "objects/thread.h"
#include "syscalls/helpers.h" #include "syscalls/helpers.h"
extern log::logger &g_logger;
namespace syscalls { namespace syscalls {
j6_status_t j6_status_t
@@ -29,9 +31,10 @@ system_noop()
} }
j6_status_t 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 j6_status_t