initial hasty attempt at porting over my VBE code
authorJohn Tsiombikas <nuclear@member.fsf.org>
Wed, 2 May 2018 03:55:08 +0000 (06:55 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Wed, 2 May 2018 03:55:08 +0000 (06:55 +0300)
Makefile
src/boot/boot2.s
src/kmain.c
src/test/vbetest.c [new file with mode: 0644]
src/test/vbetest.h [new file with mode: 0644]
src/vbe.c [new file with mode: 0644]
src/vbe.h [new file with mode: 0644]
src/video.c
src/video.h

index 0438d12..23c8eaf 100644 (file)
--- 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)
index 719f37e..7470aef 100644 (file)
@@ -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:
index d008217..e0d1358 100644 (file)
@@ -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 (file)
index 0000000..1525bd8
--- /dev/null
@@ -0,0 +1,22 @@
+#include <string.h>
+#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 (file)
index 0000000..fa2899a
--- /dev/null
@@ -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 (file)
index 0000000..58cf2e7
--- /dev/null
+++ b/src/vbe.c
@@ -0,0 +1,81 @@
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#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(&regs, 0, sizeof regs);
+       regs.es = (uint32_t)low_mem_buffer >> 4;
+       regs.eax = 0x4f00;
+       int86(0x10, &regs);
+
+       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(&regs, 0, sizeof regs);
+       regs.es = (uint32_t)low_mem_buffer >> 4;
+       regs.eax = 0x4f01;
+       regs.ecx = mode;
+       int86(0x10, &regs);
+
+       if(regs.eax & 0xff00) {
+               return 0;
+       }
+
+       return mi;
+}
+
+int vbe_set_mode(int mode)
+{
+       struct int86regs regs;
+
+       memset(&regs, 0, sizeof regs);
+       regs.eax = 0x4f02;
+       regs.ebx = mode;
+       int86(0x10, &regs);
+
+       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 (file)
index 0000000..15fb101
--- /dev/null
+++ b/src/vbe.h
@@ -0,0 +1,65 @@
+#ifndef VBE_H_
+#define VBE_H_
+
+#include <inttypes.h>
+
+#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_ */
index 702273a..277dcbd 100644 (file)
@@ -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 <https://www.gnu.org/licenses/>.
 */
-#include "video.h"
+#include <stdio.h>
 #include <string.h>
+#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, &regs);
 }
+
+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;
+}
+
index 20f3ea8..bbeb224 100644 (file)
@@ -19,6 +19,7 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #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);