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,
13.08.2010, 10:36
 

With DPMI into protect mode and back (Developers)

I have a 16 bit realmode program. It would be nice for it to add possibility for writing a info about installed DPMI manager. But the problem is than I can't call the INT31h interrupts from real mode (nor from VM86 mode).

If I understand the documentation correct, I can switch into protect mode by calling address provided in INT2Fh/AX=1687h but there is no transparent way how to get back into real (VM86) mode.
The only way is just to terminate the application. But I don't want to terminate it. Maybe is possible to run some child process but I don't want to call any external EXE file.
So,
Japheth (or anybode else),
could you write for our, dummies, some example program which starts in real mode, somewhat switch into protect, writes some info about DPMI environment, switch back into real, writes "still alive" and only after it ends?

---
DOS-u-akbar!

ecm

Homepage E-mail

Düsseldorf, Germany,
13.08.2010, 14:30
(edited by cm, 13.08.2010, 14:57)

@ Laaca
 

With DPMI into protect mode and back - EDIT: example

> If I understand the documentation correct, I can switch into protect mode
> by calling address provided in INT2Fh/AX=1687h but there is no transparent
> way how to get back into real (VM86) mode.
> The only way is just to terminate the application.

Correct.

> But I don't want to
> terminate it. Maybe is possible to run some child process but I don't want
> to call any external EXE file.

This is correct too. To accomplish this without relying on files, create a fake process. You can do this manually, then set the PSP with Int21.50 or use Int21.26 or Int21.55.

EDIT: Here's an example program that switches to 32-bit PM within a child process, does some debugging/testing stuff then returns to its parent process in RM. Worked in NTVDM after assembling with NASM 2.08rc-something. Based on some TSR installation/relocation stuff and some DPMI test program.

;%include "CMMACROS.MAC"
%define _4digitshex(h)  ((((h)/1000h)% 10h)+'0' +(('A'-'9'-1)*((((h)/1000h)% 10h)/0Ah))), \
                        ((((h)/100h)% 10h)+'0' +(('A'-'9'-1)*((((h)/100h)% 10h)/0Ah))), \
                        ((((h)/10h)% 10h)+'0' +(('A'-'9'-1)*((((h)/10h)% 10h)/0Ah))), \
                        (((h)% 10h)+'0' +(('A'-'9'-1)*(((h)% 10h)/0Ah)))
                ; ASCIZ string
                ;
                ; %1+ = Optional string
        %imacro asciz 0-1+.nolist
%if %0 >= 1
                db %1
%endif
                db 0
        %endmacro


        cpu 386
        org 100h
        bits 16
start:
        pop ax                  ; get word saved on stack for COM files
        mov bx, sp
        shr bx, 4
        jnz .smallstack
        mov bx, 1000h           ; it was a full 64 KiB stack
.smallstack:
        mov ah, 4Ah             ; free unused memory
        int 21h
        xor ax, ax
        xchg ax, word [2Ch]
        mov es, ax
        mov ah, 49h
        int 21h                 ; free environment if any

        mov bx, 80h
        mov ah, 48h
        int 21h                 ; allocate memory for child process
        jc nomemory

                ; ax:0-> DOS memory allocated for child process
        mov es, ax
        xor di, di              ; es:di->
        xor si, si
        mov cx, 8*8
        rep cs movsw            ; copy process segment prefix into newly allocated block
        dec ax
        mov ds, ax              ; ds = MCB of allocated block
        inc ax                  ; ax = allocated block!
        mov word [ 8 ], "DP"
        mov word [ 8+2 ], "MI"
        mov word [ 8+4 ], "PS"
        mov word [ 8+6 ], "PC"        ; Force MCB string to "DPMIPSPC"
        ; mov word [ 1 ], ax    ; Set owner to itself
        ; (leave owner as us)

        mov es, ax              ; es = new PSP
        mov dx, cs
        mov ds, dx              ; ds = old PSP
        mov di, 18h
        mov cx, 20
        mov word [ es:32h ], cx
        mov word [ es:34h ], di
        mov word [ es:34h+2 ], ax       ; fix the new PSP's PHT pointer
        mov word [ es:0Ah ], childterminated
        mov word [ es:0Ah+2 ], dx       ; set termination address
        mov word [ es:16h ], dx ; set parent PSP to current one

                                ; The stack address set on the child's termination
                                ; is that of the last Int21 call to a usual function
                                ; (such as Int21.48 or .45) from the parent process.
                                ; All registers will be lost though, because we don't
                                ; build a fake stack frame.

        push di
        mov al, -1
        rep stosb               ; initialize new PHT with empty entries
        pop di
        mov cx, word [ 32h ]    ; = number of current process handles
        cmp cx, 20
        jbe .normalpht
        mov cx, 20
