Page 1 of 1

[SOLVED] VESA and Bochs

Posted: Tue Aug 11, 2009 2:12 am
by AlfaOmega08
Hi, I finally got a Virtual 8086 monitor working, and now I'm trying to switch to a graphic mode. I want higher resolution than VGA so I'm working on VESA. After the kernel initialization, I check for the presence of VESA on the system with INT 0x10 AX = 0x4F00. Then I try to detect the best resolution available on the system between modes 0x113, 0x115, 0x116, 0x118, 0x119, 0x11B (800x600, 1024x768, 1280x1024 at 16bpp or 32bpp), using INT 0x10 AX = 0x4F01 and checking for the bits 0, 4 and 5 of the mode attribute to see if it can be used. Found the mode I switch to it using INT 0x10 AX = 0x4F02. This works well on my desktop hardware and on virtualbox but it doesn't on bochs or my eeePC. Bochs gives always attribute = 0 for any of the modes but if I try to force the switch it change the mode but won't let me writing pixels.

May I have misconfigured bochs? Or is a code problem?

Re: VESA and Bochs

Posted: Tue Aug 11, 2009 2:35 am
by f2
I never had any problems with Bochs with VESA modes. If Bochs was misconfigured, INT 0x10 says that there is no VESA support.
I think there's an error in your code.

Re: VESA and Bochs

Posted: Tue Aug 11, 2009 3:32 am
by AlfaOmega08
Uhm... now it doesn't work neither on real hardware... Here is my code :mrgreen:

Code: Select all

struct VESAHeader {
	char signature[4];
	short version;
	short oemString[2];
	unsigned char capabilities[4];
	short videomodes[2];
	short totalMemory;
};

struct VESAModeInfo {
	word attributes;
	byte winA,winB;
	word granularity;
	word winsize;
	word segmentA, segmentB;
	dword realFctPtr;
	word pitch;

	word Xres, Yres;
	byte Wchar, Ychar, planes, bpp, banks;
	byte memory_model, bank_size, image_pages;
	byte reserved0;

	byte red_mask, red_position;
	byte green_mask, green_position;
	byte blue_mask, blue_position;
	byte rsv_mask, rsv_position;
	byte directcolor_attributes;

	dword physbase;
} __attribute__ ((packed));

void setbank(int n) {
	struct regs regs;
	regs.eax = 0x4F05;
	regs.ebx = 0;
	regs.edx = n;
	v86_int(0x10, &regs);
}

int curBank = 0;
void PutPixel(int x, int y, dword color, dword gran, dword max, dword bpp) {
	int addr = y * max + x;
	int banksize = gran * max;
	int bnum = addr / banksize;
	int boff = addr % banksize;
	
	if (bnum != curBank) {
		setbank(bnum);
		curBank = bnum;
	}
	
	if (bpp == 16) {
		word *ptr = (word *) (0xC00A0000 + boff * 2);
		*ptr = color & 0xFFFFFF;
	} else if (bpp == 24) {
		byte *ptr = (byte *) (0xC00A0000 + boff * 3);
		ptr[0] = color & 0xFF;
		ptr[1] = color >> 8 & 0xFF;
		ptr[2] = color >> 16 & 0xFF;
	} else if (bpp == 32) {
		dword *ptr = (dword *) (0xC00A0000 + boff * 4);
		*ptr = color;
	}		    	
}

