Back to home page

DOS ain't dead

Forum index page

Log in | Register

Back to index page
Thread view  Board view
Laaca

Homepage

Czech republic,
11.05.2020, 13:37
 

DPMI code from .COM file? (Developers)

I am curious whether is possible to call some DPMI code from .COM file. Because if yes it would be easy to f.e. bundle machine-code modules as a payloads into normal real-mode turbo pascal programs.
To narrow the question:
In FASM distribution is a example file USEDPMI.ASM
It prints a message "Hello from protected mode!"
Here is the listing:

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     error
        test    bl,1                    ; 32-bit programs supported?
        jz      error
        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      error
        mov     es,ax
        mov     ax,1
        call    far [mode_switch]       ; switch to protected mode
        jc      error

        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

    error:
        mov     ax,4CFFh
        int     21h

  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


Is possible to convert the code to be compilable not as a .EXE but as a .COM?

---
DOS-u-akbar!

ecm

Homepage E-mail

Düsseldorf, Germany,
11.05.2020, 14:42

@ Laaca
 

DPMI code from .COM file?

> Is possible to convert the code to be compilable not as a .EXE but as a
> .COM?

It certainly is possible, but I don't know FASM much and haven't looked into your example. The FreeDOS Debug releases come with some DPMI example programs for DebugX, at least some of which are or used to be compiled into flat .COM files using NASM.

---
l

Laaca

Homepage

Czech republic,
11.05.2020, 14:50

@ ecm
 

DPMI code from .COM file?

> It certainly is possible, but I don't know FASM much and haven't looked
> into your example. The FreeDOS Debug releases come with some DPMI example
> programs for DebugX, at least some of which are or used to be compiled into
> flat .COM files using NASM.

You are right!
It is possible and I even found a source for it. Uploaded here: http://www.laaca.sweb.cz/tinycom.asm

But...
If I want to somehow include it into realmode pascal source I need to end the program by instruction RETF and not by INT 21/4C because it would end whole my application and only my routine...

---
DOS-u-akbar!

ecm

Homepage E-mail

Düsseldorf, Germany,
11.05.2020, 15:07

@ Laaca
 

DPMI code from .COM file?

> You are right!
> It is possible and I even found a source for it. Uploaded here:
> http://www.laaca.sweb.cz/tinycom.asm
>
> But...
> If I want to somehow include it into realmode pascal source I need to end
> the program by instruction RETF and not by INT 21/4C because it would end
> whole my application and only my routine...

DPMI programs must end with Int 21.4C to allow the DPMI host to learn of the termination. What you can do is create a new PSP, and set its Int 22 address (Parent Return Address) and Parent Process field so as to return into your program. Then when the DPMI part is finished you use protected-mode Int 21.4C which eventually has the host drop into 86 Mode to run DOS's interrupt 21h handler, and then DOS returns to your process (closing all file handles in the new PSP and freeing memory allocated to that new PSP).

If you want to keep calling into DPMI and returning back, you can use the raw mode switch entrypoints (Int 31.0305 and .0306) or use the other Int 31.03 functions to call 86 Mode code from protected mode.

---
l

ecm

Homepage E-mail

Düsseldorf, Germany,
11.05.2020, 16:07
(edited by ecm, 18.08.2021, 14:28)

@ Laaca
 

DPMI code from .COM file?

Here's a full example (from my lDebug/assorted/tests/ directory, wasn't yet in any repo) that builds a new child PSP from the current PSP, DUPs the file handles to use in the child, sets this child PSP as active, enters protected mode, then returns back to the original process in 86 Mode. (Plus, it shows some callback usages.) It builds with nasm dpmipsp.asm -f bin -o dpmipsp.com -l dpmipsp.lst

---
l

Laaca

Homepage

Czech republic,
11.05.2020, 22:44

@ ecm
 

DPMI code from .COM file?

Wow!
It is really impressive. But it is too complicated for me and do not understand the code much.
However - is possible to change the lines 313-314 from "mov ax,4c00h / int 21h" to RETF ?

Why I examine all this stuff - I have a quite nice pascal unit and I am proud that it is a amphiguous code - it compiles in DOS 32-bit Freepascal and 16-bit realmode turbopascal.
I almost always use the Freepascal and 32-bit protected mode but anyway, in this unit I want to keep full compatibility with Turbo pascal.
And in this unit I have a function Get_DPMI_Info.
No problem in FreePascal as I simply call the DPMI function 400h and 401h.
But in Turbopascal we are in real mode but the DPMI server may or may not be installed (although not active in this moment). And it would be nice to get some info about this non-active daemon.

---
DOS-u-akbar!

ecm

Homepage E-mail

Düsseldorf, Germany,
11.05.2020, 23:05

@ Laaca
 

