[fb] Create fb driver
Create a new framebuffer driver. Also hackily passing frame buffer size in the list of init handles to all processes and mapping the framebuffer into all processes. Changed bootloader passing frame buffer as a module to its own struct.
This commit is contained in:
10
modules.yaml
10
modules.yaml
@@ -87,6 +87,16 @@ modules:
|
||||
- src/drivers/nulldrv/main.s
|
||||
- src/drivers/nulldrv/serial.cpp
|
||||
|
||||
fb:
|
||||
kind: exe
|
||||
target: user
|
||||
output: fb.elf
|
||||
deps:
|
||||
- libc
|
||||
source:
|
||||
- src/drivers/fb/main.cpp
|
||||
- src/drivers/fb/main.s
|
||||
|
||||
kutil:
|
||||
kind: lib
|
||||
output: libkutil.a
|
||||
|
||||
@@ -190,6 +190,9 @@ build $builddir/fatroot/efi/boot/bootx64.efi : cp $builddir/boot/boot.efi
|
||||
build $builddir/fatroot/nulldrv.elf : cp $builddir/user/nulldrv.elf
|
||||
name = null driver to FAT image
|
||||
|
||||
build $builddir/fatroot/fb.elf : cp $builddir/user/fb.elf
|
||||
name = fb driver to FAT image
|
||||
|
||||
build $builddir/fatroot/terminal.elf : cp $builddir/user/nulldrv.elf
|
||||
name = terminal driver to FAT image
|
||||
|
||||
@@ -198,6 +201,7 @@ build ${builddir}/fatroot/symbol_table.dat : makest ${builddir}/jsix.elf
|
||||
build $builddir/jsix.img : makefat | $
|
||||
$builddir/fatroot/symbol_table.dat $
|
||||
$builddir/fatroot/nulldrv.elf $
|
||||
$builddir/fatroot/fb.elf $
|
||||
$builddir/fatroot/terminal.elf $
|
||||
$builddir/fatroot/jsix.elf $
|
||||
$builddir/fatroot/efi/boot/bootx64.efi
|
||||
|
||||
@@ -49,9 +49,10 @@ wstrlen(const wchar_t *s)
|
||||
|
||||
|
||||
console::console(uefi::boot_services *bs, uefi::protos::simple_text_output *out) :
|
||||
m_rows(0),
|
||||
m_cols(0),
|
||||
m_out(out)
|
||||
m_rows {0},
|
||||
m_cols {0},
|
||||
m_out {out},
|
||||
m_fb {0, 0}
|
||||
{
|
||||
pick_mode(bs);
|
||||
|
||||
@@ -93,7 +94,7 @@ console::pick_mode(uefi::boot_services *bs)
|
||||
(uefi::graphics_output_mode_info *)gfx_out_proto->mode;
|
||||
|
||||
uint32_t res = info->horizontal_resolution * info->vertical_resolution;
|
||||
int is_fb = info->pixel_format != uefi::pixel_format::blt_only;
|
||||
int pixmode = static_cast<int>(info->pixel_format);
|
||||
|
||||
for (uint32_t i = 0; i < modes; ++i) {
|
||||
size_t size = 0;
|
||||
@@ -107,17 +108,27 @@ console::pick_mode(uefi::boot_services *bs)
|
||||
#endif
|
||||
|
||||
const uint32_t new_res = info->horizontal_resolution * info->vertical_resolution;
|
||||
const int new_is_fb = info->pixel_format != uefi::pixel_format::blt_only;
|
||||
int new_pixmode = static_cast<int>(info->pixel_format);
|
||||
|
||||
if (new_is_fb > is_fb && new_res >= res) {
|
||||
if (new_pixmode <= pixmode && new_res >= res) {
|
||||
best = i;
|
||||
res = new_res;
|
||||
pixmode = new_pixmode;
|
||||
}
|
||||
}
|
||||
|
||||
try_or_raise(
|
||||
gfx_out_proto->set_mode(best),
|
||||
L"Failed to set graphics mode");
|
||||
|
||||
if (pixmode <= static_cast<int>(uefi::pixel_format::bgr8)) {
|
||||
m_fb.phys_addr = gfx_out_proto->mode->frame_buffer_base;
|
||||
m_fb.size = gfx_out_proto->mode->frame_buffer_size;
|
||||
m_fb.vertical = gfx_out_proto->mode->info->vertical_resolution;
|
||||
m_fb.horizontal = gfx_out_proto->mode->info->horizontal_resolution;
|
||||
m_fb.scanline = gfx_out_proto->mode->info->pixels_per_scanline;
|
||||
m_fb.type = static_cast<kernel::args::fb_type>(pixmode);
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
@@ -387,61 +398,4 @@ status_line::finish()
|
||||
print_status_tag();
|
||||
}
|
||||
|
||||
/*
|
||||
uefi::status
|
||||
con_get_framebuffer(
|
||||
EFI_BOOT_SERVICES *bootsvc,
|
||||
void **buffer,
|
||||
size_t *buffer_size,
|
||||
uint32_t *hres,
|
||||
uint32_t *vres,
|
||||
uint32_t *rmask,
|
||||
uint32_t *gmask,
|
||||
uint32_t *bmask)
|
||||
{
|
||||
uefi::status status;
|
||||
|
||||
uefi::protos::graphics_output *gop;
|
||||
status = bootsvc->LocateProtocol(&guid_gfx_out, NULL, (void **)&gop);
|
||||
if (status != EFI_NOT_FOUND) {
|
||||
CHECK_EFI_STATUS_OR_RETURN(status, "LocateProtocol gfx");
|
||||
|
||||
*buffer = (void *)gop->Mode->FrameBufferBase;
|
||||
*buffer_size = gop->Mode->FrameBufferSize;
|
||||
*hres = gop->Mode->Info->horizontal_resolution;
|
||||
*vres = gop->Mode->Info->vertical_resolution;
|
||||
|
||||
switch (gop->Mode->Info->PixelFormat) {
|
||||
case PixelRedGreenBlueReserved8BitPerColor:
|
||||
*rmask = 0x0000ff;
|
||||
*gmask = 0x00ff00;
|
||||
*bmask = 0xff0000;
|
||||
return EFI_SUCCESS;
|
||||
|
||||
case PixelBlueGreenRedReserved8BitPerColor:
|
||||
*bmask = 0x0000ff;
|
||||
*gmask = 0x00ff00;
|
||||
*rmask = 0xff0000;
|
||||
return EFI_SUCCESS;
|
||||
|
||||
case PixelBitMask:
|
||||
*rmask = gop->Mode->Info->PixelInformation.RedMask;
|
||||
*gmask = gop->Mode->Info->PixelInformation.GreenMask;
|
||||
*bmask = gop->Mode->Info->PixelInformation.BlueMask;
|
||||
return EFI_SUCCESS;
|
||||
|
||||
default:
|
||||
// Not a framebuffer, fall through to zeroing out
|
||||
// values below.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*buffer = NULL;
|
||||
*buffer_size = *hres = *vres = 0;
|
||||
*rmask = *gmask = *bmask = 0;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
*/
|
||||
|
||||
} // namespace boot
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include <stddef.h>
|
||||
#include <uefi/boot_services.h>
|
||||
#include <uefi/protos/simple_text_output.h>
|
||||
#include "kernel_args.h"
|
||||
#include "types.h"
|
||||
|
||||
namespace boot {
|
||||
|
||||
@@ -12,6 +14,8 @@ namespace boot {
|
||||
class console
|
||||
{
|
||||
public:
|
||||
using framebuffer = kernel::args::framebuffer;
|
||||
|
||||
console(uefi::boot_services *bs, uefi::protos::simple_text_output *out);
|
||||
|
||||
size_t print_hex(uint32_t n) const;
|
||||
@@ -20,6 +24,8 @@ public:
|
||||
size_t print_long_dec(uint64_t n) const;
|
||||
size_t printf(const wchar_t *fmt, ...) const;
|
||||
|
||||
const framebuffer & fb() const { return m_fb; };
|
||||
|
||||
static console & get() { return *s_console; }
|
||||
static size_t print(const wchar_t *fmt, ...);
|
||||
|
||||
@@ -31,6 +37,7 @@ private:
|
||||
|
||||
size_t m_rows, m_cols;
|
||||
uefi::protos::simple_text_output *m_out;
|
||||
framebuffer m_fb;
|
||||
|
||||
static console *s_console;
|
||||
};
|
||||
|
||||
@@ -37,6 +37,7 @@ struct program_desc
|
||||
const program_desc program_list[] = {
|
||||
{L"kernel", L"jsix.elf"},
|
||||
{L"null driver", L"nulldrv.elf"},
|
||||
{L"fb driver", L"fb.elf"},
|
||||
//{L"terminal driver", L"terminal.elf"},
|
||||
};
|
||||
|
||||
@@ -127,6 +128,8 @@ bootloader_main_uefi(
|
||||
memory::module_type);
|
||||
add_module(args, args::mod_type::symbol_table, symbols);
|
||||
|
||||
args->video = con.fb();
|
||||
|
||||
for (auto &desc : program_list) {
|
||||
buffer buf = loader::load_file(disk, desc.name, desc.path);
|
||||
args::program &program = args->programs[args->num_programs++];
|
||||
|
||||
41
src/drivers/fb/main.cpp
Normal file
41
src/drivers/fb/main.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "j6/types.h"
|
||||
#include "j6/errors.h"
|
||||
#include "j6/signals.h"
|
||||
|
||||
#include <j6libc/syscalls.h>
|
||||
|
||||
extern "C" {
|
||||
void _init_libc(j6_process_init *);
|
||||
int main(int, const char **);
|
||||
}
|
||||
|
||||
j6_handle_t sys = j6_handle_invalid;
|
||||
size_t size = 0;
|
||||
|
||||
void
|
||||
_init_libc(j6_process_init *init)
|
||||
{
|
||||
sys = init->handles[0];
|
||||
size = reinterpret_cast<size_t>(init->handles[1]);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, const char **argv)
|
||||
{
|
||||
_syscall_system_log("fb driver starting");
|
||||
|
||||
if (size == 0)
|
||||
return 1;
|
||||
|
||||
uint32_t *fb = reinterpret_cast<uint32_t*>(0x100000000);
|
||||
for (size_t i=0; i < size/4; ++i) {
|
||||
fb[i] = 0xff;
|
||||
}
|
||||
|
||||
_syscall_system_log("fb driver done, exiting");
|
||||
return 0;
|
||||
}
|
||||
|
||||
24
src/drivers/fb/main.s
Normal file
24
src/drivers/fb/main.s
Normal file
@@ -0,0 +1,24 @@
|
||||
section .bss
|
||||
mymessage:
|
||||
resq 1024
|
||||
|
||||
extern main
|
||||
extern _init_libc
|
||||
extern exit
|
||||
|
||||
section .text
|
||||
|
||||
global _start
|
||||
_start:
|
||||
mov rbp, rsp
|
||||
|
||||
mov rdi, rsp
|
||||
call _init_libc
|
||||
|
||||
mov rdi, 0
|
||||
mov rsi, 0
|
||||
|
||||
call main
|
||||
|
||||
mov rdi, rax
|
||||
call exit
|
||||
@@ -11,8 +11,7 @@ constexpr uint32_t magic = 0x600dda7a;
|
||||
constexpr uint16_t version = 1;
|
||||
|
||||
enum class mod_type : uint32_t {
|
||||
symbol_table,
|
||||
framebuffer
|
||||
symbol_table
|
||||
};
|
||||
|
||||
struct module {
|
||||
@@ -21,6 +20,20 @@ struct module {
|
||||
mod_type type;
|
||||
};
|
||||
|
||||
enum class fb_type : uint16_t {
|
||||
rgb8,
|
||||
bgr8
|
||||
};
|
||||
|
||||
struct framebuffer {
|
||||
uintptr_t phys_addr;
|
||||
size_t size;
|
||||
uint32_t vertical;
|
||||
uint32_t horizontal;
|
||||
uint16_t scanline;
|
||||
fb_type type;
|
||||
};
|
||||
|
||||
struct program {
|
||||
uintptr_t phys_addr;
|
||||
uintptr_t virt_addr;
|
||||
@@ -74,6 +87,8 @@ struct header {
|
||||
|
||||
void *runtime_services;
|
||||
void *acpi_table;
|
||||
|
||||
framebuffer video;
|
||||
}
|
||||
__attribute__((aligned(alignof(max_align_t))));
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "log.h"
|
||||
#include "objects/channel.h"
|
||||
#include "objects/event.h"
|
||||
#include "objects/thread.h"
|
||||
#include "scheduler.h"
|
||||
#include "serial.h"
|
||||
#include "symbol_table.h"
|
||||
@@ -44,6 +45,10 @@ run_constructors()
|
||||
|
||||
extern void __kernel_assert(const char *, unsigned, const char *);
|
||||
|
||||
/// TODO: not this. this is awful.
|
||||
uintptr_t fb_loc = 0;
|
||||
size_t fb_size = 0;
|
||||
|
||||
/// Bootstrap the memory managers.
|
||||
void memory_initialize_pre_ctors(kernel::args::header *kargs);
|
||||
void memory_initialize_post_ctors(kernel::args::header *kargs);
|
||||
@@ -131,6 +136,11 @@ kernel_main(args::header *header)
|
||||
}
|
||||
}
|
||||
|
||||
if (header->video.size > 0) {
|
||||
fb_size = header->video.size;
|
||||
fb_loc = header->video.phys_addr;
|
||||
}
|
||||
|
||||
log::debug(logs::boot, " jsix header is at: %016lx", header);
|
||||
log::debug(logs::boot, " Memory map is at: %016lx", header->mem_map);
|
||||
log::debug(logs::boot, "ACPI root table is at: %016lx", header->acpi_table);
|
||||
@@ -176,7 +186,10 @@ kernel_main(args::header *header)
|
||||
// Skip program 0, which is the kernel itself
|
||||
for (size_t i = 1; i < header->num_programs; ++i) {
|
||||
args::program &prog = header->programs[i];
|
||||
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) {
|
||||
th->set_state(thread::state::constant);
|
||||
}
|
||||
}
|
||||
|
||||
sched->create_kernel_task(logger_task, scheduler::max_priority-1, true);
|
||||
|
||||
@@ -28,6 +28,8 @@ enum class vm_flags : uint32_t
|
||||
large_pages = 0x00000100,
|
||||
huge_pages = 0x00000200,
|
||||
|
||||
mmio = 0x00010000,
|
||||
|
||||
user_mask = 0x0000ffff ///< flags allowed via syscall
|
||||
};
|
||||
|
||||
|
||||
@@ -22,6 +22,9 @@
|
||||
|
||||
scheduler *scheduler::s_instance = nullptr;
|
||||
|
||||
extern uintptr_t fb_loc;
|
||||
extern size_t fb_size;
|
||||
|
||||
const uint64_t rflags_noint = 0x002;
|
||||
const uint64_t rflags_int = 0x202;
|
||||
|
||||
@@ -87,6 +90,12 @@ load_process_image(uintptr_t phys, uintptr_t virt, size_t bytes, TCB *tcb)
|
||||
init->handles[1] = j6_handle_invalid;
|
||||
init->handles[2] = j6_handle_invalid;
|
||||
|
||||
// Crazypants framebuffer part
|
||||
init->handles[1] = reinterpret_cast<j6_handle_t>(fb_size);
|
||||
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));
|
||||
|
||||
thread::current().clear_state(thread::state::loading);
|
||||
return tcb->rsp3;
|
||||
}
|
||||
@@ -107,7 +116,7 @@ scheduler::create_process(bool user)
|
||||
return th;
|
||||
}
|
||||
|
||||
void
|
||||
thread *
|
||||
scheduler::load_process(uintptr_t phys, uintptr_t virt, size_t size, uintptr_t entry)
|
||||
{
|
||||
|
||||
@@ -145,6 +154,8 @@ scheduler::load_process(uintptr_t phys, uintptr_t virt, size_t size, uintptr_t e
|
||||
log::debug(logs::task, " RSP %016lx", tcb->rsp);
|
||||
log::debug(logs::task, " RSP0 %016lx", tcb->rsp0);
|
||||
log::debug(logs::task, " PML4 %016lx", tcb->pml4);
|
||||
|
||||
return th;
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -45,7 +45,8 @@ public:
|
||||
/// \arg virt Virtual address of the loaded program image
|
||||
/// \arg size Size of the program image, in bytes
|
||||
/// \arg entry Virtual address of the program entrypoint
|
||||
void load_process(uintptr_t phys, uintptr_t virt, size_t size, uintptr_t entry);
|
||||
/// \returns The main thread of the loaded process
|
||||
thread * load_process(uintptr_t phys, uintptr_t virt, size_t size, uintptr_t entry);
|
||||
|
||||
/// Create a new kernel task
|
||||
/// \arg proc Function to run as a kernel task
|
||||
|
||||
@@ -30,6 +30,14 @@ vm_mapper_single::unmap(uintptr_t offset, size_t count)
|
||||
m_space.clear(m_area, offset, count, true);
|
||||
}
|
||||
|
||||
void
|
||||
vm_mapper_single::remove(vm_space *space)
|
||||
{
|
||||
size_t count = memory::page_count(m_area.size());
|
||||
bool keep = m_area.flags() && vm_flags::mmio;
|
||||
m_space.clear(m_area, 0, count, !keep);
|
||||
}
|
||||
|
||||
|
||||
|
||||
vm_mapper_multi::vm_mapper_multi(vm_area &area) :
|
||||
@@ -88,11 +96,13 @@ void
|
||||
vm_mapper_multi::remove(vm_space *space)
|
||||
{
|
||||
size_t count = memory::page_count(m_area.size());
|
||||
bool keep = m_area.flags() && vm_flags::mmio;
|
||||
|
||||
for (int i = 0; i < m_spaces.count(); ++i) {
|
||||
if (m_spaces[i] == space) {
|
||||
m_spaces.remove_swap_at(i);
|
||||
space->clear(m_area, 0, count, m_spaces.count() == 0);
|
||||
keep &= m_spaces.count() > 0;
|
||||
space->clear(m_area, 0, count, !keep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,8 @@ public:
|
||||
|
||||
vm_space & space() { return m_space; }
|
||||
|
||||
virtual void remove(vm_space *space) override;
|
||||
|
||||
private:
|
||||
vm_area &m_area;
|
||||
vm_space &m_space;
|
||||
|
||||
@@ -175,8 +175,10 @@ vm_space::page_in(const vm_area &vma, uintptr_t offset, uintptr_t phys, size_t c
|
||||
page_table::iterator it {virt, m_pml4};
|
||||
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
it.entry(page_table::level::pt) =
|
||||
(phys + i * frame_size) | flags;
|
||||
uint64_t &entry = it.entry(page_table::level::pt);
|
||||
entry = (phys + i * frame_size) | flags;
|
||||
log::debug(logs::paging, "Setting entry for %016llx: %016llx [%04llx]",
|
||||
it.vaddress(), (phys + i * frame_size), flags);
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user