]> xenbits.xensource.com Git - osstest/seabios.git/commitdiff
vbe: implement function 09h (get/set palette data)
authorDaniel Verkamp <daniel@drv.nu>
Tue, 12 Mar 2024 03:26:18 +0000 (20:26 -0700)
committerKevin O'Connor <kevin@koconnor.net>
Fri, 15 Mar 2024 14:27:52 +0000 (10:27 -0400)
Since the VBE mode attributes indicate that all modes are not VGA
compatible, applications must use VBE function 09h to manipulate the
palette rather than directly accessing the VGA registers.

This implementation uses the standard VGA registers for all hardware,
which may not be appropriate; I only verified qemu -device VGA.

Without this patch, the get/set palette function returns an error code,
so programs that use 8-bit indexed color modes fail. For example, Quake
(DOS) printed "Error: Unable to load VESA palette" and exited when
trying to set a SVGA mode like 640x480, but with the patch it succeeds.
This fixes qemu issue #251 and #1862.

<https://gitlab.com/qemu-project/qemu/-/issues/251>
<https://gitlab.com/qemu-project/qemu/-/issues/1862>

Signed-off-by: Daniel Verkamp <daniel@drv.nu>
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
vgasrc/vbe.c

index 20437dbaff78041973158f2ef95ffdb0635a1014..d7ce941326d1ef2e8dc058b9302486bcf6fe221f 100644 (file)
@@ -376,6 +376,63 @@ fail:
     regs->ax = 0x014f;
 }
 
+static void
+vbe_104f09(struct bregs *regs)
+{
+    if (!CONFIG_VGA_STDVGA_PORTS) {
+        // DAC palette support only available on devices with stdvga ports
+        regs->ax = 0x0100;
+        return;
+    }
+
+    struct vgamode_s *vmode_g = get_current_mode();
+    if (! vmode_g)
+        goto fail;
+    u8 memmodel = GET_GLOBAL(vmode_g->memmodel);
+    u8 depth = GET_GLOBAL(vmode_g->depth);
+    if (memmodel == MM_DIRECT || memmodel == MM_YUV || depth > 8) {
+        regs->ax = 0x034f;
+        return;
+    }
+    if (regs->dh)
+        goto fail;
+    u8 start = regs->dl;
+    int count = regs->cx;
+    int max_colors = 1 << depth;
+    if (start + count > max_colors)
+        goto fail;
+    u16 seg = regs->es;
+    u8 *data_far = (void*)(regs->di+0);
+    u8 rgb[3];
+    int i;
+    switch (regs->bl) {
+    case 0x80:
+    case 0x00:
+        for (i = 0; i < count; i++) {
+            rgb[0] = GET_FARVAR(seg, data_far[i*4 + 2]);
+            rgb[1] = GET_FARVAR(seg, data_far[i*4 + 1]);
+            rgb[2] = GET_FARVAR(seg, data_far[i*4 + 0]);
+            stdvga_dac_write(GET_SEG(SS), rgb, start + i, 1);
+        }
+        break;
+    case 0x01:
+        for (i = 0; i < count; i++) {
+            stdvga_dac_read(GET_SEG(SS), rgb, start + i, 1);
+            SET_FARVAR(seg, data_far[i*4 + 0], rgb[2]);
+            SET_FARVAR(seg, data_far[i*4 + 1], rgb[1]);
+            SET_FARVAR(seg, data_far[i*4 + 2], rgb[0]);
+            SET_FARVAR(seg, data_far[i*4 + 3], 0);
+        }
+        break;
+    default:
+        goto fail;
+    }
+    regs->ax = 0x004f;
+    return;
+fail:
+    regs->ax = 0x014f;
+}
+
 static void
 vbe_104f0a(struct bregs *regs)
 {
@@ -456,6 +513,7 @@ handle_104f(struct bregs *regs)
     case 0x06: vbe_104f06(regs); break;
     case 0x07: vbe_104f07(regs); break;
     case 0x08: vbe_104f08(regs); break;
+    case 0x09: vbe_104f09(regs); break;
     case 0x0a: vbe_104f0a(regs); break;
     case 0x10: vbe_104f10(regs); break;
     case 0x15: vbe_104f15(regs); break;