.normalpht:
        lds si, [ 34h ]         ; -> current process handle table
        xor bx, bx
.phtloop:
        mov dl, -1
        cmp byte [si+bx], dl    ; source PHT handle used?
        je .phtnext             ; no -->
        mov ah, 45h
        int 21h                 ; DUP
        jc nohandle
        xchg ax, bx
        xchg dl, byte [si+bx]   ; get DUPed handle and kill PHT entry
        xchg ax, bx
        mov byte [es:di+bx], dl ; write into PHT of new process
.phtnext:
        inc bx                  ; next handle
        loop .phtloop

        mov bx, es
        mov ah, 50h
        int 21h                 ; set current PSP to new
        ; mov ah, 1Ah
        ; mov ds,
        ; mov dx, 80h
        ; int 21h               ; set DTA

                ; Now executing in the child process's environment.
                ; Terminating will return to label childterminated.

        mov ax, cs
        mov word [rmcallstruc0.cs], ax
        mov word [rmcallstruc0.ds], ax
        mov word [rmcallstruc0.es], ax
        mov word [rmcallstruc0.ss], ax
        pushf
        pop word [rmcallstruc0.flags]   ; setup with RM values

        mov ax, 1687h
        int 2Fh
        or ax, ax               ; DPMI host installed?
        jnz nohost
        push es                 ; save DPMI entry address
        push di
        or si, si               ; host requires client-specific DOS memory?
        jz .nomemneeded         ; no -->
        mov bx, si
        mov ah, 48h             ; alloc DOS memory
        int 21h
        jc nomemory
        mov es, ax
.nomemneeded:
        mov si, msg.debuginfo
        call printstring
        int3
        mov bp, sp
        mov ax, 0001h           ; start a 32-bit client
        call far [bp]           ; initial switch to protected-mode
        jnc initsuccessful
initfailed:
        mov si, msg.initfailed
        jmp short rmerror
nohandle:
        mov si, msg.nohandle
        jmp short rmerror
nohost:
        mov si, msg.nohost
        jmp short rmerror
nomemory:
        mov si, msg.nomemory
rmerror:
        call printstring
        mov ax, 4CFFh
        int 21h

initsuccessful:
initsuccessful_ofs equ (initsuccessful-$$+100h)
                        ; now in protected mode
        mov bx, cs
        mov cx, cs
        lar cx, cx
        shr cx, 8
        or ch, 40h              ; make a 32-bit cs
        mov ax, 9
        int 31h
                        ; now in 32-bit PM
bits 32
now32bit:
now32bit_ofs equ (now32bit-$$+100h)
        mov word [ data.pspsel ], es
        push ds
        pop es

        mov esi, msg.welcome
        call printstring

        mov ax, 0303h
        push cs
        pop ds
        mov esi, callback       ; ds:esi-> called procedure
        mov edi, rmcallstruc1   ; es:edi-> (inreentrant) real mode call structure
        int 31h                 ; allocate RM callback
        push ss
        pop ds
        jc nocallback
        mov dword [callrm.callback], edx
        mov word [callrm.callback+2], cx

        mov ax, 0302h
        xor ebx, ebx
        xor ecx, ecx
        mov edi, rmcallstruc0
callingrm:
callingrm_ofs equ (callingrm-$$+100h)
        int 31h                 ; call RM procedure with interrupt stack
        jc callrmfailed

        mov ecx, dword [callrm.callback+2]
        mov edx, dword [callrm.callback]
        mov ax, 0304h
        int 31h                 ; free RM callback
        mov esi, msg.bye
        call printstring
        mov ax, 4C00h           ; normal client exit
        int 21h

