Back to home page

DOS ain't dead

Forum index page

Log in | Register

Back to the board
Thread view  Mix view  Order
Laaca

Homepage

Czech republic,
29.04.2023, 00:41
 

DPMI - how to chain user and original RM handler? (Developers)

Hello!
I have a problem with my INT15h handler written in DPMI program.
I am able to redirect the realmode interrupt to my protected mode routine.
If I return back to real mode everything is fine.
The problem is when I want to call the original routine from the main.

I am trying to implement the INT 15h/AH=4Fh keyboard interrupt.
If I detect the 4Fh in the AH I can do what I want.
But if there is not the 4Fh (if there is f.e. AX=E820h) I have to put my hands off and just to call the original routine.
But I do not know how because my program crashes here....



procedure int15_handler; {$IFDEF NEWFPC}nostackframe;{$ENDIF}assembler;
{Handler for software interrupt 15h, installed by:
get_rm_callback(@int15_handler, int15_regs, newint15_handler);
Set_rm_interrupt($15, newint15_handler);}

{In Entrance:
 DS:ESI = real mode SS:SP
 ES:EDI = copied real mode registers to our protected mode segment
 disabled hardware interrupts}
 asm
 push ds
 push eax
 mov ax,es    {ES points to our protected mode segment}
 mov ds,ax    {Let also DS point to our segment to be FreePacal happy}


 pushad
 mov ax,DOSmemSelector
 mov fs,ax
 call Internal_Int15_Handler;  {written in pascal}

 popad


 pop eax
 pop ds       {restore DS}


 call es:[oldint15_handler]  {DOES NOT WORK !!! (Crashes here)}
{oldint15_handler is got from Get_rm_interrupt($15, oldint15_handler)}


 mov eax,ds:[esi+0]                         {restore return address (CS:IP)}
 mov es:[edi+2Ah],eax

 (*
 mov eax,ds:[esi+4]             {do we have to do anything with flags?}
 mov es:[edi+20h],ax
 *)

 add word ptr es:[edi+2Eh],6                {updates SP}
 iret
end;

---
DOS-u-akbar!

ecm

Homepage E-mail

Düsseldorf, Germany,
29.04.2023, 08:43

@ Laaca

DPMI - how to chain user and original RM handler?

> call es:[oldint15_handler] {DOES NOT WORK !!! (Crashes here)}
> {oldint15_handler is got from Get_rm_interrupt($15, oldint15_handler)}

You need to far call the downlink in Real/Virtual 86 Mode, not in PM. And you need a pushfw instruction before the far call.

> mov eax,ds:[esi+0] {restore return address
> (CS:IP)}
> mov es:[edi+2Ah],eax
>
> (*
> mov eax,ds:[esi+4] {do we have to do anything with flags?}
> mov es:[edi+20h],ax
> *)
>
> add word ptr es:[edi+2Eh],6 {updates SP}
> iret
> end;

You probably should restore the flags too.

---
l

ecm

Homepage E-mail

Düsseldorf, Germany,
29.04.2023, 08:45

@ ecm

DPMI - how to chain user and original RM handler?

> > call es:[oldint15_handler] {DOES NOT WORK !!! (Crashes here)}
> > {oldint15_handler is got from Get_rm_interrupt($15, oldint15_handler)}
>
> You need to far call the downlink in Real/Virtual 86 Mode, not in PM. And
> you need a pushfw instruction before the far call.
>
> > mov eax,ds:[esi+0] {restore return address
> > (CS:IP)}
> > mov es:[edi+2Ah],eax

You can probably get away with loading the dword from oldint15_handler and store it in [es:edi + 2Ah], then do not change the stack pointer.

---
l

Laaca

Homepage

Czech republic,
29.04.2023, 14:04

@ ecm

DPMI - how to chain user and original RM handler?

> You can probably get away with loading the dword from oldint15_handler and
> store it in [es:edi + 2Ah], then do not change the stack pointer.

I see, it sounds simple. I can't try it just know but it is definitely interresting.
But if it will for any reason not work, is possible to call the old routine via
"INT 31h/0302 - Call Real Mode Procedure With IRET Frame" ?

---
DOS-u-akbar!

ecm

Homepage E-mail

Düsseldorf, Germany,
29.04.2023, 15:17

@ Laaca

DPMI - how to chain user and original RM handler?

