vesa mode problem on real h/w

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
johnsa
Member
Member
Posts: 296
Joined: Mon Oct 15, 2007 3:04 pm

vesa mode problem on real h/w

Post 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
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: vesa mode problem on real h/w

Post 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
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
johnsa
Member
Member
Posts: 296
Joined: Mon Oct 15, 2007 3:04 pm

Re: vesa mode problem on real h/w

Post 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...
djmauretto
Member
Member
Posts: 116
Joined: Wed Oct 22, 2008 2:21 am
Location: Roma,Italy

Re: vesa mode problem on real h/w

Post 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.
johnsa
Member
Member
Posts: 296
Joined: Mon Oct 15, 2007 3:04 pm

Re: vesa mode problem on real h/w

Post 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... :(
jal
Member
Member
Posts: 1385
Joined: Wed Oct 31, 2007 9:09 am

Re: vesa mode problem on real h/w

Post 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
djmauretto
Member
Member
Posts: 116
Joined: Wed Oct 22, 2008 2:21 am
Location: Roma,Italy

Re: vesa mode problem on real h/w

Post 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
johnsa
Member
Member
Posts: 296
Joined: Mon Oct 15, 2007 3:04 pm

Re: vesa mode problem on real h/w

Post 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.. :)
johnsa
Member
Member
Posts: 296
Joined: Mon Oct 15, 2007 3:04 pm

Re: vesa mode problem on real h/w

Post 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..
djmauretto
Member
Member
Posts: 116
Joined: Wed Oct 22, 2008 2:21 am
Location: Roma,Italy

Re: vesa mode problem on real h/w

Post 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.
johnsa
Member
Member
Posts: 296
Joined: Mon Oct 15, 2007 3:04 pm

Re: vesa mode problem on real h/w

Post 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
	
johnsa
Member
Member
Posts: 296
Joined: Mon Oct 15, 2007 3:04 pm

Re: vesa mode problem on real h/w

Post 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
djmauretto
Member
Member
Posts: 116
Joined: Wed Oct 22, 2008 2:21 am
Location: Roma,Italy

Re: vesa mode problem on real h/w

Post 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, :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	

	
johnsa
Member
Member
Posts: 296
Joined: Mon Oct 15, 2007 3:04 pm

Re: vesa mode problem on real h/w

Post 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.
djmauretto
Member
Member
Posts: 116
Joined: Wed Oct 22, 2008 2:21 am
Location: Roma,Italy

Re: vesa mode problem on real h/w

Post by djmauretto »

One Moment I'm writing an boot example for you to test.
Post Reply