This patch series enables support for writing to a framebuffer that has been setup by coreboot using its native VGA initialization. This may be a good solution for those wishing to run standard boot loaders and common operating systems without having to run a third part vgabios (on those systems where coreboot supports native vga init).
-Kevin
Kevin O'Connor (4): vgabios: Add option to control use of standard VGA IO ports and ranges. vgabios: Add support for writing text to framebuffers in high memory. coreboot: Make coreboot table searching available to other code. vgabios: Initial support for coreboot native vga vgabios.
Makefile | 5 +- src/fw/coreboot.c | 58 ++++++++++-------- src/util.h | 3 + vgasrc/Kconfig | 26 +++++++++ vgasrc/cbvga.c | 169 +++++++++++++++++++++++++++++++++++++++++++++++++++++ vgasrc/cbvga.h | 20 +++++++ vgasrc/vgabios.c | 44 ++++++++++---- vgasrc/vgabios.h | 8 +++ vgasrc/vgafb.c | 40 +++++++++++-- vgasrc/vgahighfb.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++++ vgasrc/vgahw.h | 27 +++++++++ vgasrc/vgainit.c | 3 +- 12 files changed, 514 insertions(+), 43 deletions(-) create mode 100644 vgasrc/cbvga.c create mode 100644 vgasrc/cbvga.h create mode 100644 vgasrc/vgahighfb.c
Add option CONFIG_VGA_STDVGA_PORTS. When this option is disabled, the main BIOS code will not attempt to access any of the legacy VGA IO ports.
Add option CONFIG_VGA_STDVGA_FRAMEBUFFER. When this option is disabled, the code to read/write to the 0xA0000-0xC0000 is not included in the vgabios.
Signed-off-by: Kevin O'Connor kevin@koconnor.net --- vgasrc/Kconfig | 15 +++++++++++++++ vgasrc/vgabios.c | 44 ++++++++++++++++++++++++++++++++------------ vgasrc/vgafb.c | 26 ++++++++++++++++++++++++++ vgasrc/vgainit.c | 3 ++- 4 files changed, 75 insertions(+), 13 deletions(-)
diff --git a/vgasrc/Kconfig b/vgasrc/Kconfig index b442b3e..a058a86 100644 --- a/vgasrc/Kconfig +++ b/vgasrc/Kconfig @@ -13,6 +13,8 @@ menu "VGA ROM" config VGA_STANDARD_VGA depends on QEMU bool "QEMU/Bochs Original IBM 256K VGA" + select VGA_STDVGA_PORTS + select VGA_STDVGA_FRAMEBUFFER help Build basic VGA BIOS support (pre Super-VGA) for use on emulators. @@ -20,6 +22,8 @@ menu "VGA ROM" config VGA_CIRRUS depends on QEMU bool "QEMU/Bochs Cirrus SVGA" + select VGA_STDVGA_PORTS + select VGA_STDVGA_FRAMEBUFFER help Build support for Cirrus VGA emulation found on QEMU and Bochs emulators. This is for emulators; it is not @@ -28,17 +32,23 @@ menu "VGA ROM" config VGA_BOCHS depends on QEMU bool "QEMU/Bochs VBE SVGA" + select VGA_STDVGA_PORTS + select VGA_STDVGA_FRAMEBUFFER help Build support for Bochs DISPI interface (a custom VBE protocol) found on QEMU and Bochs emulators.
config VGA_GEODEGX2 bool "GeodeGX2" + select VGA_STDVGA_PORTS + select VGA_STDVGA_FRAMEBUFFER help Build support for Geode GX2 vga.
config VGA_GEODELX bool "GeodeLX" + select VGA_STDVGA_PORTS + select VGA_STDVGA_FRAMEBUFFER help Build support for Geode LX vga. endchoice @@ -68,6 +78,11 @@ menu "VGA ROM" bool default !NO_VGABIOS
+ config VGA_STDVGA_PORTS + bool + config VGA_STDVGA_FRAMEBUFFER + bool + config VGA_ALLOCATE_EXTRA_STACK depends on BUILD_VGABIOS bool "Allocate an internal stack for 16bit interrupt entry point" diff --git a/vgasrc/vgabios.c b/vgasrc/vgabios.c index 44502b3..040a7ae 100644 --- a/vgasrc/vgabios.c +++ b/vgasrc/vgabios.c @@ -59,6 +59,9 @@ set_cursor_shape(u8 start, u8 end) u16 curs = (start << 8) + end; SET_BDA(cursor_type, curs);
+ if (!CONFIG_VGA_STDVGA_PORTS) + return; + u8 modeset_ctl = GET_BDA(modeset_ctl); u16 cheight = GET_BDA(char_height); if ((modeset_ctl & 0x01) && (cheight > 8) && (end < 8) && (start < 0x20)) { @@ -92,6 +95,9 @@ set_cursor_pos(struct cursorpos cp) // Bios cursor pos SET_BDA(cursor_pos[page], (y << 8) | x);
+ if (!CONFIG_VGA_STDVGA_PORTS) + return; + // Set the hardware cursor u8 current = GET_BDA(video_page); if (cp.page != current) @@ -300,7 +306,7 @@ vga_set_mode(int mode, int flags) SET_BDA(cursor_type, 0x0000); } SET_BDA(video_pagesize, calc_page_size(memmodel, width, height)); - SET_BDA(crtc_address, stdvga_get_crtc()); + SET_BDA(crtc_address, CONFIG_VGA_STDVGA_PORTS ? stdvga_get_crtc() : 0); SET_BDA(char_height, cheight); SET_BDA(video_ctl, 0x60 | (flags & MF_NOCLEARMEM ? 0x80 : 0x00)); SET_BDA(video_switches, 0xF9); @@ -485,6 +491,10 @@ handle_100bXX(struct bregs *regs) static void handle_100b(struct bregs *regs) { + if (!CONFIG_VGA_STDVGA_PORTS) { + handle_100bXX(regs); + return; + } switch (regs->bh) { case 0x00: handle_100b00(regs); break; case 0x01: handle_100b01(regs); break; @@ -641,6 +651,10 @@ handle_1010XX(struct bregs *regs) static void handle_1010(struct bregs *regs) { + if (!CONFIG_VGA_STDVGA_PORTS) { + handle_1010XX(regs); + return; + } switch (regs->al) { case 0x00: handle_101000(regs); break; case 0x01: handle_101001(regs); break; @@ -838,16 +852,20 @@ handle_1011XX(struct bregs *regs) static void handle_1011(struct bregs *regs) { + if (CONFIG_VGA_STDVGA_PORTS) { + switch (regs->al) { + case 0x00: handle_101100(regs); break; + case 0x01: handle_101101(regs); break; + case 0x02: handle_101102(regs); break; + case 0x03: handle_101103(regs); break; + case 0x04: handle_101104(regs); break; + case 0x10: handle_101110(regs); break; + case 0x11: handle_101111(regs); break; + case 0x12: handle_101112(regs); break; + case 0x14: handle_101114(regs); break; + } + } switch (regs->al) { - case 0x00: handle_101100(regs); break; - case 0x01: handle_101101(regs); break; - case 0x02: handle_101102(regs); break; - case 0x03: handle_101103(regs); break; - case 0x04: handle_101104(regs); break; - case 0x10: handle_101110(regs); break; - case 0x11: handle_101111(regs); break; - case 0x12: handle_101112(regs); break; - case 0x14: handle_101114(regs); break; case 0x30: handle_101130(regs); break; case 0x20: handle_101120(regs); break; case 0x21: handle_101121(regs); break; @@ -912,8 +930,10 @@ handle_101231(struct bregs *regs) static void handle_101232(struct bregs *regs) { - stdvga_enable_video_addressing(regs->al); - regs->al = 0x12; + if (CONFIG_VGA_STDVGA_PORTS) { + stdvga_enable_video_addressing(regs->al); + regs->al = 0x12; + } }
static void diff --git a/vgasrc/vgafb.c b/vgasrc/vgafb.c index 2efaab5..a31db46 100644 --- a/vgasrc/vgafb.c +++ b/vgasrc/vgafb.c @@ -43,6 +43,8 @@ static void scroll_pl4(struct vgamode_s *vmode_g, int nblines, int attr , struct cursorpos ul, struct cursorpos lr) { + if (!CONFIG_VGA_STDVGA_FRAMEBUFFER || !CONFIG_VGA_STDVGA_PORTS) + return; int cheight = GET_BDA(char_height); int cwidth = 1; int stride = GET_BDA(video_cols) * cwidth; @@ -79,6 +81,8 @@ static void scroll_cga(struct vgamode_s *vmode_g, int nblines, int attr , struct cursorpos ul, struct cursorpos lr) { + if (!CONFIG_VGA_STDVGA_FRAMEBUFFER) + return; int cheight = GET_BDA(char_height) / 2; int cwidth = GET_GLOBAL(vmode_g->depth); int stride = GET_BDA(video_cols) * cwidth; @@ -117,6 +121,8 @@ static void scroll_lin(struct vgamode_s *vmode_g, int nblines, int attr , struct cursorpos ul, struct cursorpos lr) { + if (!CONFIG_VGA_STDVGA_FRAMEBUFFER) + return; int cheight = GET_BDA(char_height); int cwidth = 8; int stride = GET_BDA(video_cols) * cwidth; @@ -146,6 +152,8 @@ static void scroll_text(struct vgamode_s *vmode_g, int nblines, int attr , struct cursorpos ul, struct cursorpos lr) { + if (!CONFIG_VGA_STDVGA_FRAMEBUFFER) + return; int cheight = 1; int cwidth = 2; int stride = GET_BDA(video_cols) * cwidth; @@ -225,6 +233,8 @@ static void write_gfx_char_pl4(struct vgamode_s *vmode_g , struct cursorpos cp, struct carattr ca) { + if (!CONFIG_VGA_STDVGA_FRAMEBUFFER || !CONFIG_VGA_STDVGA_PORTS) + return; u16 nbcols = GET_BDA(video_cols); if (cp.x >= nbcols) return; @@ -255,6 +265,8 @@ static void write_gfx_char_cga(struct vgamode_s *vmode_g , struct cursorpos cp, struct carattr ca) { + if (!CONFIG_VGA_STDVGA_FRAMEBUFFER) + return; u16 nbcols = GET_BDA(video_cols); if (cp.x >= nbcols) return; @@ -295,6 +307,8 @@ static void write_gfx_char_lin(struct vgamode_s *vmode_g , struct cursorpos cp, struct carattr ca) { + if (!CONFIG_VGA_STDVGA_FRAMEBUFFER) + return; // Get the dimensions u16 nbcols = GET_BDA(video_cols); if (cp.x >= nbcols) @@ -321,6 +335,8 @@ static void write_text_char(struct vgamode_s *vmode_g , struct cursorpos cp, struct carattr ca) { + if (!CONFIG_VGA_STDVGA_FRAMEBUFFER) + return; int cheight = 1; int cwidth = 2; int stride = GET_BDA(video_cols) * cwidth; @@ -365,6 +381,8 @@ vgafb_write_char(struct cursorpos cp, struct carattr ca) struct carattr vgafb_read_char(struct cursorpos cp) { + if (!CONFIG_VGA_STDVGA_FRAMEBUFFER) + goto fail; // Get the mode struct vgamode_s *vmode_g = get_current_mode(); if (!vmode_g) @@ -399,6 +417,8 @@ fail: ; void vgafb_write_pixel(u8 color, u16 x, u16 y) { + if (!CONFIG_VGA_STDVGA_FRAMEBUFFER) + return; // Get the mode struct vgamode_s *vmode_g = get_current_mode(); if (!vmode_g) @@ -407,6 +427,8 @@ vgafb_write_pixel(u8 color, u16 x, u16 y) u8 *addr_far, mask, attr, data, i; switch (GET_GLOBAL(vmode_g->memmodel)) { case MM_PLANAR: + if (!CONFIG_VGA_STDVGA_PORTS) + return; addr_far = (void*)(x / 8 + y * GET_BDA(video_cols)); mask = 0x80 >> (x & 0x07); for (i=0; i<4; i++) { @@ -456,6 +478,8 @@ vgafb_write_pixel(u8 color, u16 x, u16 y) u8 vgafb_read_pixel(u16 x, u16 y) { + if (!CONFIG_VGA_STDVGA_FRAMEBUFFER) + return 0; // Get the mode struct vgamode_s *vmode_g = get_current_mode(); if (!vmode_g) @@ -464,6 +488,8 @@ vgafb_read_pixel(u16 x, u16 y) u8 *addr_far, mask, attr=0, data, i; switch (GET_GLOBAL(vmode_g->memmodel)) { case MM_PLANAR: + if (!CONFIG_VGA_STDVGA_PORTS) + return 0; addr_far = (void*)(x / 8 + y * GET_BDA(video_cols)); mask = 0x80 >> (x & 0x07); attr = 0x00; diff --git a/vgasrc/vgainit.c b/vgasrc/vgainit.c index 13221fd..87bc75c 100644 --- a/vgasrc/vgainit.c +++ b/vgasrc/vgainit.c @@ -153,7 +153,8 @@ vga_post(struct bregs *regs)
SET_VGA(video_save_pointer_table.videoparam , SEGOFF(get_global_seg(), (u32)video_param_table)); - stdvga_build_video_param(); + if (CONFIG_VGA_STDVGA_PORTS) + stdvga_build_video_param();
extern void entry_10(void); SET_IVT(0x10, SEGOFF(get_global_seg(), (u32)entry_10));
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; + } +}
Make the coreboot table searching code available to code outside coreboot.c, and make it runnable from 16bit mode.
Signed-off-by: Kevin O'Connor kevin@koconnor.net --- src/fw/coreboot.c | 58 +++++++++++++++++++++++++++++++++---------------------- src/util.h | 3 +++ 2 files changed, 38 insertions(+), 23 deletions(-)
diff --git a/src/fw/coreboot.c b/src/fw/coreboot.c index df8fca8..2435329 100644 --- a/src/fw/coreboot.c +++ b/src/fw/coreboot.c @@ -92,11 +92,12 @@ ipchksum(char *buf, int count) u16 *p = (u16*)buf; u32 sum = 0; while (count > 1) { - sum += *p++; + sum += GET_FARVAR(0, *p); + p++; count -= 2; } if (count) - sum += *(u8*)p; + sum += GET_FARVAR(0, *(u8*)p); sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); return ~sum; @@ -104,19 +105,20 @@ ipchksum(char *buf, int count)
// Try to locate the coreboot header in a given address range. static struct cb_header * -find_cb_header(char *addr, int len) +find_cb_header(u32 addr, int len) { - char *end = addr + len; + u32 end = addr + len; for (; addr < end; addr += 16) { - struct cb_header *cbh = (struct cb_header *)addr; - if (cbh->signature != CB_SIGNATURE) + struct cb_header *cbh = (void*)addr; + if (GET_FARVAR(0, cbh->signature) != CB_SIGNATURE) continue; - if (! cbh->table_bytes) + u32 tsize = GET_FARVAR(0, cbh->table_bytes); + if (! tsize) continue; - if (ipchksum(addr, sizeof(*cbh)) != 0) + if (ipchksum((void*)addr, sizeof(*cbh)) != 0) continue; - if (ipchksum(addr + sizeof(*cbh), cbh->table_bytes) - != cbh->table_checksum) + if (ipchksum((void*)addr + sizeof(*cbh), tsize) + != GET_FARVAR(0, cbh->table_checksum)) continue; return cbh; } @@ -124,20 +126,37 @@ find_cb_header(char *addr, int len) }
// Try to find the coreboot memory table in the given coreboot table. -static void * +void * find_cb_subtable(struct cb_header *cbh, u32 tag) { char *tbl = (char *)cbh + sizeof(*cbh); + u32 count = GET_FARVAR(0, cbh->table_entries); int i; - for (i=0; i<cbh->table_entries; i++) { - struct cb_memory *cbm = (struct cb_memory *)tbl; - tbl += cbm->size; - if (cbm->tag == tag) + for (i=0; i<count; i++) { + struct cb_memory *cbm = (void*)tbl; + tbl += GET_FARVAR(0, cbm->size); + if (GET_FARVAR(0, cbm->tag) == tag) return cbm; } return NULL; }
+struct cb_header * +find_cb_table(void) +{ + struct cb_header *cbh = find_cb_header(0, 0x1000); + if (!cbh) + return NULL; + struct cb_forward *cbf = find_cb_subtable(cbh, CB_TAG_FORWARD); + if (cbf) { + dprintf(3, "Found coreboot table forwarder.\n"); + cbh = find_cb_header(GET_FARVAR(0, cbf->forward), 0x100); + if (!cbh) + return NULL; + } + return cbh; +} + static struct cb_memory *CBMemTable; const char *CBvendor = "", *CBpart = "";
@@ -151,16 +170,9 @@ coreboot_preinit(void) dprintf(3, "Attempting to find coreboot table\n");
// Find coreboot table. - struct cb_header *cbh = find_cb_header(0, 0x1000); + struct cb_header *cbh = find_cb_table(); if (!cbh) goto fail; - struct cb_forward *cbf = find_cb_subtable(cbh, CB_TAG_FORWARD); - if (cbf) { - dprintf(3, "Found coreboot table forwarder.\n"); - cbh = find_cb_header((char *)((u32)cbf->forward), 0x100); - if (!cbh) - goto fail; - } dprintf(3, "Now attempting to find coreboot memory map\n"); struct cb_memory *cbm = CBMemTable = find_cb_subtable(cbh, CB_TAG_MEMORY); if (!cbm) diff --git a/src/util.h b/src/util.h index b8acbfa..c2e49cf 100644 --- a/src/util.h +++ b/src/util.h @@ -84,6 +84,9 @@ void coreboot_platform_setup(void); void cbfs_payload_setup(void); void coreboot_preinit(void); void coreboot_cbfs_init(void); +struct cb_header; +void *find_cb_subtable(struct cb_header *cbh, u32 tag); +struct cb_header *find_cb_table(void);
// fw/csm.c int csm_bootprio_fdc(struct pci_device *pci, int port, int fdid);
Signed-off-by: Kevin O'Connor kevin@koconnor.net --- Makefile | 3 +- vgasrc/Kconfig | 9 +++ vgasrc/cbvga.c | 169 +++++++++++++++++++++++++++++++++++++++++++++++++++++ vgasrc/cbvga.h | 20 +++++++ vgasrc/vgabios.h | 1 + vgasrc/vgahighfb.c | 2 +- vgasrc/vgahw.h | 27 +++++++++ 7 files changed, 229 insertions(+), 2 deletions(-) create mode 100644 vgasrc/cbvga.c create mode 100644 vgasrc/cbvga.h
diff --git a/Makefile b/Makefile index ffe0650..fc1aabb 100644 --- a/Makefile +++ b/Makefile @@ -204,7 +204,8 @@ 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/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 + vgasrc/clext.c vgasrc/bochsvga.c vgasrc/geodevga.c \ + src/fw/coreboot.c vgasrc/cbvga.c
CFLAGS16VGA = $(CFLAGS16INC) -Isrc
diff --git a/vgasrc/Kconfig b/vgasrc/Kconfig index bdb8f5b..20ac2ce 100644 --- a/vgasrc/Kconfig +++ b/vgasrc/Kconfig @@ -51,6 +51,15 @@ menu "VGA ROM" select VGA_STDVGA_FRAMEBUFFER help Build support for Geode LX vga. + + config VGA_COREBOOT + depends on COREBOOT + bool "coreboot linear framebuffer" + select VGA_HIGH_FRAMEBUFFER + help + Build support for a vgabios wrapper around video + devices initialized using coreboot native vga init. + endchoice
choice diff --git a/vgasrc/cbvga.c b/vgasrc/cbvga.c new file mode 100644 index 0000000..d3dc2a4 --- /dev/null +++ b/vgasrc/cbvga.c @@ -0,0 +1,169 @@ +// Simple framebuffer vgabios for use with coreboot native vga init. +// +// 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 "cbvga.h" // cbvga_setup +#include "output.h" // dprintf +#include "util.h" // find_cb_table +#include "vgabios.h" // VGAREG_* + +#define CBMODENUM 0x140 +static struct vgamode_s CBmode VAR16 = { + MM_DIRECT, 0, 0, 0, 8, 16, 0 +}; +static u32 CBlinelength VAR16; + +struct vgamode_s *cbvga_find_mode(int mode) +{ + if (mode == CBMODENUM) + return &CBmode; + return NULL; +} + +void +cbvga_list_modes(u16 seg, u16 *dest, u16 *last) +{ + if (dest<last) { + SET_FARVAR(seg, *dest, CBMODENUM); + dest++; + } + SET_FARVAR(seg, *dest, 0xffff); +} + +int +cbvga_get_window(struct vgamode_s *vmode_g, int window) +{ + return -1; +} + +int +cbvga_set_window(struct vgamode_s *vmode_g, int window, int val) +{ + return -1; +} + +int +cbvga_get_linelength(struct vgamode_s *vmode_g) +{ + return GET_GLOBAL(CBlinelength); +} + +int +cbvga_set_linelength(struct vgamode_s *vmode_g, int val) +{ + return -1; +} + +int +cbvga_get_displaystart(struct vgamode_s *vmode_g) +{ + return 0; +} + +int +cbvga_set_displaystart(struct vgamode_s *vmode_g, int val) +{ + return -1; +} + +int +cbvga_get_dacformat(struct vgamode_s *vmode_g) +{ + return -1; +} + +int +cbvga_set_dacformat(struct vgamode_s *vmode_g, int val) +{ + return -1; +} + +int +cbvga_save_restore(int cmd, u16 seg, void *data) +{ + if (cmd & (SR_HARDWARE|SR_DAC|SR_REGISTERS)) + return -1; + return bda_save_restore(cmd, seg, data); +} + +int +cbvga_set_mode(struct vgamode_s *vmode_g, int flags) +{ + if (!(flags & MF_NOCLEARMEM)) { + int i, lines = GET_GLOBAL(CBmode.height); + u32 stride = GET_GLOBAL(CBlinelength); + void *dest = (void*)GET_GLOBAL(VBE_framebuffer); + for (i=0; i<lines; i++, dest+=stride) + memset_high(vmode_g, dest, 0, stride); + } + return 0; +} + +#define CB_TAG_FRAMEBUFFER 0x0012 +struct cb_framebuffer { + u32 tag; + u32 size; + + u64 physical_address; + u32 x_resolution; + u32 y_resolution; + u32 bytes_per_line; + u8 bits_per_pixel; + u8 red_mask_pos; + u8 red_mask_size; + u8 green_mask_pos; + u8 green_mask_size; + u8 blue_mask_pos; + u8 blue_mask_size; + u8 reserved_mask_pos; + u8 reserved_mask_size; +}; + +int +cbvga_setup(void) +{ + dprintf(1, "coreboot vga init\n"); + + if (GET_GLOBAL(HaveRunInit)) + return 0; + + struct cb_header *cbh = find_cb_table(); + if (!cbh) { + dprintf(1, "Unable to find coreboot table\n"); + return -1; + } + struct cb_framebuffer *cbfb = find_cb_subtable(cbh, CB_TAG_FRAMEBUFFER); + if (!cbfb) { + dprintf(1, "Unable to find coreboot framebuffer table\n"); + return -1; + } + + u64 addr = GET_FARVAR(0, cbfb->physical_address); + u8 bpp = GET_FARVAR(0, cbfb->bits_per_pixel); + u32 xlines = GET_FARVAR(0, cbfb->x_resolution); + u32 ylines = GET_FARVAR(0, cbfb->y_resolution); + u32 linelength = GET_FARVAR(0, cbfb->bytes_per_line); + dprintf(1, "Found FB @ %llx %dx%d with %d bpp (%d stride)\n" + , addr, xlines, ylines, bpp, linelength); + + if (!addr || addr > 0xffffffff + || (bpp != 15 && bpp != 16 && bpp != 24 && bpp != 32)) { + dprintf(1, "Unable to use FB\n"); + return -1; + } + + SET_VGA(VBE_framebuffer, addr); + SET_VGA(VBE_total_memory, linelength * ylines); + SET_VGA(CBlinelength, linelength); + SET_VGA(CBmode.width, xlines); + SET_VGA(CBmode.height, ylines); + SET_VGA(CBmode.depth, bpp); + + // Setup BDA + vga_set_mode(CBMODENUM, MF_NOCLEARMEM); + + return 0; +} diff --git a/vgasrc/cbvga.h b/vgasrc/cbvga.h new file mode 100644 index 0000000..fb892c8 --- /dev/null +++ b/vgasrc/cbvga.h @@ -0,0 +1,20 @@ +#ifndef __CBVGA_H +#define __CBVGA_H + +#include "types.h" // u16 + +struct vgamode_s *cbvga_find_mode(int mode); +void cbvga_list_modes(u16 seg, u16 *dest, u16 *last); +int cbvga_get_window(struct vgamode_s *vmode_g, int window); +int cbvga_set_window(struct vgamode_s *vmode_g, int window, int val); +int cbvga_get_linelength(struct vgamode_s *vmode_g); +int cbvga_set_linelength(struct vgamode_s *vmode_g, int val); +int cbvga_get_displaystart(struct vgamode_s *vmode_g); +int cbvga_set_displaystart(struct vgamode_s *vmode_g, int val); +int cbvga_get_dacformat(struct vgamode_s *vmode_g); +int cbvga_set_dacformat(struct vgamode_s *vmode_g, int val); +int cbvga_save_restore(int cmd, u16 seg, void *data); +int cbvga_set_mode(struct vgamode_s *vmode_g, int flags); +int cbvga_setup(void); + +#endif // cbvga.h diff --git a/vgasrc/vgabios.h b/vgasrc/vgabios.h index 1e3b0b2..4940750 100644 --- a/vgasrc/vgabios.h +++ b/vgasrc/vgabios.h @@ -96,6 +96,7 @@ void vgafb_write_pixel(u8 color, u16 x, u16 y); u8 vgafb_read_pixel(u16 x, u16 y);
// vgahighfb.c +void memset_high(struct vgamode_s *vmode_g, void *dest, u32 attr, u32 len); 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 diff --git a/vgasrc/vgahighfb.c b/vgasrc/vgahighfb.c index 0498b16..dced86b 100644 --- a/vgasrc/vgahighfb.c +++ b/vgasrc/vgahighfb.c @@ -78,7 +78,7 @@ memcpy_high(struct vgamode_s *vmode_g, void *dest, void *src, u32 len) : : "cc", "memory"); }
-static void +void memset_high(struct vgamode_s *vmode_g, void *dest, u32 attr, u32 len) { u32 pixels[8]; diff --git a/vgasrc/vgahw.h b/vgasrc/vgahw.h index 3e84357..39f818a 100644 --- a/vgasrc/vgahw.h +++ b/vgasrc/vgahw.h @@ -4,6 +4,7 @@ #include "types.h" // u8 #include "config.h" // CONFIG_*
+#include "cbvga.h" // cbvga_setup #include "clext.h" // clext_set_mode #include "bochsvga.h" // bochsvga_set_mode #include "stdvga.h" // stdvga_set_mode @@ -14,6 +15,8 @@ static inline struct vgamode_s *vgahw_find_mode(int mode) { return clext_find_mode(mode); if (CONFIG_VGA_BOCHS) return bochsvga_find_mode(mode); + if (CONFIG_VGA_COREBOOT) + return cbvga_find_mode(mode); return stdvga_find_mode(mode); }
@@ -22,6 +25,8 @@ static inline int vgahw_set_mode(struct vgamode_s *vmode_g, int flags) { return clext_set_mode(vmode_g, flags); if (CONFIG_VGA_BOCHS) return bochsvga_set_mode(vmode_g, flags); + if (CONFIG_VGA_COREBOOT) + return cbvga_set_mode(vmode_g, flags); return stdvga_set_mode(vmode_g, flags); }
@@ -30,6 +35,8 @@ static inline void vgahw_list_modes(u16 seg, u16 *dest, u16 *last) { clext_list_modes(seg, dest, last); else if (CONFIG_VGA_BOCHS) bochsvga_list_modes(seg, dest, last); + else if (CONFIG_VGA_COREBOOT) + cbvga_list_modes(seg, dest, last); else stdvga_list_modes(seg, dest, last); } @@ -41,6 +48,8 @@ static inline int vgahw_setup(void) { return bochsvga_setup(); if (CONFIG_VGA_GEODEGX2 || CONFIG_VGA_GEODELX) return geodevga_setup(); + if (CONFIG_VGA_COREBOOT) + return cbvga_setup(); return stdvga_setup(); }
@@ -49,6 +58,8 @@ static inline int vgahw_get_window(struct vgamode_s *vmode_g, int window) { return clext_get_window(vmode_g, window); if (CONFIG_VGA_BOCHS) return bochsvga_get_window(vmode_g, window); + if (CONFIG_VGA_COREBOOT) + return cbvga_get_window(vmode_g, window); return stdvga_get_window(vmode_g, window); }
@@ -58,6 +69,8 @@ static inline int vgahw_set_window(struct vgamode_s *vmode_g, int window return clext_set_window(vmode_g, window, val); if (CONFIG_VGA_BOCHS) return bochsvga_set_window(vmode_g, window, val); + if (CONFIG_VGA_COREBOOT) + return cbvga_set_window(vmode_g, window, val); return stdvga_set_window(vmode_g, window, val); }
@@ -66,6 +79,8 @@ static inline int vgahw_get_linelength(struct vgamode_s *vmode_g) { return clext_get_linelength(vmode_g); if (CONFIG_VGA_BOCHS) return bochsvga_get_linelength(vmode_g); + if (CONFIG_VGA_COREBOOT) + return cbvga_get_linelength(vmode_g); return stdvga_get_linelength(vmode_g); }
@@ -74,6 +89,8 @@ static inline int vgahw_set_linelength(struct vgamode_s *vmode_g, int val) { return clext_set_linelength(vmode_g, val); if (CONFIG_VGA_BOCHS) return bochsvga_set_linelength(vmode_g, val); + if (CONFIG_VGA_COREBOOT) + return cbvga_set_linelength(vmode_g, val); return stdvga_set_linelength(vmode_g, val); }
@@ -82,6 +99,8 @@ static inline int vgahw_get_displaystart(struct vgamode_s *vmode_g) { return clext_get_displaystart(vmode_g); if (CONFIG_VGA_BOCHS) return bochsvga_get_displaystart(vmode_g); + if (CONFIG_VGA_COREBOOT) + return cbvga_get_displaystart(vmode_g); return stdvga_get_displaystart(vmode_g); }
@@ -90,18 +109,24 @@ static inline int vgahw_set_displaystart(struct vgamode_s *vmode_g, int val) { return clext_set_displaystart(vmode_g, val); if (CONFIG_VGA_BOCHS) return bochsvga_set_displaystart(vmode_g, val); + if (CONFIG_VGA_COREBOOT) + return cbvga_set_displaystart(vmode_g, val); return stdvga_set_displaystart(vmode_g, val); }
static inline int vgahw_get_dacformat(struct vgamode_s *vmode_g) { if (CONFIG_VGA_BOCHS) return bochsvga_get_dacformat(vmode_g); + if (CONFIG_VGA_COREBOOT) + return cbvga_get_dacformat(vmode_g); return stdvga_get_dacformat(vmode_g); }
static inline int vgahw_set_dacformat(struct vgamode_s *vmode_g, int val) { if (CONFIG_VGA_BOCHS) return bochsvga_set_dacformat(vmode_g, val); + if (CONFIG_VGA_COREBOOT) + return cbvga_set_dacformat(vmode_g, val); return stdvga_set_dacformat(vmode_g, val); }
@@ -110,6 +135,8 @@ static inline int vgahw_save_restore(int cmd, u16 seg, void *data) { return clext_save_restore(cmd, seg, data); if (CONFIG_VGA_BOCHS) return bochsvga_save_restore(cmd, seg, data); + if (CONFIG_VGA_COREBOOT) + return cbvga_save_restore(cmd, seg, data); return stdvga_save_restore(cmd, seg, data); }