Page 1 of 2
vesa mode problem on real h/w
Posted: Mon Mar 30, 2009 1:13 pm
by johnsa
hey all,
quick question on VBE mode on real hardware, the following code works for me under all the emulators (Vesa 2.x) but on all my real machines (Vesa 3.x) it goes completely haywire..
I first determine if VBE is present and if so it's version:
Code: Select all
mov ax,4f00h
int 10h
; fill VBEInfo table and get version...
Then I get the mode info for the particular mode I'm trying to use:
Code: Select all
mov ax,4f01h
mov cx,115h ; the mode im using 800x600xtrue colour
int 10h
; this fills the modeinfo structure
The from the mode info structure I look at two params:
BytesPerScanLine
and BitsPerPixel
as some cards will use true-colour mode in 24bit while others will use 32bits..
These factors are accounted for in the drawing code..
Then I set the mode as follows:
Code: Select all
mov ax,4f02h
mov bx,115h
or bh,01000000b ; set bit 14 for LFB
push ds
pop es
mov di,offset crtinfo
int 10h
I check for AH != 0 after every call to check for a failed function call.
All this works sofar in both emulator and real h/w... the problem comes once I start drawing:
I use the PhysBaseAddr field from the mode info block and then treat the vid-mem as normal using the pitch and if it's 3 bytes or 4 bytes per pixel as either R,G,B or R,G,B,A...
The output on real h/w looks totally whacked.. like its banked or planar or something.. not too sure.. Anyone have any ideas?
John
Re: vesa mode problem on real h/w
Posted: Mon Mar 30, 2009 5:46 pm
by Brendan
Hi,
johnsa wrote:The output on real h/w looks totally whacked.. like its banked or planar or something.. not too sure.. Anyone have any ideas?
Some notes...
First, (for VBE 2.0 or later) you can't assume that any video mode will have any specific video mode number. Video mode number 115h might be "800*600*24-bpp" but it can just as easily be anything else or nothing at all. The correct method is to get a list of video mode numbers from the "return VBE controller information" function, and for each mode number listed you'd use the "return VBE mode information" function to see if it's the mode you want.
When you're checking the "VBE mode information" you need to check if the optional data is present (and if it's not present, then it's an old mode with a fixed mode number, so in this case you can assume that video mode number 115h is "800*600*24-bpp"). If the optional data is present you'd need to check the bits per pixel field, and the horizontal and vertical resolution fields. Then check the memory model field. If the memory model is "packed pixel" then you've found the mode you want. If the memory model field is "direct colour" then you need to check the direct colour fields (red_mask, red_position, green_mask, green_position, etc) to make sure that its "8r:8g:8b" and not something else (e.g. "8b:8g:8r" or "7r:10g:7b"). Then you'd need to see if the video mode supports LFB (and set the "use LFB" flag in the video mode number when you set the video mode).
When you're writing data to display memory you need to use something like "address = base + y * VBEinfo.bytesPerScanline + x * bytesPerPixel" and you can't use something like "address = base + (y * Yresolution + x) * bytesPerPixel". This is because there's often spare/unused space at the end of each screen line (especially for 24-bpp). Note that (for VBE 3.0) there's 2 different "bytesPerScanline" fields in the VBE mode information structure - one for bank switching, and another one for LFB (and you need to use the right one).
Finally, you can't assume that the video card supports any 24-bpp modes (e.g. some only support 32-bpp); and if the card supports both "800*600*24-bpp" and "800*600*32-bpp" then it's probably better to use "800*600*32-bpp" to avoid alignment issues. You can't assume that the monitor will support the video mode either (but that's a separate issue).
Cheers,
Brendan
Re: vesa mode problem on real h/w
Posted: Tue Mar 31, 2009 1:55 am
by johnsa
Hey,
Ok I've made a few updates. I already run through and store the list of VBE video modes. I've now additionally used that list to determine a mode number that meets my specifications of 800x600x24 or 32bpp.
For each mode in the list I call 4f01h and from the modeinfo structure check the x resolution, y resolution and then bits per pixel if present.
After all of this I then set that mode if it's present.
In terms of drawing my code already caters for 24bit or 32bit and already uses the BPP to determine such as well as using either BytesPerScanLine or LinBytesPerScanLine (for VBE3+) to do the calculations for X,Y.
It still works perfectly under all the emulators.. still looks completely poked on real h/w...
Re: vesa mode problem on real h/w
Posted: Tue Mar 31, 2009 3:27 am
by djmauretto
Poste your code so i can try to my pc,
note that Vesa is not reliable, it's full of bug,
anyway below there is a utility that wrote some time
ago for dos/win98/xp.
Re: vesa mode problem on real h/w
Posted: Tue Mar 31, 2009 4:19 am
by johnsa
Hey,
thanks for that useful little app!
I ran it on my machine and it's reporting exactly the same params for the video mode I'm interested in.
On hardware my mode 115h is 800x600x32bit, 3200 bytes scanline width, direct colour with A:8,R:8,G:8,B:8 format.
My boot code picks up exactly the same..
Where things seems to go wrong is when writing to video-mem, it's looking to me like when I set that mode.. it's not actually 800x600 or the scanline width in bytes it reports is not correct..If i just do a test blanket fill of 800x600 pixels in red, it works (fills the whole screen) in emulators but on the real h/w it only fills half the screen.
I have an Intel GMA965 graphics card onboard.. I'm wondering if it's just dodgy full of bugs...

