From 395502ec9dab0fda04bacb223f1fecdbbbdbe1b7 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Wed, 2 May 2018 06:55:08 +0300 Subject: [PATCH] initial hasty attempt at porting over my VBE code --- Makefile | 4 +- src/boot/boot2.s | 2 + src/kmain.c | 10 ++++- src/test/vbetest.c | 22 +++++++++++ src/test/vbetest.h | 6 +++ src/vbe.c | 81 +++++++++++++++++++++++++++++++++++++++ src/vbe.h | 65 +++++++++++++++++++++++++++++++ src/video.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++- src/video.h | 1 + 9 files changed, 295 insertions(+), 4 deletions(-) create mode 100644 src/test/vbetest.c create mode 100644 src/test/vbetest.h create mode 100644 src/vbe.c create mode 100644 src/vbe.h diff --git a/Makefile b/Makefile index 0438d12..23c8eaf 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -csrc = $(wildcard src/*.c) $(wildcard src/libc/*.c) +csrc = $(wildcard src/*.c) $(wildcard src/libc/*.c) $(wildcard src/test/*.c) ssrc = $(wildcard src/*.s) $(wildcard src/libc/*.s) $(wildcard src/boot/*.s) Ssrc = $(wildcard src/*.S) obj = $(csrc:.c=.o) $(ssrc:.s=.o) $(Ssrc:.S=.o) @@ -9,7 +9,7 @@ bin = test.bin warn = -pedantic -Wall #opt = -O2 dbg = -g -inc = -Isrc -Isrc/libc +inc = -Isrc -Isrc/libc -Isrc/test gccopt = -fno-pic -ffreestanding -nostdinc -fno-builtin CFLAGS = $(ccarch) -march=i386 $(warn) $(opt) $(dbg) $(gccopt) $(inc) $(def) diff --git a/src/boot/boot2.s b/src/boot/boot2.s index 719f37e..7470aef 100644 --- a/src/boot/boot2.s +++ b/src/boot/boot2.s @@ -841,3 +841,5 @@ int_op: int $0 # buffer used by the track loader ... to load tracks. .align 16 buffer: + .global low_mem_buffer +low_mem_buffer: diff --git a/src/kmain.c b/src/kmain.c index d008217..e0d1358 100644 --- a/src/kmain.c +++ b/src/kmain.c @@ -51,10 +51,18 @@ void pcboot_main(void) halt_cpu(); while((c = kb_getkey()) >= 0) { - if(c >= KB_F1 && c <= KB_F12) { + switch(c) { + case KB_F1: set_vga_mode(0x13); logohack(); set_vga_mode(3); + break; + + case KB_F2: + set_video_mode(640, 480, 16); + vbetest(); + set_vga_mode(3); + break; } if(isprint(c)) { printf("key: %d '%c' \n", c, (char)c); diff --git a/src/test/vbetest.c b/src/test/vbetest.c new file mode 100644 index 0000000..1525bd8 --- /dev/null +++ b/src/test/vbetest.c @@ -0,0 +1,22 @@ +#include +#include "video.h" +#include "asmops.h" +#include "keyb.h" + +static uint16_t *framebuf; + +int vbetest(void) +{ + if(!(framebuf = set_video_mode(640, 480, 16))) { + return -1; + } + + memset(framebuf, 0xff, 640 * 240 * 2); + + while(kb_getkey() == -1) { + halt_cpu(); + } + + set_vga_mode(3); + return 0; +} diff --git a/src/test/vbetest.h b/src/test/vbetest.h new file mode 100644 index 0000000..fa2899a --- /dev/null +++ b/src/test/vbetest.h @@ -0,0 +1,6 @@ +#ifndef VBETEST_H_ +#define VBETEST_H_ + +int vbetest(void); + +#endif /* VBETEST_H_ */ diff --git a/src/vbe.c b/src/vbe.c new file mode 100644 index 0000000..58cf2e7 --- /dev/null +++ b/src/vbe.c @@ -0,0 +1,81 @@ +#include +#include +#include +#include "vbe.h" +#include "asmops.h" +#include "int86.h" + +#define SEG_ADDR(s) ((uint32_t)(s) << 4) + +#define MODE_LFB (1 << 14) + +extern void *low_mem_buffer; + +struct vbe_info *vbe_get_info(void) +{ + struct vbe_info *info; + struct int86regs regs; + + info = low_mem_buffer; + + memcpy(info->sig, "VBE2", 4); + + memset(®s, 0, sizeof regs); + regs.es = (uint32_t)low_mem_buffer >> 4; + regs.eax = 0x4f00; + int86(0x10, ®s); + + return info; +} + +struct vbe_mode_info *vbe_get_mode_info(int mode) +{ + struct vbe_mode_info *mi; + struct int86regs regs; + + mi = low_mem_buffer; + + memset(®s, 0, sizeof regs); + regs.es = (uint32_t)low_mem_buffer >> 4; + regs.eax = 0x4f01; + regs.ecx = mode; + int86(0x10, ®s); + + if(regs.eax & 0xff00) { + return 0; + } + + return mi; +} + +int vbe_set_mode(int mode) +{ + struct int86regs regs; + + memset(®s, 0, sizeof regs); + regs.eax = 0x4f02; + regs.ebx = mode; + int86(0x10, ®s); + + if(regs.eax == 0x100) { + return -1; + } + return 0; +} + +void print_mode_info(struct vbe_mode_info *mi) +{ + static unsigned int maskbits[] = {0, 1, 3, 7, 0xf, 0x1f, 0x3f, 0x7f, 0xff}; + + printf("resolution: %dx%d\n", mi->xres, mi->yres); + printf("color depth: %d\n", mi->bpp); + printf("mode attributes: %x\n", mi->mode_attr); + printf("bytes per scanline: %d\n", mi->scanline_bytes); + printf("number of planes: %d\n", (int)mi->num_planes); + printf("number of banks: %d\n", (int)mi->num_banks); + printf("mem model: %d\n", (int)mi->mem_model); + printf("red bits: %d (mask: %x)\n", (int)mi->rmask_size, maskbits[mi->rmask_size] << mi->rpos); + printf("green bits: %d (mask: %x)\n", (int)mi->gmask_size, maskbits[mi->gmask_size] << mi->gpos); + printf("blue bits: %d (mask: %x)\n", (int)mi->bmask_size, maskbits[mi->bmask_size] << mi->bpos); + printf("framebuffer address: %x\n", (unsigned int)mi->fb_addr); +} diff --git a/src/vbe.h b/src/vbe.h new file mode 100644 index 0000000..15fb101 --- /dev/null +++ b/src/vbe.h @@ -0,0 +1,65 @@ +#ifndef VBE_H_ +#define VBE_H_ + +#include + +#define VBE_ATTR_LFB (1 << 7) +#define VBE_MODE_LFB (1 << 14) + +struct vbe_info { + uint8_t sig[4]; + uint16_t version; + uint32_t oem_str_ptr; + uint8_t caps[4]; /* capabilities */ + uint32_t vid_mode_ptr; /* vbefarptr to video mode list */ + uint16_t total_mem; /* num of 64k mem blocks */ + uint16_t oem_sw_rev; /* VBE implementation software revision */ + uint32_t oem_vendor_name_ptr; + uint32_t oem_product_name_ptr; + uint32_t oem_product_rev_ptr; + uint8_t reserved[222]; + uint8_t oem_data[256]; +} __attribute__((packed)); + +struct vbe_mode_info { + uint16_t mode_attr; + uint8_t wina_attr, winb_attr; + uint16_t win_gran, win_size; + uint16_t wina_seg, winb_seg; + uint32_t win_func; + uint16_t scanline_bytes; + + /* VBE 1.2 and above */ + uint16_t xres, yres; + uint8_t xcharsz, ycharsz; + uint8_t num_planes; + uint8_t bpp; + uint8_t num_banks; + uint8_t mem_model; + uint8_t bank_size; /* bank size in KB */ + uint8_t num_img_pages; + uint8_t reserved1; + + /* direct color fields */ + uint8_t rmask_size, rpos; + uint8_t gmask_size, gpos; + uint8_t bmask_size, bpos; + uint8_t xmask_size, xpos; + uint8_t cmode_info; /* direct color mode attributes */ + + /* VBE 2.0 and above */ + uint32_t fb_addr; /* physical address of the linear framebuffer */ + uint32_t reserved2; + uint16_t reserved3; + + uint8_t reserved4[206]; +} __attribute__((packed)); + +struct vbe_info *vbe_get_info(void); +struct vbe_mode_info *vbe_get_mode_info(int mode); + +int vbe_set_mode(int mode); + +void print_mode_info(struct vbe_mode_info *modei); + +#endif /* VBE_H_ */ diff --git a/src/video.c b/src/video.c index 702273a..277dcbd 100644 --- a/src/video.c +++ b/src/video.c @@ -15,10 +15,26 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#include "video.h" +#include #include +#include "video.h" +#include "vbe.h" #include "int86.h" +#define REALPTR(s, o) (void*)(((uint32_t)(s) << 4) + (uint32_t)(o)) +#define VBEPTR(x) REALPTR(((x) & 0xffff0000) >> 16, (x) & 0xffff) +#define VBEPTR_SEG(x) (((x) & 0xffff0000) >> 16) +#define VBEPTR_OFF(x) ((x) & 0xffff) + + +#define SAME_BPP(a, b) \ + ((a) == (b) || ((a) == 16 && (b) == 15) || ((a) == 15 && (b) == 16) || \ + ((a) == 32 && (b) == 24) || ((a) == 24 && (b) == 32)) + + + +static struct vbe_info *vbe_info; +static struct vbe_mode_info *mode_info; void set_vga_mode(int mode) { @@ -28,3 +44,93 @@ void set_vga_mode(int mode) regs.eax = mode; int86(0x10, ®s); } + +void *set_video_mode(int xsz, int ysz, int bpp) +{ + int i; + static uint16_t *modes; + uint16_t best = 0; + + /* check for VBE2 support and output some info */ + if(!vbe_info) { + if(!(vbe_info = vbe_get_info())) { + printf("VESA BIOS Extensions not available\n"); + return 0; + } + + printf("VBE Version: %x.%x\n", vbe_info->version >> 8, vbe_info->version & 0xff); + if(vbe_info->version < 0x200) { + printf("VBE >=2.0 not available. VBE 1.x support not implemented yet."); + return 0; + } + + printf("Graphics adapter: %s, %s (%s)\n", (char*)VBEPTR(vbe_info->oem_vendor_name_ptr), + (char*)VBEPTR(vbe_info->oem_product_name_ptr), (char*)VBEPTR(vbe_info->oem_product_rev_ptr)); + printf("Video memory: %dkb\n", vbe_info->total_mem << 6); + + modes = VBEPTR(vbe_info->vid_mode_ptr); + } + + for(i=0; i<1024; i++) { /* impose an upper limit to avoid inf-loops */ + if(modes[i] == 0xffff) { + break; /* reached the end */ + } + + mode_info = vbe_get_mode_info(modes[i] | VBE_MODE_LFB); + if(!mode_info || mode_info->xres != xsz || mode_info->yres != ysz) { + continue; + } + if(SAME_BPP(mode_info->bpp, bpp)) { + best = modes[i]; + } + } + + if(best) { + mode_info = vbe_get_mode_info(best); + } else { + printf("Requested video mode (%dx%d %dbpp) is unavailable\n", xsz, ysz, bpp); + return 0; + } + + if(vbe_set_mode(best | VBE_MODE_LFB) == -1) { + printf("Failed to set video mode %dx%d %dbpp\n", mode_info->xres, mode_info->yres, mode_info->bpp); + return 0; + } + + return (void*)mode_info->fb_addr; +} + +int get_color_bits(int *rbits, int *gbits, int *bbits) +{ + if(!mode_info) { + return -1; + } + *rbits = mode_info->rmask_size; + *gbits = mode_info->gmask_size; + *bbits = mode_info->bmask_size; + return 0; +} + +int get_color_mask(unsigned int *rmask, unsigned int *gmask, unsigned int *bmask) +{ + static unsigned int maskbits[] = {0, 1, 3, 7, 0xf, 0x1f, 0x3f, 0x7f, 0xff}; + if(!mode_info) { + return -1; + } + *rmask = maskbits[mode_info->rmask_size] << mode_info->rpos; + *gmask = maskbits[mode_info->gmask_size] << mode_info->gpos; + *bmask = maskbits[mode_info->bmask_size] << mode_info->bpos; + return 0; +} + +int get_color_shift(int *rshift, int *gshift, int *bshift) +{ + if(!mode_info) { + return -1; + } + *rshift = mode_info->rpos; + *gshift = mode_info->gpos; + *bshift = mode_info->bpos; + return 0; +} + diff --git a/src/video.h b/src/video.h index 20f3ea8..bbeb224 100644 --- a/src/video.h +++ b/src/video.h @@ -19,6 +19,7 @@ along with this program. If not, see . #define VIDEO_H_ void set_vga_mode(int mode); +void *set_video_mode(int xsz, int ysz, int bpp); /* defined in video_asm.s */ void wait_vsync(void); -- 1.7.10.4