vbeinfo

changeset 0:4b33fa83e381

vbeinfo initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 05 Dec 2015 07:28:47 +0200
parents
children d2d777a5da95
files Makefile src/dpmi.c src/dpmi.h src/inttypes.h src/main.c src/vbe.c src/vbe.h
diffstat 7 files changed, 440 insertions(+), 0 deletions(-) [+]
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/Makefile	Sat Dec 05 07:28:47 2015 +0200
     1.3 @@ -0,0 +1,22 @@
     1.4 +obj = main.obj vbe.obj dpmi.obj
     1.5 +bin = vbeinfo.exe
     1.6 +
     1.7 +#opt = -5 -fp5 -otexan
     1.8 +dbg = -d1
     1.9 +
    1.10 +CC = wcc386
    1.11 +CFLAGS = $(dbg) $(opt) -zq -bt=dos -Isrc\stl
    1.12 +LD = wlink
    1.13 +
    1.14 +$(bin): $(obj)
    1.15 +	%write objects.lnk file { $(obj) }
    1.16 +	$(LD) debug all name $@ @objects $(LDFLAGS)
    1.17 +
    1.18 +.c: src
    1.19 +
    1.20 +.c.obj: .autodepend
    1.21 +	$(CC) $(CFLAGS) $[*
    1.22 +
    1.23 +clean: .symbolic
    1.24 +	del *.obj
    1.25 +	del $(bin)
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/src/dpmi.c	Sat Dec 05 07:28:47 2015 +0200
     2.3 @@ -0,0 +1,55 @@
     2.4 +#include "dpmi.h"
     2.5 +
     2.6 +void dpmi_real_int(int inum, struct dpmi_real_regs *regs)
     2.7 +{
     2.8 +	unsigned char int_num = (unsigned char)inum;
     2.9 +	__asm {
    2.10 +		mov eax, 0x300
    2.11 +		mov edi, regs
    2.12 +		mov bl, int_num
    2.13 +		mov bh, 0
    2.14 +		xor ecx, ecx
    2.15 +		int 0x31
    2.16 +	}
    2.17 +}
    2.18 +
    2.19 +void *dpmi_mmap(uint32_t phys_addr, unsigned int size)
    2.20 +{
    2.21 +	uint16_t mem_high, mem_low;
    2.22 +	uint16_t phys_high = phys_addr >> 16;
    2.23 +	uint16_t phys_low = phys_addr & 0xffff;
    2.24 +	uint16_t size_high = size >> 16;
    2.25 +	uint16_t size_low = size & 0xffff;
    2.26 +	unsigned int err, res = 0;
    2.27 +
    2.28 +	__asm {
    2.29 +		mov eax, 0x800
    2.30 +		mov bx, phys_high
    2.31 +		mov cx, phys_low
    2.32 +		mov si, size_high
    2.33 +		mov di, size_low
    2.34 +		int 0x31
    2.35 +		add res, 1
    2.36 +		mov err, eax
    2.37 +		mov mem_high, bx
    2.38 +		mov mem_low, cx
    2.39 +	}
    2.40 +
    2.41 +	if(res == 2) {
    2.42 +		return 0;
    2.43 +	}
    2.44 +	return (void*)(((uint32_t)mem_high << 16) | ((uint32_t)mem_low));
    2.45 +}
    2.46 +
    2.47 +void dpmi_munmap(void *addr)
    2.48 +{
    2.49 +	uint16_t mem_high = (uint32_t)addr >> 16;
    2.50 +	uint16_t mem_low = (uint16_t)addr;
    2.51 +
    2.52 +	__asm {
    2.53 +		mov eax, 0x801
    2.54 +		mov bx, mem_high
    2.55 +		mov cx, mem_low
    2.56 +		int 0x31
    2.57 +	}
    2.58 +}
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/src/dpmi.h	Sat Dec 05 07:28:47 2015 +0200
     3.3 @@ -0,0 +1,26 @@
     3.4 +#ifndef DPMI_H_
     3.5 +#define DPMI_H_
     3.6 +
     3.7 +#include "inttypes.h"
     3.8 +
     3.9 +struct dpmi_real_regs {
    3.10 +	uint32_t edi, esi, ebp;
    3.11 +	uint32_t reserved;
    3.12 +	uint32_t ebx, edx, ecx, eax;
    3.13 +	uint16_t flags;
    3.14 +	uint16_t es, ds, fs, gs;
    3.15 +	uint16_t ip, cs, sp, ss;
    3.16 +};
    3.17 +
    3.18 +unsigned short dpmi_alloc(unsigned int par);
    3.19 +#pragma aux dpmi_alloc = \
    3.20 +		"mov eax, 0x100" \
    3.21 +		"int 0x31" \
    3.22 +		value[ax] parm[ebx];
    3.23 +
    3.24 +void dpmi_real_int(int inum, struct dpmi_real_regs *regs);
    3.25 +
    3.26 +void *dpmi_mmap(uint32_t phys_addr, unsigned int size);
    3.27 +void dpmi_munmap(void *addr);
    3.28 +
    3.29 +#endif	/* DPMI_H_ */
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/src/inttypes.h	Sat Dec 05 07:28:47 2015 +0200
     4.3 @@ -0,0 +1,18 @@
     4.4 +#ifndef INT_TYPES_H_
     4.5 +#define INT_TYPES_H_
     4.6 +
     4.7 +#if defined(__DOS__) || defined(WIN32)
     4.8 +typedef char int8_t;
     4.9 +typedef short int16_t;
    4.10 +typedef long int32_t;
    4.11 +
    4.12 +typedef unsigned char uint8_t;
    4.13 +typedef unsigned short uint16_t;
    4.14 +typedef unsigned long uint32_t;
    4.15 +
    4.16 +typedef unsigned long intptr_t;
    4.17 +#else
    4.18 +#include <stdint.h>
    4.19 +#endif
    4.20 +
    4.21 +#endif	/* INT_TYPES_H_ */
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/main.c	Sat Dec 05 07:28:47 2015 +0200
     5.3 @@ -0,0 +1,96 @@
     5.4 +#include <stdio.h>
     5.5 +#include <stdlib.h>
     5.6 +#include "vbe.h"
     5.7 +
     5.8 +#define REALPTR(s, o)	(void*)(((uint32_t)(s) << 4) + (uint32_t)(o))
     5.9 +#define VBEPTR(x)		REALPTR(((x) & 0xffff0000) >> 16, (x) & 0xffff)
    5.10 +#define VBEPTR_SEG(x)	(((x) & 0xffff0000) >> 16)
    5.11 +#define VBEPTR_OFF(x)	((x) & 0xffff)
    5.12 +
    5.13 +struct video_mode {
    5.14 +	int xres, yres, bpp;
    5.15 +};
    5.16 +
    5.17 +void sort_modes(struct video_mode *arr, int sz, int field);
    5.18 +/*int modecmp(const void *pa, const void *pb);*/
    5.19 +
    5.20 +int main(int argc, char **argv)
    5.21 +{
    5.22 +	int i, nmodes;
    5.23 +	struct vbe_info *vbe;
    5.24 +	struct vbe_mode_info *mode;
    5.25 +	uint16_t *modes;
    5.26 +	struct video_mode *vmodes;
    5.27 +
    5.28 +	if(!(vbe = vbe_get_info())) {
    5.29 +		fprintf(stderr, "VBE not found\n");
    5.30 +		return 1;
    5.31 +	}
    5.32 +	printf("VBE version: %x.%x\n", vbe->version >> 8, vbe->version & 0xff);
    5.33 +	printf("Graphics adapter: %s, %s (%s)\n", VBEPTR(vbe->oem_vendor_name_ptr),
    5.34 +				VBEPTR(vbe->oem_product_name_ptr), VBEPTR(vbe->oem_product_rev_ptr));
    5.35 +	printf("Video memory: %dmb\n", vbe->total_mem << 6);
    5.36 +
    5.37 +	modes = VBEPTR(vbe->vid_mode_ptr);
    5.38 +	nmodes = 0;
    5.39 +	for(i=0; i<1024; i++) {
    5.40 +		if(modes[i] == 0xffff) break;
    5.41 +		nmodes++;
    5.42 +	}
    5.43 +	printf("%d video modes found:\n", nmodes);
    5.44 +
    5.45 +	if(!(vmodes = malloc(nmodes * sizeof *vmodes))) {
    5.46 +		fprintf(stderr, "failed to allocate video modes array\n");
    5.47 +		return 1;
    5.48 +	}
    5.49 +
    5.50 +	for(i=0; i<nmodes; i++) {
    5.51 +		if(!(mode = vbe_get_mode_info(modes[i]))) {
    5.52 +			fprintf(stderr, "failed to get mode %d info\n", i);
    5.53 +		}
    5.54 +		vmodes[i].xres = mode->xres;
    5.55 +		vmodes[i].yres = mode->yres;
    5.56 +		vmodes[i].bpp = mode->bpp;
    5.57 +	}
    5.58 +
    5.59 +	/*qsort(vmodes, nmodes, sizeof *vmodes, modecmp);*/
    5.60 +	sort_modes(vmodes, nmodes, 2);
    5.61 +	sort_modes(vmodes, nmodes, 1);
    5.62 +
    5.63 +	for(i=0; i<nmodes; i++) {
    5.64 +		if(i == 0 || vmodes[i].xres != vmodes[i - 1].xres ||
    5.65 +				vmodes[i].yres != vmodes[i - 1].yres) {
    5.66 +			printf("\n%4dx%d - depth:", vmodes[i].xres, vmodes[i].yres);
    5.67 +		}
    5.68 +		printf(" %d", vmodes[i].bpp);
    5.69 +	}
    5.70 +	putchar('\n');
    5.71 +
    5.72 +	free(vmodes);
    5.73 +	return 0;
    5.74 +}
    5.75 +/*
    5.76 +int modecmp(const void *pa, const void *pb)
    5.77 +{
    5.78 +	const struct video_mode *va = pa;
    5.79 +	const struct video_mode *vb = pb;
    5.80 +
    5.81 +	return va->xres * va->yres < vb->xres * vb->yres;
    5.82 +}
    5.83 +*/
    5.84 +
    5.85 +void sort_modes(struct video_mode *arr, int sz, int field)
    5.86 +{
    5.87 +	int i, j;
    5.88 +	struct video_mode tmp;
    5.89 +
    5.90 +	for(i=0; i<sz; i++) {
    5.91 +		for(j=i+1; j<sz; j++) {
    5.92 +			if(((int*)(arr + i))[field] >= ((int*)(arr + j))[field]) {
    5.93 +				tmp = arr[i];
    5.94 +				arr[i] = arr[j];
    5.95 +				arr[j] = tmp;
    5.96 +			}
    5.97 +		}
    5.98 +	}
    5.99 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/src/vbe.c	Sat Dec 05 07:28:47 2015 +0200
     6.3 @@ -0,0 +1,153 @@
     6.4 +#include <stdio.h>
     6.5 +#include <string.h>
     6.6 +#include "vbe.h"
     6.7 +#include "dpmi.h"
     6.8 +
     6.9 +/* VGA DAC registers used for palette setting in 8bpp modes */
    6.10 +#define VGA_DAC_STATE		0x3c7
    6.11 +#define VGA_DAC_ADDR_RD		0x3c7
    6.12 +#define VGA_DAC_ADDR_WR		0x3c8
    6.13 +#define VGA_DAC_DATA		0x3c9
    6.14 +
    6.15 +#define MODE_LFB	(1 << 14)
    6.16 +
    6.17 +
    6.18 +struct vbe_info *vbe_get_info(void)
    6.19 +{
    6.20 +	static unsigned short info_block_seg;
    6.21 +	static struct vbe_info *info;
    6.22 +	struct dpmi_real_regs regs;
    6.23 +
    6.24 +	if(!info) {
    6.25 +		/* allocate 32 paragraphs (512 bytes) */
    6.26 +		info_block_seg = dpmi_alloc(32);
    6.27 +		info = (struct vbe_info*)(info_block_seg << 4);
    6.28 +	}
    6.29 +
    6.30 +	memcpy(info->sig, "VBE2", 4);
    6.31 +
    6.32 +	memset(&regs, 0, sizeof regs);
    6.33 +	regs.es = info_block_seg;
    6.34 +	regs.eax = 0x4f00;
    6.35 +
    6.36 +	dpmi_real_int(0x10, &regs);
    6.37 +
    6.38 +	return info;
    6.39 +}
    6.40 +
    6.41 +struct vbe_mode_info *vbe_get_mode_info(int mode)
    6.42 +{
    6.43 +	static unsigned short mode_info_seg;
    6.44 +	static struct vbe_mode_info *mi;
    6.45 +	struct dpmi_real_regs regs;
    6.46 +
    6.47 +	if(!mi) {
    6.48 +		/* allocate 16 paragraphs (256 bytes) */
    6.49 +		mode_info_seg = dpmi_alloc(16);
    6.50 +		mi = (struct vbe_mode_info*)(mode_info_seg << 4);
    6.51 +	}
    6.52 +
    6.53 +	memset(&regs, 0, sizeof regs);
    6.54 +	regs.es = mode_info_seg;
    6.55 +	regs.eax = 0x4f01;
    6.56 +	regs.ecx = mode;
    6.57 +	regs.es = mode_info_seg;
    6.58 +
    6.59 +	dpmi_real_int(0x10, &regs);
    6.60 +	if(regs.eax & 0xff00) {
    6.61 +		return 0;
    6.62 +	}
    6.63 +
    6.64 +	return mi;
    6.65 +}
    6.66 +
    6.67 +int vbe_set_mode(int mode)
    6.68 +{
    6.69 +	struct dpmi_real_regs regs;
    6.70 +
    6.71 +	memset(&regs, 0, sizeof regs);
    6.72 +	regs.eax = 0x4f02;
    6.73 +	regs.ebx = mode;
    6.74 +	dpmi_real_int(0x10, &regs);
    6.75 +
    6.76 +	if(regs.eax == 0x100) {
    6.77 +		return -1;
    6.78 +	}
    6.79 +	return 0;
    6.80 +}
    6.81 +
    6.82 +int vbe_set_palette_bits(int bits)
    6.83 +{
    6.84 +	struct dpmi_real_regs regs;
    6.85 +
    6.86 +	memset(&regs, 0, sizeof regs);
    6.87 +	regs.eax = 0x4f08;
    6.88 +	regs.ebx = bits << 8;	/* bits in bh */
    6.89 +	dpmi_real_int(0x10, &regs);
    6.90 +
    6.91 +	if((regs.eax >> 8) & 0xff == 3) {
    6.92 +		return -1;
    6.93 +	}
    6.94 +	return regs.ebx >> 8 & 0xff;	/* new color bits in bh */
    6.95 +}
    6.96 +
    6.97 +/* TODO: implement palette setting through the VBE2 interface for
    6.98 + * non-VGA displays (actually don't).
    6.99 + */
   6.100 +void vbe_set_palette(int idx, int *col, int count, int bits)
   6.101 +{
   6.102 +	int i, shift = 8 - bits;
   6.103 +
   6.104 +	__asm {
   6.105 +		mov dx, VGA_DAC_ADDR_WR
   6.106 +		mov eax, idx
   6.107 +		out dx, al
   6.108 +	}
   6.109 +
   6.110 +	for(i=0; i<count; i++) {
   6.111 +		unsigned char r = *col++;
   6.112 +		unsigned char g = *col++;
   6.113 +		unsigned char b = *col++;
   6.114 +
   6.115 +		if(shift) {
   6.116 +			r >>= shift;
   6.117 +			g >>= shift;
   6.118 +			b >>= shift;
   6.119 +		}
   6.120 +
   6.121 +		__asm {
   6.122 +			mov dx, VGA_DAC_DATA
   6.123 +			mov al, r
   6.124 +			out dx, al
   6.125 +			mov al, g
   6.126 +			out dx, al
   6.127 +			mov al, b
   6.128 +			out dx, al
   6.129 +		}
   6.130 +	}
   6.131 +}
   6.132 +
   6.133 +static unsigned int get_mask(int sz, int pos)
   6.134 +{
   6.135 +	unsigned int i, mask = 0;
   6.136 +
   6.137 +	for(i=0; i<sz; i++) {
   6.138 +		mask |= 1 << i;
   6.139 +	}
   6.140 +	return mask << pos;
   6.141 +}
   6.142 +
   6.143 +void print_mode_info(FILE *fp, struct vbe_mode_info *mi)
   6.144 +{
   6.145 +	fprintf(fp, "resolution: %dx%d\n", mi->xres, mi->yres);
   6.146 +	fprintf(fp, "color depth: %d\n", mi->bpp);
   6.147 +	fprintf(fp, "mode attributes: %x\n", mi->mode_attr);
   6.148 +	fprintf(fp, "bytes per scanline: %d\n", mi->scanline_bytes);
   6.149 +	fprintf(fp, "number of planes: %d\n", (int)mi->num_planes);
   6.150 +	fprintf(fp, "number of banks: %d\n", (int)mi->num_banks);
   6.151 +	fprintf(fp, "mem model: %d\n", (int)mi->mem_model);
   6.152 +	fprintf(fp, "red bits: %d (mask: %x)\n", (int)mi->rmask_size, get_mask(mi->rmask_size, mi->rpos));
   6.153 +	fprintf(fp, "green bits: %d (mask: %x)\n", (int)mi->gmask_size, get_mask(mi->gmask_size, mi->gpos));
   6.154 +	fprintf(fp, "blue bits: %d (mask: %x)\n", (int)mi->bmask_size, get_mask(mi->bmask_size, mi->bpos));
   6.155 +	fprintf(fp, "framebuffer address: %x\n", mi->fb_addr);
   6.156 +}
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/src/vbe.h	Sat Dec 05 07:28:47 2015 +0200
     7.3 @@ -0,0 +1,70 @@
     7.4 +#ifndef VBE_H_
     7.5 +#define VBE_H_
     7.6 +
     7.7 +#include "inttypes.h"
     7.8 +
     7.9 +#define VBE_ATTR_LFB	(1 << 7)
    7.10 +#define VBE_MODE_LFB	(1 << 14)
    7.11 +
    7.12 +#pragma pack (push, 0)
    7.13 +struct vbe_info {
    7.14 +	uint8_t sig[4];
    7.15 +	uint16_t version;
    7.16 +	uint32_t oem_str_ptr;
    7.17 +	uint8_t caps[4];			/* capabilities */
    7.18 +	uint32_t vid_mode_ptr;		/* vbefarptr to video mode list */
    7.19 +	uint16_t total_mem;			/* num of 64k mem blocks */
    7.20 +	uint16_t oem_sw_rev;		/* VBE implementation software revision */
    7.21 +	uint32_t oem_vendor_name_ptr;
    7.22 +	uint32_t oem_product_name_ptr;
    7.23 +	uint32_t oem_product_rev_ptr;
    7.24 +	uint8_t reserved[222];
    7.25 +	uint8_t oem_data[256];
    7.26 +};
    7.27 +
    7.28 +struct vbe_mode_info {
    7.29 +	uint16_t mode_attr;
    7.30 +	uint8_t wina_attr, winb_attr;
    7.31 +	uint16_t win_gran, win_size;
    7.32 +	uint16_t wina_seg, winb_seg;
    7.33 +	uint32_t win_func;
    7.34 +	uint16_t scanline_bytes;
    7.35 +
    7.36 +	/* VBE 1.2 and above */
    7.37 +	uint16_t xres, yres;
    7.38 +	uint8_t xcharsz, ycharsz;
    7.39 +	uint8_t num_planes;
    7.40 +	uint8_t bpp;
    7.41 +	uint8_t num_banks;
    7.42 +	uint8_t mem_model;
    7.43 +	uint8_t bank_size;		/* bank size in KB */
    7.44 +	uint8_t num_img_pages;
    7.45 +	uint8_t reserved1;
    7.46 +
    7.47 +	/* direct color fields */
    7.48 +	uint8_t rmask_size, rpos;
    7.49 +	uint8_t gmask_size, gpos;
    7.50 +	uint8_t bmask_size, bpos;
    7.51 +	uint8_t xmask_size, xpos;
    7.52 +	uint8_t cmode_info;		/* direct color mode attributes */
    7.53 +
    7.54 +	/* VBE 2.0 and above */
    7.55 +	uint32_t fb_addr;		/* physical address of the linear framebuffer */
    7.56 +	uint32_t reserved2;
    7.57 +	uint16_t reserved3;
    7.58 +
    7.59 +	uint8_t reserved4[206];
    7.60 +};
    7.61 +#pragma pack (pop)
    7.62 +
    7.63 +struct vbe_info *vbe_get_info(void);
    7.64 +struct vbe_mode_info *vbe_get_mode_info(unsigned int mode);
    7.65 +
    7.66 +int vbe_set_mode(unsigned int mode);
    7.67 +
    7.68 +int vbe_set_palette_bits(int bits);
    7.69 +void vbe_set_palette(int idx, int *col, int count, int bits);
    7.70 +
    7.71 +void print_mode_info(FILE *fp, struct vbe_mode_info *modei);
    7.72 +
    7.73 +#endif	/* VBE_H_ */