home *** CD-ROM | disk | FTP | other *** search
- Path: sparky!uunet!mcsun!sun4nl!wtrlnd!contrast!postmaster
- From: berend@contrast.wlink.nl (Berend de Boer)
- Newsgroups: comp.lang.pascal
- Subject: Pt 1/2: Protected Mode Tips
- Message-ID: <727633957.AA01185@contrast.wlink.nl>
- Date: Thu, 21 Jan 1993 14:07:04
- Sender: postmaster@contrast.wlink.nl
- Lines: 148
-
- Hello All,
-
- Compiling real to protected mode has been very simple for most of us. Just
- compile and go ahead. 99.5% of your code works fine. But the other 0.5% is
- going to give you some hard, hard work. In this article I describe first how I
- first stuck on the protected stone. Than I try to give a general overview of
- problems one might encounter when using interrupts. Next I describe the
- solutions or give at least some hints. At last I give a solution to the
- original program which made me aware of protected mode conversion problems.
- References can be found at the end of this article. Of course, all disclaimers
- you can come up with apply!
-
-
- When compiling a big program, which supported DesqView, a GP fault occurred. It
- was simple to trace the bug down: TDX would show me the offending code. You can
- get the same error if you try to run the following program in protected mode:
-
- ========cut here==========================
- program Test;
-
- function dv_win_me : longint; assembler;
- asm
- mov bx,0001h
- mov ah,12h
- int 15h {* push dword handle on stack *}
- pop ax {* pop it *}
- pop dx {* and return it *}
- end;
-
- begin
- writeln(dv_win_me);
- end.
- ========cut here==========================
-
- This little program must be run under DesqView. When run under DesqView it
- returns the current window handle on the stack. BUT: when compiled under
- protected mode NO dword handle is returned on the stack. So a stack fault
- occurs.
-
- What happened? I stuck on one of those unsupported interrupts. Only supported
- interupts guarantee to return correct results. You can find a list of all
- supported interrupts in the Borland Open Architecture Handboek for Pascal,
- Chapter 2 (seperate sold by Borland, not included in your BP7 package).
- Supported are the general Dos and Bios interrupts.
-
- Before eleborating on supported and unsupported interrupts, I have to explain a
- few issues which are probably new to us Pascal programmers. Whenever a user
- interrupt occurs in protected mode (you issue a int xx call) Borlands DPMI
- Extender switches to real mode, issues the interrupt, and switches back to
- protected mode.
- This works find for most cases: interrupts which only pass
- register parameters work fine. But what happens if you, for example, called the
- Print String function? (int 21h, ah=09h). You pass it a variable from your Data
- segment. But, this data segment resides in protected mode. And the DS register
- contains a selector. Dos can't work with this, it needs segments, not
- selectors, and the data needs to be below the 1MB boundary.
- So Borland's DPMI Extender does more: it translates selectors to segments when
- appropriate. But, it can only do so for interrupts it knows that they need a
- translation. Such interrupts are called supported. Interrupts about which
- Borland's DPMI Extender does not know about are unsupported. And they are going
- to give you real problems!
-
- So you see, when only some data are passed in registers, everything works fine.
- Selectors cause problems. But why did the above program not work? It didn't use
- selectors you might ask. Well, there is another set of interrupts that are
- unsupported: those that return values on the stack. This is the case with the
- above program.
-
- So, to conclude:
- * supported interrupts
- - simple parameter passing using registers, no segments/selectors or
- stacks included
- - interrupts which Borland's DPMI Extender knows about (too few for most
- of us)
- * unsupported interrupts
- - using segments/selectors
- - involving stacks
-
- I will give code of how to fix both types of problems. Usefull is the DPMI
- unit, which comes with the Open Architecture Handbook. You do not need this
- unit, simply looking the interrupts up in Ralph Brown's interrupts list and
- writing functions/procedures for them, works fine.
-
-
- Unsupported interrupts which need segments
- ------------------------------------------
-
- Because the data segment and stack segment reside in protected mode, you need
- to allocate memory in real mode, copy your data and issue the interrupt by
- calling the DPMI Simulate Real Interrupt. So our to-do list is:
- 1) allocate real mode memory
- 2) copy data from protected mode to real mode
- 3) set up the real mode registers
- 4) issue interrupt
- 5) examine results
-
- 1) You can allocate real mode memory by issueing a GlobalDosAlloc (not
- referenced the online help, although in the manuals) request. The
- GlobalDosAlloc is in the WinApi unit. For example:
- uses WinAPI;
- var
- Return : longint;
- MemSize : longint;
- begin
- MemSize := 1024;
- Return := GlobalDosAlloc(MemSize);
- end;
- This call allocates a block of memory, 1K in size, below the 1MB
- boundary. The value in Return should be split in LongRec(Return).Lo and
- LongRec(Return).Hi. The Hi-order word contains the segment base address of
- the block. The low-order word contains the selector for the block.
-
- 2) You use the selector to acces the block from protected mode and you use
- the segment of the block to acces the block from real mode (your
- interrupt).
- For example: we wanted to exchange messages with some interrupt. The code
- for this would be:
- uses WinAPI;
- var
- Return : longint;
- MemSize : longint;
- RealModeSel : pointer;
- RealModeSeg : pointer;
- Message : string;
- begin
- MemSize := 256;
- Return := GlobalDosAlloc(MemSize);
- PtrRec(RealModeSel).seg := LongRec(Return).Lo;
- PtrRec(RealModeSel).ofs := 0;
- PtrRec(RealModeSeg).seg := LongRec(Return).Hi;
- PtrRec(RealModeSeg).ofs := 0;
-
- {* Both RealModeSel(ector) and RealModeSeg(ment) point to the same
- absolute address now. *}
-
- {* move message below 1MB using a selector *}
- Message := 'How are your?';
- Move(Message, RealModeSel^, SizeOf(Message));
-
- {* issue interupt, explained below *}
- { <..code..> }
- {* the interrupt returns a message *}
-
- {* move interrupt's message below 1MB to protected mode *}
- Move(RealModeSel^, Message, SizeOf(Message));
- writeln(Message); {* "yes, I'm fine. Thank you!" *} end;
-
- <...continued in next message...>
-