flat assembler
Message board for the users of flat assembler.

Index > DOS > VESA from DPMI

Author
Thread Post new topic Reply to topic
DOS386



Joined: 08 Dec 2006
Posts: 1900
DOS386 05 Jan 2007, 23:28
I'd like to use VESA graph modes from DPMI. Well, i DID use the
forum search and Google search, and there were some "hits", but none of
them usable:
- In most forum "hits" about VESA the thing was asked, but not really
clarified since I need a classic DOS / DPMI version
- Google hits are mostly "C" or PASCAL, quite useless for me Confused

For simplicity, I limit to LFB'ed 24 and 32 bpp modes 800x600 and
1024x768, and VESA 2.0 version, and no "MTTRR".

I need to do from DPMI, and not from "raw" PC, not from real mode,
and not from Unreal mode ...

What it the simplest and correct way to do ?

Can I rely on the mode numbers or not ?

Probably need:

Code:
Int 10/AX=4F01h - VESA SuperVGA BIOS - GET SuperVGA MODE INFORMATION
Int 10/AX=4F02h - VESA SuperVGA BIOS - SET SuperVGA VIDEO MODE
    


but:

Code:
   10  ax=1002h set all palette registers ES:E/DX
   10  ax=1009h get all palette registers ES:E/DX
   10  ax=1012h set DAC registers ES:E/DX
   10  ax=1017h get DAC registers ES:E/DX
   13  ah=02h   disk read into buffer ES:E/BX
   13  ah=03h   disk write from buffer ES:E/BX
   13  ah=08h   for FD return drive parameter table in ES:E/DI
   15  ah=C0h   read configuration into ES:E/BX
   15  ax=C207h set pointing device event proc ES:E/BX
   25           absolute disk read buffer in DS:E/BX
   26           absolute disk write buffer in DS:E/BX
   2F  ax=168Ah supports vendor "MS-DOS" and "VIRTUAL SUPPORT" 
                callback for "MS-DOS" supports function 100h (LDT sel)
   33  ax=0009h define graphics cursor ES:E/DX
   33  ax=000Ch define interrupt subroutine ES:E/DX
   33  ax=0012h define large graphics cursor ES:E/DX
   33  ax=0014h exchange interrupt subroutine ES:E/DX
   33  ax=0016h save driver state ES:E/DX
   33  ax=0017h restore driver state ES:E/DX
   33  ax=0018h set alternate mouse user handler ES:E/DX
    


VESA seems to be barred out ^^^ from the "DOS API" translation Confused

Do I need

Code:
Int 31/AX=0300h  - DPMI 0.9+ - SIMULATE REAL MODE INTERRUPT
    


http://www.ctyme.com/intr/rb-5831.htm

this ^^^ thing ??

How to execute the INT ? Need DOS memory ? I should already have some
allocated.

EDIT: answered my question myself later (with help of Tomasz, Japheth, ...)

http://board.flatassembler.net/download.php?id=3472

_________________
Bug Nr.: 12345

Title: Hello World program compiles to 100 KB !!!

Status: Closed: NOT a Bug


Last edited by DOS386 on 16 Jan 2008, 01:44; edited 1 time in total
Post 05 Jan 2007, 23:28
View user's profile Send private message Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8349
Location: Kraków, Poland
Tomasz Grysztar 05 Jan 2007, 23:49
You may call the "set mode" function directly from pm, since it doesn't use any pointers, however for "get mode" you need to provide buffer in DOS memory, thus you'll need to use int 31h/300h for it (and some DOS memory allocated).
And you need to call "get mode" first, to check whether the given mode is supported and get some important information about it - like the "pitch" of the screen (the amount of bytes at which the rows are aligned, this is not necessarily equal to the amount of bytes per all pixels in row - such assumption is a frequent mistake) and the physical address of LFB.

And to access the LFB you need a physical address mapping - you've got function 800h of int 31h for this.
Post 05 Jan 2007, 23:49
View user's profile Send private message Visit poster's website Reply with quote
DOS386



Joined: 08 Dec 2006
Posts: 1900
DOS386 06 Jan 2007, 00:22
Thanks.

Quote:
you need to provide buffer in DOS memory, thus you'll need to use int 31h/300h for it (and some DOS memory allocated)


OK, I think I have the DOS memory, (from loading my MZ-loader/stub,
alternatively, HDPMI has a 8 KB buffer)

Could you please provide an example how to call Int 10/AX=4F02h with
int 31h/300h ? Question

Quote:
like the "pitch" of the screen (the amount of bytes at which the rows are aligned, this is not necessarily equal to the amount of bytes per all pixels in row - such assumption is a frequent mistake)


Didn't know this Confused

Quote:
And to access the LFB you need a physical address mapping - you've got function 800h of int 31h for this.


http://www.ctyme.com/intr/rb-5861.htm

Quote:
Implementations may refuse this call because it can circumvent protects. The caller must build an appropriate selector for the memory. Do not use for memory mapped in the first megabyte


Seems I neen both: Create a segment/selector AND INT $31,$800 ???

In what order to execute all the stuff ? Or are there some GOOD
(FASM, DPMI) examples around ?

_________________
Bug Nr.: 12345

Title: Hello World program compiles to 100 KB !!!

