Metropoli BBS
VIEWER: newfront.pas MODE: TEXT (ASCII)
unit NewFrontier;

{ New Frontier  Version 6.00  09.09.1995  Dietmar Meschede }
{                                                          }
{ Copyright (c) 1993,1995 Dietmar Meschede                 }
{                                                          }
{ Use at OWN risk!                                         }

{ BP 7.0 protected mode 32 bit DPMI support unit. }

{$DEFINE PROTECTED}
{$I STDUNIT.OPT}

interface

uses
  WinAPI;

type
  TPtr        = record
                  Ofs, Seg: Word;
                end;
  TSelector   = Word;
  TOffset32   = Longint;
  Pointer48   = Real;
  TSelOfs32   = record
                  Offset32: TOffset32;
                  Selector: TSelector;
                end;
  TDescriptor = record
                  SegmentLimit0: Word;
                  BaseAddress0 : Word;
                  BaseAddress1 : Byte;
                  Flags0       : Byte;
                  Flags1       : Byte;
                  BaseAddress2 : Byte;
                end;

function AllocateDescriptor(No: Word): TSelector;
procedure FreeDescriptor(Selector: TSelector);

function SetSegmentBaseAddress(Selector: TSelector; Base: Longint): Boolean;
function SetSegmentLimit(Selector: TSelector; Limit: Longint): Boolean;

function GetSegmentAccessRights(Selector: TSelector): Word;
function SetSegmentAccessRights(Selector: TSelector; Rights: Word): Boolean;

function CreateDescriptor(Base, Limit: Longint): TSelector;
function CreateCodeDescriptor(Base, Limit: Longint): TSelector;

function CreateAliasDescriptor(Selector: TSelector): TSelector;

function GetDescriptor(Selector: TSelector; var Descr: TDescriptor): Boolean;
function SetDescriptor(Selector: TSelector; var Descr: TDescriptor): Boolean;

function CreateCode32Alias(Selector: TSelector): TSelector;
function CreateData32Alias(Selector: TSelector): TSelector;

function PhysicalAddressMapping(Address, Size: Longint): Longint;
function FreePhysicalAddressMapping(LinearAddress: Longint): Boolean;

function MaxAvail32: Longint;
function MemAvail32: Longint;

procedure GetMem32(var Selector: TSelector; Size: Longint);
procedure FreeMem32(var Selector: TSelector);

procedure Move32(Source, Dest: Pointer48; Count: Longint);

procedure FillChar32(P: Pointer48; Count: Longint; Value: Byte);
procedure FillWord32(P: Pointer48; Count: Longint; Value: Word);
procedure FillLong32(P: Pointer48; Count: Longint; Value: Longint);

procedure BlockReadWrite32(var F: file; SourceDest: Pointer48; Count: Longint;
                           var Result: Longint; Write: Boolean);

procedure BlockRead32(var F: file; var P: Pointer48; Count: Longint; var Result: Longint);
procedure BlockWrite32(var F: file; var P: Pointer48; Count: Longint; var Result: Longint);

function BLoadSave32(Name: string; P: Pointer48; Count: Longint; Write: Boolean): Boolean;

function BLoad32(Name: string; P: Pointer48; Count: Longint): Boolean;
function BSave32(Name: string; P: Pointer48; Count: Longint): Boolean;

function MapRealPointer(P: Pointer): Pointer48;

function Ptr48(Selector: TSelector; Offset32: TOffset32): Pointer48;
  inline($58/           { POP AX }
         $5B/           { POP BX }
         $5A            { POP DX }
        );

function Seg48(P: Pointer48): TSelector;
  inline($58/           { POP AX }
         $58/           { POP AX }
         $58            { POP AX }
        );

function Ofs48(P: Pointer48): TOffset32;
  inline($58/           { POP AX }
         $5A/           { POP DX }
         $5B);          { POP BX }

function FarPtr(P: Pointer): Pointer48;
  inline($58/           { POP AX    }
         $31/$DB/       { XOR BX,BX }
         $5A            { POP DX    }
        );

function ReadMem32B(P: Pointer48): Byte;
  inline($66/$5E/               { POP  ESI          }
         $07/                   { POP  ES           }
         $26/$67/$8A/$06        { MOV  AL,[ES:ESI]  }
        );

function ReadMem32W(P: Pointer48): Word;
  inline($66/$5E/               { POP  ESI          }
         $07/                   { POP  ES           }
         $26/$67/$8B/$06        { MOV  AX,[ES:ESI]  }
        );

