[Back to MEMORY SWAG index]  [Back to Main SWAG index]  [Original]

{
 XDR> I'm currently developing an application that I would gladly spread in
 XDR> protected mode... But could someone explain to me what can I NOT do in
 XDR> DPMI pascal

This is actually explained quite clearly in Ch. 17 of the BP7 Language Guide.

The main difference is that memory is no longer yours to do with as you
please; you can only "touch" memory that has been allocated to your program.
This is where the "protected" in "protected mode" stems from.

The following is a rather simplified view of things, but it does illustrate
the general priciple:

In pmode a pointer such as ptr($B800, 0) does NOT point to memory location
$B800:0000. The segment part (called the "selector" in pmode), $B800,
is treated as an index into a system maintained table, which *does* contain
the actual physical memory location (called the "base"), and the number of
bytes allocated to that base (called the "limit"). This table is unavailable
to your program.
At the start of your program, all entries in this table are marked "not in
use" and therefore illegal.
During program execution, whenever you attempt to read or write Mem[S:O],
the CPU checks (in that table) to see if S is a legal index (i.e., if S is
a valid base), and if so, whether O is within the limit of that base.
If at least one of these checks fail, the memory access is invalid, and you
will be presented with run time error 216 a.k.a. the dreaded General
Protection Failure (GPF) a.k.a. Exception $0D.

 XDR> Ag: I can no more acces the screen at an Obsolute $b800:000 but at
 XDR> absolute Segb800:000, why?

Btw: ABSOLUTE SegB800:0 won't compile.
Use "mem[SegB800:0]" instead, or use a pointer, like so:

VAR VidMemStart: pointer;
BEGIN VidMemStart:=ptr(SegB800, 0) END;

and manipulate video memory using VidMemStart^.

The reason should now be clear: $B800 is almost certainly *not* a valid
selector. Since no one has asked the DPMI server to associate selector $B800
with a physical memory location, it is illegal.
You *can* use SegB800, as your program startup code asks the DPMI server to
associate SegB800 with video memory.

You should not pass pmode pointers to real mode routines nor the other way
around (they are invalid in the "receiving" mode).
It can be done, but you'll need the cooperation of the DPMI server.
Find a DPMI unit (I can't post mine, as it is commercial). Below you'll
find such a unit - I've never used it, so no guarantees.

Notes: - if you attempt to write to code segments, or read from invalid
         pointers, a GPF will result.
       - if you attempt to read an invalid stack element, you will receive
         an Exception $0C (Stack Fault), which BP will convert to run time
         error 202.
       - Exception 6 (Invalid Opcode) is not related to memory accesses.
         It means the CPU has received a couple of bytes which it cannot
         interpret as a valid instruction.
       - prior to distribution, be sure to read file DPMIUSER.DOC.
         You can find that file in archive DOC.ZIP on your BP7 distribution
         disks.

The above three exceptions are likely the only ones you'll see.

Happy programming,

Peter. }

===== Start of includefile FDEFINE.DEF =====

{ Include file FDEFINE.DEF - general include file for the unit systems
                             conditional defines }

 (***************************************************************************

            RELEASE 1.04 - as contained in the file PRUS100.LZH
                by Orazio Czerwenka, 2:2450/540.55, GERMANY

               --------------------------------------------
                organized for Fido's PASCAL related echoes
               --------------------------------------------

     06/21/1994 to --/--/---- by Orazio Czerwenka, 2:2450/540.55, GERMANY

 ***************************************************************************)

{ ==========================================================================
  WHICH VERSION OF TURBO PASCAL DO YOU COMPILE WITH ?
  THE DEFAULT IS TURBO PASCAL 6.0x !
  ========================================================================== }

  { The following conditional defines do not yet have any effect, ... }

  {.$define ver30}       { Turbo Pascal 3.0x }
  {.$define ver40}       { Turbo Pascal 4.0x }
  {.$define ver50}       { Turbo Pascal 5.0x }
  {.$define ver55}       { Turbo Pascal 5.5x }
  {$define ver60}       { Turbo Pascal 6.0x }
  {.$define ver70}       { Turbo/Borland Pascal 7.0x }

  { ... these commenting lines will be deleted once that should be changed. }


{ ==========================================================================
  WHAT LANGUAGE DO YOU WANT YOUR PROGRAMS TO DISPLAY MESSAGES IN BY DEFAULT?
  ========================================================================== }

  {$define English}
  {.$define German}


{ ==========================================================================
  ACTIVATE THE FOLLOWING DISABLED COMPILER DIRECTIVE IF YOU WANT TO BE ABLE
  TO USE THE UNIT SYSTEM FROM WITHIN OVERLAYS !
  ========================================================================== }

  {.$O+}   { This tells your compiler - if activated - to produce a unit
             that will be allowed to be used from within overlays. }

  {$IFOPT O+}
    {$DEFINE Overlays}                                    { easier to read }
  {$ENDIF}

{ ==========================================================================
  WHAT KIND OF PROCESSOR ARE YOU COMPILING FOR ? SOME CPU DEPENDEND DEFINES.
  ========================================================================== }

  (* Some of the units use inline assembler designed to work on machines
     with at least 80286 processor, so generally you can tell your compiler
     to produce 80286 code anyway.
  *)

  {$G+}   { This tells - if activated - your compiler to produce 80286
            code. }

  (* In addition you might want to specify one of the following higher
     processors, if you want your programmes ONLY to run on THESE and
     higher machines.
  *)

  { The following conditional defines do not yet have any effect, ... }

  {.$define cpu386}           { Use specific code for 80386 machines }
  {.$define cpu486}           { Use specific code for 80486 machines }

  { ... these commenting lines will be deleted once that should be changed. }

{ -------------------------------------------------------------------------- }

  (* Define one of the following CRT replacements (or CRT) for use by the
     units FTMODE and FSPEAKER, depending on what you've got.
     If you don't have a replacement, take the CRT, it is a bit slower but
     it should work as well.
     -----------------------------------------------------------------------
     NOTICE THAT THE UNIT FCRT SHOULD ALSO BE INCLUDED IN THIS FILE PACKAGE!
     -----------------------------------------------------------------------
     Note that at least one of those units shoul be defined to be used !
     By default this should be the unit FCRT.

     In case you should also want to use TP CRT's screen handling related
     functions in addition to the routines provided by FCONDRV and FCRT
     you probably will have to define the usage of TP's CRT here.
     By default the usage of TP's CRT is *NOT* defined in order to avoid
     smaller drawbacks in speed and unnecessarilly 'blown up' code.
  *)

  {$define FCRT}
  {.$define CRT}
  {.$define CRT2}



{ -------------------------------------------------------------------------- }

  (* The following conditional define will specify wether the unit(s) FTMODE
     will use the BIOS for the 80x25 mode or try programming it by hand. You
     should leave it inactivated, since who would want to force the user to
     use 80x25 ? I (MM) implemented it, since on my system, mode 3 corresponds
     to 90x28 through a TSR, and a small program would have helped here :-)
     Note that forcing will only take place if FTMODE's SetVideoMode(3) does
     not result in an 80 column mode.
  *)

