[SeaBIOS] [PATCH 2/4] vgabios: Add support for writing text to framebuffers in high memory.

Kevin O'Connor kevin at koconnor.net
Wed Feb 12 18:31:41 CET 2014


Add code for manipulating "direct" style linear RGB framebuffers that
may be in high memory.  This adds simple font writing and scrolling
support.

Signed-off-by: Kevin O'Connor <kevin at koconnor.net>
---
 Makefile           |   2 +-
 vgasrc/Kconfig     |   2 +
 vgasrc/vgabios.h   |   7 +++
 vgasrc/vgafb.c     |  14 +++--
 vgasrc/vgahighfb.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 173 insertions(+), 6 deletions(-)
 create mode 100644 vgasrc/vgahighfb.c

diff --git a/Makefile b/Makefile
index 488bd04..ffe0650 100644
--- a/Makefile
+++ b/Makefile
@@ -201,7 +201,7 @@ $(OUT)bios.bin.elf: $(OUT)rom.o $(OUT)bios.bin.prep
 
 # VGA src files
 SRCVGA=src/output.c src/string.c src/hw/pci.c src/hw/serialio.c \
-    vgasrc/vgainit.c vgasrc/vgabios.c vgasrc/vgafb.c \
+    vgasrc/vgainit.c vgasrc/vgabios.c vgasrc/vgafb.c vgasrc/vgahighfb.c \
     vgasrc/vgafonts.c vgasrc/vbe.c \
     vgasrc/stdvga.c vgasrc/stdvgamodes.c vgasrc/stdvgaio.c \
     vgasrc/clext.c vgasrc/bochsvga.c vgasrc/geodevga.c
diff --git a/vgasrc/Kconfig b/vgasrc/Kconfig
index a058a86..bdb8f5b 100644
--- a/vgasrc/Kconfig
+++ b/vgasrc/Kconfig
@@ -82,6 +82,8 @@ menu "VGA ROM"
         bool
     config VGA_STDVGA_FRAMEBUFFER
         bool
+    config VGA_HIGH_FRAMEBUFFER
+        bool
 
     config VGA_ALLOCATE_EXTRA_STACK
         depends on BUILD_VGABIOS
diff --git a/vgasrc/vgabios.h b/vgasrc/vgabios.h
index 6949560..1e3b0b2 100644
--- a/vgasrc/vgabios.h
+++ b/vgasrc/vgabios.h
@@ -89,11 +89,18 @@ int vga_set_mode(int mode, int flags);
 // vgafb.c
 void vgafb_scroll(int nblines, int attr
                   , struct cursorpos ul, struct cursorpos lr);
+struct segoff_s get_font_data(u8 c);
 void vgafb_write_char(struct cursorpos cp, struct carattr ca);
 struct carattr vgafb_read_char(struct cursorpos cp);
 void vgafb_write_pixel(u8 color, u16 x, u16 y);
 u8 vgafb_read_pixel(u16 x, u16 y);
 
+// vgahighfb.c
+void scroll_direct(struct vgamode_s *vmode_g, int nblines, int attr
+                   , struct cursorpos ul, struct cursorpos lr);
+void write_gfx_char_direct(struct vgamode_s *vmode_g
+                           , struct cursorpos cp, struct carattr ca);
+
 // vbe.c
 extern u32 VBE_total_memory;
 extern u32 VBE_capabilities;
diff --git a/vgasrc/vgafb.c b/vgasrc/vgafb.c
index a31db46..5da11d2 100644
--- a/vgasrc/vgafb.c
+++ b/vgasrc/vgafb.c
@@ -200,10 +200,12 @@ vgafb_scroll(int nblines, int attr, struct cursorpos ul, struct cursorpos lr)
     case MM_CGA:
         scroll_cga(vmode_g, nblines, attr, ul, lr);
         break;
-    case MM_DIRECT:
     case MM_PACKED:
         scroll_lin(vmode_g, nblines, attr, ul, lr);
         break;
+    case MM_DIRECT:
+        scroll_direct(vmode_g, nblines, attr, ul, lr);
+        break;
     default:
         break;
     }
@@ -214,7 +216,7 @@ vgafb_scroll(int nblines, int attr, struct cursorpos ul, struct cursorpos lr)
  * Read/write characters to screen
  ****************************************************************/
 
