From 6a9dc5562db9e6b0c519f9e7439e6964b326c419 Mon Sep 17 00:00:00 2001 From: Liav A Date: Fri, 4 Jun 2021 11:25:42 +0300 Subject: [PATCH] Kernel: Use IO ports instad of MMIO with Bochs graphics in VirtualBox This is needed for VirtualBox, because it doesn't support controlling the device with MMIO. Fixes #7558. --- Kernel/Graphics/BochsGraphicsAdapter.cpp | 53 ++++++++++++++++++++++-- Kernel/Graphics/BochsGraphicsAdapter.h | 3 ++ 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/Kernel/Graphics/BochsGraphicsAdapter.cpp b/Kernel/Graphics/BochsGraphicsAdapter.cpp index 0cfd1dd278..5b815b1bad 100644 --- a/Kernel/Graphics/BochsGraphicsAdapter.cpp +++ b/Kernel/Graphics/BochsGraphicsAdapter.cpp @@ -56,6 +56,11 @@ UNMAP_AFTER_INIT BochsGraphicsAdapter::BochsGraphicsAdapter(PCI::Address pci_add m_framebuffer_console = Graphics::FramebufferConsole::initialize(PhysicalAddress(PCI::get_BAR0(pci_address) & 0xfffffff0), 1024, 768, 1024 * sizeof(u32)); // FIXME: This is a very wrong way to do this... GraphicsManagement::the().m_console = m_framebuffer_console; + + // Note: If we use VirtualBox graphics adapter (which is based on Bochs one), we need to use IO ports + auto id = PCI::get_id(pci_address); + if (id.vendor_id == 0x80ee && id.device_id == 0xbeef) + m_io_required = true; set_safe_resolution(); } @@ -80,6 +85,32 @@ void BochsGraphicsAdapter::set_safe_resolution() VERIFY(result); } +static void set_register_with_io(u16 index, u16 data) +{ + IO::out16(VBE_DISPI_IOPORT_INDEX, index); + IO::out16(VBE_DISPI_IOPORT_DATA, data); +} + +static u16 get_register_with_io(u16 index) +{ + IO::out16(VBE_DISPI_IOPORT_INDEX, index); + return IO::in16(VBE_DISPI_IOPORT_DATA); +} + +void BochsGraphicsAdapter::set_resolution_registers_via_io(size_t width, size_t height) +{ + dbgln_if(BXVGA_DEBUG, "BochsGraphicsAdapter resolution registers set to - {}x{}", width, height); + + set_register_with_io(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED); + set_register_with_io(VBE_DISPI_INDEX_XRES, (u16)width); + set_register_with_io(VBE_DISPI_INDEX_YRES, (u16)height); + set_register_with_io(VBE_DISPI_INDEX_VIRT_WIDTH, (u16)width); + set_register_with_io(VBE_DISPI_INDEX_VIRT_HEIGHT, (u16)height * 2); + set_register_with_io(VBE_DISPI_INDEX_BPP, 32); + set_register_with_io(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED); + set_register_with_io(VBE_DISPI_INDEX_BANK, 0); +} + void BochsGraphicsAdapter::set_resolution_registers(size_t width, size_t height) { dbgln_if(BXVGA_DEBUG, "BochsGraphicsAdapter resolution registers set to - {}x{}", width, height); @@ -105,16 +136,32 @@ bool BochsGraphicsAdapter::try_to_set_resolution(size_t output_port_index, size_ if (Checked::multiplication_would_overflow(width, height, sizeof(u32))) return false; - set_resolution_registers(width, height); + if (m_io_required) + set_resolution_registers_via_io(width, height); + else + set_resolution_registers(width, height); dbgln_if(BXVGA_DEBUG, "BochsGraphicsAdapter resolution test - {}x{}", width, height); - if (!validate_setup_resolution(width, height)) - return false; + if (m_io_required) { + if (!validate_setup_resolution_with_io(width, height)) + return false; + } else { + if (!validate_setup_resolution(width, height)) + return false; + } dbgln("BochsGraphicsAdapter: resolution set to {}x{}", width, height); m_framebuffer_console->set_resolution(width, height, width * sizeof(u32)); return true; } +bool BochsGraphicsAdapter::validate_setup_resolution_with_io(size_t width, size_t height) +{ + if ((u16)width != get_register_with_io(VBE_DISPI_INDEX_XRES) || (u16)height != get_register_with_io(VBE_DISPI_INDEX_YRES)) { + return false; + } + return true; +} + bool BochsGraphicsAdapter::validate_setup_resolution(size_t width, size_t height) { auto registers = map_typed_writable(m_mmio_registers); diff --git a/Kernel/Graphics/BochsGraphicsAdapter.h b/Kernel/Graphics/BochsGraphicsAdapter.h index 6a3816b54d..56bf5da18d 100644 --- a/Kernel/Graphics/BochsGraphicsAdapter.h +++ b/Kernel/Graphics/BochsGraphicsAdapter.h @@ -50,6 +50,8 @@ private: bool validate_setup_resolution(size_t width, size_t height); u32 find_framebuffer_address(); void set_resolution_registers(size_t width, size_t height); + void set_resolution_registers_via_io(size_t width, size_t height); + bool validate_setup_resolution_with_io(size_t width, size_t height); void set_y_offset(size_t); PhysicalAddress m_mmio_registers; @@ -57,6 +59,7 @@ private: RefPtr m_framebuffer_console; SpinLock m_console_mode_switch_lock; bool m_console_enabled { false }; + bool m_io_required { false }; }; }