callrmfailed:
        mov esi, msg.callrmfailed
        jmp short pmerror
nocallback:
        mov esi, msg.nocallback
pmerror:
        call printstring
        movzx ecx, word [callrm.callback+2]
        movzx edx, word [callrm.callback]
        mov eax, edx
        and eax, ecx
        inc ax
        jnz .done
        mov ax, 0304h
        int 31h                 ; free RM callback
.done:
        mov ax, 4CFFh
        int 21h

                ; This is a RM callback. Called from RM, executed in PM.
                ;
                ; INP:  es:edi-> RM call structure
                ;       ds:esi-> RM stack
                ;       ss:esp-> DPMI host internal stack
                ; CHG:  all (?) except es:edi
                ;       read/write RM call structure to communicate with RM code
callback:
        push dword [esi]
        pop dword [es:edi+2Ah]  ; set RM cs:ip
        add word [es:edi+2Eh], byte 4   ; pop 4 byte from the stack
                                ; The int3 trap doesn't work here with the debugger.
                                ; int 03h however does. Note that both might crash
                                ; the DPMI host if no debugger is installed.
        iret

bits 16

callrm:
        int3                    ; int 03h or int3 traps (in real or V86 mode)
                                ; don't cause any problems.
        xor ax, ax
        push ax
        push ax
        call -1:-1
.callback equ $-4
        pop ax
        pop ax
        int3
        iret


                ; Print a string with simple instructions. Don't use
                ; pointers or instructions depending on the default operation
                ; size, this is called in both 16- and 32-bit modes.
printstring.next:
        mov dl, al
        mov ah, 2
        int 21h
printstring:
        lodsb
        or al, al
        jnz .next
        retn


                ; The (DPMIed) child process has terminated.
childterminated:
childterminated_ofs equ (childterminated-$$+100h)
        push cs
        pop ds
        mov ah, 4Dh
        int 21h
        mov si, msg.backsuccess
        test al, al
        jz .success
        mov si, msg.backerror
.success:
        call printstring
        mov ax, 4C00h
        int 21h                 ; terminate DOS process


data:
.pspsel:        dw 0

                ; This one is used to call down to our RM part
                ; from the 32-bit PM code. All values are filled
                ; in either here or in our RM initialization.
rmcallstruc0:
.edi:           dd 0
.esi:           dd 0
.ebp:           dd 0
                dd 0
.ebx:           dd 0
.edx:           dd 0
.ecx:           dd 0
.eax:           dd 0
.flags:         dw 0
.es:            dw 0
.ds:            dw 0
.fs:            dw 0
.gs:            dw 0
.ip:            dw callrm
.cs:            dw 0
.sp:            dw rmcallsp
.ss:            dw 0

                ; This one is utilized by the DPMI host and
                ; our RM callback when called from RM. All
                ; values are filled in by the DPMI host.
rmcallstruc1:
.edi:           dd 0
.esi:           dd 0
.ebp:           dd 0
                dd 0
.ebx:           dd 0
.edx:           dd 0
.ecx:           dd 0
.eax:           dd 0
.flags:         dw 0
.es:            dw 0
.ds:            dw 0
.fs:            dw 0
.gs:            dw 0
.ip:            dw 0
.cs:            dw 0
.sp:            dw 0
.ss:            dw 0

msg:
.callrmfailed:  asciz "Calling real mode procedure failed.",13,10
.bye:           asciz "Calling real mode procedure which called callback successful.",13,10
.backsuccess:   asciz "Child process terminated okay, back in real mode.",13,10
.backerror:     asciz "Child process terminated with error, back in real mode.",13,10
.nocallback:    asciz "Could not allocate real mode callback.",13,10
.nohost:        asciz "No DPMI host installed.",13,10
.nohandle:      asciz "No free DOS file handle for child process creation.",13,10
.nomemory:      db    "Not enough DOS memory for child process creation or"
                asciz "client initialization.",13,10
