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