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@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@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; + } +}