> I see, it sounds simple. I can't try it just know but it is definitely
> interresting.
> But if it will for any reason not work, is possible to call the old routine
> via
> "INT 31h/0302 - Call Real Mode Procedure With IRET Frame" ?

Maybe, but you could run into reentrancy problems with the DPMI host. Better to pass execution to a Real/Virtual 86 Mode handler that will then either iret or chain to the prior handler.

---
l

bretjohn

Homepage E-mail

Rio Rancho, NM,
04.05.2023, 04:03

@ Laaca

DPMI - how to chain user and original RM handler?

> I am trying to implement the INT 15h/AH=4Fh keyboard interrupt.
> If I detect the 4Fh in the AH I can do what I want.
> But if there is not the 4Fh (if there is f.e. AX=E820h) I have to put my
> hands off and just to call the original routine.

INT 15.4F isn't really the keyboard interrupt -- it is used to modify scancodes.
I'm trying to imagine a scenario where implementing an INT 15.4F routine in DPMI would be useful and I can't think of one. What exactly are you trying to accomplish?

Also, you will need to let the original routine process even if it's INT 15.4F but the scancode isn't the one you're trying to "trap". You may also need/want to call the original routine _before_ you do any of your own processing in case there is another handler that modifies some of the same scancodes you're trying to process (like a foreign keyboard layout driver that uses INT 15.4F instead of INT 09).

CandyMan

05.05.2023, 12:36

@ Laaca

DPMI - how to chain user and original RM handler?

Below is working assembly code that do it. Tested on true Dos.

        format  Flat on "D:\CW\D3XX.EXE"

StackSwitch = 0

        mov     [SelDS],ds
        mov     [SelFS],fs

        mov     edi,cRealRegs
        mov     ax,cs
        mov     ds,ax
        mov     esi,PopupStart
        mov     ax,0303h
        int     31h
        mov     ax,es
        mov     ds,ax

        cli
        xchg    [fs:4*15h+0],dx
        xchg    [fs:4*15h+2],cx
        mov     [PrevOfs],dx
        mov     [PrevSeg],cx

        mov     eax,dword [PrevOfs]
        mov     [dRealRegs+2Ah],eax     ;CS:IP

        sti
@@:
        mov     ah,10h
        int     16h
        cmp     al,1Bh
        jnz     @B

        mov     eax,dword [PrevOfs]
        mov     [fs:4*15h],eax

        mov     ah,4Ch
        int     21h

PopupStart:
        mov     ax,[esi]
        mov     [es:edi+2Ah],ax         ; RealIP
        mov     ax,[esi+02h]
        mov     [es:edi+2Ch],ax         ; RealCS
        add     word [es:edi+2Eh],6     ; RealSP (callfar = 4 | int = 6)

        push    ds es fs
        pushad

        cld

        mov     ds,[cs:SelDS]
        mov     es,ds
        mov     fs,[cs:SelFS]
        ;
if StackSwitch
        mov     [PrevStack+4],ss
        mov     [PrevStack+0],esp
        lss     esp,[MainStack]
end if
        ;
        cmp     [cRealRegs+1Dh],byte 4Fh        ;AH=4Fh ?
        jnz     NotFunction4F
        ;
        call    MainHandler
        ;
NotFunction4F:
        ;
        mov     esi,cRealRegs
        mov     edi,dRealRegs
        mov     ecx,2Ah/2
        rep     movsw
        ;
        mov     ax,0302h
        mov     edi,dRealRegs
        xor     bh,bh
        xor     ecx,ecx
        mov     [edi+2Eh],ecx
        int     31h
        ;
if StackSwitch
        lss     esp,[cs:PrevStack]
end if
        popad
        pop     fs es ds
        iretd

MainHandler:
        mov     al,'#'
        int     29h
        ret

dRealRegs:      rb 50
cRealRegs:      rb 50

SelDS   dw ?
SelFS   dw ?

PrevOfs dw ?
PrevSeg dw ?


Binaries are here: https://megawrzuta.pl/download/52b3f37a42fc8503969ef82d717d9ab9.html
Good luck!

Laaca

Homepage

Czech republic,
05.05.2023, 21:53

@ CandyMan

DPMI - how to chain user and original RM handler?

Wow!
Thank you very much.
Unfortunately I will be very busy next few days but then I will definitely try and adapt your code.

---
DOS-u-akbar!

Laaca

Homepage

Czech republic,
12.06.2023, 23:39

