# HG changeset patch # User John Tsiombikas # Date 1449293327 -7200 # Node ID 4b33fa83e3815ca8d94ec56c9ad95f86faadef9f vbeinfo initial commit diff -r 000000000000 -r 4b33fa83e381 Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Makefile Sat Dec 05 07:28:47 2015 +0200 @@ -0,0 +1,22 @@ +obj = main.obj vbe.obj dpmi.obj +bin = vbeinfo.exe + +#opt = -5 -fp5 -otexan +dbg = -d1 + +CC = wcc386 +CFLAGS = $(dbg) $(opt) -zq -bt=dos -Isrc\stl +LD = wlink + +$(bin): $(obj) + %write objects.lnk file { $(obj) } + $(LD) debug all name $@ @objects $(LDFLAGS) + +.c: src + +.c.obj: .autodepend + $(CC) $(CFLAGS) $[* + +clean: .symbolic + del *.obj + del $(bin) diff -r 000000000000 -r 4b33fa83e381 src/dpmi.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dpmi.c Sat Dec 05 07:28:47 2015 +0200 @@ -0,0 +1,55 @@ +#include "dpmi.h" + +void dpmi_real_int(int inum, struct dpmi_real_regs *regs) +{ + unsigned char int_num = (unsigned char)inum; + __asm { + mov eax, 0x300 + mov edi, regs + mov bl, int_num + mov bh, 0 + xor ecx, ecx + int 0x31 + } +} + +void *dpmi_mmap(uint32_t phys_addr, unsigned int size) +{ + uint16_t mem_high, mem_low; + uint16_t phys_high = phys_addr >> 16; + uint16_t phys_low = phys_addr & 0xffff; + uint16_t size_high = size >> 16; + uint16_t size_low = size & 0xffff; + unsigned int err, res = 0; + + __asm { + mov eax, 0x800 + mov bx, phys_high + mov cx, phys_low + mov si, size_high + mov di, size_low + int 0x31 + add res, 1 + mov err, eax + mov mem_high, bx + mov mem_low, cx + } + + if(res == 2) { + return 0; + } + return (void*)(((uint32_t)mem_high << 16) | ((uint32_t)mem_low)); +} + +void dpmi_munmap(void *addr) +{ + uint16_t mem_high = (uint32_t)addr >> 16; + uint16_t mem_low = (uint16_t)addr; + + __asm { + mov eax, 0x801 + mov bx, mem_high + mov cx, mem_low + int 0x31 + } +} diff -r 000000000000 -r 4b33fa83e381 src/dpmi.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dpmi.h Sat Dec 05 07:28:47 2015 +0200 @@ -0,0 +1,26 @@ +#ifndef DPMI_H_ +#define DPMI_H_ + +#include "inttypes.h" + +struct dpmi_real_regs { + uint32_t edi, esi, ebp; + uint32_t reserved; + uint32_t ebx, edx, ecx, eax; + uint16_t flags; + uint16_t es, ds, fs, gs; + uint16_t ip, cs, sp, ss; +}; + +unsigned short dpmi_alloc(unsigned int par); +#pragma aux dpmi_alloc = \ + "mov eax, 0x100" \ + "int 0x31" \ + value[ax] parm[ebx]; + +void dpmi_real_int(int inum, struct dpmi_real_regs *regs); + +void *dpmi_mmap(uint32_t phys_addr, unsigned int size); +void dpmi_munmap(void *addr); + +#endif /* DPMI_H_ */ diff -r 000000000000 -r 4b33fa83e381 src/inttypes.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/inttypes.h Sat Dec 05 07:28:47 2015 +0200 @@ -0,0 +1,18 @@ +#ifndef INT_TYPES_H_ +#define INT_TYPES_H_ + +#if defined(__DOS__) || defined(WIN32) +typedef char int8_t; +typedef short int16_t; +typedef long int32_t; + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned long uint32_t; + +typedef unsigned long intptr_t; +#else +#include +#endif + +#endif /* INT_TYPES_H_ */ diff -r 000000000000 -r 4b33fa83e381 src/main.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main.c Sat Dec 05 07:28:47 2015 +0200 @@ -0,0 +1,96 @@ +#include +#include +#include "vbe.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) + +struct video_mode { + int xres, yres, bpp; +}; + +void sort_modes(struct video_mode *arr, int sz, int field); +/*int modecmp(const void *pa, const void *pb);*/ + +int main(int argc, char **argv) +{ + int i, nmodes; + struct vbe_info *vbe; + struct vbe_mode_info *mode; + uint16_t *modes; + struct video_mode *vmodes; + + if(!(vbe = vbe_get_info())) { + fprintf(stderr, "VBE not found\n"); + return 1; + } + printf("VBE version: %x.%x\n", vbe->version >> 8, vbe->version & 0xff); + printf("Graphics adapter: %s, %s (%s)\n", VBEPTR(vbe->oem_vendor_name_ptr), + VBEPTR(vbe->oem_product_name_ptr), VBEPTR(vbe->oem_product_rev_ptr)); + printf("Video memory: %dmb\n", vbe->total_mem << 6); + + modes = VBEPTR(vbe->vid_mode_ptr); + nmodes = 0; + for(i=0; i<1024; i++) { + if(modes[i] == 0xffff) break; + nmodes++; + } + printf("%d video modes found:\n", nmodes); + + if(!(vmodes = malloc(nmodes * sizeof *vmodes))) { + fprintf(stderr, "failed to allocate video modes array\n"); + return 1; + } + + for(i=0; ixres; + vmodes[i].yres = mode->yres; + vmodes[i].bpp = mode->bpp; + } + + /*qsort(vmodes, nmodes, sizeof *vmodes, modecmp);*/ + sort_modes(vmodes, nmodes, 2); + sort_modes(vmodes, nmodes, 1); + + for(i=0; ixres * va->yres < vb->xres * vb->yres; +} +*/ + +void sort_modes(struct video_mode *arr, int sz, int field) +{ + int i, j; + struct video_mode tmp; + + for(i=0; i= ((int*)(arr + j))[field]) { + tmp = arr[i]; + arr[i] = arr[j]; + arr[j] = tmp; + } + } + } +} diff -r 000000000000 -r 4b33fa83e381 src/vbe.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vbe.c Sat Dec 05 07:28:47 2015 +0200 @@ -0,0 +1,153 @@ +#include +#include +#include "vbe.h" +#include "dpmi.h" + +/* VGA DAC registers used for palette setting in 8bpp modes */ +#define VGA_DAC_STATE 0x3c7 +#define VGA_DAC_ADDR_RD 0x3c7 +#define VGA_DAC_ADDR_WR 0x3c8 +#define VGA_DAC_DATA 0x3c9 + +#define MODE_LFB (1 << 14) + + +struct vbe_info *vbe_get_info(void) +{ + static unsigned short info_block_seg; + static struct vbe_info *info; + struct dpmi_real_regs regs; + + if(!info) { + /* allocate 32 paragraphs (512 bytes) */ + info_block_seg = dpmi_alloc(32); + info = (struct vbe_info*)(info_block_seg << 4); + } + + memcpy(info->sig, "VBE2", 4); + + memset(®s, 0, sizeof regs); + regs.es = info_block_seg; + regs.eax = 0x4f00; + + dpmi_real_int(0x10, ®s); + + return info; +} + +struct vbe_mode_info *vbe_get_mode_info(int mode) +{ + static unsigned short mode_info_seg; + static struct vbe_mode_info *mi; + struct dpmi_real_regs regs; + + if(!mi) { + /* allocate 16 paragraphs (256 bytes) */ + mode_info_seg = dpmi_alloc(16); + mi = (struct vbe_mode_info*)(mode_info_seg << 4); + } + + memset(®s, 0, sizeof regs); + regs.es = mode_info_seg; + regs.eax = 0x4f01; + regs.ecx = mode; + regs.es = mode_info_seg; + + dpmi_real_int(0x10, ®s); + if(regs.eax & 0xff00) { + return 0; + } + + return mi; +} + +int vbe_set_mode(int mode) +{ + struct dpmi_real_regs regs; + + memset(®s, 0, sizeof regs); + regs.eax = 0x4f02; + regs.ebx = mode; + dpmi_real_int(0x10, ®s); + + if(regs.eax == 0x100) { + return -1; + } + return 0; +} + +int vbe_set_palette_bits(int bits) +{ + struct dpmi_real_regs regs; + + memset(®s, 0, sizeof regs); + regs.eax = 0x4f08; + regs.ebx = bits << 8; /* bits in bh */ + dpmi_real_int(0x10, ®s); + + if((regs.eax >> 8) & 0xff == 3) { + return -1; + } + return regs.ebx >> 8 & 0xff; /* new color bits in bh */ +} + +/* TODO: implement palette setting through the VBE2 interface for + * non-VGA displays (actually don't). + */ +void vbe_set_palette(int idx, int *col, int count, int bits) +{ + int i, shift = 8 - bits; + + __asm { + mov dx, VGA_DAC_ADDR_WR + mov eax, idx + out dx, al + } + + for(i=0; i>= shift; + g >>= shift; + b >>= shift; + } + + __asm { + mov dx, VGA_DAC_DATA + mov al, r + out dx, al + mov al, g + out dx, al + mov al, b + out dx, al + } + } +} + +static unsigned int get_mask(int sz, int pos) +{ + unsigned int i, mask = 0; + + for(i=0; ixres, mi->yres); + fprintf(fp, "color depth: %d\n", mi->bpp); + fprintf(fp, "mode attributes: %x\n", mi->mode_attr); + fprintf(fp, "bytes per scanline: %d\n", mi->scanline_bytes); + fprintf(fp, "number of planes: %d\n", (int)mi->num_planes); + fprintf(fp, "number of banks: %d\n", (int)mi->num_banks); + fprintf(fp, "mem model: %d\n", (int)mi->mem_model); + fprintf(fp, "red bits: %d (mask: %x)\n", (int)mi->rmask_size, get_mask(mi->rmask_size, mi->rpos)); + fprintf(fp, "green bits: %d (mask: %x)\n", (int)mi->gmask_size, get_mask(mi->gmask_size, mi->gpos)); + fprintf(fp, "blue bits: %d (mask: %x)\n", (int)mi->bmask_size, get_mask(mi->bmask_size, mi->bpos)); + fprintf(fp, "framebuffer address: %x\n", mi->fb_addr); +} diff -r 000000000000 -r 4b33fa83e381 src/vbe.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vbe.h Sat Dec 05 07:28:47 2015 +0200 @@ -0,0 +1,70 @@ +#ifndef VBE_H_ +#define VBE_H_ + +#include "inttypes.h" + +#define VBE_ATTR_LFB (1 << 7) +#define VBE_MODE_LFB (1 << 14) + +#pragma pack (push, 0) +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]; +}; + +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]; +}; +#pragma pack (pop) + +struct vbe_info *vbe_get_info(void); +struct vbe_mode_info *vbe_get_mode_info(unsigned int mode); + +int vbe_set_mode(unsigned int mode); + +int vbe_set_palette_bits(int bits); +void vbe_set_palette(int idx, int *col, int count, int bits); + +void print_mode_info(FILE *fp, struct vbe_mode_info *modei); + +#endif /* VBE_H_ */