Re: vesa mode problem on real h/w
Posted: Tue Mar 31, 2009 4:49 am
by jal
johnsa wrote:If i just do a test blanket fill of 800x600 pixels in red, it works (fills the whole screen) in emulators but on the real h/w it only fills half the screen.
You are talking about setting VESA modes through int10h: I assume you set the mode in real mode. You are talking about filling the screen: I assume you do that in protected mode. So the questions are: is your pmode setup correct (flat memory for example), do you use paging (and if so, is nothing botched there), etc. Also, what if you use a different mode, e.g. 640x480, or 1024x768? Is it still half in all modes, or does the filled area size with the mode?
JAL
Re: vesa mode problem on real h/w
Posted: Tue Mar 31, 2009 4:56 am
by djmauretto
ok, try with some test,
eg: fill one column and check if width is exact,
then count how many rows you must fill to
fill in entirety the screen
Re: vesa mode problem on real h/w
Posted: Tue Mar 31, 2009 5:19 am
by johnsa
Hi,
I set the mode and do the drawing both in unreal mode.. that stuff is all 100%
As a test I did the following:
The mode is definately 800x600x32bit confirmed.
Draw a block 400x300 in red starting at PhysBaseAddr, writing dwords at a time.
Code: Select all
; EDI points to PhysBaseAddr....
mov ebp,300
fillplop1:
mov ecx,400
mov eax,00ff0000h
fillplop0:
mov es:[edi],eax
add edi,4
dec ecx
jnz short fillplop0
mov eax,VBE_PITCH
sub eax,(400*4)
add edi,eax
dec ebp
jnz short fillplop1
; Now we draw a white block following on writing bytes at a time (this was just to make sure that nothing brakes by writing bytes in 32bit mode instead of full dwords)
mov ebp,300
fillplop2:
mov ecx,400
mov al,0ffh
fillplop3:
mov es:[edi],al
mov es:[edi+1],al
mov es:[edi+2],al
add edi,4
dec ecx
jnz short fillplop3
mov eax,VBE_PITCH
sub eax,(400*4)
add edi,eax
dec ebp
jnz short fillplop2
So that sort of works, but I see where the problem comes.. around line 350 or so the white block has started to draw correctly, but then all of a sudden the drawing shifts back to the top of the monitor but
offset to the right by about 200 pixels..
It's almost as if one of the following is an issue.. 1Mb of vidmem boundary reached and it wraps back around somehow... or .. i dunno.. the bottom half of the screen is just buggered..