function ReadMem32L(P: Pointer48): Longint;
  inline($66/$5E/               { POP  ESI          }
         $07/                   { POP  ES           }
         $66/$26/$67/$8B/$06/   { MOV  EAX,[ES:ESI] }
         $8B/$D0/               { MOV  DX,AX        }
         $66/$C1/$E8/$10/       { SHR  EAX,16       }
         $92                    { XCHG AX,DX        }
        );

procedure WriteMem32B(P: Pointer48; Value: Byte);
  inline($58/                   { POP  AX           }
         $66/$5F/               { POP  EDI          }
         $07/                   { POP  ES           }
         $26/$67/$88/$07        { MOV  [ES:EDI],AL  }
        );

procedure WriteMem32W(P: Pointer48; Value: Word);
  inline($58/                   { POP  AX           }
         $66/$5F/               { POP  EDI          }
         $07/                   { POP  ES           }
         $26/$67/$89/$07        { MOV  [ES:EDI],AX  }
        );

procedure WriteMem32L(P: Pointer48; Value: Longint);
  inline($66/$58/               { POP  EAX          }
         $66/$5F/               { POP  EDI          }
         $07/                   { POP  ES           }
         $66/$26/$67/$89/$07    { MOV  [ES:EDI],EAX }
        );

var
  LowMem: TSelector;

implementation

const
  DPMI = $31;   { Interruptnumber for DPMI functions }

{ export }
function AllocateDescriptor(No: Word): TSelector; assembler;
asm
        MOV     AX,$0000                { Allocate LDT Descriptor }
        MOV     CX,[No]
        OR      CX,CX
        JE      @@End
        INT     DPMI
        JNC     @@End
        XOR     AX,AX
@@End:
end; { AllocateDescriptor }

{ export }
procedure FreeDescriptor(Selector: TSelector); assembler;
asm
        MOV     AX,$0001                { Free LDT Descriptor }
        MOV     BX,[Selector]
        OR      BX,BX
        JE      @@End
        INT     DPMI
@@End:
end; { FreeDescriptor }

procedure SetDescriptorBaseAddress(var Descr: TDescriptor; Base: Longint);
begin
  with Descr do begin
    BaseAddress0 := Word(Base);
    BaseAddress1 := Byte(Base shr 16);
    BaseAddress2 := Byte(Base shr 24);
  end; { with }
end; { SetDescriptorBaseAddress }

{ export }
function SetSegmentBaseAddress(Selector: TSelector; Base: Longint): Boolean;
var
  Descr: TDescriptor;
begin
  SetSegmentBaseAddress := False;
  if Selector = 0 then Exit;
  if not GetDescriptor(Selector, Descr) then Exit;
  SetDescriptorBaseAddress(Descr, Base);
  SetSegmentBaseAddress := SetDescriptor(Selector, Descr);
end; { SetSegmentBaseAddress }

procedure SetDescriptorLimit(var Descr: TDescriptor; Limit: LongInt);
begin
  with Descr do begin
    if Limit > 0 then Dec(Limit);
    if Limit >= $100000 then begin      { > 1MB ? }
      Limit  := Limit shr 12;
      Flags1 := Flags1 or $80;          { Granularity = 4KB }
    end; { if }
    SegmentLimit0 := Word(Limit);
    Flags1 := Flags1 or Byte(Limit shr 16);
  end; { with }
end; { SetSegmentLimit }

{ export }
function SetSegmentLimit(Selector: TSelector; Limit: Longint): Boolean;
var
  Descr: TDescriptor;
begin
  SetSegmentLimit := False;
  if Selector = 0 then Exit;
  if not GetDescriptor(Selector, Descr) then Exit;
  SetDescriptorLimit(Descr, Limit);
  SetSegmentLimit := SetDescriptor(Selector, Descr);
end; { SetSegmentLimit }

{ export }
function GetSegmentAccessRights(Selector: TSelector): Word;
var
  Descr: TDescriptor;
begin
  if GetDescriptor(Selector, Descr) then
    GetSegmentAccessRights := (Word(Descr.Flags1) shl 8) or Descr.Flags0
  else GetSegmentAccessRights := 0;
end; { GetSegmentAccessRights }

procedure SetDescriptorAccessRights(var Descr: TDescriptor; Rights: Word);
begin
  with Descr do begin
    Flags0 := Byte(Rights);
    Flags1 := Byte(Rights shr 8);
  end; { with }