@ CandyMan

DPMI - how to chain user and original RM handler?

Ufff!
It was unexpectedly difficult to adapt your ideas to Freepascal.
It still did not work and I did not know why.

Only today I found the reason.
Normaly FPC assumes that DS=ES=SS (CS and FS are different)

But from these registers we have inside the callback only ES set to original value.
There is no problem with DS (mov ax,es;mov ds,ax) but there remains problem with SS.
If we do "mov ax,es;mov ss,ax" we get the immediate crash.
Se we have to work in unusual configuration when SS<>DS.

Fortunately it in most of cases works but not in all cases. There occur problems with several functions mixing pascal and assembler code.

And, what is relevant here, it makes problems with calling the DPMI functions which use the TRealRegs structure in situation when the TRealRegs structure is the local variable. Local variables are accessed not through DS/ES but through SS.

And as the DPMI funcs. 300h, 302h and 304h use ES:EDI for pointing the TRealRegs we can have a problem. The simple "mov edi,real_regs_struct" is not sufficient here because SS<>ES.

This issue is also the reason why inside the callbacks do not work many RTL functions like <Writeln>, <Readln> and do on. On the end they call the RTL function SimulateRealModeInterrupt (from unit Go32) which also call DPMI 300h with local variable.

(BTW: I suppose that most of this also applies to DJGPP)

However, at the end I succeed to chain user and original interrupt handler.





> Below is working assembly code that do it. Tested on true Dos.
>
>         format  Flat on "D:\CW\D3XX.EXE"
>
> StackSwitch = 0
>
> mov     [SelDS],ds
> mov     [SelFS],fs
>
> mov     edi,cRealRegs
> mov     ax,cs
> mov     ds,ax
> mov     esi,PopupStart
> mov     ax,0303h
> int     31h
> mov     ax,es
> mov     ds,ax
>
> cli
> xchg    [fs:4*15h+0],dx
> xchg    [fs:4*15h+2],cx
> mov     [PrevOfs],dx
> mov     [PrevSeg],cx
>
> mov     eax,dword [PrevOfs]
> mov     [dRealRegs+2Ah],eax     ;CS:IP
>
> sti
> @@:
> mov     ah,10h
> int     16h
> cmp     al,1Bh
> jnz     @B
>
> mov     eax,dword [PrevOfs]
> mov     [fs:4*15h],eax
>
> mov     ah,4Ch
> int     21h
>
> PopupStart:
> mov     ax,[esi]
> mov     [es:edi+2Ah],ax         ; RealIP
> mov     ax,[esi+02h]
> mov     [es:edi+2Ch],ax         ; RealCS
> add     word [es:edi+2Eh],6     ; RealSP (callfar = 4 | int = 6)
>
> push    ds es fs
> pushad
>
> cld
>
> mov     ds,[cs:SelDS]
> mov     es,ds
> mov     fs,[cs:SelFS]
> ;
> if StackSwitch
> mov     [PrevStack+4],ss
> mov     [PrevStack+0],esp
> lss     esp,[MainStack]
> end if
> ;
> cmp     [cRealRegs+1Dh],byte 4Fh        ;AH=4Fh ?
> jnz     NotFunction4F
> ;
> call    MainHandler
> ;
> NotFunction4F:
> ;
> mov     esi,cRealRegs
> mov     edi,dRealRegs
> mov     ecx,2Ah/2
> rep     movsw
> ;
> mov     ax,0302h
> mov     edi,dRealRegs
> xor     bh,bh
> xor     ecx,ecx
> mov     [edi+2Eh],ecx
> int     31h
> ;
> if StackSwitch
> lss     esp,[cs:PrevStack]
> end if
> popad
> pop     fs es ds
> iretd
>
> MainHandler:
> mov     al,'#'
> int     29h
> ret
>
> dRealRegs:      rb 50
> cRealRegs:      rb 50
>
> SelDS   dw ?
> SelFS   dw ?
>
> PrevOfs dw ?
> PrevSeg dw ?

>
> Binaries are here:
> https://megawrzuta.pl/download/52b3f37a42fc8503969ef82d717d9ab9.html
> Good luck!

---
DOS-u-akbar!

Back to the board
Thread view  Mix view  Order
22049 Postings in 2034 Threads, 396 registered users, 86 users online (0 registered, 86 guests)
DOS ain't dead | Admin contact
RSS Feed
powered by my little forum