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 2/2: Protected Mode Tips
- Message-ID: <727633957.AA01186@contrast.wlink.nl>
- Date: Thu, 21 Jan 1993 15:52:00
- Sender: postmaster@contrast.wlink.nl
- Lines: 201
-
- <continued from previous message>
-
- 3) We will examine how to setup an interrupt for real mode. Most of the time
- this is transparantly done by Borland's DPMI Extender, but we are on our own
- now.
- The Simulate Real Mode Interrupt function needs a real mode register data
- structure. We pass this data structure to this function. Than a switch is
- made to real mode and the contents of the data structure is copied into the
- register, the interrupt is made, registers are copied back to the data
- structure, the processor switches back to protected mode and voila: you are
- in control again.
- Maybe you ask: why need I to setup such a data structure? Why can I not
- simply pass registers? Several reasons exist, but take for example the
- RealModeSeg of the previous example. You cannot simply load a RealModeSeg in
- a register. Most likely a segment violation would occur (referring to a non
- existing segment or you do not have enough rights etc.). Therefore only in
- real mode can real mode segments be loaded.
- The data structure to pass registers between protected and real mode can
- be found in the DPMI Unit which I repeat here:
-
- 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;
-
- This looks reasonably complex, does it! More simply is the following
- structure (found in, for example, "Extending Dos" by Ray Duncan e.a.) Offset
- Lenght Contents
- 00h 4 DI or EDI
- 04h 4 SI or ESI
- 08h 4 BP or EBP
- 0Ch 4 reserved, should be zero
- 10h 4 BX or EBX
- 14h 4 DX or EDX
- 18h 4 CX or ECX
- 1Ch 4 AX or EAX
- 20h 2 CPU status flags
- 22h 2 ES
- 24h 2 DS
- 26h 2 FS
- 28h 2 GS
- 2Ah 2 IP (reserved, ignored)
- 2Ch 2 CS (reserved, ignored)
- 2Eh 2 SP (ignored when zero)
- 30h 2 SS (ignored when zero)
-
- In the following example, I set the registers for the above message
- exchanging function. It's best to clear all registers (or at least the SS:SP
- registers) before using them.
- uses DPMI;
- var
- Regs : TRealModeRegs;
- begin
- FillChar(Regs, SizeOf(TRealModeRegs), #0); {* clear all registers *}
- with Regs do begin
- ah := $xx;
- es := PtrRec(RealModeSeg).Seg;
- di := PtrRec(RealModeSeg).Ofs
- end; { of with }
- end;
- All this is fairly standard. Just set up the registers you interrupts
- expect, very much like the Intr procedure.
-
- 4) We can now issue the interrupt in Real mode using the RealModeInt
- procedure (in the DPMI unit). Its definition is
-
- procedure RealModeInt(Int: Byte; var Regs: TRealModeRegs);
-
- Or you can call int 31h, function 0300h, see Ralph Brown's interrupt
- list. For our message exchanging program it would simply be:
- RealModeInt(xx, Regs);
-
- 5) Examine the results. Modified registers are passed in the Regs data
- structure so you can check the results.
-
-
- Unsupported interrupts which use the stack
- ------------------------------------------
- The second type of unsupported interrupts are the ones which make use of the
- stack. We can distinguish between:
- 1. interrupts which need parameters on the stack
- 2. interrupts which return parameters on the stack
-
- 1) For the first type we need a modified RealModeInt. Int 31h, function
- 0300h can also copy words from the protected stack to the real mode stack.
- There is an extra compilication, which I had not told yet. As the stack in
- protected mode resides in a protected mode segment it is unusable for the
- real mode interrups. So Borland's DPMI Extender switches from the protected
- to a real mode stack (and back). We can supply a default real mode stack of
- we set the registers in the real mode register data structure to zero.
- Failure to set them up properly could have disastrous results!
- The RealModeInt in the DPMI unit cannot be used for this situations, we
- have to go the assembler level. Say we want to copy 2 words from the stack,
- and lets say that Regs has been set up:
-
- uses DPMI;
- var
- Regs : TRealModeRegs;
- Value1, Value2 : word; {* values to pass as stack parameters to *}
- {* the interrupt *}
- begin
- {* set up Regs here *}
- asm
- mov ax,Value1 {* push two values on the protected stack *}
- push ax
- mov ax,Value2
- push ax
- MOV BL,Int {* bl contains the interrupt *} XOR
- BH,BH {* clear bh *}
- mov cx,2 {* cx contains the number of words *}
- {* which should be copied from the *}
- {* protected mode stack to the real stack *} LES DI,Regs {*
- es:di point to regs *}
- MOV AX,0300H
- INT 31H {* issue Simulate Real Mode Interrupt *} end;
- end;
-
- Note that register cx contains the number of stack WORDS (not BYTES) to
- be copied.
-
- 2) The most difficult situation I think. A default stack (by setting SS and
- SP to zero) does not suffice. We have to set up a real mode stack ourselves.
- We can get a real mode segment by calling GlobalDosAlloc and setting SS to
- the returned segment and SP to the size of the allocated memory. An example
- is given below, where a solution to my original problem is given.
-
-
- Solution for the dv_win_me procedure:
-
- uses DVAPI, Objects, WinApi, WinTypes, DPMI;
-
- function dv_win_me : longint;
- const
- StackSize = SizeOf(longint);
- var
- Regs : TRealModeRegs;
- RealStackSeg : word;
- RealStackSel : word;
- l : longint;
- begin
- {* allocate a 1 dword stack *}
- l := GlobalDosAlloc(StackSize);
- RealStackSeg := LongRec(l).Hi;
- RealStackSel := LongRec(l).Lo;
-
- {* clear the stack (not necessary) *}
- FillChar(Ptr(RealStackSel, 0)^, StackSize, #0);
-
- {* clear all registers *}
- FillChar(Regs, SizeOf(TRealModeRegs), #0);
-
- {* set registers *}
- with Regs do begin
- bx := $0001;
- ah := $12;
- ss := RealStackSeg;
- sp := StackSize;
- end; { of with }
-
- {* perform real mode interrupt *}
- RealModeInt($15, Regs);
- dv_win_me := PLongint(Ptr(RealStackSel, 0))^;
- end;
-
- begin
- writeln(dv_win_me);
- end.
-
-
- You see, code size bloats in protected mode! (Therefore you have 16MB....)
-
-
- References
- ----------
- - The usual Borland set of handbooks
-
- - "Borland Open Architecture Handbook for Pascal", sold separately by
- Borland, 184 pages.
-
- - "Extending Dos, a programmer's Guide to protected-mode dos", Ray Duncan,
- Charles Petzold, Andrew Schulman, M. Steven Baker, Ross P. Nelson, Stephen R.
- Davis and Robert Moote. Addison-Wesly, 1992. ISBN: 0-201-56798-9
-
- - "PC Magazine Programmer's Technical Reference: The Processor and
- Coprocessor", Robert L. Hummel. Ziff-Davis Press, 1992.
- ISBN: 1-56276-016-5
-
-
- Berend
- fido: 2:281/527.23
- email: berend@contrast.wlink.nl
-
-