Status: Closed: NOT a Bug
Post 06 Jan 2007, 00:22
View user's profile Send private message Reply with quote
Japheth



Joined: 26 Oct 2004
Posts: 151
Japheth 07 Jan 2007, 09:22
Here is an example for Vesa 4F00h, but written for MASM and for a non-flat model:

rmcs is a DPMI Real Mode Call Structure
@flat is a FLAT, zero-based selector

Code:
GetVesaInfo proc public pVesaInfo:ptr VESAINFO

local   dosmemsel:dword
local   linDosMem:dword
local   rcptr:dword
local   rmcs:RMCS

                xor     eax,eax
                mov     dosmemsel,eax
                mov     ax,0100h                ;alloc DOS memory
                mov     bx,20h                  ;256+256 bytes = sizeof VESAINFO
                int     31h
                jc      svmx_er
                mov     dosmemsel,edx
                mov     rmcs.rES,ax
                mov     rmcs.rAX,4F00h
                mov     rmcs.rDI,0
                mov     rmcs.rSSSP,0
                                                                ;clear the VESA info buffer                     
                movzx   eax,ax
                shl     eax,4
                mov     linDosMem, eax

                mov     edi,eax
                mov     ecx,200h/4
                xor     eax,eax
                push es
                push @flat
                pop es
                rep     stosd
                pop es

                mov     ebx, linDosMem
;               mov     eax,"ASEV"
                mov     eax,"2EBV"
                mov     @flat:[ebx],eax
                push    ebx
                lea     edi,rmcs
                push    es
                push    ss
                pop     es
                mov     bx,0010h
                mov     cx,0000h
                mov     ax,0300h
                int     31h
                pop     es
                pop     ebx
                jc      svmx_er
                cmp     rmcs.rAX,004Fh
                jnz     svmx_er
                mov     esi,linDosMem 
                mov     edi, pVesaInfo
                mov     ecx,sizeof VESAINFO
                push    ds
                push    @flat
                pop     ds
                rep     movsb
                pop     ds

                mov     eax,1
                jmp     svmx_ex
svmx_er:
                xor     eax,eax
svmx_ex:
                mov     edx,dosmemsel
                and     edx,edx
                jz      @F
                push    eax
                mov     ax,0101h
                int     31h
                pop     eax
@@:
                ret
GetVesaInfo endp
    
Post 07 Jan 2007, 09:22
View user's profile Send private message Reply with quote
DOS386



Joined: 08 Dec 2006
Posts: 1900
DOS386 14 Jan 2007, 05:00
Quote:
Here is an example for Vesa 4F00h


Thanks.

Quote:
but written for MASM


The instructions seem OK, but the MASM stuff ... Confused

Quote:
and for a non-flat model


flat / non-flat , zero / non-zero Confused ... Is this a problem ? My model is from
2 previous threads: code running in DPMI memory, additional 0-based
segment for "dosmemget" and "dosmemput", well, and the starting/loader
segment from USEDPMI - should I kick this one maybe ???

Quote:
rmcs is a DPMI Real Mode Call Structure


This is the problem. Confused Declared somewhere ... in MASM style ... and lacking
in the example ... what is it ? A buffer in DPMI memory ? Zeroized ?

Quote:
@flat is a FLAT, zero-based selector


For my "dosmemget&dosmemput-segment" from previous thread ?

Code:
;
; *** Get VESA info ***

;pVesaInfo
;local   dosmemsel:dword
;local   linDosMem:dword
;local   rcptr:dword
;local   rmcs:RMCS

; *** mem alloc, rmcs ??? ***
                xor     eax,eax
                mov     dosmemsel,eax           ; No alloc yet
                mov     ax,0100h                ; Alloc DOS memory
                mov     bx,20h                  ; $200 bytes = sizeof VESAINFO
                int     $31
                jc      svmx_er                 ; Failure
                mov     dosmemsel,edx    ; Selector: only for deallocation // may NOT (?) = 0
                mov     rmcs.rES,ax      ; Segment
                mov     rmcs.rAX,$4F00   ; INT $10/$4F00
                mov     rmcs.rDI,0       ; ???
                mov     rmcs.rSSSP,0     ; ???

; *** clear the VESA info buffer ***
                movzx   eax,ax                  ; Clear 16 top bits in EAX
                shl     eax,4                   ; Segment to linear
                mov     linDosMem, eax

                mov     edi,eax
                mov     ecx,$80                 ; $200/4
                xor     eax,eax                 ; eax:=0
                push es
                push xxxflat
                pop es
                rep     stosd            ; write EAX (=0) to ES:EDI and this ECX times !!!
                pop es                   ; restore es

; *** Finally execute the INT ***
                mov     ebx, linDosMem
