flat assembler
Message board for the users of flat assembler.
Index
> DOS > Starting devel for DOS with FASM (DPMI32) Goto page 1, 2 Next |
Author |
|
DOS386 08 Dec 2006, 18:43
I intentionally start a new thread - did read the other (real mode) one
Trying to start coding for DOS in ASM. Tried several high lang compilers before and results were frustrating (HELLO.EXE 100 KiB !!!, DOS host & target unsupported, buggy, dead, ...). Prefer DPMI32 from real mode. Code: ; fasm example of writing 32-bit program using DPMI ; requires DPMI host installed in system format MZ heap 0 ; no additional memory segment loader use16 push cs pop ds mov ax,1687h int 2Fh or ax,ax ; DPMI installed? jnz error1 test bl,1 ; 32-bit programs supported? jz error2 mov word [mode_switch],di mov word [mode_switch+2],es mov bx,si ; allocate memory for DPMI data mov ah,48h int 21h jc error3 mov es,ax mov ax,1 call far [mode_switch] ; switch to protected mode jc error3 mov cx,1 xor ax,ax int 31h ; allocate descriptor for code mov si,ax xor ax,ax int 31h ; allocate descriptor for data mov di,ax mov dx,cs lar cx,dx shr cx,8 or cx,0C000h mov bx,si mov ax,9 int 31h ; set code descriptor access rights mov dx,ds lar cx,dx shr cx,8 or cx,0C000h mov bx,di int 31h ; set data descriptor access rights mov ecx,main shl ecx,4 mov dx,cx shr ecx,16 mov ax,7 ; set descriptor base address int 31h mov bx,si int 31h mov cx,0FFFFh mov dx,0FFFFh mov ax,8 ; set segment limit to 4 GB int 31h mov bx,di int 31h mov ds,di mov es,di mov fs,di mov gs,di push 0 push si push dword start retfd error1: mov dx,error1t jmp waaa error2: mov dx,error2t jmp waaa error3: mov dx,error3t waaa: mov ah,9 int 21h mov ax,4CFFh int 21h error1t db 'Fool! No DPMI!',24h error2t db 'Fool! DPMI is 16 bit only!',24h error3t db 'Fool! Fatal DPMI problem',24h mode_switch dd ? segment main use32 start: mov esi,hello .loop: lodsb or al,al jz .done mov dl,al mov ah,2 int 21h jmp .loop .done: mov ax,4C00h int 21h hello db 'Hello from protected mode!',0Dh,0Ah,0 Added 3 error messages to original code and seems to work like a charm (could verify only 2 of them). Some questions: - Is FASM a good choice for 32-bit DOS development ? YES ! - FASM itself seems to be coded in a rare and weird (in a positive sense) way - 16-bit MZ EXE, no DOS extender, runs on "raw" DPMI if available, in unreal mode otherwise (failure on EMM386 ?) - is this correct ? NO - prefers unreal from DPMI (may fail in some cases) - What DOS extender should I use ? Well, I already reduced the number of candidates to cca 2: - DOS/32A - HDPMI32 There seem to be 2 fundamentally different approaches: - WATCOM-like (DOS extender merged with DPMI kernel), followed by LE-EXE - DGJPP-like (COFF executable including the extender, DPMI kernel separated) Is both possible with FASM ? What is better ? All is possible (WATCOM/LE-like, HDPMI32-like-raw, HDPMI32-like-PE, CWSDPMI-like) , see : http://board.flatassembler.net/topic.php?t=8670 , HDPMI32 is most likely the best way The USEDPMI example exposes excellent efficiency (my improved USEDPMI.EXE "Hello" has 341 bytes (instead of 100 KB ), but possibly has a problem: limits code size to 64 KB. What is the best way to get >64KB for code ? MZ-32 (but low memory limits), WATCOM/LE, LOADPEX/PE, load raw flat (see below) EDIT (2008-05-03, 1+1/2 years later ) : Answered my questions, in RED Last edited by DOS386 on 03 May 2008, 16:40; edited 1 time in total |
|||
08 Dec 2006, 18:43 |
|
DOS386 08 Dec 2006, 20:01
Quote:
Thanks. Tried the 70'000 NOP hack - works. Does it mean that DOS MZ executable can contain blocks >64 KB and DOS is supposed to load them correctly ? Nevertheless: One could need more than 600 KB (for included multimedial data rather than for code ) - What is the best way to do ? _________________ Bug Nr.: 12345 Title: Hello World program compiles to 100 KB !!! Status: Closed: NOT a Bug |
|||
08 Dec 2006, 20:01 |
|
Tomasz Grysztar 08 Dec 2006, 20:12
NTOSKRNL_VXE wrote: Tried the 70'000 NOP hack - works. Does it mean that DOS MZ executable The complete MZ executable is always loaded into a continuous memory block, no matter how large it is. NTOSKRNL_VXE wrote: Nevertheless: One could need more than 600 KB (for included multimedial You can put your data as an overlay into your MZ program (in the same way as PE executable is built on top of the MZ one) and load it yourself into extended memory after the program starts. |
|||
08 Dec 2006, 20:12 |
|
DOS386 08 Dec 2006, 21:42
Thanks.
Quote:
Like DOS extenders do. But, when using ASM, is there a need or benefit from using a complete DOS extedner (like DOS/32A), or is using of "raw" DPMI better ? Will the DPMI kernel (prefer HDPMI32, do not bother about lacks of others) itself handle interrupts (mouse driver, keyboard, ...) correctly ? Can I simply access INT's from DPMI code in exactly same way as from real mode ? Code: segment main use32 times 70000 nop start: mov esi,hello ;In PM now ... .loop: lodsb or al,al jz .done mov dl,al mov ah,2 int 21h ;simple INT will always work ???? jmp .loop .done: mov ax,4C00h ;exit now - but switch back to RM ? int 21h hello db 'Hello from protected mode!',0Dh,0Ah,0 Where does the switch back to real mode occur ? _________________ Bug Nr.: 12345 Title: Hello World program compiles to 100 KB !!! Status: Closed: NOT a Bug |
|||
08 Dec 2006, 21:42 |
|
Tomasz Grysztar 08 Dec 2006, 22:40
NTOSKRNL_VXE wrote: Like DOS extenders do. But, when using ASM, is there a need or benefit from The advantage of using a complete extender is that you are not dependent on DPMI server having to be installed in system. On the other hand, when there is a DPMI server, using an additional extender may be a waste of resources. Also, if the server implements only the official DPMI 0.9 (or even 1.0) services (it's this way with CWSDPMI, for example), the extender may have another advantage, that it may implement some of features of what I heard sometimes called True DPMI. As I once read, it was as set of functions in the first draft of DPMI, removed during the standard defining process. It included the 32-bit versions of the most of interrupt 21h functions, which would be a great thing if it was a standard, however it never made it into official specifications. But the fact is, that some of the DPMI implementations made by companies that perhaps knew the initial design of the DPMI, include the TrueDPMI services. Such ones that I'm aware of is the DOS subsystem of Windows, and the QDPMI server by Quarterdeck. NTOSKRNL_VXE wrote: Will the DPMI kernel (prefer HDPMI32, do not bother about lacks of others) The DPMI by default forwards all the interrupts to their real-mode handlers (unless you install your own 32-bit handler for some interrupt), thus when interrupt occurs, it switches either to V86 or real mode (depending on the implementation) and call the real-mode handler for that interrupt. The general registers are passed unchanged to that handler. Thus the function 2 of interrupt 21h in the example is called through the DPMI forwarding and it appears to be working just as if you called it from real mode. However the problem arises when you need to pass addresses - since in protected mode you've got selectors, while in real mode you've got segments. Thus if you called an interrupt function that needs an address among it parameters, you have to somehow pass the segmented address to the real-mode handler to get it working. To help calling the interrupt functions with pointers as parameters, there's a DPMI function 300h, which you can use to define exactly contents of all segment registers and general registers that should be passed to real-mode interrupt handler. The use of this function is a bit more complicated than calling the interrupt directly - see the "dpmi_dos_int" routine in the DOS/SYSTEM.INC file in fasm's sources. If the DPMI server supports the True DPMI services, as the one in Windows' subsystem does, the thing is much more simpler, however. The functions of interrupt 21h have their 32-bit versions implemented, and thus you can do things simply like: Code: ; WARNING: works only with True DPMI start: mov edx,hello mov ah,9 int 21h mov ax,4C00h int 21h hello db 'Hello from protected mode!',0Dh,0Ah,'$' |
|||
08 Dec 2006, 22:40 |
|
DOS386 08 Dec 2006, 23:40
Code: mov ax,4C00h int 21h Does it mean that this INT switches back to real mode, whether the DPMI is true or not ? Quote: However the problem arises when you need to pass addresses I see. That is why the PM hello prints text letter by letter, with one INT per letter. The question is: does HDPMI provide TrueDPMI ? Code: 6.8 DOS API Translation HDPMI supports DOS-API translation, both in 16-bit mode and in 32-bit mode. For translation purposes, HDPMI allocates a static translation buffer of 8 KB. For the important read/write functions HDPMI will try to allocate a temporary 64k buffer, if the size of the i/o-operation exceeds the size of the static translation buffer. Is ^^ this ^^ the same as TrueDPMI ? How to read my data into the DPMI memory ? Could you please provide a simple example: - Allocate 4 MB of DPMI memory - Zeroize it - Read (file supposed already opened) 2 MB from a file into this memory - Jump to the begin of this 2 MB block Will code in this memory automatically work (32bit "raw" code) or are there additional problems ? My example executable (just to make sure the method will work for everything I might code in future) could look following way: - cca 1 KB small 16-bit "stub" - cca 1 MB of code (1 MB is VERY much code I know) - cca 1 MB of multimedial data The stub should: - Verify system requirements (I have some ideas/examples/hints how to do this) - Switch to PM - Allocate 4 MB of DPMI memory - read the 1+1 MB from my file (skipping the "stub") into this DPMI memory - jump to this code The final 32-bit code in DPMI memory would access the 1 MB of my MM data and use the free 2 MB for temporary buffers. _________________ Bug Nr.: 12345 Title: Hello World program compiles to 100 KB !!! Status: Closed: NOT a Bug |
|||
08 Dec 2006, 23:40 |
|
DOS386 09 Dec 2006, 00:26
Tested:
Code: ; WARNING: works only with True DPMI start: mov edx,hello mov ah,9 int 21h mov ax,4C00h int 21h hello db 'Hello from protected mode!',0Dh,0Ah,'$' HDPMI32: Works This is GOOD CWSDPMI: Failure (huge mess printed, then exits) This is irrelevant ... But still I'd like to know how to read from a file into DPMI memory and execute code there in (see post above). EDIT: removed split request _________________ Bug Nr.: 12345 Title: Hello World program compiles to 100 KB !!! Status: Closed: NOT a Bug Last edited by DOS386 on 09 Dec 2006, 20:20; edited 3 times in total |
|||
09 Dec 2006, 00:26 |
|
DOS386 14 Dec 2006, 00:38
I experimented with the example:
1 Code: ; fasm example of writing 32-bit program using HDPMI32 format MZ heap 0 ; no additional memory stack 4000h stubsize = 400h ;guess qpsp = stubsize ;2 bytes qmodesw = stubsize + 2 ;4 bytes segment uselessdummylabel1 use16 mov ax,ds ;save DS - contains PSP addr !!! push cs pop ds mov word [qpsp],ax ;save here ;######################################### mov ax,1687h int 2Fh or ax,ax ; DPMI installed? jnz error1 test bl,1 ; 32-bit programs supported? jz error2 mov word [qmodesw],di mov word [qmodesw+2],es mov bx,si ; allocate memory for DPMI data mov ah,48h int 21h jc error3 mov es,ax mov ax,1 call far [qmodesw] ; switch to protected mode !!!!!!!!!!!!!!!!!!!!!!!!! jc error3 2 Code: mov cx,1 xor ax,ax int 31h ; allocate descriptor for code mov si,ax xor ax,ax int 31h ; allocate descriptor for data mov di,ax mov dx,cs lar cx,dx shr cx,8 or cx,0C000h mov bx,si mov ax,9 int 31h ; set code descriptor access rights mov dx,ds lar cx,dx shr cx,8 or cx,0C000h mov bx,di int 31h ; set data descriptor access rights mov ecx,main32a shl ecx,4 mov dx,cx shr ecx,16 mov ax,7 ; set descriptor base address int 31h mov bx,si int 31h mov cx,0FFFFh mov dx,0FFFFh mov ax,8 ; set segment limit to 4 GB int 31h mov bx,di int 31h mov ds,di mov es,di mov fs,di mov gs,di push 0 push si push dword 0 ;& jump to main32 - relative addr is 0 !!! retfd ;& 3 Code: error1: mov dx,error1t jmp @f error2: mov dx,error2t jmp @f error3: mov dx,error3t @@: mov ah,9 int 21h mov ax,4CFFh ;Ending with a FAILURE int 21h error1t db 'Fool! No DPMI!',24h error2t db 'Fool! DPMI is 16 bit only!',24h error3t db 'Fool! Fatal DPMI problem!',24h 4 Code: segment main32a use32 mov ah,9 mov edx,thello int 21h jmp short @f thello db 'Hello from protected mode!',0Dh,0Ah,24h @@: mov ax,4C00h int 21h ;======================================================== rb 4000h ;======================================================== Could someone explain me: - What does block 2 do ? We are (?) already in PM at begin of this block ... - Is the jump to block 4 required ? Why is it workarounded with RETFD - JMP would not work ? - How to allocate a large amount of DPMI memory, load a file (a "flat"/"raw" code file, no messy COFF) into it, and execute code there ? Quote:
What value will label "main32a" have ? 1 according to this text ? _________________ Bug Nr.: 12345 Title: Hello World program compiles to 100 KB !!! Status: Closed: NOT a Bug |
|||
14 Dec 2006, 00:38 |
|
Japheth 14 Dec 2006, 09:52
> - Is the jump to block 4 required ? Why is it workarounded with RETFD - JMP would not work ?
yes, it switches from 16-bit to 32-bit CS. RETFD is used because the segment part of the far address is unknown at link time and therefore it is the simplest method to do a far jump. A simple RETF would also work here, however: Code:
push si
push 0
retf
- How to allocate a large amount of DPMI memory there exists dpmi function int 31h, ax=0x501 for this task. > load a file (a "flat"/"raw" code file, no messy COFF) into it if the DPMI host implements DOS API translation, it is as simple as in real-mode DOS. indeed even more simple, because int 21h, ah=3Fh will understand DS:EDX as buffer address and ECX as bytes to read. > and execute code there you will have to setup a code/data descriptor the way it is done in "2". |
|||
14 Dec 2006, 09:52 |
|
DOS386 14 Dec 2006, 20:55
Thanks.
Code: segment main32a use32 mov ah,9 mov edx,t1 int 21h jmp short @f t1 db 'Hey ... not yet hello ... trying to allocate INT 31,501 !',0Dh,0Ah,24h @@: mov bx,40h ;BX is high mov cx,0 ;CX is low 4MB mov ax,0501h int 31h ;BX:CX = linear address of allocated memory block jnc @f ;OK mov ax,0900h mov edx,t2 int 21h jmp short qend t2 db 'INT 31,501 ran in a failure !!!',0Dh,0Ah,24h @@: mov ax,0900h mov edx,t3 int 21h jmp short qend t3 db 'INT 31,501 success !',0Dh,0Ah,24h qend: mov ax,4C00h int 21h ;======================================================== rb 4000h ;======================================================== Quote:
Seems to work. BX:CX, higher 16 bits in BX and lower 16 bits in CX. But how to activate it, so that I can write into it, and execute code there ? Quote: you will have to setup a code/data descriptor the way That's what I expected ... any info or examples how to do this ? Need to reduce "segment limit" in "2" from 4 GB to 4 KB ? Quote: if the DPMI host implements DOS API translation You call it "DOS API translation", Tomasz Grysztar calls it "TrueDPMI", seems to be same thing and to work. _________________ Bug Nr.: 12345 Title: Hello World program compiles to 100 KB !!! Status: Closed: NOT a Bug |
|||
14 Dec 2006, 20:55 |
|
Japheth 14 Dec 2006, 22:03
> That's what I expected Rolling Eyes ... any info or examples how to do this ?
"2" can be used, just replace the "main32a" by the linear address returned by the 0x501 function. Don't care about the segment limit, 4 GB is good as a start. of course, before executing the RETFD, dont forget to first read your precious code into the memory: Code: mov ds,di mov es,di mov fs,di mov gs,di push 0 push si push dword 0 ;& jump to offset 0 mov bx, ??? mov edx,0 mov ecx,400000h mov ah,3Fh int 21h jc didntwork retfd |
|||
14 Dec 2006, 22:03 |
|
DOS386 14 Dec 2006, 23:19
Thanks.
Quote:
"BX:CX" - Higher 16 bits in BX and lower 16 bits in CX again (double BIG endian ?) ? Put it together and push into ECX instead "main32a" label ? Quote:
Can I have many segments at same time, all with 4 GB limit ? What I wanted to reduce to 4 KB was the original "4" segment in "low"/DOS memory, not my new (4 MB so far in examples above) one. _________________ Bug Nr.: 12345 Title: Hello World program compiles to 100 KB !!! Status: Closed: NOT a Bug |
|||
14 Dec 2006, 23:19 |
|
Tomasz Grysztar 14 Dec 2006, 23:21
NTOSKRNL_VXE wrote: You call it "DOS API translation", Tomasz Grysztar calls it "TrueDPMI", seems to be same thing and to work. I started using the term "True DPMI" after reading this excellent lecture somewhere around 1999: http://lists.gnu.org/archive/html/lynx-dev/1998-04/msg00773.html It's more about the history than technical stuff, however I really recommend reading this. |
|||
14 Dec 2006, 23:21 |
|
DOS386 16 Dec 2006, 20:12
Code: mov ds,di mov es,di mov fs,di mov gs,di push 0 push si push dword 0 ;& jump to offset 0 mov bx, ??? mov edx,0 mov ecx,400000h mov ah,3Fh int 21h jc didntwork retfd Tried to write the code using hints provided but ran into a fundamendal problem: How to access 2 segments at same time ? All code before "retfd" must run in "old" segment Filename is stored in the old one Contents of the file must read to the new one If reading fails continue in old segment Print error text stored in old segment Exit correctly from old segment How to "switch" or get around this ? _________________ Bug Nr.: 12345 Title: Hello World program compiles to 100 KB !!! Status: Closed: NOT a Bug |
|||
16 Dec 2006, 20:12 |
|
Japheth 17 Dec 2006, 09:13
> but ran into a fundamendal problem:
where is it? you must call int 21h, ah=3Fh with DS set to the new segment, but anything else can be stored/done in the old one. Code: jmp @F binname db ".\code32.bin",0 @@: mov edx, binname mov ax,3D00h int 21h jc openfailed mov ds,di mov es,di mov fs,di mov gs,di push 0 push si push dword 0 ;& jump to offset 0 mov bx, ax mov edx,0 mov ecx,400000h mov ah,3Fh int 21h pushf mov ah,3Eh int 21h popf jc readfailed retfd openfailed: mov edx,openerr mov ah,9 int 21h mov ax,4cffh int 21h readfailed: push ds pop cs mov edx,readerr mov ah,9 int 21h mov ax,4cffh int 21h openerr db "file not found",13,10,'$' readerr db "read error",13,10,'$' |
|||
17 Dec 2006, 09:13 |
|
DOS386 19 Dec 2006, 14:20
Quote:
Thanks. I'll retry. Code:
mov ds,di
Then ^^^ this ^^^ is the instruction switching the segment. Does it mean that all the preparation of the "new" segment does not affect the "old" one, and the only thing I have to care about is to set the "ds" correctly ? Code: readfailed: push ds ;!!! pop cs ;!!! mov edx,readerr mov ah,9 int 21h mov ax,4cffh int 21h Is this correct ? I could follow the code if the 2 lines were swapped Code: mov es,di mov fs,di mov gs,di What is the goal of the "es", "fs", "gs" ? _________________ Bug Nr.: 12345 Title: Hello World program compiles to 100 KB !!! Status: Closed: NOT a Bug |
|||
19 Dec 2006, 14:20 |
|
Japheth 19 Dec 2006, 17:51
> Does it mean that all the preparation of the "new" segment does not
Yes > push ds ;!!! > pop cs ;!!! IIRC "pop cs" does no longer exist on cpus > 8086. > What is the goal of the "es", "fs", "gs" ? it was *your* source which contained this stuff, I just added some lines. So you should ask yourself about the goal . |
|||
19 Dec 2006, 17:51 |
|
DOS386 19 Dec 2006, 18:14
Quote:
Means "cs" and "ds" should be swapped (but not the complete lines as I wrote above) ... Quote: it was *your* source which contained this stuff, I just added some lines. So you should ask yourself about the goal It is not really *my* source, it is the "USEDPMI" example ... Code: ; DPMICL32.ASM NASM Sample for a 32-bit DPMI client. ; To assemble, use: ; nasm dpmicl32.asm -O 2 -f obj -o dpmicl32.obj ; ; To link, use: ; valx /32 dpmicl32.obj; LF equ 10 CR equ 13 cpu 386 segment _text use16 public class=CODE ..start: mov ax, dgroup mov ds, ax mov ax, ss mov cx, es sub ax, cx mov bx, sp shr bx, 4 add bx, ax ;release unused DOS memory mov ah, 4Ah int 21h mov ax, 1687h ;DPMI host installed? int 2Fh and ax, ax jnz nohost push es ;save DPMI entry address push di and si, si ;requires host client-specific DOS memory? jz nomemneeded mov bx, si mov ah, 48h ;alloc DOS memory int 21h jc nomem mov es, ax nomemneeded: mov bp, sp mov ax, 0001 ;start a 32-bit client call far [bp] ;initial switch to protected-mode jc initfailed mov cx,1 ;get a descriptor for the 32-bit code segment mov ax,0 int 31h jc dpmierr mov bx,ax mov dx,_text32 mov cx,dx shl dx,4 shr cx,12 mov ax,7 ;set base int 31h or dx,-1 xor cx,cx mov ax,8 ;set limit int 31h mov cx,cs lar cx,cx shr cx,8 or ch,40h ;make a 32bit CS mov ax,9 int 31h push bx push start32 retf ;jump to 32bit CS nohost: mov dx, dErr1 error: mov ah, 9 int 21h mov ax, 4C00h int 21h nomem: mov dx, dErr2 jmp error initfailed: mov dx, dErr3 jmp error dpmierr: mov dx, dErr4 jmp error ;--- the 32-bit code segment segment _text32 use32 public align=16 class=CODE start32: mov esi, szWelcome call printstring mov ax, 4C00h ;normal client exit int 21h ;--- print a string in protected-mode with simple ;--- DOS commands not using pointers. printstring: lodsb and al,al jz stringdone mov dl,al mov ah,2 int 21h jmp printstring stringdone: ret segment _data use16 public align=16 class=DATA szWelcome db "welcome in protected-mode",CR,LF,0 dErr1 db "no DPMI host installed",CR,LF,'$' dErr2 db "not enough DOS memory for client initialisation",CR,LF,'$' dErr3 db "DPMI initialisation failed",CR,LF,'$' dErr4 db "no LDT descriptors available",CR,LF,'$' segment stack use16 stack align=16 class=STACK resb 1024 group dgroup _data stack OK, found this code in FreeDOS Debug ... NOT dealing with this ES, FS & GS _________________ Bug Nr.: 12345 Title: Hello World program compiles to 100 KB !!! Status: Closed: NOT a Bug |
|||
19 Dec 2006, 18:14 |
|
DOS386 19 Dec 2006, 22:06
I got my code that it is complete (for now ) and should work -
but doesn't. ... EDIT: crappy code and attach kicked _________________ Bug Nr.: 12345 Title: Hello World program compiles to 100 KB !!! Status: Closed: NOT a Bug Last edited by DOS386 on 15 Aug 2007, 01:41; edited 1 time in total |
|||
19 Dec 2006, 22:06 |
|
Goto page 1, 2 Next < Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.