end; { SetDescriptorAccressRights }

{ export }
function SetSegmentAccessRights(Selector: TSelector; Rights: Word): Boolean;
var
  Descr: TDescriptor;
begin
  SetSegmentAccessRights := False;
  if Selector = 0 then Exit;
  if not GetDescriptor(Selector, Descr) then Exit;
  SetDescriptorAccessRights(Descr, Rights);
  SetSegmentAccessRights := SetDescriptor(Selector, Descr);
end; { SetSegmentAccessRights }

{ export }
function CreateDescriptor(Base, Limit: Longint): TSelector;
var
  Selector: TSelector; Descr: TDescriptor;
begin
  CreateDescriptor := 0;
  Selector := AllocateDescriptor(1);
  if Selector <> 0 then begin
    if not GetDescriptor(Selector, Descr) then Exit;
    SetDescriptorBaseAddress(Descr, Base);
    SetDescriptorLimit(Descr, Limit);
    Descr.Flags1 := Descr.Flags1 and $BF;               { 16-Bit-Segment }
    if not SetDescriptor(Selector, Descr) then Exit;
  end; { if }
  CreateDescriptor := Selector;
end; { CreateDescriptor }

{ export }
function CreateCodeDescriptor(Base, Limit: Longint): TSelector;
var
  Selector: TSelector; Descr: TDescriptor;
begin
  CreateCodeDescriptor := 0;
  Selector := AllocateDescriptor(1);
  if Selector <> 0 then begin
    if not GetDescriptor(Selector, Descr) then Exit;
    SetDescriptorBaseAddress(Descr, Base);
    SetDescriptorLimit(Descr, Limit);
    Descr.Flags0 := (Descr.Flags0 and $FB) or $0A;    { no conforming, code segment, readable }
    Descr.Flags1 := Descr.Flags1 and $BF;             { 16-Bit-Segment }
    if not SetDescriptor(Selector, Descr) then Exit;
  end; { if }
  CreateCodeDescriptor := Selector;
end; { CreateCodeDescriptor }

{ export }
function CreateAliasDescriptor(Selector: TSelector): TSelector; assembler;
asm
        MOV     AX,$000A        { Create Code Segment Alias Descriptor }
        MOV     BX,[Selector]
        INT     DPMI
        JNC     @@End
        XOR     AX,AX
@@End:
end; { CreateAliasDescriptor }

{ export }
function GetDescriptor(Selector: TSelector; var Descr: TDescriptor): Boolean; assembler;
asm
        MOV     AX,$000B        { Get Descriptor (LDT) }
        MOV     BX,[Selector]
        LES     DI,[Descr]
        INT     DPMI
        MOV     AX,False
        JC      @@End
        MOV     AX,True
@@End:
end; { GetDescriptor }

{ export }
function SetDescriptor(Selector: TSelector; var Descr: TDescriptor): Boolean; assembler;
asm
        MOV     AX,$000C        { Set Descriptor (LDT) }
        MOV     BX,[Selector]
        OR      BX,BX
        JE      @@End
        LES     DI,[Descr]
        INT     DPMI
        MOV     AX,False
        JC      @@End
        MOV     AX,True
@@End:
end; { SetDescriptor }

{ export }
function CreateCode32Alias(Selector: TSelector): TSelector;
var
  Descr: TDescriptor;
begin
  Selector := CreateAliasDescriptor(Selector);
  if Selector <> 0 then begin
    GetDescriptor(Selector, Descr);
    with Descr do begin
      Flags1 := Flags1 or $40;                  { 32-Bit-Segment }
      Flags0 := (Flags0 and $F0) or $0B;        { Code Segment   }
    end; { with }
    SetDescriptor(Selector, Descr);
  end; { if }
  CreateCode32Alias := Selector;
end; { CreateCode32Alias }

{ export }
function CreateData32Alias(Selector: TSelector): TSelector;
var
  NewSelector: TSelector; Descr: TDescriptor;
begin
  NewSelector := AllocateDescriptor(1);
  if NewSelector <> 0 then begin
    GetDescriptor(Selector, Descr);
    with Descr do begin
      Flags1 := Flags1 or $40;                  { 32-Bit-Segment }
      Flags0 := (Flags0 and $F0) or $03;        { Data Segment   }
    end; { with }
    SetDescriptor(NewSelector, Descr);
  end; { if }
  CreateData32Alias := NewSelector;
end; { CreateCode32Alias }