;               mov     eax,"ASEV"
                mov     eax,"2EBV"
                mov     xxxflat:[ebx],eax ; Just write to DOS mem without segment reg hack ???
                push    ebx
                lea     edi,rmcs       ; ??????????????????????????
                push    es
                push    ss             ; vvv
                pop     es             ; ^^^ ES:=SS but why ???
                mov     bx,$0010       ; Should be INT $10 finally
                mov     cx,0           ; Don't copy stack junk ???
                mov     ax,$0300       ; The "simulate real mode INT" thing
                int     31h
                pop     es             ; Restore ES
                pop     ebx            ; Restore EBX, was "linDosMem"
                jc      svmx_er        ; INT $300 failure
                cmp     rmcs.rAX,$004F ; Anything else means FAILURE Sad
                jnz     svmx_er
                mov     esi,linDosMem 
                mov     edi, pVesaInfo       ; ????????????????????????????????
                mov     ecx,sizeof VESAINFO  ; ???????????????? simply $200 maybe ???
                push    ds
                push    xxxflat
                pop     ds             ; ds:=xxxflat // "es" was NEVER set !!!
                rep     movsb          ; MOVE DS:ESI -> ES:EDI, ECX (bytes)
                pop     ds             ; Restore ds

                mov     eax,1     ; 1 : OK
                jmp     svmx_ex
svmx_er:
                xor     eax,eax   ; 0 : Failure Grrrrrhhhhhhhhh Sad
svmx_ex:
                mov     edx,dosmemsel
                and     edx,edx   ; cmp edx,0
                jz      @F        ; No memory
                push    eax
                mov     ax,$0101  ; Deallocate the memory
                int     $31       ; Ignore potential errors
                pop     eax
@@:
                ret               ; Hard work done Wink
    


Nice code Smile (added comments), some issues:

- RMSC ???
- RCPTR ???
- dosmemsel&lindosmem: 2 UINT32 variables in code segment ?
- PVESAinfo: ??? Addr of buffer in code segment, $200 bytes ?
- "sizeof VESAINFO": complicated way to say $200 ?
- ES=??? supposed to be ES=CS at code start ?
- "lea edi,rmcs" what does this do ? Would "mov" not work ?
- "mov xxxflat:[ebx],eax" is "dosmemput" that easy (when I have
the segment/selector) ??? Idea
- Why is ES set to SS before INT $300 ?

_________________
Bug Nr.: 12345

Title: Hello World program compiles to 100 KB !!!

Status: Closed: NOT a Bug
Post 14 Jan 2007, 05:00
View user's profile Send private message Reply with quote
Japheth



Joined: 26 Oct 2004
Posts: 151
Japheth 14 Jan 2007, 08:39
for

- RMSC ???
- "lea edi,rmcs" what does this do ? Would "mov" not work ?
- Why is ES set to SS before INT $300 ?

issues see RBIL (search "310300")

- ES=??? supposed to be ES=CS at code start ?

Yes. Code is for a flat (but not necessarily zero-base) memory model,
that is, CS=ES=DS.
No assumption is made about SS, however.

- RCPTR ???

is a leftover

- dosmemsel&lindosmem: 2 UINT32 variables in code segment ?

they are local (temporary) variables
Post 14 Jan 2007, 08:39
View user's profile Send private message Reply with quote
DOS386



Joined: 08 Dec 2006
Posts: 1900
DOS386 15 Jan 2007, 02:50
Thanks.

Quote:

- RMSC ???
- "lea edi,rmcs" what does this do ? Would "mov" not work ?
- Why is ES set to SS before INT $300 ?

issues see RBIL (search "310300")


This one: http://www.ctyme.com/intr/rb-5831.htm Question

Code:
Int 31/AX=0300h

DPMI 0.9+ - SIMULATE REAL MODE INTERRUPT

AX = 0300h
BL = interrupt number
BH = flags

bit 0:
Reset the interrupt controller and A20 line (DPMI 0.9) 
reserved, must be 0 ( DPMI 1.0+ )

others:
Reserved, must be 0. 

CX = number of words to copy from 
protected mode to real mode stack.

