From 5787aff866a8cd53fa1c3534e71fa39c21b93875 Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Sun, 27 Dec 2020 18:49:38 -0800 Subject: [PATCH] [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. --- modules.yaml | 10 ++++ scripts/templates/build.ninja.j2 | 4 ++ src/boot/console.cpp | 80 +++++++------------------------- src/boot/console.h | 7 +++ src/boot/main.cpp | 3 ++ src/drivers/fb/main.cpp | 41 ++++++++++++++++ src/drivers/fb/main.s | 24 ++++++++++ src/include/kernel_args.h | 19 +++++++- src/kernel/main.cpp | 15 +++++- src/kernel/objects/vm_area.h | 2 + src/kernel/scheduler.cpp | 13 +++++- src/kernel/scheduler.h | 3 +- src/kernel/vm_mapper.cpp | 12 ++++- src/kernel/vm_mapper.h | 2 + src/kernel/vm_space.cpp | 6 ++- 15 files changed, 170 insertions(+), 71 deletions(-) create mode 100644 src/drivers/fb/main.cpp create mode 100644 src/drivers/fb/main.s diff --git a/modules.yaml b/modules.yaml index 5c7f6b1..c60391f 100644 --- a/modules.yaml +++ b/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 diff --git a/scripts/templates/build.ninja.j2 b/scripts/templates/build.ninja.j2 index 44d6d6b..5ee5aca 100644 --- a/scripts/templates/build.ninja.j2 +++ b/scripts/templates/build.ninja.j2 @@ -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 diff --git a/src/boot/console.cpp b/src/boot/console.cpp index 8554913..9448352 100644 --- a/src/boot/console.cpp +++ b/src/boot/console.cpp @@ -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(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(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(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(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 diff --git a/src/boot/console.h b/src/boot/console.h index 43acb95..4fc852b 100644 --- a/src/boot/console.h +++ b/src/boot/console.h @@ -5,6 +5,8 @@ #include #include #include +#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; }; diff --git a/src/boot/main.cpp b/src/boot/main.cpp index 08815cb..16574c1 100644 --- a/src/boot/main.cpp +++ b/src/boot/main.cpp @@ -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++]; diff --git a/src/drivers/fb/main.cpp b/src/drivers/fb/main.cpp new file mode 100644 index 0000000..d14b319 --- /dev/null +++ b/src/drivers/fb/main.cpp @@ -0,0 +1,41 @@ +#include +#include + +#include "j6/types.h" +#include "j6/errors.h" +#include "j6/signals.h" + +#include + +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(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(0x100000000); + for (size_t i=0; i < size/4; ++i) { + fb[i] = 0xff; + } + + _syscall_system_log("fb driver done, exiting"); + return 0; +} + diff --git a/src/drivers/fb/main.s b/src/drivers/fb/main.s new file mode 100644 index 0000000..e79154b --- /dev/null +++ b/src/drivers/fb/main.s @@ -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 diff --git a/src/include/kernel_args.h b/src/include/kernel_args.h index c02f0b4..12ebda0 100644 --- a/src/include/kernel_args.h +++ b/src/include/kernel_args.h @@ -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)))); diff --git a/src/kernel/main.cpp b/src/kernel/main.cpp index 2731d83..5fc72bb 100644 --- a/src/kernel/main.cpp +++ b/src/kernel/main.cpp @@ -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); diff --git a/src/kernel/objects/vm_area.h b/src/kernel/objects/vm_area.h index 3857d6e..e8b34c2 100644 --- a/src/kernel/objects/vm_area.h +++ b/src/kernel/objects/vm_area.h @@ -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 }; diff --git a/src/kernel/scheduler.cpp b/src/kernel/scheduler.cpp index a11e692..c355f5e 100644 --- a/src/kernel/scheduler.cpp +++ b/src/kernel/scheduler.cpp @@ -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(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 diff --git a/src/kernel/scheduler.h b/src/kernel/scheduler.h index 9718fd1..90a7789 100644 --- a/src/kernel/scheduler.h +++ b/src/kernel/scheduler.h @@ -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 diff --git a/src/kernel/vm_mapper.cpp b/src/kernel/vm_mapper.cpp index a70855e..2a2d3b3 100644 --- a/src/kernel/vm_mapper.cpp +++ b/src/kernel/vm_mapper.cpp @@ -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); } } } diff --git a/src/kernel/vm_mapper.h b/src/kernel/vm_mapper.h index 2ac8f63..0149922 100644 --- a/src/kernel/vm_mapper.h +++ b/src/kernel/vm_mapper.h @@ -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; diff --git a/src/kernel/vm_space.cpp b/src/kernel/vm_space.cpp index 78c28fc..28bbbe6 100644 --- a/src/kernel/vm_space.cpp +++ b/src/kernel/vm_space.cpp @@ -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; } }