From b957c61e6f9a9cb947f8bda2d926fba70429c9b0 Mon Sep 17 00:00:00 2001 From: Conrad Pankoff Date: Sun, 18 Aug 2019 14:54:52 +1000 Subject: [PATCH] Kernel: Implement generic VGA device using multiboot info This implements a very basic VGA device using the information provided to us by the bootloader in the multiboot header. This allows Serenity to boot to the desktop on basically any halfway modern system. --- Kernel/Boot/boot.S | 6 +- Kernel/Devices/MBVGADevice.cpp | 102 +++++++++++++++++++++++++++++++++ Kernel/Devices/MBVGADevice.h | 31 ++++++++++ Kernel/Makefile | 1 + Kernel/init.cpp | 12 +++- 5 files changed, 148 insertions(+), 4 deletions(-) create mode 100644 Kernel/Devices/MBVGADevice.cpp create mode 100644 Kernel/Devices/MBVGADevice.h diff --git a/Kernel/Boot/boot.S b/Kernel/Boot/boot.S index d37bfe964b..10892fc4e1 100644 --- a/Kernel/Boot/boot.S +++ b/Kernel/Boot/boot.S @@ -1,7 +1,7 @@ .set MULTIBOOT_MAGIC, 0x1badb002 .set MULTIBOOT_PAGE_ALIGN, 0x1 .set MULTIBOOT_MEMORY_INFO, 0x2 -.set MULTIBOOT_VIDEO_MODE, 0x0 +.set MULTIBOOT_VIDEO_MODE, 0x4 .set multiboot_flags, MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO | MULTIBOOT_VIDEO_MODE .set multiboot_checksum, -(MULTIBOOT_MAGIC + multiboot_flags) @@ -22,8 +22,8 @@ /* for MULTIBOOT_VIDEO_MODE */ .long 0x00000000 /* mode_type */ -.long 0 /* width */ -.long 0 /* height */ +.long 1024 /* width */ +.long 768 /* height */ .long 32 /* depth */ .section .stack, "aw", @nobits diff --git a/Kernel/Devices/MBVGADevice.cpp b/Kernel/Devices/MBVGADevice.cpp new file mode 100644 index 0000000000..a730fd25b6 --- /dev/null +++ b/Kernel/Devices/MBVGADevice.cpp @@ -0,0 +1,102 @@ +#include +#include +#include +#include +#include +#include + +static MBVGADevice* s_the; + +MBVGADevice& MBVGADevice::the() +{ + return *s_the; +} + +MBVGADevice::MBVGADevice(PhysicalAddress addr, int pitch, int width, int height) + : BlockDevice(29, 0) + , m_framebuffer_address(addr) + , m_framebuffer_pitch(pitch) + , m_framebuffer_width(width) + , m_framebuffer_height(height) +{ + s_the = this; +} + +KResultOr MBVGADevice::mmap(Process& process, FileDescription&, VirtualAddress preferred_vaddr, size_t offset, size_t size, int prot) +{ + ASSERT(offset == 0); + ASSERT(size == framebuffer_size_in_bytes()); + auto vmo = AnonymousVMObject::create_for_physical_range(m_framebuffer_address, framebuffer_size_in_bytes()); + auto* region = process.allocate_region_with_vmo( + preferred_vaddr, + framebuffer_size_in_bytes(), + move(vmo), + 0, + "MBVGA Framebuffer", + prot); + kprintf("MBVGA: %s(%u) created Region{%p} with size %u for framebuffer P%x with vaddr L%x\n", + process.name().characters(), process.pid(), + region, region->size(), m_framebuffer_address.as_ptr(), region->vaddr().get()); + ASSERT(region); + return region; +} + +int MBVGADevice::ioctl(FileDescription&, unsigned request, unsigned arg) +{ + switch (request) { + case FB_IOCTL_GET_SIZE_IN_BYTES: { + auto* out = (size_t*)arg; + if (!current->process().validate_write_typed(out)) + return -EFAULT; + *out = framebuffer_size_in_bytes(); + return 0; + } + case FB_IOCTL_GET_BUFFER: { + auto* index = (int*)arg; + if (!current->process().validate_write_typed(index)) + return -EFAULT; + *index = 0; + return 0; + } + case FB_IOCTL_GET_RESOLUTION: { + auto* resolution = (FBResolution*)arg; + if (!current->process().validate_write_typed(resolution)) + return -EFAULT; + resolution->pitch = m_framebuffer_pitch; + resolution->width = m_framebuffer_width; + resolution->height = m_framebuffer_height; + return 0; + } + case FB_IOCTL_SET_RESOLUTION: { + auto* resolution = (FBResolution*)arg; + if (!current->process().validate_read_typed(resolution) || !current->process().validate_write_typed(resolution)) + return -EFAULT; + resolution->pitch = m_framebuffer_pitch; + resolution->width = m_framebuffer_width; + resolution->height = m_framebuffer_height; + return 0; + } + default: + return -EINVAL; + }; +} + +bool MBVGADevice::can_read(FileDescription&) const +{ + ASSERT_NOT_REACHED(); +} + +bool MBVGADevice::can_write(FileDescription&) const +{ + ASSERT_NOT_REACHED(); +} + +ssize_t MBVGADevice::read(FileDescription&, u8*, ssize_t) +{ + ASSERT_NOT_REACHED(); +} + +ssize_t MBVGADevice::write(FileDescription&, const u8*, ssize_t) +{ + ASSERT_NOT_REACHED(); +} diff --git a/Kernel/Devices/MBVGADevice.h b/Kernel/Devices/MBVGADevice.h new file mode 100644 index 0000000000..b465d3ecce --- /dev/null +++ b/Kernel/Devices/MBVGADevice.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include +#include +#include + +class MBVGADevice final : public BlockDevice { + AK_MAKE_ETERNAL +public: + static MBVGADevice& the(); + + MBVGADevice(PhysicalAddress addr, int pitch, int width, int height); + + virtual int ioctl(FileDescription&, unsigned request, unsigned arg) override; + virtual KResultOr mmap(Process&, FileDescription&, VirtualAddress preferred_vaddr, size_t offset, size_t, int prot) override; + +private: + virtual const char* class_name() const override { return "MBVGA"; } + virtual bool can_read(FileDescription&) const override; + virtual bool can_write(FileDescription&) const override; + virtual ssize_t read(FileDescription&, u8*, ssize_t) override; + virtual ssize_t write(FileDescription&, const u8*, ssize_t) override; + + size_t framebuffer_size_in_bytes() const { return m_framebuffer_pitch * m_framebuffer_height; } + + PhysicalAddress m_framebuffer_address; + int m_framebuffer_pitch { 0 }; + int m_framebuffer_width { 0 }; + int m_framebuffer_height { 0 }; +}; diff --git a/Kernel/Makefile b/Kernel/Makefile index 97e1a17369..6afbf161fb 100644 --- a/Kernel/Makefile +++ b/Kernel/Makefile @@ -44,6 +44,7 @@ KERNEL_OBJS = \ FileSystem/SharedMemory.o \ FileSystem/DevPtsFS.o \ Devices/BXVGADevice.o \ + Devices/MBVGADevice.o \ PCI.o \ Devices/PS2MouseDevice.o \ Devices/SerialDevice.o \ diff --git a/Kernel/init.cpp b/Kernel/init.cpp index d90e6130ff..e8b2904645 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -229,7 +230,16 @@ extern "C" [[noreturn]] void init() ); }); - new BXVGADevice; + if (multiboot_info_ptr->framebuffer_type == 1) { + new MBVGADevice( + PhysicalAddress((u32)(multiboot_info_ptr->framebuffer_addr)), + multiboot_info_ptr->framebuffer_pitch, + multiboot_info_ptr->framebuffer_width, + multiboot_info_ptr->framebuffer_height + ); + } else { + new BXVGADevice; + } auto e1000 = E1000NetworkAdapter::autodetect();