void vesa_init() {
	struct regs regs;

	// Read the vesa header
	regs.eax = 0x4F00;
	regs.es = 0;
	regs.edi = 0x2000;
	v86_int(0x10, &regs);
	
	if (regs.eax != 0x004F) {
		panic("VESA is not present on this system\n");
	}
	
	struct VESAHeader *vbe = (struct VESAHeader *) 0xC0002000;
	if (strncmp(vbe->signature, "VESA", 4)) {
		panic("Wrong VESA signature\n");
	}

	word Modes[6] = { 0x113, 0x115, 0x116, 0x118, 0x119, 0x11B };

	int i, best = -1;
	for (i = 0; i < 6; i++) {
		// Get Mode informations
		regs.eax = 0x4F01;
		regs.ebx = Modes[i];
		regs.es = 0;
		regs.edi = 0x3000;
		v86_int(0x10, &regs);
		
		struct VESAModeInfo *tmp = (struct VESAModeInfo *) 0xC0003000;
		if (tmp->attributes & 0x19 == 0x19) {
			kprintf("Mode %04X, %dx%dx%d detected\n", Modes[i], tmp->Xres, tmp->Yres, tmp->bpp);
			best = Modes[i];
		} else {
			kprintf("Bad mode %04X attr %d\n", Modes[i], tmp->attributes);
		}
	}
	
	if (best == -1) {
		panic("Unable to find an available VESA mode");
	}
	
	kprintf("Best mode found: %04X", Modes[best]);
	
	struct VESAModeInfo *tmp = (struct VESAModeInfo *) 0xC0003000;
	
	// Set video mode
	regs.eax = 0x4F02;
	regs.ebx = Modes[best];
	v86_int(0x10, &regs);

	int gran = tmp->granularity;
	int maxX = tmp->Xres;
	int maxY = tmp->Yres;
	int bpp = tmp->bpp;

	for (i = 0; i < maxX; i++) {
		int j;
		for (j = 0; j < maxY; j++) {
			PutPixel(i, j, 0xFFFFFFFF, gran, maxX, bpp);
		}
	}
}
please help me [-o<

Re: VESA and Bochs

Posted: Tue Aug 11, 2009 3:37 am
by giszo
AlfaOmega08 wrote:please help me [-o<
What about using packed attribute on the VESA structs? :roll:

Re: VESA and Bochs

Posted: Tue Aug 11, 2009 3:42 am
by AlfaOmega08
well, the packed attribute, may be one of the causes, but it hasn't solved the problem.
thanks for the trying

Re: VESA and Bochs

Posted: Tue Aug 11, 2009 3:55 am
by f2

Code: Select all

best = Modes[i];

...

regs.ebx = Modes[best];
Perhaps the problem is here...
Should be:

Code: Select all

regs.ebx = best;
Another thing:
AlfaOmega08 wrote:and checking for the bits 0, 4 and 5
0x19 -> 11001 -> bit 0, 3 and 4 are set here.
Note: if you use banks, you shouldn't check if bit 5 is set.

Re: VESA and Bochs

Posted: Tue Aug 11, 2009 4:32 am
by AlfaOmega08
thank you tommy the first error was the cause for witch the code didn't work anymore on real hardware. However I still have problems anywhere else...

I prefer to use lfb instead of banks so as suggested on the wiki I check for bits 0x90 of the attribute instead of 0x19. I noticed that Bochs returns as resolutions for any of the modes 0x0 at 0 bpp with attribute 0. Isn't that nice?

However now the code is:

Code: Select all

struct VESAHeader {
	char signature[4];
	short version;
	short oemString[2];
	unsigned char capabilities[4];
	short videomodes[2];
	short totalMemory;
} __attribute__ ((packed));

struct VESAModeInfo {
	word attributes;
	byte winA,winB;
	word granularity;
	word winsize;
	word segmentA, segmentB;
	dword realFctPtr;
	word pitch;

	word Xres, Yres;
	byte Wchar, Ychar, planes, bpp, banks;
	byte memory_model, bank_size, image_pages;
	byte reserved0;

	byte red_mask, red_position;
	byte green_mask, green_position;
	byte blue_mask, blue_position;
	byte rsv_mask, rsv_position;
	byte directcolor_attributes;

	dword physbase;
} __attribute__ ((packed));

void PutPixel(int x, int y, dword color, dword max, dword bpp, dword buff) {
	int addr = y * max + x;

	if (bpp == 16) {
		word *ptr = (word *) (0xC00A0000 + addr * 2);
		*ptr = color & 0xFFFFFF;
	} else if (bpp == 24) {
		byte *ptr = (byte *) (0xC00A0000 + addr * 3);
		ptr[0] = color & 0xFF;
		ptr[1] = color >> 8 & 0xFF;
		ptr[2] = color >> 16 & 0xFF;
	} else if (bpp == 32) {
		dword *ptr = (dword *) (0xC00A0000 + addr * 4);
		*ptr = color;
	}		    	
}

void vesa_init() {
	struct regs regs;

	// Read the vesa header
	regs.eax = 0x4F00;
	regs.es = 0;
	regs.edi = 0x2000;
	v86_int(0x10, &regs);
	
	if (regs.eax != 0x004F) {
		panic("VESA is not present on this system\n");
	}
	
	struct VESAHeader *vbe = (struct VESAHeader *) 0xC0002000;
	if (strncmp(vbe->signature, "VESA", 4)) {
		panic("Wrong VESA signature\n");
	}

	word Modes[6] = { 0x113, 0x115, 0x116, 0x118, 0x119, 0x11B };

	int i, best = -1;
	for (i = 0; i < 6; i++) {
		// Get Mode informations
		regs.eax = 0x4F01;
		regs.ebx = Modes[i];
		regs.es = 0;
		regs.edi = 0x3000;
		v86_int(0x10, &regs);
		
		struct VESAModeInfo *tmp = (struct VESAModeInfo *) 0xC0003000;
		if (tmp->attributes & 0x90 == 0x90) {
			kprintf("Mode %04X, %dx%dx%d detected\n", Modes[i], tmp->Xres, tmp->Yres, tmp->bpp);
			best = Modes[i];
		} else {
			kprintf("Bad mode %04X attr %d, %dx%d\n", Modes[i], tmp->attributes, tmp->Xres, tmp->Yres);
		}
	}
	
	if (best == -1) {
		panic("Unable to find an available VESA mode");
	}
	
	kprintf("Best mode found: %04X", best);
	
	struct VESAModeInfo *tmp = (struct VESAModeInfo *) 0xC0003000;
	
	// Set video mode
	regs.eax = 0x4F02;
	regs.ebx = best;
	v86_int(0x10, &regs);

	int buff = tmp->physbase;
	int maxX = tmp->Xres;
	int maxY = tmp->Yres;
	int bpp = tmp->bpp;

	for (i = 0; i < maxX; i++) {
		int j;
		for (j = 0; j < maxY; j++) {
			PutPixel(i, j, 0xFFFFFFFF, maxX, bpp, buff);
		}
	}
}

Re: VESA and Bochs

Posted: Thu Aug 13, 2009 1:38 pm
by AlfaOmega08
OK, while JamesM is on the road of 2D Graphic acceleration :shock: , I am still unable to use VESA. Something strange is happenin in my code. I changed all the extensions from .c to .cpp and did the needed changes to the code to be compiled as c++ (casting void * for maths and for mallocs, changing char * to const char * etc...) and the code shown before just does its work. On bochs as well as on real hardware. The strange thing is that if I put a "while (1);" just before the mode switch interrupt, the code doesn't find any good VESA mode on bochs anymore. If I remove that while (1) the mode is found and switched :shock: :shock: :shock: . May this be a G++/GCC bug?

Re: VESA and Bochs

Posted: Thu Aug 13, 2009 2:02 pm
by tantrikwizard
AlfaOmega08 wrote:May this be a G++/GCC bug?
highly unlikely. VESA works fine on my bochs build. Make sure you have vga: extension=vbe in the bochsrc It might not be related to your problem but I think it's required to use VBE. Bochs does not fully implement all the VBE extensions but it does implement the stuff you're trying to use.

Re: VESA and Bochs

Posted: Thu Aug 13, 2009 2:49 pm
by AlfaOmega08
Bochs has VBE extension enabled. I have vga: extension=vbe in bochsrc.txt. As I said the code works until I insert a while(1) after the mode search. If I insert a "while(1)" line the code stops working

Re: VESA and Bochs

Posted: Thu Aug 13, 2009 4:04 pm
by AlfaOmega08
Got it!!!

// Get Mode informations
regs.eax = 0x4F01;
regs.ebx = Modes;
regs.es = 0;
regs.edi = 0x3000;
v86_int(0x10, &regs);

Reading the RBIL I discovered that the mode have to be set in ecx, not in ebx... Now I have to understand why did I use ebx :mrgreen:

Re: VESA and Bochs

Posted: Thu Aug 13, 2009 6:11 pm
by tantrikwizard
AlfaOmega08 wrote:Got it!!!
Why not read the docs? The spec fully outlines the register formats and interrupts.