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