[SeaBIOS] [PATCH v2] vbe: implement function 09h (get/set palette data)

Daniel Verkamp posted 1 patch 9 months ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/seabios tags/patchew/20240312032644.1439715-1-daniel@drv.nu
vgasrc/vbe.c   | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++
vgasrc/vgahw.h | 10 +++++++++
2 files changed, 71 insertions(+)
[SeaBIOS] [PATCH v2] vbe: implement function 09h (get/set palette data)
Posted by Daniel Verkamp 9 months ago
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>
---

V2: use existing stdvga_dac_read/write() functions

vgasrc/vbe.c   | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++
 vgasrc/vgahw.h | 10 +++++++++
 2 files changed, 71 insertions(+)

diff --git a/vgasrc/vbe.c b/vgasrc/vbe.c
index 91abc9ab..7e4b80bf 100644
--- a/vgasrc/vbe.c
+++ b/vgasrc/vbe.c
@@ -376,6 +376,66 @@ fail:
     regs->ax = 0x014f;
 }
 
+static void
+vbe_104f09(struct bregs *regs)
+{
+    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 ret = 0;
+    int i;
+    switch (regs->bl) {
+    case 0x80:
+    case 0x00:
+        for (i = 0; i < count; i++) {
+            SET_SEG(ES, seg);
+            rgb[0] = GET_VAR(ES, data_far[i*4 + 2]);
+            rgb[1] = GET_VAR(ES, data_far[i*4 + 1]);
+            rgb[2] = GET_VAR(ES, data_far[i*4 + 0]);
+            ret = vgahw_dac_write(GET_SEG(SS), rgb, start + i, 1);
+            if (ret < 0)
+                goto fail;
+        }
+        break;
+    case 0x01:
+        for (i = 0; i < count; i++) {
+            ret = vgahw_dac_read(GET_SEG(SS), rgb, start + i, 1);
+            if (ret < 0)
+                goto fail;
+            SET_SEG(ES, seg);
+            SET_VAR(ES, data_far[i*4 + 0], rgb[2]);
+            SET_VAR(ES, data_far[i*4 + 1], rgb[1]);
+            SET_VAR(ES, data_far[i*4 + 2], rgb[0]);
+            SET_VAR(ES, data_far[i*4 + 3], 0);
+        }
+        break;
+    default:
+        goto fail;
+    }
+    if (ret < 0)
+        goto fail;
+    regs->ax = 0x004f;
+    return;
+fail:
+    regs->ax = 0x014f;
+}
+
 static void
 vbe_104f0a(struct bregs *regs)
 {
@@ -456,6 +516,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;
diff --git a/vgasrc/vgahw.h b/vgasrc/vgahw.h
index 8b64660e..b10075ac 100644
--- a/vgasrc/vgahw.h
+++ b/vgasrc/vgahw.h
@@ -141,6 +141,16 @@ static inline int vgahw_set_dacformat(struct vgamode_s *vmode_g, int val) {
     return stdvga_set_dacformat(vmode_g, val);
 }
 
+static inline int vgahw_dac_write(u16 seg, u8 *data_far, u8 start, int count) {
+    stdvga_dac_write(seg, data_far, start, count);
+    return 0;
+}
+
+static inline int vgahw_dac_read(u16 seg, u8 *data_far, u8 start, int count) {
+    stdvga_dac_read(seg, data_far, start, count);
+    return 0;
+}
+
 static inline int vgahw_save_restore(int cmd, u16 seg, void *data) {
     if (CONFIG_VGA_CIRRUS)
         return clext_save_restore(cmd, seg, data);
-- 
2.43.0

_______________________________________________
SeaBIOS mailing list -- seabios@seabios.org
To unsubscribe send an email to seabios-leave@seabios.org
[SeaBIOS] Re: [PATCH v2] vbe: implement function 09h (get/set palette data)
Posted by Kevin O'Connor 9 months ago
On Mon, Mar 11, 2024 at 08:26:18PM -0700, Daniel Verkamp wrote:
> 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>
> ---
> 
> V2: use existing stdvga_dac_read/write() functions

Thanks.  How about the below instead?  This alternate version checks
for CONFIG_VGA_STDVGA_PORTS up front, uses GET/SET_FARVAR(), and
directly calls stdvga_dac_read/write() (as vgabios.c does).  I don't
have a good way to test this.

-Kevin


From 03f5202aacfb18ca1b15691b1330262091e1a51f Mon Sep 17 00:00:00 2001
From: Daniel Verkamp <daniel@drv.nu>
Date: Mon, 11 Mar 2024 20:26:18 -0700
Subject: [PATCH] vbe: implement function 09h (get/set palette data)

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 | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 59 insertions(+)

diff --git a/vgasrc/vbe.c b/vgasrc/vbe.c
index 20437db..9068e91 100644
--- a/vgasrc/vbe.c
+++ b/vgasrc/vbe.c
@@ -376,6 +376,64 @@ 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
+        debug_stub(regs);
+        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 +514,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;
-- 
2.43.0

_______________________________________________
SeaBIOS mailing list -- seabios@seabios.org
To unsubscribe send an email to seabios-leave@seabios.org
[SeaBIOS] Re: [PATCH v2] vbe: implement function 09h (get/set palette data)
Posted by Daniel Verkamp 9 months ago
On Tue, Mar 12, 2024 at 7:55 AM Kevin O'Connor <kevin@koconnor.net> wrote:
>
> On Mon, Mar 11, 2024 at 08:26:18PM -0700, Daniel Verkamp wrote:
> > 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>
> > ---
> >
> > V2: use existing stdvga_dac_read/write() functions
>
> Thanks.  How about the below instead?  This alternate version checks
> for CONFIG_VGA_STDVGA_PORTS up front, uses GET/SET_FARVAR(), and
> directly calls stdvga_dac_read/write() (as vgabios.c does).  I don't
> have a good way to test this.
>
> -Kevin

The alternate version looks good to me and works in my testing. I'm
using the freely-available shareware version of Quake
(https://archive.org/details/Quake_802) with FreeDOS, if you would
like to reproduce the results.

Thanks,
-- Daniel

>
> From 03f5202aacfb18ca1b15691b1330262091e1a51f Mon Sep 17 00:00:00 2001
> From: Daniel Verkamp <daniel@drv.nu>
> Date: Mon, 11 Mar 2024 20:26:18 -0700
> Subject: [PATCH] vbe: implement function 09h (get/set palette data)
>
> 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 | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 59 insertions(+)
>
> diff --git a/vgasrc/vbe.c b/vgasrc/vbe.c
> index 20437db..9068e91 100644
> --- a/vgasrc/vbe.c
> +++ b/vgasrc/vbe.c
> @@ -376,6 +376,64 @@ 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
> +        debug_stub(regs);
> +        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 +514,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;
> --
> 2.43.0
>
_______________________________________________
SeaBIOS mailing list -- seabios@seabios.org
To unsubscribe send an email to seabios-leave@seabios.org
[SeaBIOS] Re: [PATCH v2] vbe: implement function 09h (get/set palette data)
Posted by Kevin O'Connor 9 months ago
On Tue, Mar 12, 2024 at 09:09:23PM -0700, Daniel Verkamp wrote:
> On Tue, Mar 12, 2024 at 7:55 AM Kevin O'Connor <kevin@koconnor.net> wrote:
> >
> > On Mon, Mar 11, 2024 at 08:26:18PM -0700, Daniel Verkamp wrote:
> > > 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>
> > > ---
> > >
> > > V2: use existing stdvga_dac_read/write() functions
> >
> > Thanks.  How about the below instead?  This alternate version checks
> > for CONFIG_VGA_STDVGA_PORTS up front, uses GET/SET_FARVAR(), and
> > directly calls stdvga_dac_read/write() (as vgabios.c does).  I don't
> > have a good way to test this.
> >
> > -Kevin
> 
> The alternate version looks good to me and works in my testing. I'm
> using the freely-available shareware version of Quake
> (https://archive.org/details/Quake_802) with FreeDOS, if you would
> like to reproduce the results.

Thanks, I removed the unnecessary call to debug_stub() that I added,
and I committed this change.

-Kevin
_______________________________________________
SeaBIOS mailing list -- seabios@seabios.org
To unsubscribe send an email to seabios-leave@seabios.org