.initfailed:    asciz "DPMI initialization failed.",13,10
.debuginfo:     db "Protected mode breakpoint at ",_4digitshex(initsuccessful_ofs),"h.",13,10
                db "32-bit code segment breakpoint at ",_4digitshex(now32bit_ofs),"h.",13,10
                db "Real mode procedure called at ",_4digitshex(callingrm_ofs),"h.",13,10
                db "Return from child process at "
                db _4digitshex(childterminated_ofs),"h.",13,10
                asciz 13,10
.welcome:       asciz "Welcome in 32-bit protected mode.",13,10

        align 2
rmcallsp:

---
l

DOS386

26.08.2010, 09:18

@ ecm
 

With DPMI into protect mode and back - EDIT: example

> > The only way is just to terminate the application.
> Correct.

Not that much.

> > terminate it. Maybe is possible to run some child process but I don't
> > want to call any external EXE file

> This is correct too. To accomplish this without relying on files, create a
> fake process. You can do this manually, then set the PSP with Int21.50 or
> use Int21.26 or Int21.55.

Right. You exposed a big advantage of DOS compared to Windows:

In DOS there is a (hacky, as usual) way to brew a separate process without brewing a file. In Windaube this is impossible to accomplish (except very aggressive kernel intrusion at least):

> The name of the module to be executed. This module can be a
> Windows-based application. It can be some other type of
> module (for example, MS-DOS or OS/2

> process in RM. Worked in NTVDM after

WtF ??? :confused:

Works for me in FreeDOS and EDR-DOS (my own, not example above).

BTW, I prefer INC CR0 from DPMI :-)

---
This is a LOGITECH mouse driver, but some software expect here
the following string:*** This is Copyright 1983 Microsoft ***

ecm

Homepage E-mail

Düsseldorf, Germany,
26.08.2010, 14:35

@ DOS386
 

With DPMI into protect mode and back - EDIT: example

> > > The only way is just to terminate the application.
> > Correct.
>
> Not that much.

Well tell us. The way I've shown is to terminate the application - just with it being a fake application executed as child process.

> In DOS there is a (hacky, as usual) way to brew a separate process without
> brewing a file. In Windaube this is
> impossible
> to accomplish (except very aggressive kernel intrusion at least):
>
> > The name of the module to be executed. This module can be a
> > Windows-based application. It can be some other type of
> > module (for example, MS-DOS or OS/2

How bout you just execute your own executable? This is generally more dependable in Windows NT because you always get the path supplied - as opposed to DOS where that (A) depends on COMMAND.COM or any other parent process to set the right environment and (B) isn't done by all versions of COMMAND.COM even.

Besides, this particular issue doesn't exist for a Windows process and without a problem to work around, faking a child isn't useful anyway.

> > process in RM. Worked in NTVDM after
>
> :confused:

NTVDM has so many bugs, if it works within it will work with HDPMI too :-D

> BTW, I prefer INC CR0 from DPMI :-)

(1) There is no such instruction as INC CR0. You mean MOV EAX, CR0, INC EAX, MOV CR0, EAX. In other news: lol if u b trollin b trollin r8 dude

(2) I prefer DPMI. Although you don't have ring 0 access right away, it's just so much easier to set up. Especially because the host works out just about any memory setup for you, so I don't have to care about A20, XMS, XMS locking, Int15, VCPI or 400 other things you have to consider when switching to PM. Duh. (BTW for ring 0 access I prefer JLMs.)

---
l

DOS386

27.08.2010, 03:33

@ ecm
 

With DPMI into protect mode and back - EDIT: example

> > > > The only way is just to terminate the application.
> > > Correct.
> > Not that much.
> Well tell us.

NO I won't. No need to duplicate Japheth's work, see above.

> How bout you just execute your own executable?

Bad hack.

> Besides, this particular issue doesn't exist for a Windows process and
> without a problem to work around, faking a child isn't useful anyway.

Strange, how do you execute 3rd party crappy code then ? And why did Firefox ban crappy plugins (most notably Flash) into a separate process ?

> In other news: lol if u b trollin b trollin r8 dude

Is it 64-bit code ? Does it compile ???

