Laaca 
        
  
  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 
        
    
  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 
        
    
  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 
        
  
  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 
        
    
  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 
        
    
  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 
        
  
  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 
        
  
  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!  |