diff --git a/kexts/drivers/video/qemufb/extension.yaml b/kexts/drivers/video/qemufb/extension.yaml new file mode 100644 index 0000000..0ddcade --- /dev/null +++ b/kexts/drivers/video/qemufb/extension.yaml @@ -0,0 +1,8 @@ +name: qemufb +description: | + QEMU virtual video controller driver. +id: net.doorstuck.socks.qemufb +license: BSD-3-Clause +copyright: Copyright © Max Wash 2023 +sources: + - main.c diff --git a/kexts/drivers/video/qemufb/main.c b/kexts/drivers/video/qemufb/main.c new file mode 100644 index 0000000..f3bc712 --- /dev/null +++ b/kexts/drivers/video/qemufb/main.c @@ -0,0 +1,84 @@ +#include +#include +#include +#include +#include +#include + +#define VBE_DISPI_INDEX_ID 0x00u +#define VBE_DISPI_INDEX_XRES 0x01u +#define VBE_DISPI_INDEX_YRES 0x02u +#define VBE_DISPI_INDEX_BPP 0x03u +#define VBE_DISPI_INDEX_ENABLE 0x04u +#define VBE_DISPI_INDEX_BANK 0x05u +#define VBE_DISPI_INDEX_VIRT_WIDTH 0x06u +#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x07u +#define VBE_DISPI_INDEX_X_OFFSET 0x08u +#define VBE_DISPI_INDEX_Y_OFFSET 0x09u + +#define VBE_DISPI_LFB_ENABLED 0x40 + +static struct pci_driver *qemufb_driver = NULL; + +static struct pci_device_id qemufb_device_ids[] = { + PCI_DEVICE_ID(0x1234, 0x1111), + PCI_DEVICE_ID_INVALID, +}; + +static inline uint16_t dispi_mmio_offset(int index) +{ + return (0x500 + (index << 1)) >> 1; +} + +static kern_status_t qemufb_set_varinfo(struct device *dev, const struct framebuffer_varinfo *varinfo) +{ + uint32_t mmio_base = pci_device_read_field(dev, PCI_REG_BAR2, 4); + uint16_t *mmio = vm_phys_to_virt(mmio_base); + + mmio[dispi_mmio_offset(VBE_DISPI_INDEX_ENABLE)] = 0; + mmio[dispi_mmio_offset(VBE_DISPI_INDEX_XRES)] = varinfo->fb_xres; + mmio[dispi_mmio_offset(VBE_DISPI_INDEX_YRES)] = varinfo->fb_yres; + mmio[dispi_mmio_offset(VBE_DISPI_INDEX_BPP)] = varinfo->fb_bpp; + mmio[dispi_mmio_offset(VBE_DISPI_INDEX_ENABLE)] = 1 | VBE_DISPI_LFB_ENABLED; + + if (mmio[dispi_mmio_offset(VBE_DISPI_INDEX_XRES)] != varinfo->fb_xres || + mmio[dispi_mmio_offset(VBE_DISPI_INDEX_YRES)] != varinfo->fb_yres || + mmio[dispi_mmio_offset(VBE_DISPI_INDEX_BPP)] != varinfo->fb_bpp) { + return KERN_UNSUPPORTED; + } + + return KERN_OK; +} + +static struct framebuffer_device_ops qemufb_ops = { + .set_varinfo = qemufb_set_varinfo, +}; + +static kern_status_t qemufb_probe(struct pci_driver *driver, struct device *dev) +{ + struct framebuffer_device *fb = framebuffer_device_from_generic(dev); + (void)fb; + snprintf(dev->dev_name, sizeof dev->dev_name, "qemufb"); + + fb->fb_ops = &qemufb_ops; + + return device_register(dev, pci_driver_base(qemufb_driver), NULL); +} + +static kern_status_t online(struct kext *self) +{ + printk("qemufb: registering PCI driver"); + qemufb_driver = pci_driver_create(self, "qemufb", qemufb_device_ids); + if (!qemufb_driver) { + return KERN_NO_MEMORY; + } + + qemufb_driver->probe = qemufb_probe; + + pci_driver_register(qemufb_driver); + return KERN_OK; +} + +DEFINE_KEXT("net.doorstuck.socks.qemufb", + online, NULL, + PCI_SUBSYSTEM_KEXT_ID);