[Back to INTERRUP SWAG index] [Back to Main SWAG index] [Original]
{
> One part of the program I am writing must call an interrupt (6A I believe
> - it is a networking interrupt). The interrupt expects ds:dx to point to a
> structure I have to create. I know my procedures work because I have
> tested them in real mode. The problem comes when Is witch into protected
> mode. The interrupt can no longer find the record that I create. How can I
> do this without too much trouble? I was thinking of using a known segment,
> such as SegB000 (which I am not using right now), and using memcpy to
> copy the record I create to that segment. Then I could just point ds:
> SegB000 and dx: 0 and do my interrupt.
Here's the unit I use to solve such problems. What you need to do :
- allocate memory in the first megabyte, using AllocateLowMem,
- properly set-up your structure in this memory area, using ProtectedPtr,
- set-up a TRealModeRegs, DS being initialized with the RealSegment of
the previously allocated memory block,
- call your interrupt with RealModeInt.
From: zlika@chaos2.frmug.fr.net (Raphael Vanney)
}
{ Outils DPMI }
{$x+,g+}
{$IfNDef DPMI}
You don't need that unit.
{$EndIf}
Unit MinDPMI ;
Interface
Type TRealModeRegs =
Record
Case Integer Of
0: ( EDI, ESI, EBP, EXX, EBX, EDX, ECX, EAX: Longint;
Flags, ES, DS, FS, GS, IP, CS, SP, SS: Word) ;
1: ( DI,DIH, SI, SIH, BP, BPH, XX, XXH: Word;
Case Integer of
0: (BX, BXH, DX, DXH, CX, CXH, AX, AXH: Word);
1: (BL, BH, BLH, BHH, DL, DH, DLH, DHH,
CL, CH, CLH, CHH, AL, AH, ALH, AHH: Byte));
End ;
TLowMemoryBlock =
{ TLowMemoryBlock is used to point to a memory area within the
first megabyte, which can thus be accessed both in protected
and real mode. }
Record
ProtectedPtr : Pointer ; { pointer valid in protected mode }
RealSegment : Word ; { segment valid in real mode (ofs=0) }
Size : Word ; { size of allocated memory area }
End ;
Procedure ClearRegs(Var RealRegs : TRealModeRegs) ;
Function RealModeInt( IntNo : Byte ;
Var RealRegs : TRealModeRegs) : Boolean ;
{ Important notes :
. If SS and SP are set to 0, the DPMI server will provide a 30 bytes stack.
. Calling ClearRegs before initializing registers used for a RealModeInt
sets SS ans SP to 0.
}
Procedure AllocateLowMem(Var Pt : TLowMemoryBlock ; Size : Word) ;
Procedure FreeLowMem(Var Pt : TLowMemoryBlock) ;
Procedure SetProtectedIntVec(No : Byte ; p : Pointer) ;
Procedure GetProtectedIntVec(No : Byte ; Var p : Pointer) ;
Implementation
Uses WinAPI ;
Type TDouble =
Record
Lo, Hi : Word ;
End ;
Procedure ClearRegs ;
Begin
FillChar(RealRegs, SizeOf(RealRegs), 0) ;
End ;
Function RealModeInt( IntNo : Byte ;
Var RealRegs : TRealModeRegs) : Boolean ;
Assembler ;
Asm
Mov AX, $0300
Mov BL, IntNo
XOr BH, BH
XOr CX, CX
LES DI, RealRegs
Int $31
Mov AX, 0 { don't use XOr }
JNC @Ok
Inc AX
@Ok:
Or AX, AX
End ;
Procedure AllocateLowMem ;
Var Adr : LongInt ;
Begin
Adr:=GlobalDOSAlloc(Size) ;
If Adr=0 Then Size:=0 ;
Pt.ProtectedPtr:=Ptr(TDouble(Adr).Lo, 0) ;
Pt.RealSegment:=TDouble(Adr).Hi ;
Pt.Size:=Size ;
End ;
Procedure FreeLowMem ;
Begin
GlobalDOSFree(Seg(Pt.ProtectedPtr^)) ;
FillChar(Pt, SizeOf(Pt), 0) ; { Fills with NIL }
End ;
Procedure SetProtectedIntVec(No : Byte ; p : Pointer) ; Assembler ;
Asm
Mov AX, $0205
Mov BL, No
Mov CX, TDouble[p].Hi { Selector }
Mov DX, TDouble[p].Lo { Offset }
Int $31
End ;
Procedure GetProtectedIntVec(No : Byte ; Var p : Pointer) ; Assembler ;
Asm
Mov AX, $0204
Mov BL, No
Int $31
LES DI, p
{ Mov ES:[DI], DX }
{ Mov ES:[DI+2], CX }
Mov TDouble[ES:DI].Lo, DX
Mov TDouble[ES:DI].Hi, CX
End ;
Function HugeAdr(Slct : Word ; Ofst : LongInt) : Pointer ;
Assembler ;
Asm
Mov AX, SelectorInc
Mul TDouble[Ofst].Hi
Add AX, Slct { First selector of bloc }
Mov DX, AX { New selector }
Mov AX, TDouble[Ofst].Lo { Low word of offset is the same }
End ;
End.
[Back to INTERRUP SWAG index] [Back to Main SWAG index] [Original]