-static struct segoff_s
+struct segoff_s
 get_font_data(u8 c)
 {
     int char_height = GET_BDA(char_height);
@@ -369,10 +371,12 @@ vgafb_write_char(struct cursorpos cp, struct carattr ca)
     case MM_CGA:
         write_gfx_char_cga(vmode_g, cp, ca);
         break;
-    case MM_DIRECT:
     case MM_PACKED:
         write_gfx_char_lin(vmode_g, cp, ca);
         break;
+    case MM_DIRECT:
+        write_gfx_char_direct(vmode_g, cp, ca);
+        break;
     default:
         break;
     }
@@ -464,12 +468,12 @@ vgafb_write_pixel(u8 color, u16 x, u16 y)
         }
         SET_FARVAR(SEG_CTEXT, *addr_far, data);
         break;
-    case MM_DIRECT:
     case MM_PACKED:
         addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8));
         SET_FARVAR(SEG_GRAPH, *addr_far, color);
         break;
     default:
+    case MM_DIRECT:
     case MM_TEXT:
         return;
     }
@@ -511,12 +515,12 @@ vgafb_read_pixel(u16 x, u16 y)
         else
             attr = (data >> (7 - (x & 0x07))) & 0x01;
         break;
-    case MM_DIRECT:
     case MM_PACKED:
         addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8));
         attr = GET_FARVAR(SEG_GRAPH, *addr_far);
         break;
     default:
+    case MM_DIRECT:
     case MM_TEXT:
         return 0;
     }