{ export }
function PhysicalAddressMapping(Address, Size: Longint): Longint; assembler;
asm
        MOV     AX,$0800                        { Physical Address Mapping }
        MOV     CX,WORD [Address]
        MOV     BX,WORD [Address+2]
        MOV     DI,WORD [Size]
        MOV     SI,WORD [Size+2]
        INT     DPMI
        MOV     AX,CX
        MOV     DX,BX
        JNC     @@End
        XOR     AX,AX
        XOR     DX,DX
@@End:
end; { PhysicalAddressMapping }

{ export }
function FreePhysicalAddressMapping(LinearAddress: Longint): Boolean; assembler;
asm
        MOV     AX,$0801                        { Free Physical Address Mapping }
        MOV     CX,WORD [LinearAddress]
        MOV     BX,WORD [LinearAddress+2]
        INT     DPMI
        MOV     AX,False
        JC      @@End
        MOV     AX,True
@@End:
end; { FreePhysicalAddressMapping }

{ export }
function MaxAvail32: Longint;
begin
  MaxAvail32 := GlobalCompact(0);
end; { MaxAvail32 }

{ export }
function MemAvail32: Longint;
begin
  MemAvail32 := GetFreeSpace(0);
end; { MemAvail32 }

{ export }
procedure GetMem32(var Selector: TSelector; Size: Longint);
var
  P: Pointer; SelectorNo: Word; Base: Longint;
  Ok: Boolean; i: Word; Descr: TDescriptor;
begin
  P := GlobalAllocPtr(gmem_Fixed, Size);
  if (P <> nil) and (Ofs(P^) = 0) then begin
    Ok := True;
    Selector := Seg(P^);
    Base := GetSelectorBase(Selector);
    SelectorNo := Size div $10000;
    if (Size mod $10000) <> 0 then Inc(SelectorNo);
    for i := 1 to SelectorNo-1 do begin
      Inc(Base, $10000);
      if Base <> GetSelectorBase(Selector+SelectorInc*i) then begin
        Ok := False; Break;
      end; { if }
    end; { for }
    if Ok then begin
      GetDescriptor(Selector, Descr);
      SetDescriptorLimit(Descr, Size);
      Descr.Flags1 := Descr.Flags1 and $BF;     { 16-Bit-Segment }
      SetDescriptor(Selector, Descr);
    end; { if }
    if not Ok then begin
      GlobalFreePtr(P);
      Selector := 0;
    end; { if }
  end { if }
  else Selector := 0;
end; { GetMem32 }

{ export }
procedure FreeMem32(var Selector: TSelector);
begin
  if Selector <> 0 then begin
    GlobalFreePtr(Ptr(Selector, 0));
    Selector := 0;
  end; { if }
end; { FreeMem32 }

{ export }
procedure Move32(Source, Dest: Pointer48; Count: Longint); assembler;
asm
        CLD
        PUSH    DS
        DB      66h
        LDS     SI,DWORD [Source]
        DB      66h
        LES     DI,DWORD [Dest]
        DB      66h
        MOV     CX,WORD [Count]
        PUSH    CX
        DB      66h
        SHR     CX,2
        DB      66h, 67h
        REP     MOVSW
        POP     CX
        AND     CX,0003h
        DB      67h
        REP     MOVSB
        POP     DS
end; { Move32 }

{ export }
procedure FillChar32(P: Pointer48; Count: Longint; Value: Byte); assembler;
asm
        CLD
        DB      66h
        LES     DI,DWORD [P]
        DB      66h
        MOV     CX,WORD [Count]
        MOV     AL,[Value]
        MOV     AH,AL
        MOV     BX,AX
        DB      66h
        SHL     AX,16
        MOV     AX,BX
        PUSH    CX
        DB      66h
        SHR     CX,2
        DB      66h, 67h
        REP     STOSW
        POP     CX
        AND     CX,0003h
        DB      67h
        REP     STOSB
end; { FillChar32 }

{ export }
procedure FillWord32(P: Pointer48; Count: Longint; Value: Word); assembler;
asm
        CLD
        DB      66h
        LES     DI,DWORD [P]
        DB      66h
        MOV     CX,WORD [Count]
        MOV     AX,[Value]
        MOV     BX,AX
        DB      66h
        SHL     AX,16
        MOV     AX,BX
        PUSH    CX
        DB      66h
        SHR     CX,1
        DB      66h, 67h
        REP     STOSW
        POP     CX
        AND     CX,0001h
        DB      67h
        REP     STOSW
end; { FillWord32 }