> (2) I prefer DPMI. Although you don't have ring 0 access right away, it's
> just so much easier to set up.

Right, no pain no gain :-)

> (BTW for ring 0 access I prefer JLMs.)

Sure, and this works without external files :-)

---
This is a LOGITECH mouse driver, but some software expect here
the following string:*** This is Copyright 1983 Microsoft ***

ecm

Homepage E-mail

Düsseldorf, Germany,
30.08.2010, 21:51

@ DOS386
 

With DPMI into protect mode and back - EDIT: example

> > > > > The only way is just to terminate the application.
> > > > Correct.
> > > Not that much.
> > Well tell us.
>
> NO I won't. No need to duplicate Japheth's work, see above.

Using RM callbacks (which I did use too, but that's not the point) doesn't properly remove the "DPMI process" or "context", so you're not really back. In that state, it might be a bad idea to terminate the current DOS process. (Japheth probably knows more about that, regarding HDPMI.)

> > How bout you just execute your own executable?
>
> Bad hack.

Right, but it works well enough if you get the name.

> > Besides, this particular issue doesn't exist for a Windows process and
> > without a problem to work around, faking a child isn't useful anyway.
>
> Strange, how do you execute 3rd party crappy code then ? And why did
> Firefox ban crappy plugins (most notably Flash) into a separate process ?

I would think Firefox is not a DOS or DPMI program, so that this would not be the particular issue that we talked about.

> > In other news: lol if u b trollin b trollin r8 dude
>
> Is it 64-bit code ? Does it compile ???

Why would it even be 64-bit code. And yes, it does compile:

D:\>debug
Executed initcont
-a
0F88:0100 mov eax,cr0
0F88:0103 inc eax
0F88:0105 mov cr0,eax
0F88:0108
-u 100l8
0F88:0100 0F20C0            MOV     EAX,CR0
0F88:0103 6640              INC     EAX
0F88:0105 0F22C0            MOV     CR0,EAX
-


See? (True, it's not optimal and all the other preparations to properly go into PM are still missing, but better than not compiling at all.)

(EDIT: No, not all text that contains the token "r8" (or any other register name) is code.)

> > (BTW for ring 0 access I prefer JLMs.)
>
> Sure, and this works without external files.

Sure, and going into PM on your own works with an EMM, XMM or DPMI host installed.

---
l

DOS386

06.09.2010, 20:08

@ ecm
 

With DPMI into protect mode and back | physical memory

> Using RM callbacks (which I did use too, but that's not
> the point) doesn't properly remove the "DPMI process"
> or "context", so you're not really back.

There is so-called "raw" switch ... (my "raw" is DEC CR0 ...)

> I would think Firefox is not a DOS or DPMI program,
> so that this would not be the particular issue
> that we talked about.

Right, but it may be useful to execute external dangerous code in a separate process on any OS :-)

> and going into PM on your own works with an EMM, XMM or DPMI host installed.

Right (not inside NTVDM of course, but hey, isn't this maybe deliberate ??? :clap: ).

BTW, how do you hog physical memory in DPMI ??? :hungry:

---
This is a LOGITECH mouse driver, but some software expect here
the following string:*** This is Copyright 1983 Microsoft ***

ecm

Homepage E-mail

Düsseldorf, Germany,
07.09.2010, 17:04

@ DOS386
 

With DPMI into protect mode and back | physical memory

> > Using RM callbacks (which I did use too, but that's not
> > the point) doesn't properly remove the "DPMI process"
> > or "context", so you're not really back.
>
> There is so-called "raw" switch...

What's it do with the "DPMI process" or "context"? Nothing. And that's not better than the callback method, that's worse, because I want those to be properly removed.

> Right, but it may be useful to execute external dangerous code in a
> separate process on any OS.

True.

> > and going into PM on your own works with an EMM, XMM or DPMI host
> installed.
>
> RightWrong, it neither works with any EMM nor with some XMMs and DPMI hosts.

Yeah, that's what I meant.

> BTW, how do you hogallocate or map physical memory in DPMI???

Maybe Int31.0508 (DPMI 1.0)? Otherwise, Int31.08 (DPMI 0.9+). As I understand it, you have to allocate an XMS memory block first and lock that, then access it with the linear address Int31.0800 returns.

---
l

DOS386

08.09.2010, 00:51

@ ecm
 

With DPMI into protect mode and back | physical memory

> Yeah, that's what I meant.

Right: no NTVDM support. :-)

> BTW, how do you hog allocate or map physical memory in DPMI??????
> Maybe Int31.0508 (DPMI 1.0)? Otherwise, Int31.08 (DPMI 0.9+). As I
> understand it, you have to allocate an XMS memory block first and lock
> that, then access it with the linear address Int31.0800 returns.

This might work under some special optimal circumstances ... but what do you do if there is no XMS host ? BTW, I had very deliberately asked about physical memory hogging and not mapping, because there is (one of many) critical "design" fault in DPMI: no "official" way to hog physical memory :-(

---
This is a LOGITECH mouse driver, but some software expect here
the following string:*** This is Copyright 1983 Microsoft ***

ecm

Homepage E-mail

Düsseldorf, Germany,
08.09.2010, 20:53

@ DOS386
 

With DPMI into protect mode and back | physical memory

> This might work under some special optimal circumstances... but what do
> you do if there is no XMS host? BTW, I had very deliberately asked about
> physical memory hoggingallocation and not mapping, because there is
> a critical design fault (one of many) in DPMI: no "official" way to
> hogallocate physical memory.

There might not be specific DPMI functions for this, but your "special" optimal circumstances (an XMM) are the default on most DOS systems. Otherwise, abort the operation/process requiring physical memory and inform the user that he needs to configure his set-up to include an XMM. (Sometimes using memory handled by DOS can solve this, as this should be mapped exactly to physical memory if there is no XMM/EMM.) Not nice, but it's nothing critical.

Japheth might know this better.


You didn't even mention that physical memory can't be allocated in NTVDM! Oh no!

---
l

DOS386

11.09.2010, 01:02

@ ecm
 

With DPMI into protect mode and back | physical memory

> abort the operation/process requiring physical memory and inform
> the user that he needs to configure his set-up to include an XMM

That's exactly how things should NOT be - user having to workaround application flaws coming from bad "standards" :-(

> (Sometimes using memory handled by DOS can solve this, as this should be
> mapped exactly to physical memory if there is no XMM/EMM.)

It works even with XMS host (and maybe even EMM386 ???), but there are only cca 1/2 MiB of low memory available, so it will work with "legacy" LDA sound cards, but not with HHDA (hyper high definition audio: 8 channels, 32 bits per channel sample, 196 KHz, see MPXPLAY forum ;-) ) because the 1:1-mapped low memory is not big enough :-( Another flaw: you can request neither a preferred address nor minimal alignment when hogging low memory. This means, that for a 64-KiB aligned 64 KiB buffer you must hog 128 KiB and "find" the buffer inside, the other 64 KiB are wasted. Not cool at all (consider the low-memory-wars about just a few 100 Byte's with German keyboard "drivers" :-D ).

> Not nice, but it's nothing critical.
> You didn't even mention that physical memory can't be allocated in NTVDM!
> Oh no!

:-P

---
This is a LOGITECH mouse driver, but some software expect here
the following string:*** This is Copyright 1983 Microsoft ***

ecm

Homepage E-mail

Düsseldorf, Germany,
11.09.2010, 01:25

@ DOS386
 

With DPMI into protect mode and back | physical memory

> That's exactly how things should NOT be - user having to work around
> application flaws coming from bad standards.

Agreed. It's your turn to travel back in time and establish better standards.

> It works even with XMS host (and maybe even EMM386 ???), [...]

It possibly doesn't work in EMM-remapped UMA space.

With an EMM, but no XMS available (maybe all allocated (maybe by the EMM)) you might go allocate some physical memory in VCPI then access that from the DPMI code. That's more cumbersome than with XMS but should still work.

> but there are only cca 1/2 MiB of low memory available,

I thought that was implicit when I said that DOS-handled memory can only sometimes solve this.

> [...], the other 64 KiB are wasted.

If you can re-use the space (partly), it's not (fully) wasted. Either the part behind or after the 64 KiB buffer will be at least 32 KiB large. Similarly, you can then re-use the remaining space in allocations of 16 KiB, 8 KiB, 4 KiB etc, alternating between the part behind and the one after the buffer as necessary. This requires little code and some pointers stored somewhere to reference where these data chunks are located. Some of these pointers or code could be stored in the "wasted" space, which still wastes some of the space but considerably less of it.

---
l

Japheth

Homepage

Germany (South),
18.08.2010, 08:04

@ Laaca
 

With DPMI into protect mode and back

> If I understand the documentation correct, I can switch into protect mode
> by calling address provided in INT2Fh/AX=1687h but there is no transparent
> way how to get back into real (VM86) mode.
> The only way is just to terminate the application. But I don't want to
> terminate it. Maybe is possible to run some child process but I don't want
> to call any external EXE file.

There a 3 methods to switch "back":
1. terminate the DPMI client
2. using Int 31h, ax=0300h/0301h/0302h
3. using raw mode switch (int 31h, ax=0306h)

Here's a sample using the int 31h, ax=0301h method - it's a slightly modified dpmicl16.asm which is supplied with FD DEBUG:


;--- DPMIBACK.ASM: 16bit DPMI application written in MASM syntax.
;--- this sample temporarily switches back to real-mode.
;--- assemble: JWasm -bin -Fo dpmiback.com dpmiback.asm

LF  equ 10
CR  equ 13

    .286
    .model tiny

;--- DPMI real-mode call structure

RMCS struct
rEDI    dd ?
rESI    dd ?
rEBP    dd ?
        dd ?
rEBX    dd ?
rEDX    dd ?
rECX    dd ?
rEAX    dd ?
rFlags  dw ?
rES     dw ?
rDS     dw ?
rFS     dw ?
rGS     dw ?
rIP     dw ?
rCS     dw ?
rSP     dw ?
rSS     dw ?
RMCS ends

    .data

szWelcome db "welcome in protected-mode",CR,LF,0

dBack db "back in real-mode",CR,LF,'$'
dErr1 db "no DPMI host installed",CR,LF,'$'
dErr2 db "not enough DOS memory for initialisation",CR,LF,'$'
dErr3 db "DPMI initialisation failed",CR,LF,'$'

    .code

    org 100h

;--- the 16bit initialization part

start:
    pop ax          ;get word saved on stack for COM files
    mov bx, sp
    shr bx, 4
    jnz @F
    mov bx,1000h    ;it was a full 64kB stack
@@:
    mov ah, 4Ah     ;free unused memory
    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 bx, cs      ;save real-mode value of CS in BX
    mov ax, 0000    ;start a 16-bit client
    call far ptr [bp]   ;initial switch to protected-mode
    jc initfailed

;--- now in protected-mode

    push bx
    mov si, offset szWelcome
    call printstring
    pop bx

;--- switch back to real-mode

    sub sp, sizeof RMCS
    mov bp,sp
    mov [bp].RMCS.rIP, offset backtoreal
    mov [bp].RMCS.rCS, bx
    mov [bp].RMCS.rFlags, 0
    lea ax,[bp-20h]
    mov [bp].RMCS.rSP, ax
    mov [bp].RMCS.rSS, bx
    xor bx,bx
    xor cx,cx
    mov di,bp
    push ss
    pop es
    mov ax,0301h
    int 31h
    mov ax, 4C00h   ;normal client exit
    int 21h
backtoreal:
    push cs
    pop ds
    mov dx,offset dBack
    mov ah,9
    int 21h
    retf            ;back to protected-mode for final exit


nohost:
    mov dx, offset dErr1
    jmp error
nomem:
    mov dx, offset dErr2
    jmp error
initfailed:
    mov dx, offset dErr3
error:
    push cs
    pop ds
    mov ah, 9
    int 21h
    mov ax, 4C00h
    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

    end start

---
MS-DOS forever!

Japheth

Homepage

Germany (South),
18.10.2010, 11:17
(edited by Japheth, 19.10.2010, 08:22)

@ Japheth
 

With DPMI into protect mode and back

> Here's a sample using the int 31h, ax=0301h method - it's a slightly
> modified dpmicl16.asm which is supplied with FD DEBUG:
>
>
[snipped]
>


It's probably worth to be noted that it was this example which made me aware that DEBUG v1.18 wasn't able to reset its breakpoints when a mode switch occured in the debuggee ( fixed in v1.19 ).

Another note: the bugfix for v1.19 includes a temporary mode switch inside the debugger under certain conditions. Debug uses DPMI raw-mode switches for this. It has turned out that this approach won't work with CWSDPMI v5. HDPMI, Windows 9x/ME and Windows XP are ok. DosEmu is untested yet.

Edit: DosEmu is also ok.

---
MS-DOS forever!

Rugxulo

Homepage

Usono,
18.10.2010, 23:07

@ Japheth
 

With DPMI into protect mode and back

> Another note: the bugfix for v1.19 includes a temporary mode switch inside
> the debugger under certain conditions. Debug uses DPMI raw-mode switches
> for this. It has turned out that this approach won't work with CWSDPMI v5.

I doubt r7 is better in this particular part, but you should definitely test against that. It's default on DJ's Zip Picker now anyways (though I'm not denying that r5 exists in a ton of places). Also, I know you're busy, but if it's really a bug, he should be notified. I'll (weakly) do it if you're unwilling.

Japheth

Homepage

Germany (South),
19.10.2010, 09:58

@ Rugxulo
 

With DPMI into protect mode and back

> I doubt r7 is better in this particular part, but you should definitely
> test against that. It's default on DJ's Zip Picker now anyways (though I'm
> not denying that r5 exists in a ton of places). Also, I know you're busy,
> but if it's really a bug, he should be notified. I'll (weakly) do it if
> you're unwilling.

I tested r7 and didn't note a difference.

However, the cause of the problem is found. Here's the output of DPMI.EXE with CWSDPMI loaded:
-------------------------------------------------
Cpu is in V86-mode
[snipped]
state save protected-mode: 002B:000012A2, real-mode: 0306:12A2
size state save buffer: 0000
raw jump to real-mode: 0068:00000000, protected-mode: 0306:1267
[snipped]
-------------------------------------------------

Size of the state buffer is zero, that is, one doesn't need to call the "state save" routines for raw-mode switches. DEBUGX does, no matter what size the buffer has. This is - or "should be" - ok, according to DPMI docs.

With CWSDPMI, it isn't ok, because the protected-mode address, 002B:12A2, is a 16-bit code segment and contains just a RETF. It has to be a 32-bit RETF, however, so there's a 66h byte missing before the RETF.

---
MS-DOS forever!

Rugxulo

Homepage

Usono,
19.10.2010, 10:09

@ Japheth
 

With DPMI into protect mode and back

> I tested r7 and didn't note a difference.

Okay, I've e-mailed him, so at least he'll soon be aware of it. I'm sure he's busy as always, but since his kids are in college now, he might? have a bit more free time.

Japheth

Homepage

Germany (South),
19.10.2010, 10:20

@ Rugxulo
 

With DPMI into protect mode and back

> Okay, I've e-mailed him, so at least he'll soon be aware of it. I'm sure
> he's busy as always, but since his kids are in college now, he might? have
> a bit more free time.

I'll implement a workaround in debugx, so there's not really a need to change cwsdpmi.

---
MS-DOS forever!

Japheth

Homepage

Germany (South),
19.10.2010, 17:59

@ Japheth
 

Possible CWSDPMI design flaw

> However, the cause of the problem is found.

That was only half of the truth. The workaround has been implemented in DEBUGX - it's simply avoiding to call DPMI "save/restore state" when the state size is zero. However, this fixes only 50%, DEBUGX on CWSDPMI is now able to temporarily switch to real-mode and back with raw switches, but the other direction ( RM -> PM -> RM ) still won't work.

CWSDPMI's state size of zero made me suspicious already, and a quick look into its source - DPMISIM.ASM - revealed that the raw switches are only supposed to work if the first switch is initiated from protected-mode. Trying to do it the other way - as DEBUGX may do - will cause a freeze.

---
MS-DOS forever!

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