DPMI code from .COM file?

> Wow!
> It is really impressive. But it is too complicated for me and do not
> understand the code much.

If you have any specific questions I can try to help you more.

> However - is possible to change the lines 313-314 from "mov ax,4c00h / int
> 21h" to RETF ?

Yes, that should be possible without problems.

However, you need to take care with the segmentation to properly address the current PSP (get using Int 21.51 if you don't have it available easily), the new PSP to be created, and your own data segments. And don't forget that after returning to the original process all register values except ss:sp may have changed, so put things on the stack (before calling Int 21.48 to allocate the process memory block) or into variables in the code segment.

Also, if you do use Int 21.48 to allocate the block for the process, you may want to make it self-owned (in line 61) so that it is freed by DOS when you terminate the child process.

Another bit to watch out for is that you may want to record into the child PSP the interrupt 23h and 24h handlers currently in use by your process. That is, use Int 21.3523 and .3524 and store the vectors into the child PSP. When the child terminates, DOS will set the vectors to those found in the child PSP. (My example just copies whatever vectors are in its own PSP, which is fine if you do not ever modify them. I guess Pascal may modify them.)

> Why I examine all this stuff - I have a quite nice pascal unit and I am
> proud that it is a amphiguous code - it compiles in DOS 32-bit Freepascal
> and 16-bit realmode turbopascal.
> I almost always use the Freepascal and 32-bit protected mode but anyway, in
> this unit I want to keep full compatibility with Turbo pascal.
> And in this unit I have a function Get_DPMI_Info.
> No problem in FreePascal as I simply call the DPMI function 400h and 401h.
> But in Turbopascal we are in real mode but the DPMI server may or may not
> be installed (although not active in this moment). And it would be nice to
> get some info about this non-active daemon.

That should be possible. Just a nitpick, if you have a DPMI server loaded "for the next client only" (I think HDPMI has such a mode) then your stint into protected mode will exhaust the DPMI server and it will uninstall itself when you terminate the DPMI client process. I guess you could expect a user to know what they are doing.

---
l

ecm

Homepage E-mail

Düsseldorf, Germany,
11.05.2020, 14:59

@ Laaca
 

DPMI code from .COM file?

> To narrow the question:
> In FASM distribution is a example file USEDPMI.ASM
> It prints a message "Hello from protected mode!"
> Here is the listing:

I edited your post to put the listing into BB-code [code] tags.

> format MZ
> heap 0 ; no additional memory
>
> segment loader use16

Insert whatever is used by FASM for flat .COM files.

> push cs
> pop ds

This is probably fine.

> mov bx,si ; allocate memory for DPMI data
> mov ah,48h
> int 21h
> jc error

Before this you need to shrink the process's memory block because flat .COM files are always loaded with max alloc = FFFFh. Shrink it to 1000h paragraphs (64 KiB), or if you want to shrink it smaller insure that the stack is below that. Eg (for NASM, adjust to whatever FASM needs):

        cpu 8086
        org 256

startprogram:
        [...]
        cmp sp, stack_end
        jb error
        mov sp, stack_end
        mov bx, ( (stack_end - startprogram) + 256 + 15 ) >> 4
        mov ah, 4Ah
        int 21h
        jc error
        [...]

        align 2
endprogram:
stack_end: equ endprogram + 512


> 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

This needs to change. Easiest is putting the "main" or "start" label in the same segment as the .COM entrypoint. In that case replace the "mov ecx, main" with:

        mov cx, cs
        movzx ecx, cx


If you want to keep using different segments then in NASM you'd need "section main vstart=0" and load ecx with CS plus whatever is the size in paragraphs of the PSP plus the section "loader". Not sure how to do that in FASM.

---
l

Rugxulo

Homepage

Usono,
13.05.2020, 04:39

@ Laaca
 

DPMI code from .COM file?

> I am curious whether is possible to call some DPMI code from .COM file.

FASM used to be .COM! And it was never real mode. But that was many versions ago, e.g. FASM 1.40 (UPX'd) from 2002.

Since .COM is easiest to reproduce (usually no linker needed, no header), for laughs I made a thread called bootstrapping FASM? two years ago. Technically, I didn't fully do it, only used old 1.40's .COM to build 1.64 then that to build 1.72. But that was my point, start from simple and go more complex. (I know that's not quite what you wanted, but just FYI.)

CandyMan

13.05.2020, 19:53

@ Laaca
 

DPMI code from .COM file?

D3XX dos extender with debugger and examples how to use it with fasm.

https://board.flatassembler.net/topic.php?p=145936#145936

Back to index page
Thread view  Board view
22049 Postings in 2034 Threads, 396 registered users, 180 users online (0 registered, 180 guests)
DOS ain't dead | Admin contact
RSS Feed
powered by my little forum