home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1993 #3 / NN_1993_3.iso / spool / comp / lang / pascal / 8436 < prev    next >
Encoding:
Internet Message Format  |  1993-01-22  |  6.3 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 1/2: Protected Mode Tips
  5. Message-ID: <727633957.AA01185@contrast.wlink.nl>
  6. Date: Thu, 21 Jan 1993 14:07:04
  7. Sender: postmaster@contrast.wlink.nl
  8. Lines: 148
  9.  
  10. Hello All,
  11.  
  12. Compiling real to protected mode has been very simple for most of us. Just
  13. compile and go ahead. 99.5% of your code works fine. But the other 0.5% is
  14. going to give you some hard, hard work. In this article I describe first how I
  15. first stuck on the protected stone. Than I try to give a general overview of
  16. problems one might encounter when using interrupts. Next I describe the
  17. solutions or give at least some hints. At last I give a solution to the
  18. original program which made me aware of protected mode conversion problems.
  19. References can be found at the end of this article. Of course, all disclaimers
  20. you can come up with apply!
  21.  
  22.  
  23. When compiling a big program, which supported DesqView, a GP fault occurred. It
  24. was simple to trace the bug down: TDX would show me the offending code. You can
  25. get the same error if you try to run the following program in protected mode:
  26.  
  27. ========cut here==========================
  28. program Test;
  29.  
  30. function  dv_win_me : longint;  assembler;
  31. asm
  32.   mov    bx,0001h
  33.   mov    ah,12h
  34.   int    15h       {* push dword handle on stack *}
  35.   pop    ax        {* pop it *}
  36.   pop    dx        {* and return it *}
  37. end;
  38.  
  39. begin
  40.   writeln(dv_win_me);
  41. end.
  42. ========cut here==========================
  43.  
  44. This little program must be run under DesqView. When run under DesqView it
  45. returns the current window handle on the stack. BUT: when compiled under
  46. protected mode NO dword handle is returned on the stack. So a stack fault
  47. occurs.
  48.  
  49. What happened? I stuck on one of those unsupported interrupts. Only supported
  50. interupts guarantee to return correct results. You can find a list of all
  51. supported interrupts in the Borland Open Architecture Handboek for Pascal,
  52. Chapter 2 (seperate sold by Borland, not included in your BP7 package).
  53. Supported are the general Dos and Bios interrupts.
  54.  
  55. Before eleborating on supported and unsupported interrupts, I have to explain a
  56. few issues which are probably new to us Pascal programmers. Whenever a user
  57. interrupt occurs in protected mode (you issue a int xx call) Borlands DPMI
  58. Extender switches to real mode, issues the interrupt, and switches back to
  59. protected mode.
  60. This works find for most cases: interrupts which only pass
  61. register parameters work fine. But what happens if you, for example, called the
  62. Print String function? (int 21h, ah=09h). You pass it a variable from your Data
  63. segment. But, this data segment resides in protected mode. And the DS register
  64. contains a selector. Dos can't work with this, it needs segments, not
  65. selectors, and the data needs to be below the 1MB boundary.
  66. So Borland's DPMI Extender does more: it translates selectors to segments when
  67. appropriate. But, it can only do so for interrupts it knows that they need a
  68. translation. Such interrupts are called supported. Interrupts about which
  69. Borland's DPMI Extender does not know about are unsupported. And they are going
  70. to give you real problems!
  71.  
  72. So you see, when only some data are passed in registers, everything works fine.
  73. Selectors cause problems. But why did the above program not work? It didn't use
  74. selectors you might ask. Well, there is another set of interrupts that are
  75. unsupported: those that return values on the stack. This is the case with the
  76. above program.
  77.  
  78. So, to conclude:
  79. * supported interrupts
  80.   - simple parameter passing using registers, no segments/selectors     or
  81. stacks included
  82.   - interrupts which Borland's DPMI Extender knows about (too few for     most
  83. of us)
  84. * unsupported interrupts
  85.   - using segments/selectors
  86.   - involving stacks
  87.  
  88. I will give code of how to fix both types of problems. Usefull is the DPMI
  89. unit, which comes with the Open Architecture Handbook. You do not need this
  90. unit, simply looking the interrupts up in Ralph Brown's interrupts list and
  91. writing functions/procedures for them, works fine.
  92.  
  93.  
  94. Unsupported interrupts which need segments
  95. ------------------------------------------
  96.  
  97. Because the data segment and stack segment reside in protected mode, you need
  98. to allocate memory in real mode, copy your data and issue the interrupt by
  99. calling the DPMI Simulate Real Interrupt. So our to-do list is:
  100. 1) allocate real mode memory
  101. 2) copy data from protected mode to real mode
  102. 3) set up the real mode registers
  103. 4) issue interrupt
  104. 5) examine results
  105.  
  106. 1) You can allocate real mode memory by issueing a GlobalDosAlloc (not   
  107. referenced the online help, although in the manuals) request. The   
  108. GlobalDosAlloc is in the WinApi unit. For example:
  109.      uses WinAPI;
  110.      var
  111.        Return : longint;
  112.        MemSize : longint;
  113.      begin
  114.        MemSize := 1024;
  115.        Return := GlobalDosAlloc(MemSize);
  116.      end;
  117.    This call allocates a block of memory, 1K in size, below the 1MB   
  118. boundary. The value in Return should be split in LongRec(Return).Lo    and
  119. LongRec(Return).Hi. The Hi-order word contains the segment base    address of
  120. the block. The low-order word contains the selector for    the block.
  121.  
  122. 2) You use the selector to acces the block from protected mode and you    use
  123. the segment of the block to acces the block from real mode (your   
  124. interrupt).
  125.    For example: we wanted to exchange messages with some interrupt. The    code
  126. for this would be:
  127.      uses WinAPI;
  128.      var
  129.        Return : longint;
  130.        MemSize : longint;
  131.        RealModeSel : pointer;
  132.        RealModeSeg : pointer;
  133.        Message : string;
  134.      begin
  135.        MemSize := 256;
  136.        Return := GlobalDosAlloc(MemSize);
  137.        PtrRec(RealModeSel).seg := LongRec(Return).Lo;
  138.        PtrRec(RealModeSel).ofs := 0;
  139.        PtrRec(RealModeSeg).seg := LongRec(Return).Hi;
  140.        PtrRec(RealModeSeg).ofs := 0;
  141.  
  142.      {* Both RealModeSel(ector) and RealModeSeg(ment) point to the same        
  143. absolute address now. *}
  144.  
  145.      {* move message below 1MB using a selector *}
  146.        Message := 'How are your?';
  147.        Move(Message, RealModeSel^, SizeOf(Message));
  148.  
  149.      {* issue interupt, explained below *}
  150.      { <..code..> }
  151.      {* the interrupt returns a message *}
  152.  
  153.      {* move interrupt's message below 1MB to protected mode *}       
  154. Move(RealModeSel^, Message, SizeOf(Message));
  155.        writeln(Message);     {* "yes, I'm fine. Thank you!" *}      end;
  156.  
  157. <...continued in next message...>
  158.