{ export }
procedure FillLong32(P: Pointer48; Count: Longint; Value: Longint); assembler;
asm
        CLD
        DB      66h
        LES     DI,DWORD [P]
        DB      66h
        MOV     CX,WORD [Count]
        DB      66h
        MOV     AX,WORD [Value]
        DB      66h, 67h
        REP     STOSW
end; { FillLong32 }

{ export }
procedure BlockReadWrite32(var F: file; SourceDest: Pointer48; Count: Longint;
                           var Result: Longint; Write: Boolean);
var
  i, Pages: Longint; Remainder, Tmp: Word; Buffer: Pointer;
begin
  Pages := Count div $8000; Remainder := Count mod $8000;
  Tmp := $8000; Result := 0;
  GetMem(Buffer, $8000);
  if Buffer = nil then Exit;
  for i := 1 to Pages do begin
    case Write of
      False: begin
               BlockRead(F, Buffer^, $8000, Tmp);
               Move32(FarPtr(Buffer), SourceDest, Tmp);
             end;
      True:  begin
               Move32(SourceDest, FarPtr(Buffer), $8000);
               BlockWrite(F, Buffer^, $8000, Tmp);
             end;
    end; { case }
    Inc(TSelOfs32(SourceDest).Offset32, $8000);
    Inc(Result, Tmp);
    if Tmp < $8000 then Break;
  end; { for }
  if (Tmp = $8000) and (Remainder > 0) then begin
    case Write of
      False: begin
               BlockRead(F, Buffer^, Remainder, Tmp);
               Move32(FarPtr(Buffer), SourceDest, Tmp);
             end;
      True:  begin
               Move32(SourceDest, FarPtr(Buffer), Remainder);
               BlockWrite(F, Buffer^, Remainder, Tmp);
             end;
    end; { case }
    Inc(Result, Tmp);
  end; { if }
  FreeMem(Buffer, $8000);
end; { BlockReadWrite32 }

{ export }
procedure BlockRead32(var F: file; var P: Pointer48; Count: Longint; var Result: Longint);
begin
  BlockReadWrite32(F, P, Count, Result, False);
end; { BlockRead32 }

{ export }
procedure BlockWrite32(var F: file; var P: Pointer48; Count: Longint; var Result: Longint);
begin
  BlockReadWrite32(F, P, Count, Result, True);
end; { BlockWrite32 }

{ export }
function BLoadSave32(Name: string; P: Pointer48; Count: Longint; Write: Boolean): Boolean;
var
  F: file; var Size, Result: Longint;
begin
  InOutRes := 0;
  BLoadSave32 := False;
  Assign(F, Name);
  case Write of
    False: Reset(F, 1);
    True:  Rewrite(F, 1);
  end; { case }
  if IOResult <> 0 then Exit;
  if not Write then begin
    Size := FileSize(F);
    if IOResult <> 0 then Exit;
  end; { if }
  BlockReadWrite32(F, P, Count, Result, Write);
  case Write of
    False: BLoadSave32 := (Result = Count) or (Result = Size);
    True:  BLoadSave32 := (Result = Count);
  end; { case }
  Close(F);
  if IOResult <> 0 then BLoadSave32 := False;
end; { BLoadSave32 }

{ export }
function BLoad32(Name: string; P: Pointer48; Count: Longint): Boolean;
begin
  BLoad32 := BLoadSave32(Name, P, Count, False);
end; { BLoad32 }

{ export }
function BSave32(Name: string; P: Pointer48; Count: Longint): Boolean;
begin
  BSave32 := BLoadSave32(Name, P, Count, True);
end; { BSave32 }

function MapRealPointer(P: Pointer): Pointer48;
var
  P48: TSelOfs32;
begin
  if LowMem <> 0 then begin
    P48.Selector := LowMem;
    P48.Offset32 := (Longint(TPtr(P).Seg) shl 4) + Longint(TPtr(P).Ofs);
    MapRealPointer := Pointer48(P48);
  end { if }
  else begin
    MapRealPointer := 0;
  end; { else }
end; { MapRealPointer }

var
  SaveExit: Pointer;

procedure NewFrontierExit; far;
begin
  ExitProc := SaveExit;
  FreeDescriptor(LowMem);
end; { NewFrontierExit }

begin
  SaveExit := ExitProc;
  ExitProc := @NewFrontierExit;
  LowMem := CreateDescriptor(0, $100000);
end. { unit NewFrontier }
[ RETURN TO DIRECTORY ]