ES: (E)DI = selector:offset of real mode call structure (see #03148)

Return:
CF clear if successful 
real mode call structure modified 
(all fields except SS:SP, CS:IP filled with return values 
from real mode interrupt) 
CF set on error 
AX = error code (DPMI 1.0+ ) 
(8012h,8013h,8014h,8021h)
(see #03143) 
protected mode stack unchanged

Notes: 16-bit programs use ES:DI as pointer, 32-bit programs 
use ES:EDI. CS:IP in the real mode call structure is 
ignored for this call, instead, the indicated interrupt 
vector is used for the address. The flags in the call 
structure are pushed on the real mode stack to form 
an interrupt stack frame, and the trace and interrupt 
flags are clear on entry to the handler. DPMI will provide 
a small (30 words) real mode stack if SS:SP is zero. 
The real mode handler must return with the stack in 
the same state as it was on being called

See Also: 
AX=0302h - AX=FF01h
INT 21/AX=2511h - INT 21/AH=E3h"OS/286" 
INT 2C/AX=0026h 
INT 2F/AX=FB42h/BX=000Dh

Format of DPMI real mode call structure: 
Offset Size Description (Table 03148)

00h DWORD EDI 
04h DWORD ESI 
08h DWORD EBP 
0Ch DWORD reserved (00h) 
10h DWORD EBX 
14h DWORD EDX 
18h DWORD ECX 
1Ch DWORD EAX 
20h WORD flags 
22h WORD ES 
24h WORD DS 
26h WORD FS 
28h WORD GS 
2Ah WORD IP 
2Ch WORD CS 
2Eh WORD SP 
30h WORD SS 
    


The lea edi,rmcs is NOT described here ^^^ and
it is a serious problem since FASM refuses to compile it Sad

Quote:

No assumption is made about SS, however.


Good, but ES is set to SS before the INT $31/$0300 and I still can't figure
out why ... and what I also noticed just now that "my" USEDPMI based
code does NOT deal with SS at all ... HDPMI32 probably creates one for
me but I have no idea where "my" stack is and how big it is Confused

Is this "rmcs" a $32 bytes buffer ? In the stack ? Confused

_________________
Bug Nr.: 12345

Title: Hello World program compiles to 100 KB !!!

Status: Closed: NOT a Bug
Post 15 Jan 2007, 02:50
View user's profile Send private message Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4624
Location: Argentina
LocoDelAssembly 15 Jan 2007, 03:03
Quote:

The lea edi,rmcs is NOT described here ^^^ and
it is a serious problem since FASM refuses to compile it

Did you use the square brackets around rcms? (LEA EDI, [rmcs])
Post 15 Jan 2007, 03:03
View user's profile Send private message Reply with quote
DOS386



Joined: 08 Dec 2006
Posts: 1900
DOS386 15 Jan 2007, 03:17
Quote:
Did you use the square brackets around rcms? (LEA EDI, [rmcs])


NO. Confused See code above.

Nevertheless: could you please explain me, what this lea does in this
code and why I can't use mov instead ?

_________________
Bug Nr.: 12345

Title: Hello World program compiles to 100 KB !!!

Status: Closed: NOT a Bug
Post 15 Jan 2007, 03:17
View user's profile Send private message Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4624
Location: Argentina
LocoDelAssembly 15 Jan 2007, 04:15
Depends on where the structure resides. If it's located at an EBP-based stack frame then you have to use "lea edi, [ebp-offset of rmcs]"(automatically done by using "lea edi, [rmcs]" if you are using PROC32.inc), but if you have a label that holds the structure then using "mov edi, label" is enough and takes one byte less than "lea edi, [label]". In your last code I don't see the structure RMCS defined nowhere so define it too.

Note that FASM requires all memory references square bracketed so things like "mov rmcs.rES,ax" must be converted to "mov [rmcs.rES],ax". LEA does not access any memory but since it needs a memory address it needs the source operand square bracketed too.

I have no experience with PMODE VESA (and the very few experience with real mode VESA I forgot it all Razz) so I can't help you beyond those sintax things, sorry
Post 15 Jan 2007, 04:15
View user's profile Send private message Reply with quote
DOS386



Joined: 08 Dec 2006
Posts: 1900
DOS386 15 Jan 2007, 04:49
Quote:
Depends on where the structure resides.


I have no idea Confused

Quote:
If it's located at an EBP-based stack frame then you have to use "lea edi, [ebp-offset of rmcs]"(automatically done by using "lea edi, [rmcs]" if you are using PROC32.inc), but if you have a label that holds the structure then using "mov edi, label" is enough and takes one byte less than "lea edi, [label]".


COOL. Seems MASM where the example comes from does such tricks. Confused

Quote:
In your last code I don't see the structure RMCS defined nowhere so define it too.


Know issue Confused

Quote:
I have no experience with PMODE VESA (and the very few experience with real mode VESA I forgot it all Razz) so I can't help you beyond those sintax things, sorry


Thanks. Hope that someone else answers also ...

_________________
Bug Nr.: 12345

Title: Hello World program compiles to 100 KB !!!

Status: Closed: NOT a Bug
Post 15 Jan 2007, 04:49
View user's profile Send private message Reply with quote
Japheth



Joined: 26 Oct 2004
Posts: 151
Japheth 15 Jan 2007, 08:37
> Good, but ES is set to SS before the INT $31/$0300 and I still can't figure
out why ...

you will have to fully understand what a local variable is. Without this knowledge you will get some troubles when coding in ASM. This line

;local rmcs:RMCS

which you commented out defines - in MASM - a local variable of type RMCS. One important difference between local and global variables is that for the first the address is known at run time only, while for the latter the address is known at link time. That's why LEA (load effective address) has to be used.

> and what I also noticed just now that "my" USEDPMI based
code does NOT deal with SS at all

the DPMI host will translate the SS segment into a selector on initial switch to protected-mode.

> but I have no idea where "my" stack is and how big it is Confused

as already mentioned, the stack's location and size won't change by the switch to protected-mode.
Post 15 Jan 2007, 08:37
View user's profile Send private message Reply with quote
DOS386



Joined: 08 Dec 2006
Posts: 1900
DOS386 16 Jan 2007, 03:02
Thanks.

Quote:
you will have to fully understand what a local variable is.


Theoretically I know this ... but thought this issue would be limited to
prog langs like PASCAL or "C" ... but have no idea how MASM handles
them Confused Does FASM support local variables at all ? Question

Quote:
Without this knowledge you will get some troubles when coding in ASM


Probably one can always stay global only ... it's a question approach Wink

I had discovered various things that make simple things complicated
in the past and local variables in ASM might join this list Wink

Quote:
This line
Code:
;local rmcs:RMCS    

which you commented out defines - in MASM - a local variable of type RMCS. One important difference between local and global variables is that for the first the address is known at run time only, while for the latter the address is known at link time. That's why LEA (load effective address) has to be used.


OK, marginally smarter again, MASM seems to translate those
mov and lea in some obscure way Confused

Quote:
the DPMI host will translate the SS segment into a selector on initial switch to protected-mode.
> but I have no idea where "my" stack is and how big it is Confused
as already mentioned, the stack's location and size won't change by the switch to protected-mode.


Does this mean that the "main" stack my DPMI app is running on is
the same stack as defined in the MZ-header (well, there are 3 more
stacks according to HDPMI docs) ?

Code:
 6.4 Stacks

   When a client is running the host will switch among 4 stacks:

   _ the protected mode stack (PMS), which is the stack the DPMI
     client uses. It can switch these stacks as it likes and there
     are no special requirements about it.

   _ the locked protected mode stack (LPMS). The DPMI host switches
     the client application to this stack when
     - a hardware interrupt (IRQ) has occured
     - an interrupt is reflected from real mode (mostly IRQs, but
       also software interrupts 1Ch, 23h and 24h.
     - the DPMI client executes a real mode callback
     - the server notifies the client about an exception
     There exists 1 LPMS only and its size must be at least 4 KB.
     Once it is "in use" the host will no longer switch stacks until
     the LPMS is free again.

   _ the real mode stack (RMS). Usually this stack is located in the
     memory block the DPMI client has to deliver to the server on its
     initial switch to protected mode. This stack's size will be at
     least 200h bytes. It is used when there is a reflection from protected
     mode interrupts to real mode. If protected-mode is reentered (by a
     real-mode callback, a raw jump or a hardware IRQ), the RMS is in use
     and HDPMI will then use the real mode SS:SP of the last entry to
     protected mode as current real-mode stack.

   _ the ring 0 stack. This stack is invisible to the client, it is
     used by the dpmi host. For HDPMI this stack is 2 kB in size, and
     it is located in conventional memory. The host uses this stack
     for it's normal processing and to save the client's segment register
     values.
    


Maybe I don't have to bother too much since HDPMI ^^^ does well for me Wink

Code:
; *** INT $31 / $0300 test ***

    use32
    org 0

; *** Print text using DOS API Translation ***

    mov    ax,$0900
    mov    edx,t8
    int    21h
    jmp @f

t8 db 'Hello (API Trans) !!!',0Dh,0Ah,24h

; *** Create ZERO-based segment ***

@@:
    mov cx,1
    xor ax,ax
    int 31h           ; allocate descriptor for data
    mov di,ax
    mov dx,ds
    lar cx,dx
    shr cx,8
    or  cx,0C000h
    mov bx,di
    int 31h           ; set data descriptor access rights
    mov ecx,0   ;ZERO
    mov edx,0
    mov ax,7          ; set descriptor base address CX:DX // CX high
    int 31h
    mov bx,di   ;HACK ???
    int 31h
    mov cx,0FFFFh
    mov dx,0FFFFh
    mov ax,8          ; set segment limit to 4 GB
    int 31h           ; result : di : data descriptor

    mov fs,di         ; store low segment

; *** Report success ***

    mov    ax,0900h
    mov    edx,t9
    int    21h
    jmp    @f

t9 db 'Zero-based seg created (API Trans) !!!',0Dh,0Ah,24h

; *** Throw text into "buffer" ***

@@:     mov eax,"Bum$"
        mov ebx,$B8000    ; Text screen, no need to allocate Wink
        mov [fs:ebx],eax  ; Just write to DOS mem without segment reg hack ???

; *** Prepare INT $300 ***

BUF32=$100000  ; 1 MB , more than high enough (code < 1KB, segment 4 MB)

        mov ecx,$32
        mov al,0
        mov ebx,BUF32
@@:     mov byte [ebx],al  ; Clear $32 bytes buffer
        inc ebx
        dec ecx
        jnz @b

        mov word [BUF32+$1C],$0900  ; AX: INT $21,9
        mov word [BUF32+$24],$B800  ; DS // DX=0 Wink

        push ds
        pop es
        mov edi,BUF32

        mov   bx,$0021       ; Should be INT $21 finally
        mov   cx,0           ; No stack junk
        mov   ax,$0300       ; The "simulate real mode INT" thing
        int   31h

@@:    mov ax,$4C00
       int $21
    


Well, testing INT $300 ^^^ and it seems to work. Exclamation

Is the code correct and safe ? (Except abusing text screen as transfer
buffer Very Happy ) ? I completely barred out lea, and reduced
the PUSHing and POPeing of segment registers Shocked Will this code
work with $10/$4F00 and any other INT or are there some potential
pitfalls ?

Code:
        mov     @flat:[ebx],eax 
    


This ^^^ does NOT compile in FASM ... but

Code:
    mov [fs:ebx],eax     ;fs is the ZERO-based segment   
    


this ^^^ is the simplest DOSMEMPUT without hacking with the
segment registers Idea

_________________
Bug Nr.: 12345

Title: Hello World program compiles to 100 KB !!!

Status: Closed: NOT a Bug
Post 16 Jan 2007, 03:02
View user's profile Send private message Reply with quote
Japheth



Joined: 26 Oct 2004
Posts: 151
Japheth 16 Jan 2007, 08:13
> Theoretically I know this ... but thought this issue would be limited to
> prog langs like PASCAL or "C" ... but have no idea how MASM handles
> them

masm creates an "EBP-based" stack frame.

> Does FASM support local variables at all ?

I'm sure it does. It's a rather trivial thing.

>Probably one can always stay global only ... it's a question approach

Yes, but "global only" is worse

> I had discovered various things that make simple things complicated
> in the past and local variables in ASM might join this list

This definitely is wrong. Using local variables whereever possible is the best thing to do.


> Is the code correct and safe ?

If it runs...

Using the text screen to store the string for int 21h, ah=09 might not always work as expected, though, if DOS happens to overwrite your input.
Post 16 Jan 2007, 08:13
View user's profile Send private message Reply with quote
DOS386



Joined: 08 Dec 2006
Posts: 1900
DOS386 27 Jan 2007, 04:15
Code:
;
; VESA
;

SOMEMEMORY = $100000            ; 1 MB , more than high enough (code < 1KB, segment 4 MB)
BUF32     = SOMEMEMORY          ; $32 = #50 bytes
DOSMEMSEL = SOMEMEMORY + $32    ; 2 bytes
DOSMEMSEG = SOMEMEMORY + $34    ; 2 bytes
DOSMEMLIN = SOMEMEMORY + $36    ; 4 bytes
VESABUF   = SOMEMEMORY + $3A    ; $200 bytes
VESAOK    = SOMEMEMORY + $023A  ; 1 byte
PBUF      = SOMEMEMORY + $023B  ; $50 = #80 bytes
VESABUFPO = SOMEMEMORY + $028B  ; 2 bytes

    use32
    org 0

; *** Print text using DOS API Translation ***

    mov    ax,$0900
    mov    edx,t8
    int    21h
    jmp @f

t8 db 'Hello (API Trans) !!!',0Dh,0Ah,24h

@@:

; *** Create ZERO-based segment ***

    mov cx,1
    xor ax,ax
    int 31h           ; allocate descriptor for data
    mov di,ax
    mov dx,ds
    lar cx,dx
    shr cx,8
    or  cx,0C000h
    mov bx,di
    int 31h           ; set data descriptor access rights
    mov ecx,0   ;ZERO
    mov edx,0
    mov ax,7          ; set descriptor base address CX:DX // CX high
    int 31h
    mov bx,di   ;HACK ???
    int 31h
    mov cx,0FFFFh
    mov dx,0FFFFh
    mov ax,8          ; set segment limit to 4 GB
    int 31h           ; result : di : data descriptor

    mov fs,di         ; store low segment

; *** Report success ***

    mov    ax,0900h
    mov    edx,t9
    int    21h
    jmp    @f

t9 db 'Zero-based seg created (API Trans) !!!',0Dh,0Ah,24h

@@:

; *** Prepare INT $300 - zeroize $32 buffer ***

        mov cl,$32
        mov al,0
        mov ebx,BUF32
@@:     mov byte [ebx],al  ; Clear $32 bytes buffer
        inc ebx
        dec cl
        jnz @b

; *** Alloc DOS memory ***

         xor     ax,ax
         mov     [VESAOK],al          ; Failure
         mov     [DOSMEMSEL],ax       ; Not yet alloced
         mov     ax,$0100             ; Alloc DOS memory
         mov     bx,$40               ; $0400 bytes (some buggy cards write > $0200 ???)
         int     $31                  ; Alloc returns: DX: selector AX: segment
         jc      xxfail               ; Failure in alloc
         mov     [DOSMEMSEL],dx
         mov     [DOSMEMSEG],ax
         movzx   eax,ax               ; Fill upper 16 bits with 0
         shl     eax,4
         mov     [DOSMEMLIN], eax     ; Linear absolute addr

; *** Zeroize the  $0400 buffer ***

           cld                        ; !!! Important !!!
           mov     edi,eax
           mov     ecx,$0100          ; $100 of 32-bit writes
           xor     eax,eax
           push  es
           push  fs                   ; Here our ZERO-based selector is stored
           pop   es                   ; ES:EDI is dest for STOSD
           rep   stosd
           pop   es                   ; Restore ES

; *** Write "VBE2" into "buffer" ***

          mov     ebx, [DOSMEMLIN]
;         mov     eax,"ASEV"
          mov     eax,"VBE2"
          mov     [fs:ebx],eax

; *** INT $0300 register block & boom ***

        mov word [BUF32+$1C],$4F00  ; AX: INT $21,$4F00 // [ES:DI]: buffer
        mov word ax, [DOSMEMSEG]
        mov word [BUF32+$22],ax     ; Set ES // DI=0 Wink

        push ds                     ; &
        pop  es                     ; &
        mov  edi,BUF32              ; & [ES:EDI] for INT $0300

        mov   bx,$0010       ; Should be INT $10 finally
        mov   cx,0           ; No stack junk
        mov   ax,$0300       ; The "simulate real mode INT" thing
        int   $31
        jc xxfail            ; INT $0300 failed

; *** Check the result ***

        mov ax,[BUF32+$1C]   ; Capture AX from "simulate" buffer
        cmp ax,$004F         ; !!! Was $4F00 now must be $004F otherwise failure !!!
        jne xxfail           ; INT $10 failed
        inc byte [VESAOK]    ; Report success

; *** Move from DOS memory to DPMI memory ***

          cld                 ; !!!
          mov     esi,[DOSMEMLIN]
          mov     edi,VESABUF
          mov     ecx,$0200   ; Number of bytes
          push    ds
          push    ds
          pop     es
          push    fs          ; Our ZERO-based selector
          pop     ds
          rep     movsb       ; MOVE [DS:ESI] -> [ES:EDI], ECX (bytes)
          pop     ds

; *** Dealloc DOS mem ? ***

xxfail:   mov   dx, [DOSMEMSEL]
          and   dx,dx            ; cmp dx,0
          jz      @F
          mov     ax,$0101       ; Deallocate
          int     $31
@@:

; *** Report ***

        mov  al,[VESAOK]
        cmp  al, 0
        jne xxok2     ; OK

        mov    ax,0900h
        mov    edx,t10
        int    21h    ; Grrrrhhh Sad((((
        jmp xxend

t10 db 'No VESA or FATAL VESA error !!!',0Dh,0Ah,$24


xxok2:  mov    ax,0900h
        mov    edx,t11
        int    21h   ; Great Wink
        jmp    @f

t11 db 'VESA info captured !!! Let',$27,'s have a look:',0Dh,0Ah,24h

@@:

; *** Dump the stuff ***

        xor ax,ax
        mov [VESABUFPO],ax  ; Pointer inside VESABUF

        call xxcpbuf        ; Clear and prepare print buffer

xxdump: mov   dx, [VESABUFPO]
        movzx ebx, dx
        add   ebx, VESABUF
        mov   al, [ebx]    ; Pick one byte Wink
        and   dl, $0F      ; VESABUFPO MOD 16 // offset in line Wink

        mov dh,al
        mov ah,al
        and ah,$0F    ; & Low 4 bits // reversed : LITTLE ENDIAN
        shr al,4      ; & High 4 bits
        add  ax,$3030 ; Convert 0 -> ASCII "0"
        cmp al,$3A
        jb @f          ; "b":below // OK, a number
        add   al, 7
@@:     cmp   ah, $3A
        jb @f          ; "b":below // OK, a number
        add   ah, 7
@@:     mov   cx, ax     ; Move the HEX to cx
        mov   al, dl     ; *1
        add   al, dl     ; *2
        add   al, dl     ; *3
        movzx ebx, al
        add   ebx, PBUF
        mov [ebx], cx    ; Write the HEX number

        cmp dh,$24
        je  xxfaultychar ; $24 ("$") is THE MOST faulty char !!!
        cmp dh,$20
        jb  xxfaultychar ; <$20, faulty char
        cmp dh,$7E
        jb  @f           ; <$7E, good char
xxfaultychar:
        mov dh, $2E      ; Replace faulty char with "."

@@:     movzx ebx, dl    ; dl still is offset in line
        add   ebx, PBUF+50
        mov [ebx], dh    ; Write the ASCII char

        cmp dl,$0F
        jne xxnyp        ; Not yet print

        mov    ax,$0900
        mov    edx,PBUF
        int    $21       ; Print content
        call xxcpbuf     ; And kick it out from buffer

        mov eax,10000000 ; 10 Mega Very Happy
@@:     nop
        or  eax,eax      ; Silly delay
        dec eax
        jnz @b

xxnyp:  mov ax, [VESABUFPO]
        inc ax
        cmp ax,$0200
        je xxend            ; End
        mov [VESABUFPO], ax
        jmp xxdump

xxend:     mov  ax,$4C00
           int  $21

; *** PROC: Clear PBUF buffer ***

;Trashes EAX,EBX,ECX // EDX remains intact

xxcpbuf:
        mov ebx,PBUF
        mov ecx,$4C         ; Count of passes
        mov al,$20
@@:     mov [ebx],al        ; Clear $4C bytes in $50 buffer
        inc ebx
        dec ecx
        jnz @b
        mov dword [PBUF+$4C],$240A0D20 ; SPC CR LF EOT
        ret

;END.

;00 DWORD EDI
;04 DWORD ESI
;08 DWORD EBP
;0C DWORD reserved (00h)
;10 DWORD EBX
;14 DWORD EDX
;18 DWORD ECX
;1C DWORD EAX
;20 WORD flags
;22 WORD ES
;24 WORD DS
;26 WORD FS
;28 WORD GS
;2A WORD IP
;2C WORD CS
;2E WORD SP
;30 WORD SS
    


Seems I got the INT $4F00 working Laughing my buffer gets filled with sort of
usable info Laughing

Code:
Format of SuperVGA information:
Offset  Size    Description     )
 00h  4 BYTEs   (ret) signature ("VESA")
                (call) VESA 2.0 request signature ("VBE2"), required to receive
                  version 2.0 info
 04h    WORD    VESA version number (one-digit minor version -- 0102h = v1.2)
 06h    DWORD   pointer to OEM name
                "761295520" for ATI
 0Ah    DWORD   capabilities flags (see #00078)
 0Eh    DWORD   pointer to list of supported VESA and OEM video modes
                (list of words terminated with FFFFh)
 12h    WORD    total amount of video memory in 64K blocks
---VBE v1.x ---
 14h 236 BYTEs  reserved
---VBE v2.0 ---
 14h    WORD    OEM software version (BCD, high byte = major, low byte = minor)
 16h    DWORD   pointer to vendor name
 1Ah    DWORD   pointer to product name
 1Eh    DWORD   pointer to product revision string
    


How to analyze the content correctly and decode all the 32-bit "pointers" ?
"761295520" for ATI ($2D6072A0) - any use of this number ?
Why do I need 32-bit pointers inside a $200 bytes buffer Confused Confused Confused

What's next ? Brute-force through all the modes using INT $4F01:

Code:
 00h    WORD    mode attributes (see #00080)
 10h    WORD    bytes per scan line
 12h    WORD    width in pixels (graphics) or characters (text)
 14h    WORD    height in pixels (graphics) or characters (text)
 19h    BYTE    number of bits per pixel
 28h    DWORD   physical address of linear video buffer
 2Ch    DWORD   pointer to start of offscreen memory

Bitfields for VESA SuperVGA mode attributes:
Bit(s)  Description     )
 0      mode supported by present hardware configuration
 1      optional information available (must be =1 for VBE v1.2+)
 2      BIOS output supported
 3      set if color, clear if monochrome
 4      set if graphics mode, clear if text mode
---VBE v2.0+ ---
 5      mode is not VGA-compatible
 6      bank-switched mode not supported
 7      linear framebuffer mode supported
    


Is it enough to analyze ^^^ this info ???

"10h WORD bytes per scan line" is the "pitch" ???

Quote:
And to access the LFB you need a physical address mapping - you've got function 800h of int 31h for this.


Code:
INT 31 - DPMI 0.9+ - PHYSICAL ADDRESS MAPPING

        AX = 0800h
        BX:CX = physical address (should be above 1 MB)
        SI:DI = size in bytes
Return: CF clear if successful
            BX:CX = linear address which maps the requested physical memory
        CF set on error
            AX = error code (DPMI 1.0+) (8003h,8021h) (see #03143)
Notes:  implementations may refuse this call because it can circumvent protects
        the caller must build an appropriate selector for the memory
        do not use for memory mapped in the first megabyte
    


How to put it together ?

Push "28h DWORD physical address of linear video buffer" and size of
the LFB into INT $31/$0800 ?

"build an appropriate selector" - Same way as I "build" for the low
DOS memory, just replace 0 with output from INT $31/$0800 ?

Is there a problem if my LFB falls into RAM area (already in use Confused) or will
someone (DPMI kernel / hardware) workaround the problem for me ?

Other things to care about ?

_________________
Bug Nr.: 12345

Title: Hello World program compiles to 100 KB !!!

Status: Closed: NOT a Bug
Post 27 Jan 2007, 04:15
View user's profile Send private message Reply with quote
Japheth



Joined: 26 Oct 2004
Posts: 151
Japheth 27 Jan 2007, 16:34
> Seems I got the INT $4F00 working Laughing my buffer gets filled with sort of

Good!

> Why do I need 32-bit pointers inside a $200 bytes buffer

those are 32-bit real-mode pointers and it is not for sure that they will point inside the 200h buffer.

> What's next ? Brute-force through all the modes using INT $4F01:

Why not? At least it is a nice exercise.

> Is it enough to analyze ^^^ this info ???

enough for what?

> "10h WORD bytes per scan line" is the "pitch" ???

yes

> Push "28h DWORD physical address of linear video buffer" and size of
> the LFB into INT $31/$0800 ?

yes

> "build an appropriate selector" - Same way as I "build" for the low
> DOS memory, just replace 0 with output from INT $31/$0800 ?

it might be sufficient to build 1 true flat (base==0) selector with limit -1 and access anything with it.

> Is there a problem if my LFB falls into RAM area (already in use or will
> someone (DPMI kernel / hardware) workaround the problem for me ?

this should never be an issue (it's similiar to the A000-BFFF video segment)
Post 27 Jan 2007, 16:34
View user's profile Send private message Reply with quote
DOS386



Joined: 08 Dec 2006
Posts: 1900
DOS386 27 Jan 2007, 19:28
Thanks.

I'll look at $4F01 and then $4F02 now Wink

Quote:
enough for what?


To set up a LFB'ed 32 or 24 bpp, 1024*768 or 800*600 mode and
be able to write into the LFB Wink as stated at thread start.

Quote:
It might be sufficient to build 1 true flat (base==0) selector with limit -1 and access anything with it


Can I just reuse the selector from code above or are there problems with
it ? The stuff is still sort of mysterious, found out that:

Code:
  push cs
  pop ds
    


known from RM generates a crash in DPMI Confused Although both have same
(non-ZERO) base address Confused

_________________
Bug Nr.: 12345

Title: Hello World program compiles to 100 KB !!!

Status: Closed: NOT a Bug
Post 27 Jan 2007, 19:28
View user's profile Send private message Reply with quote
Japheth



Joined: 26 Oct 2004
Posts: 151
Japheth 28 Jan 2007, 10:55
Code:
    push cs
    pop ds
    


it is possible to load DS with a code selector in protected-mode, but you cannot write to the memory then. Trying to load SS with a code selector (or CS with a data selector) will cause a GPF immediately.
Post 28 Jan 2007, 10:55
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.