diff --git a/vgasrc/vgahighfb.c b/vgasrc/vgahighfb.c
new file mode 100644
index 0000000..0498b16
--- /dev/null
+++ b/vgasrc/vgahighfb.c
@@ -0,0 +1,154 @@
+// Code for manipulating VGA framebuffer in high memory.
+//
+// Copyright (C) 2014  Kevin O'Connor <kevin at koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_BDA
+#include "vgabios.h" // scroll_direct
+#include "vgahw.h" // vgahw_get_displaystart
+
+// Color mapping for various pixel depth modes.
+u16 DepthMap15[16] VAR16 = {
+    0x0000, 0x0015, 0x02a0, 0x02b5, 0x5400, 0x5415, 0x5550, 0x56b5,
+    0x294a, 0x295f, 0x2bea, 0x2bff, 0x7d4a, 0x7d5f, 0x7fea, 0x7fff,
+};
+u16 DepthMap16[16] VAR16 = {
+    0x0000, 0x0015, 0x0540, 0x0555, 0xa800, 0xa815, 0xaaa0, 0xad55,
+    0x52aa, 0x52bf, 0x57ea, 0x57ff, 0xfaaa, 0xfabf, 0xffea, 0xffff,
+};
+u32 DepthMap32[16] VAR16 = {
+    0x000000, 0x0000aa, 0x00aa00, 0x00aaaa,
+    0xaa0000, 0xaa00aa, 0xaa5500, 0xaaaaaa,
+    0x555555, 0x5555ff, 0x55ff55, 0x55ffff,
+    0xff5555, 0xff55ff, 0xffff55, 0xffffff,
+};
+
+static int
+fill_pixels(struct vgamode_s *vmode_g, void *pixels, u32 attr, u8 mask)
+{
+    int i;
+    switch (GET_GLOBAL(vmode_g->depth)) {
+    case 15:
+        for (i=0; i<8; i++)
+            *(u16*)(pixels+i*2) = GET_GLOBAL(
+                DepthMap15[mask & (0x80>>i) ? attr & 0x0f : attr >> 4]);
+        return 16;
+    case 16:
+        for (i=0; i<8; i++)
+            *(u16*)(pixels+i*2) = GET_GLOBAL(
+                DepthMap16[mask & (0x80>>i) ? attr & 0x0f : attr >> 4]);
+        return 16;
+    case 24:
+        for (i=0; i<8; i++)
+            *(u32*)(pixels+i*3) = GET_GLOBAL(
+                DepthMap32[mask & (0x80>>i) ? attr & 0x0f : attr >> 4]);
+        return 24;
+    default:
+    case 32:
+        for (i=0; i<8; i++)
+            *(u32*)(pixels+i*4) = GET_GLOBAL(
+                DepthMap32[mask & (0x80>>i) ? attr & 0x0f : attr >> 4]);
+        return 32;
+    }
+}
+
+// Use int 1587 call to copy memory to/from the framebuffer.
+static void
+memcpy_high(struct vgamode_s *vmode_g, void *dest, void *src, u32 len)
+{
+    u64 gdt[6];
+    gdt[2] = GDT_DATA | GDT_LIMIT(0xfffff) | GDT_BASE((u32)src);
+    gdt[3] = GDT_DATA | GDT_LIMIT(0xfffff) | GDT_BASE((u32)dest);
+
+    // Call int 1587 to copy data.
+    len/=2;
+    u32 flags;
+    u32 eax = 0x8700;
+    u32 si = (u32)&gdt;
+    SET_SEG(ES, GET_SEG(SS));
+    asm volatile(
+        "stc\n"
+        "int $0x15\n"
+        "cli\n"
+        "cld\n"
+        "pushfl\n"
+        "popl %0\n"
+        : "=r" (flags), "+a" (eax), "+S" (si), "+c" (len)
+        : : "cc", "memory");
+}
+
+static void
+memset_high(struct vgamode_s *vmode_g, void *dest, u32 attr, u32 len)
+{
+    u32 pixels[8];
+    u32 bpp = fill_pixels(vmode_g, pixels, attr, 0x00);
+    memcpy_high(vmode_g, dest, MAKE_FLATPTR(GET_SEG(SS), pixels), bpp);
+    memcpy_high(vmode_g, dest + bpp, dest, len - bpp);
+}
+
+// Scroll the screen.
+void
+scroll_direct(struct vgamode_s *vmode_g, int nblines, int attr
+              , struct cursorpos ul, struct cursorpos lr)
+{
+    if (!CONFIG_VGA_HIGH_FRAMEBUFFER)
+        return;
+    int cheight = GET_BDA(char_height);
+    int cwidth = vga_bpp(vmode_g);
+    int stride = vgahw_get_linelength(vmode_g);
+    nblines *= cheight;
+    void *dest_far = (void*)GET_GLOBAL(VBE_framebuffer)
+        + vgahw_get_displaystart(vmode_g);
+    u32 src_delta = nblines * stride;
+    if (nblines >= 0) {
+        dest_far += ul.y * cheight * stride + ul.x * cwidth;
+    } else {
+        // Scroll down
+        dest_far += lr.y * cheight * stride + ul.x * cwidth;
+        nblines = -nblines;
+        stride = -stride;
+    }
+    if (attr < 0)
+        attr = 0x07;
+    int cols = (lr.x - ul.x + 1) * cwidth;
+    int rows = (lr.y - ul.y + 1) * cheight;
+    int copylines = rows - nblines;
+    while (copylines--) {
+        memcpy_high(vmode_g, dest_far, dest_far + src_delta, cols);
+        dest_far += stride;
+    }
+    while (nblines--) {
+        memset_high(vmode_g, dest_far, attr, cols);
+        dest_far += stride;
+    }
+}
+
+// Write a character to the screen.
+void
+write_gfx_char_direct(struct vgamode_s *vmode_g
+                      , struct cursorpos cp, struct carattr ca)
+{
+    if (!CONFIG_VGA_HIGH_FRAMEBUFFER)
+        return;
+    u16 nbcols = GET_BDA(video_cols);
+    if (cp.x >= nbcols)
+        return;
+
+    struct segoff_s font = get_font_data(ca.car);
+    int cheight = GET_BDA(char_height);
+    int cwidth = vga_bpp(vmode_g);
+    int stride = vgahw_get_linelength(vmode_g);
+    int addr = cp.y * cheight * stride + cp.x * cwidth;
+    void *dest_far = (void*)GET_GLOBAL(VBE_framebuffer)
+        + vgahw_get_displaystart(vmode_g) + addr;
+    u8 attr = ca.use_attr ? ca.attr : 0x07;
+    int i;
+    for (i = 0; i < cheight; i++) {
+        u8 fontline = GET_FARVAR(font.seg, *(u8*)(font.offset+i));
+        u32 pixels[8];
+        u32 bpp = fill_pixels(vmode_g, pixels, attr, fontline);
+        memcpy_high(vmode_g, dest_far, MAKE_FLATPTR(GET_SEG(SS), pixels), bpp);
+        dest_far += stride;
+    }
+}
-- 
1.8.5.3




More information about the SeaBIOS mailing list