home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1993 #3 / NN_1993_3.iso / spool / comp / lang / pascal / 8437 < prev    next >
Encoding:
Internet Message Format  |  1993-01-22  |  7.6 KB

  1. Path: sparky!uunet!mcsun!sun4nl!wtrlnd!contrast!postmaster
  2. From: berend@contrast.wlink.nl (Berend de Boer)
  3. Newsgroups: comp.lang.pascal
  4. Subject: Pt 2/2: Protected Mode Tips
  5. Message-ID: <727633957.AA01186@contrast.wlink.nl>
  6. Date: Thu, 21 Jan 1993 15:52:00
  7. Sender: postmaster@contrast.wlink.nl
  8. Lines: 201
  9.  
  10. <continued from previous message>
  11.  
  12. 3) We will examine how to setup an interrupt for real mode. Most of    the time
  13. this is transparantly done by Borland's DPMI Extender, but we    are on our own
  14. now.
  15.    The Simulate Real Mode Interrupt function needs a real mode register    data
  16. structure. We pass this data structure to this function. Than a    switch is
  17. made to real mode and the contents of the data structure is    copied into the
  18. register, the interrupt is made, registers are copied    back to the data
  19. structure, the processor switches back to protected    mode and voila: you are
  20. in control again.
  21.    Maybe you ask: why need I to setup such a data structure? Why can I    not
  22. simply pass registers? Several reasons exist, but take for    example the
  23. RealModeSeg of the previous example. You cannot simply    load a RealModeSeg in
  24. a register. Most likely a segment violation    would occur (referring to a non
  25. existing segment or you do not have    enough rights etc.). Therefore only in
  26. real mode can real mode    segments be loaded.
  27.    The data structure to pass registers between protected and real mode    can
  28. be found in the DPMI Unit which I repeat here:
  29.  
  30.      type
  31.        TRealModeRegs = record
  32.          case Integer of
  33.            0: (
  34.                EDI, ESI, EBP, EXX, EBX, EDX, ECX, EAX: Longint;               
  35. Flags, ES, DS, FS, GS, IP, CS, SP, SS: Word);            1: (               
  36. DI, DIH, SI, SIH, BP, BPH, XX, XXH: Word;
  37.                case Integer of
  38.                  0: (
  39.                      BX, BXH, DX, DXH, CX, CXH, AX, AXH: Word);                
  40.  1: (
  41.                      BL, BH, BLH, BHH, DL, DH, DLH, DHH,
  42.                      CL, CH, CLH, CHH, AL, AH, ALH, AHH: Byte));        end;
  43.  
  44.    This looks reasonably complex, does it! More simply is the following   
  45. structure (found in, for example, "Extending Dos" by Ray Duncan e.a.)    Offset
  46.  Lenght Contents
  47.    00h     4      DI or EDI
  48.    04h     4      SI or ESI
  49.    08h     4      BP or EBP
  50.    0Ch     4      reserved, should be zero
  51.    10h     4      BX or EBX
  52.    14h     4      DX or EDX
  53.    18h     4      CX or ECX
  54.    1Ch     4      AX or EAX
  55.    20h     2      CPU status flags
  56.    22h     2      ES
  57.    24h     2      DS
  58.    26h     2      FS
  59.    28h     2      GS
  60.    2Ah     2      IP (reserved, ignored)
  61.    2Ch     2      CS (reserved, ignored)
  62.    2Eh     2      SP (ignored when zero)
  63.    30h     2      SS (ignored when zero)
  64.  
  65.    In the following example, I set the registers for the above message   
  66. exchanging function. It's best to clear all registers (or at least    the SS:SP
  67. registers) before using them.
  68.      uses DPMI;
  69.      var
  70.        Regs : TRealModeRegs;
  71.      begin
  72.        FillChar(Regs, SizeOf(TRealModeRegs), #0); {* clear all registers *}    
  73.    with Regs do  begin
  74.          ah := $xx;
  75.          es := PtrRec(RealModeSeg).Seg;
  76.          di := PtrRec(RealModeSeg).Ofs
  77.        end;  { of with }
  78.      end;
  79.    All this is fairly standard. Just set up the registers you interrupts   
  80. expect, very much like the Intr procedure.
  81.  
  82. 4) We can now issue the interrupt in Real mode using the RealModeInt   
  83. procedure (in the DPMI unit). Its definition is
  84.  
  85.      procedure RealModeInt(Int: Byte; var Regs: TRealModeRegs);
  86.  
  87.    Or you can call int 31h, function 0300h, see Ralph Brown's interrupt   
  88. list.    For our message exchanging program it would simply be:
  89.      RealModeInt(xx, Regs);
  90.  
  91. 5) Examine the results. Modified registers are passed in the Regs data   
  92. structure so you can check the results.
  93.  
  94.  
  95. Unsupported interrupts which use the stack
  96. ------------------------------------------
  97. The second type of unsupported interrupts are the ones which make use of the
  98. stack. We can distinguish between:
  99. 1. interrupts which need parameters on the stack
  100. 2. interrupts which return parameters on the stack
  101.  
  102. 1) For the first type we need a modified RealModeInt. Int 31h, function   
  103. 0300h can also copy words from the protected stack to the real mode    stack.
  104. There is an extra compilication, which I had not told yet. As    the stack in
  105. protected mode resides in a protected mode segment it is    unusable for the
  106. real mode interrups. So Borland's DPMI Extender    switches from the protected
  107. to a real mode stack (and back).    We can supply a default real mode stack of
  108. we set the registers in    the real mode register data structure to zero.
  109. Failure to set them up    properly could have disastrous results!
  110.    The RealModeInt in the DPMI unit cannot be used for this situations,    we
  111. have to go the assembler level. Say we want to copy 2 words from    the stack,
  112. and lets say that Regs has been set up:
  113.  
  114.    uses DPMI;
  115.    var
  116.      Regs : TRealModeRegs;
  117.      Value1, Value2 : word;  {* values to pass as stack parameters to *}       
  118.                       {* the interrupt *}
  119.    begin
  120.      {* set up Regs here *}
  121.      asm
  122.        mov     ax,Value1     {* push two values on the protected stack *}      
  123.  push    ax
  124.        mov     ax,Value2
  125.        push    ax
  126.        MOV     BL,Int        {* bl contains the interrupt *}        XOR    
  127. BH,BH         {* clear bh *}
  128.        mov     cx,2          {* cx contains the number of words *}             
  129.                 {* which should be copied from the *}                          
  130.    {* protected mode stack to the real stack *}        LES     DI,Regs       {*
  131. es:di point to regs *}
  132.        MOV     AX,0300H
  133.        INT     31H           {* issue Simulate Real Mode Interrupt *}      end;
  134.    end;
  135.  
  136.    Note that register cx contains the number of stack WORDS (not BYTES)    to
  137. be copied.
  138.  
  139. 2) The most difficult situation I think. A default stack (by setting    SS and
  140. SP to zero) does not suffice. We have to set up a real mode    stack ourselves.
  141. We can get a real mode segment by calling    GlobalDosAlloc and setting SS to
  142. the returned segment and SP to the    size of the allocated memory. An example
  143. is given below, where a    solution to my original problem is given.
  144.  
  145.  
  146. Solution for the dv_win_me procedure:
  147.  
  148.   uses DVAPI, Objects, WinApi, WinTypes, DPMI;
  149.  
  150.   function dv_win_me : longint;
  151.   const
  152.     StackSize = SizeOf(longint);
  153.   var
  154.     Regs : TRealModeRegs;
  155.     RealStackSeg : word;
  156.     RealStackSel : word;
  157.     l : longint;
  158.   begin
  159.   {* allocate a 1 dword stack *}
  160.     l := GlobalDosAlloc(StackSize);
  161.     RealStackSeg := LongRec(l).Hi;
  162.     RealStackSel := LongRec(l).Lo;
  163.  
  164.   {* clear the stack (not necessary) *}
  165.     FillChar(Ptr(RealStackSel, 0)^, StackSize, #0);
  166.  
  167.   {* clear all registers *}
  168.     FillChar(Regs, SizeOf(TRealModeRegs), #0);
  169.  
  170.   {* set registers *}
  171.     with Regs do  begin
  172.       bx := $0001;
  173.       ah := $12;
  174.       ss := RealStackSeg;
  175.       sp := StackSize;
  176.     end;  { of with }
  177.  
  178.   {* perform real mode interrupt *}
  179.     RealModeInt($15, Regs);
  180.     dv_win_me := PLongint(Ptr(RealStackSel, 0))^;
  181.   end;
  182.  
  183.   begin
  184.     writeln(dv_win_me);
  185.   end.
  186.  
  187.  
  188. You see, code size bloats in protected mode! (Therefore you have 16MB....)
  189.  
  190.  
  191. References
  192. ----------
  193. - The usual Borland set of handbooks
  194.  
  195. - "Borland Open Architecture Handbook for Pascal", sold separately by  
  196. Borland, 184 pages.
  197.  
  198. - "Extending Dos, a programmer's Guide to protected-mode dos", Ray   Duncan,
  199. Charles Petzold, Andrew Schulman, M. Steven Baker, Ross P.   Nelson, Stephen R.
  200. Davis and Robert Moote. Addison-Wesly, 1992.   ISBN: 0-201-56798-9
  201.  
  202. - "PC Magazine Programmer's Technical Reference: The Processor and  
  203. Coprocessor", Robert L. Hummel. Ziff-Davis Press, 1992.
  204.   ISBN: 1-56276-016-5
  205.  
  206.  
  207. Berend
  208. fido: 2:281/527.23
  209. email: berend@contrast.wlink.nl
  210.  
  211.