1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 13:07:46 +00:00

Kernel: Support the bochs-display device

This device is a graphics display device that is not supporting
VGA functionality.
Therefore, it exposes a MMIO region to configure it, so we use that
region to set the framebuffer resolution.
This commit is contained in:
Liav A 2021-03-05 06:52:59 +02:00 committed by Andreas Kling
parent 2dcafde330
commit 86be477da0
2 changed files with 54 additions and 5 deletions

View file

@ -14,6 +14,7 @@
#include <Kernel/Process.h>
#include <Kernel/VM/AnonymousVMObject.h>
#include <Kernel/VM/MemoryManager.h>
#include <Kernel/VM/TypedMapping.h>
#include <LibC/errno_numbers.h>
#include <LibC/sys/ioctl_numbers.h>
@ -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<u16>(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<u16>(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<Region*> BXVGADevice::mmap(Process& process, FileDescription&, const Range& range, u64 offset, int prot, bool shared)
{
REQUIRE_PROMISE(video);

View file

@ -36,6 +36,9 @@ private:
virtual KResultOr<size_t> read(FileDescription&, u64, UserOrKernelBuffer&, size_t) override { return EINVAL; }
virtual KResultOr<size_t> 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 };