Re: vesa mode problem on real h/w
Posted: Tue Mar 31, 2009 5:30 am
by johnsa
Ok.. i tried it in 640x480x32 now as well.. same thing happens.. obviously you see more of the white block before it wraps around back to the top of the screen.. but the same net result at what would seem to be the address (distance from start of vidmem)... almost like its pseduo LFB but some sort of banked thing is wonky..
Re: vesa mode problem on real h/w
Posted: Tue Mar 31, 2009 6:07 am
by djmauretto
How do you set ES selector register?
Post your GDT or post your full example code so i can try on my pc.
Re: vesa mode problem on real h/w
Posted: Tue Mar 31, 2009 6:23 am
by johnsa
The code is about 4000 lines with a load of other files too..(too big to attach here)
ES is set in unreal mode to a r/w data descriptor with base address = 0, so edi = linear address of video memory.
The ES part is definitely correct as I use it to load in data files and other stuff which is all well over 64kb and at varying locations in memory and those are all 100%.
Here is the unreal mode switch part.. it works 100% .. so I don't think the problem has anything to do with that or the ES selector etc..
Code: Select all
switch_to_unreal:
mov ax,cs ; Configure 16bit unreal mode code/data entries.
movzx eax,ax
shl eax,4
mov word ptr ds:um_GDT_Entries[um_code16_selector+2],ax
mov word ptr ds:um_GDT_Entries[um_data16_selector+2],ax
ror eax,16
mov byte ptr ds:um_GDT_Entries[um_code16_selector+4],al
mov byte ptr ds:um_GDT_Entries[um_data16_selector+4],al
mov byte ptr ds:um_GDT_Entries[um_code16_selector+7],ah
mov byte ptr ds:um_GDT_Entries[um_data16_selector+7],ah
mov ax,cs
movzx eax,ax
shl eax,4
mov edi,offset um_GDT_Entries
add edi,eax
mov esi,offset um_GDTReg
mov ds:[esi+2],edi
mov di,offset um_GDTReg ; Load the Global Descriptor Table.
lgdt fword ptr ds:[di]
mov si,offset patch ; Manually patch the return from pmode address segment.
mov ax,cs
mov ds:[si],ax
cli ; Disable any ints.
call disable_nmi
call disable_irqs
mov eax,cr0 ; Enable protected mode.
or al,1
mov cr0,eax
db 0eah ; Far jump to protected mode.
dw offset pmode
dw um_code16_selector
pmode:
mov ax,um_data32_selector
mov ds,ax ; Set all segments to 4Gb limits.
mov es,ax
mov fs,ax
mov gs,ax
mov eax,cr0 ; restore real mode
and al,0feh
mov cr0,eax
db 0eah
dw offset rmode
patch: ; Because we're generating a flat image, we must manually patch the code sector value in here.
dw 0
rmode:
push cs ; Back in unreal mode, restore segments and enable ints.
pop ds
xor ax,ax
mov es,ax
clc
call enable_nmi
call enable_irqs
sti
ret
align 16
um_GDTReg dw um_gdtsize,0,0
um_GDT_Entries:
dw 4 DUP (0)
dw 0ffffh,0ffh,9a00h,0
dw 0ffffh,0ffh,9200h,0
dw 0ffffh,0ffh,9200h,8fh
um_gdtsize = ($-um_GDT_Entries)
um_null_selector = 0
um_code16_selector = 8
um_data16_selector = 16
um_data32_selector = 24
Re: vesa mode problem on real h/w
Posted: Tue Mar 31, 2009 6:47 am
by johnsa
this is odd now.. just out of interest I took the PhysBaseAddr from the mode info block.. and instead of treating it as a 32bit linear address I took the top half as a segment, and the lower half as offs...
so:
mov eax,PhysAddr
mov ebx,eax
and ebx,0ffffh
shr eax,16
shl eax,4
add eax,ebx
mov edi,eax ...... and under the emulator it still works perfectly..!>!?!? however then under real h/w the machine just reboots... odd
Re: vesa mode problem on real h/w
Posted: Tue Mar 31, 2009 7:02 am
by djmauretto
Code: Select all
um_GDT_Entries:
dw 4 DUP (0)
dw 0ffffh,0ffh,9a00h,0
dw 0ffffh,0ffh,9200h,0
dw 0ffffh,0ffh,9200h,8fh
um_gdtsize = ($-um_GDT_Entries)
Note that you have an Base Address 15:0 of 00FFH, why ?
Usually for Flat memory mode this value is 0000H ( from 0 to 4GB flat )
Code: Select all
mov eax,cr0 ; Enable protected mode.
or al,1
mov cr0,eax
db 0eah ; Far jump to protected mode.
dw offset pmode
dw um_code16_selector
pmode:
mov ax,um_data32_selector
mov ds,ax ; Set all segments to 4Gb limits.
mov es,ax
mov fs,ax
mov gs,ax
mov eax,cr0 ; restore real mode
and al,0feh
mov cr0,eax
db 0eah
dw offset rmode
patch: ; Because we're generating a flat image, we must manually patch the code sector value in here.
dw 0
rmode:
push cs ; Back in unreal mode, restore segments and enable ints.
pop ds
xor ax,ax
mov es,ax
clc
call enable_nmi
call enable_irqs
sti
ret
Too many twisted,
To set up Unreal mode:
Code: Select all
; After you uploaded GDTR is sufficient this code
;====================
; SetUP Unreal Mode
;====================
MOV EAX,CR0
OR EAX,1
MOV CR0,EAX
MOV AX,Selector
MOV ES,AX
;=====================
; Back to Real Mode
;=====================
MOV EAX,CR0
AND EAX,0FFFFFFFEH
MOV CR0,EAX
Re: vesa mode problem on real h/w
Posted: Tue Mar 31, 2009 7:12 am
by johnsa
without the jumps it's crashed on some machines... the jump/ic flush seems to be quite important.. so i kept it in for completeness... I've updated the descriptors although it shouldn't make any difference as the base is ignored anyway.. once you switch back to real mode you can put an address into the seg-reg, it's only the seg limit attribute which remains from pmode.. hence the unreal part.
Re: vesa mode problem on real h/w
Posted: Tue Mar 31, 2009 7:26 am
by djmauretto
One Moment I'm writing an boot example for you to test.