{.$define UseBIOS}



{ -------------------------------------------------------------------------- }

===== End   of includefile FDEFINE.DEF =====

===== Start of unit FDPMI =====

Unit FDPMI; { routines for DOS/DPMI communication }
 (***************************************************************************

           RELEASE 1.00 - as contained in the file PRUS100.LZH
                 by Max Maischein, 2:244/1106.17, GERMANY

               --------------------------------------------
                organized for Fido's PASCAL related echoes
               --------------------------------------------

     06/15/1994 to --/--/---- by Max Maischein, 2:244/1106.17, GERMANY

           As far as third party copyrights are not violated this
           source code is hereby placed to the public domain. Use
           it whatever way you want, but use AT YOUR OWN RISK.

           In case you should modify the source rather send your
           modifications to the unit's current organizer (see above for
           NM address) than to spread it on your own. This will help to
           keep the unit updated and grant a certain standard to all
           other users as well.

           The unit is currently still under work. So it might greatly
           benefit of your participation.

           Those who contributed to the following piece of source,
           listed in alphabethical order:
        ================================================================
           Jochen Magnus (SEGDEMO.PAS), Max Maischein (collecting,
           documenting, testing etc.), Raphael Vanney (program CHARSET
           .PAS)
        ================================================================
           YOUR NAME WILL APPEAR HERE IF YOU CONTRIBUTE USEFUL SOURCE.

 ***************************************************************************)

