[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]