@samitouri / QOSamiQemu / commits / 601eb8f8ac

ati-vga: Fix framebuffer mapping by using hardware-correct aperture sizes

Rage 128 cards always request 64MB for their linear (framebuffer) aperture and R100 cards always request 128MB. This is regardless of the amount of physical VRAM on the board. The following are results from real hardware tests: Card VRAM PCI BAR0 CONFIG_MEMSIZE CONFIG_APER_SIZE AGP_APER_OFFSET ----------------------- ---- -------- -------------- ---------------- --------------- Rage 128 Pro Ultra TF 32MB 64MB 0x02000000 0x02000000 0x02000000 Rage 128 RF/SG AGP 16MB 64MB 0x01000000 0x02000000 0x02000000 Radeon R100 QD [Radeon 7200] 64MB 128MB 0x04000000 0x04000000 N/A Radeon RV100 QY [Radeon 7000/VE] 32MB 128MB 0x02000000 0x04000000 N/A Previously the linear aperture (BAR0) would match the VRAM size. This discrepancy caused issues with the X.org and XFree86 r128 drivers. These drivers apply a mask of 0xfc000000 (2^26 = 64MB) to the linear aperture address. If that address is not on a 64MB boundary the framebuffer points to an incorrect memory location. Testing shows that the Radeon R100 also has a BAR0 larger than VRAM (128MB in this case) and the X.org radeon driver also masks to 64MB. For Rage 128, CONFIG_APER_SIZE also differs from the previous value and the behavior stated in the documentation. The Rage 128 register guide states that it should contain the size of the VRAM + AGP memory. The cards tested above show that this isn't the case. These tests also included enabling/disabling AGP with 8MB of memory. It didn't change the contents of CONFIG_APER_SIZE. For both Rage 128 and R100 the CONFIG_APER_SIZE is half of the PCI BAR0 size. Signed-off-by: Chad Jablonski <chad@jablonski.xyz> Reviewed-by: BALATON Zoltan <balaton@eik.bme.hu> Message-ID: <20260303024730.1489136-2-chad@jablonski.xyz> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>

Chad Jablonski committed Mar 2, 2026 at 21:47 UTC 601eb8f8acac3475ff3b9a4d2ba9bac3a088e99b
2 files changed +19 -2
hw/display/ati.c
+14 -2
@@ -361,7 +361,7 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size)
361 PCI_BASE_ADDRESS_0, size) & 0xfffffff0;
362 break;
363 case CONFIG_APER_SIZE:
364 - val = s->vga.vram_size / 2;
364 + val = memory_region_size(&s->linear_aper) / 2;
365 break;
366 case CONFIG_REG_1_BASE:
367 val = pci_default_read_config(&s->dev,
@@ -952,6 +952,7 @@ static void ati_vga_realize(PCIDevice *dev, Error **errp)
952 {
953 ATIVGAState *s = ATI_VGA(dev);
954 VGACommonState *vga = &s->vga;
955 + uint64_t aper_size;
956
957 #ifndef CONFIG_PIXMAN
958 if (s->use_pixman != 0) {
@@ -1011,7 +1012,18 @@ static void ati_vga_realize(PCIDevice *dev, Error **errp)
1012 /* io space is alias to beginning of mmregs */
1013 memory_region_init_alias(&s->io, OBJECT(s), "ati.io", &s->mm, 0, 0x100);
1014
1014 - pci_register_bar(dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &vga->vram);
1015 + /*
1016 + * The framebuffer is at the beginning of the linear aperture. For
1017 + * Rage128 the upper half of the aperture is reserved for an AGP
1018 + * window (which we do not emulate.)
1019 + */
1020 + aper_size = s->dev_id == PCI_DEVICE_ID_ATI_RAGE128_PF ?
1021 + ATI_RAGE128_LINEAR_APER_SIZE : ATI_R100_LINEAR_APER_SIZE;
1022 + memory_region_init(&s->linear_aper, OBJECT(dev), "ati-linear-aperture0",
1023 + aper_size);
1024 + memory_region_add_subregion(&s->linear_aper, 0, &vga->vram);
1025 +
1026 + pci_register_bar(dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->linear_aper);
1027 pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->io);
1028 pci_register_bar(dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mm);
1029
hw/display/ati_int.h
+5
@@ -10,6 +10,7 @@
10 #define ATI_INT_H
11
12 #include "qemu/timer.h"
13 +#include "qemu/units.h"
14 #include "hw/pci/pci_device.h"
15 #include "hw/i2c/bitbang_i2c.h"
16 #include "vga_int.h"
@@ -29,6 +30,9 @@
30 /* Radeon RV100 (VE) */
31 #define PCI_DEVICE_ID_ATI_RADEON_QY 0x5159
32
33 +#define ATI_RAGE128_LINEAR_APER_SIZE (64 * MiB)
34 +#define ATI_R100_LINEAR_APER_SIZE (128 * MiB)
35 +
36 #define TYPE_ATI_VGA "ati-vga"
37 OBJECT_DECLARE_SIMPLE_TYPE(ATIVGAState, ATI_VGA)
38
@@ -97,6 +101,7 @@ struct ATIVGAState {
101 QEMUCursor *cursor;
102 QEMUTimer vblank_timer;
103 bitbang_i2c_interface bbi2c;
104 + MemoryRegion linear_aper;
105 MemoryRegion io;
106 MemoryRegion mm;
107 ATIVGARegs regs;