{$I FDEFINE.DEF}

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;
(* Use these and RealModeInt() instead of Registers and Intr() under DPMI *)

Type TLongRec = Record
       Case Byte of
         0 : ( L : LongInt );
         1 : ( wLo : Word;
               wHi : Word; );
         2 : ( iLo : Integer;
               iHi : Integer );
     End;

Function RealModeInt( IntNo : Byte; Var RealRegs : TRealModeRegs) : Boolean;
(* Replacement for Intr(), returns False on error *)

Function NewSelector( Base, Limit : Longint) : Word;
(* Returns a new selector for the range [Base - (Base+Limit)]        *)
(* Base is the linear address of the memory location you want to use *)
(* You must free this selector after use with FreeSelector()         *)

Function AllocateLowMem( Size : Word; var PMPointer : Pointer ) : Word;
(* Allocates some memory in the first MB *)
(* Returns a pointer to it and a segment to pass to the real mode routine *)

Procedure FreeLowMem(Var PMPointer : Pointer );
(* Frees memory allocated with AllocateLowMem() *)

Implementation
Uses WinAPI;

Function RealModeInt( IntNo : Byte; Var RealRegs : TRealModeRegs) : Boolean;
Assembler;
{ This function switches to real mode and issues the specified interrupt,
  after filling the registers with values stored in RealRegs.
  If SS/SP as specified in RealRegs are Nil, the DPMI server provides a
  small stack. For more discution of this, see Ralf Brown's INTERxx.ZIP }
Asm
                        mov     ax, 0300h       { DPMI function "simulate real
mode int" }
                        mov     bl, [IntNo]
                        xor     bh, bh          { 0 as requested by DPMI v1.0
}                        xor     cx, cx          { bytes to copy onto "remote"
stack }
                        les     di, [RealRegs]
                        int     31h             { Returns CF set on error }
                        mov     ax, 1           { assume everything went OK }
                        sbb     ax, 0           { if carry set, decrement ax }
                                                { to signal an error }
End;

Function NewSelector(Base,Limit:longint) : Word;
Var Sel : Word;
Begin
  Sel := AllocSelector(0);
  If (sel<>0) and (setSelectorBase(sel,base)=sel) and (setSelectorLimit(sel,
limit)=0)
    then newSelector:=sel
    else newSelector:=0;
End;

Function AllocateLowMem( Size : Word; var PMPointer : Pointer ) : Word;
{ This procedure allocates memory in the first megabyte, and returns two
  ways of accessing it : a pointer valid in protected mode, and the
  segment part of a pointer valid in real mode ; offset part is always 0 }

Var  Adr  : LongInt ;
Begin
  Adr:=GlobalDOSAlloc(Size) ;
  If Adr=0 then RunError( 0 );
  PMPointer := Ptr( TLongRec(Adr).wLo, 0);
  AllocateLowMem := TLongRec(Adr).wHi;
End ;

Procedure FreeLowMem(Var PMPointer : Pointer ) ;
{ Frees memory allocated with AllocateLowMem }
Begin
  GlobalDOSFree(Seg( PMPointer^ ));
  PMPointer := nil;
End ;
{$IFnDEF DPMI}
{$IFnDEF Windows}
  You are compiling WHAT ??
{$ENDIF}
{$ENDIF}
End.

===== End   of unit FDPMI =====

[Back to MEMORY SWAG index]  [Back to Main SWAG index]  [Original]