diff --git a/Kernel/Devices/BXVGADevice.cpp b/Kernel/Devices/BXVGADevice.cpp index 8219de9c17..06be3bb785 100644 --- a/Kernel/Devices/BXVGADevice.cpp +++ b/Kernel/Devices/BXVGADevice.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -53,9 +54,13 @@ BXVGADevice& BXVGADevice::the() UNMAP_AFTER_INIT BXVGADevice::BXVGADevice() : BlockDevice(29, 0) - { m_framebuffer_address = PhysicalAddress(find_framebuffer_address()); + m_mmio_registers = find_mmio_region(); + m_vga_compatible = is_vga_compatible(); + + set_register(VBE_DISPI_INDEX_ID, 0xB0C0); + dmesgln("BXVGA: ID {}", get_register(VBE_DISPI_INDEX_ID)); set_safe_resolution(); } @@ -69,14 +74,23 @@ void BXVGADevice::set_safe_resolution() void BXVGADevice::set_register(u16 index, u16 data) { - IO::out16(VBE_DISPI_IOPORT_INDEX, index); - IO::out16(VBE_DISPI_IOPORT_DATA, data); + if (m_vga_compatible) { + IO::out16(VBE_DISPI_IOPORT_INDEX, index); + IO::out16(VBE_DISPI_IOPORT_DATA, data); + return; + } + auto reg = map_typed_writable(m_mmio_registers.offset(index * 2)); + *(reg.ptr()) = data; } u16 BXVGADevice::get_register(u16 index) { - IO::out16(VBE_DISPI_IOPORT_INDEX, index); - return IO::in16(VBE_DISPI_IOPORT_DATA); + if (m_vga_compatible) { + IO::out16(VBE_DISPI_IOPORT_INDEX, index); + return IO::in16(VBE_DISPI_IOPORT_DATA); + } + auto reg = map_typed_writable(m_mmio_registers.offset(index * 2)); + return *(reg.ptr()); } void BXVGADevice::revert_resolution() @@ -153,6 +167,36 @@ UNMAP_AFTER_INIT u32 BXVGADevice::find_framebuffer_address() return framebuffer_address; } +UNMAP_AFTER_INIT PhysicalAddress BXVGADevice::find_mmio_region() +{ + // NOTE: The QEMU card has the same PCI ID as the Bochs one. + static const PCI::ID bochs_vga_id = { 0x1234, 0x1111 }; + static const PCI::ID virtualbox_vga_id = { 0x80ee, 0xbeef }; + u32 mmio_region = 0; + PCI::enumerate([&mmio_region](const PCI::Address& address, PCI::ID id) { + if (id == bochs_vga_id || id == virtualbox_vga_id) { + mmio_region = PCI::get_BAR1(address) & 0xfffffff0; + dmesgln("BXVGA: mmio region @ {}", PhysicalAddress(mmio_region)); + } + }); + return PhysicalAddress(mmio_region); +} + +UNMAP_AFTER_INIT bool BXVGADevice::is_vga_compatible() +{ + // NOTE: The QEMU card has the same PCI ID as the Bochs one. + static const PCI::ID bochs_vga_id = { 0x1234, 0x1111 }; + static const PCI::ID virtualbox_vga_id = { 0x80ee, 0xbeef }; + bool vga_compatible = true; + PCI::enumerate([&vga_compatible](const PCI::Address& address, PCI::ID id) { + if (id == bochs_vga_id || id == virtualbox_vga_id) { + if (PCI::get_subclass(address) != 0) + vga_compatible = false; + } + }); + return vga_compatible; +} + KResultOr BXVGADevice::mmap(Process& process, FileDescription&, const Range& range, u64 offset, int prot, bool shared) { REQUIRE_PROMISE(video); diff --git a/Kernel/Devices/BXVGADevice.h b/Kernel/Devices/BXVGADevice.h index 355d258db2..b1692dc9f7 100644 --- a/Kernel/Devices/BXVGADevice.h +++ b/Kernel/Devices/BXVGADevice.h @@ -36,6 +36,9 @@ private: virtual KResultOr read(FileDescription&, u64, UserOrKernelBuffer&, size_t) override { return EINVAL; } virtual KResultOr write(FileDescription&, u64, const UserOrKernelBuffer&, size_t) override { return EINVAL; } + PhysicalAddress find_mmio_region(); + bool is_vga_compatible(); + void set_safe_resolution(); void set_register(u16 index, u16 value); @@ -50,6 +53,8 @@ private: void set_y_offset(size_t); PhysicalAddress m_framebuffer_address; + PhysicalAddress m_mmio_registers; + bool m_vga_compatible { true }; size_t m_framebuffer_pitch { 0 }; size_t m_framebuffer_width { 0 }; size_t m_framebuffer_height { 0 };