📄 xlib.doc
字号:
CSEGSEL CSEG XLIB 16-bit code segment
CSEGDSEL CSEG Data selector to CSEG
TSEGSEL TSEG 32-bit code segment
TSEGDSEL TSEG Data selector to TSEG
DSEGSEL DSEG XLIB data segment
FLATSEL . Flat-model code selector
FLATDSEL . Flat-model data selector
DGROUPSEL DGROUP DGROUP data group
SCRNSEL . Screen data (color or monochrome)
-----------------------------------------------------------------------------
The flat-model and TSEG descriptors have limit FFFFFFFFH. All other
descriptors have limit FFFFH. The screen descriptor has base set to B8000H
for color monitors and B0000H for monochrome monitors. The data descriptors
have their big bits set; consequently, implicit stack instructions will use
ESP rather then SP. All code segments are readable and nonconforming.
3
Descriptor privilege levels and requested privilege levels are set to zero
unless DPMI is installed. Privilege levels under DPMI will be dictated by the
DPMI host, but will generally be set to three.
The values contained in the above selectors will be different under DPMI
than other environments. Moreover, DPMI selectors values can differ under
different DPMI environments depending upon the DPMI host and the presence of
other DPMI clients. The user should therefore always read selector values
from these locations.
Since selectors are contained in DSEG, the user must never lose track of
the DSEG selector. This could prove a problem in interrupt handlers where no
assumptions can be made as to segment register contents. Consequently, XLIB
places a copy of the DSEG selector in TSEG where it can always be found. It
is stored under WORD symbol CSDSEGSEL and may be read with CS segment
override. For example from TSEG code you can always load DS with DSEGSEL
using MOV DS,CS:CSDSEGSEL.
TSEG may be larger than 64K provided that certain rules are observed.
First, only 32-bit protected-mode code should be placed in TSEG. The
processor will not generally be able to execute real-mode code in this segment
because the offsets will be 32-bit values. Second, real-mode code should
never write to or read from TSEG. Such instructions will also require 32-bit
offsets. If you need to make modifications to TSEG, then do them from a TSEG
protected-mode procedure. Finally, never encode segment constants in TSEG.
For example, the symbols CSEG, TSEG, DSEG, and DGROUP should never be found in
TSEG. DOS will not be able to perform relocation fixups on these constants if
they are in a segment larger than 64K. To read these values from TSEG,
initialize memory locations in a 16-bit segment to the values and then read
the memory locations. Memory locations in DSEG have already been initialized
for XLIB segments. See Appendix A.
4
3. Mode Switching
As illustrated in Example 1, CALLPM may be used to transfer control to
protected mode. When execution is returned to real mode after CALLPM, only
segment registers and ESP are restored to their original values. Real mode
receives other registers (except EFLAGS) at values as of the protected-mode
RET instruction. Control may be returned from protected mode to real mode
either by RET or by a near jump to RETPM (return from protected mode). RETPM
is an XLIB procedure which successfully returns control to real mode
regardless of stack state.
Execution may also be transferred to protected mode with the ENTERPM
(enter protected mode) procedure. This procedure is specially designed to
accommodate mixed language programming with high-level languages operating in
real mode. High-level language modules may be linked with libraries
containing protected-mode procedures. These procedures may then be called
from high-level code. However, such procedures must generally be careful to
preserve register state. ENTERPM restores register state as required by
Microsoft high-level languages. In particular, ENTERPM restores all 16-bit
and 32-bit registers (including system and control flags in EFLAGS) except EAX
and EDX. EAX and EDX are not restored since these are typically used by high-
level languages for return values. ENTERPM otherwise functions exactly as
CALLPM.
Both CALLPM and ENTERPM save register state as of call; however, upon
return to real mode, CALLPM restores only segment registers and ESP while
ENTERPM restores all registers except EAX and EDX. CALLPM and ENTERPM will
also save and restore the state of the floating point unit (FPU) if requested.
FPU save/restore can be enabled by setting bit 2 of OFLAGS (operation flags).
The bit is clear by default. OFLAGS is a public WORD in DSEG.
FPU state is saved with the FSAVE instruction executed from real mode.
This instruction resets the FPU; consequently, the FPU control word must be
redefined. XLIB will therefore load FPUCW (FPU control word) to the FPU
control word after performing FSAVE. FPUCW is a public WORD location in DSEG.
FPU state is restored with the FRSTOR instruction executed in real mode.
Control may be returned to real mode after ENTERPM either with the RET
instruction or by a near jump to EXITPM. EXITPM will return control to real
mode regardless of stack state.
The return address placed on the stack by CALLPM is actually a near
return to RETPM. Likewise, ENTERPM places a near return to EXITPM. CALLPM
and ENTERPM are otherwise identical procedures. EXITPM restores all registers
except EAX and EDX. RETPM restores only segment registers and ESP.
CALLPM and ENTERPM save registers to public locations in DSEG. The
following table specifies the symbols under which the registers are stored.
The calling stack is always saved after the real-mode return address and the
protected-mode target address have been popped from it.
5
Table 2: CALLPM/ENTERPM Register Storage Locations by Public Symbol
-----------------------------------------------------------------------------
Register Symbol Symbol Type
EBX ORGEBX DWORD
ECX ORGECX DWORD
ESI ORGESI DWORD
EDI ORGEDI DWORD
EBP ORGEBP DWORD
ESP ORGESP DWORD
EFLAGS ORGEFLAGS DWORD
SS ORGSS WORD
DS ORGDS WORD
ES ORGES WORD
FS ORGFS WORD
GS ORGGS WORD
FPU State ORGFPU BYTE[94]
-----------------------------------------------------------------------------
The protected-mode targets of CALLPM and ENTERPM receive the XLIB
protected mode stack (SS = TSEGSEL) with 1000H bytes of free space. The
target also receives DS = FLATDSEL (flat-model data selector), ES = TSEGDSEL
(TSEG data selector), FS = DSEGSEL (DSEG selector), and GS = DGROUPSEL (DGROUP
selector). The target procedure may switch stacks if desired.
Once within protected mode, far procedures in real mode can be called
using CALLRM (call real mode), which is a near procedure in TSEG. CALLRM
should be called with the real-mode target address on the stack (push segment
first) CALLRM saves and restores only segments registers and ESP. The target
address receives the XLIB real-mode stack (SS = DSEG) with 200H free bytes, DS
= DGROUP, and ES = DSEG. Code called by this routine cannot perform XLIB
shifts back to protected mode. This excludes usage of the XLIB memory
management procedures and XLIB interrupt-vector management procedures since
these require protected-mode execution.
CALLRM saves segment registers and ESP at public locations in DSEG. The
following table specifies the symbols under which the registers are stored.
The calling stack is saved after popping the protected-mode near return and
the real-mode target address.
Table 3: CALLRM Register Storage Locations by Public Symbol
-----------------------------------------------------------------------------
Register Symbol Symbol Type
ESP CALLESP DWORD
SS CALLSS WORD
DS CALLDS WORD
ES CALLES WORD
FS CALLFS WORD
GS CALLGS WORD
-----------------------------------------------------------------------------
6
4. Interrupt Management
XLIB handles nearly all interrupts occurring in protected mode by
shifting to real mode and calling the inherited real-mode interrupt handlers.
All interrupts are handled this way except the keyboard interrupt (IRQ 1) and
the FPU interrupt (IRQ 13). XLIB has its own handlers for these routines.
These handlers are activated as of protected-mode entry through CALLPM or
ENTERPM. They remain active during calls back to real mode through CALLRM.
They are disabled upon return to CALLPM/ENTERPM. The user may replace or
disable these handlers if desired.
It is generally desirable for the user to be able to terminate a program
or subroutine with a certain keypress combination. Unfortunately, it is
difficult to safely abort protected-mode execution from an interrupt handler.
This is particularly the case under DPMI. The DPMI host traps all interrupts
before transferring control to the interrupt handler. If control is not
returned back to the host with an IRET instruction, the host will be left in
an irregular and potentially unstable state. Similar problems could occur
under a VCPI multitasking control program. Consequently, a keyboard interrupt
handler cannot be safely used to immediately abort execution upon a keypress.
The XLIB keyboard interrupt handler provides the best alternative. The
handler examines keyboard input to determine if a user definable hot key has
been pressed. If a pressed key is not the hot key, the interrupt handler
cascades the interrupt to the inherited real-mode handler. If the hot key is
pressed, then a flag is placed in a DWORD condition code whose linear address
is stored in CCODEPTR (condition code pointer). CCODEPRR is a public DWORD in
DSEG. The condition code may then be polled by code in the main thread of
execution where termination can be safely accomplished. The hot key is not
cascaded.
The hot key specification is stored in DSEG at a public WORD location
called HOTKEY. The lower byte of HOTKEY contains the scan code of the hot key
while the upper byte specifies the state of the shift keys. Bit 8 specifies
the state of SHIFT; bit 9 specifies CTRL, and bit 10 specifies ALT. All other
bits are ignored. Set bits require that the designated shift key be pressed.
The default setting for HOTKEY is 022EH (CTRL C). The condition code flag for
the hot key is included among XLIB error codes in Appendix C.
By default CCODEPTR contains the linear address to public DWORD location
CCODE which is in DSEG. Therefore, the hot key flag would be written to CCODE
by default. CCODEPTR may be changed by the user; however, it must point to an
address in conventional memory.
The XLIB interrupt handler for the FPU performs three functions upon the
occurrence of any FPU exception that is unmasked in the FPU control word.
First, an error code is loaded to EAX and is also recorded at the linear
address in CCODEPTR. Next, the FPU is initialized with FNINIT (the FPU
control word is preserved). Third, control is transferred to EXITPM to return
to real mode. The high word stored in EAX and the condition code will be the
FPU status word. This word may be examined to determine the nature of the
exception.
The response of the FPU to exception conditions is largely determined by
the settings in the FPU control word. If FPU save/restore is enabled, then
the FPU control word will be set to FPUCW upon execution of CALLPM/ENTERPM.
The default value for FPUCW is 0332H. This sets rounding control to nearest,
precision control to 64 bits, and unmasks exceptions for overflow, zero
divide, and invalid operations. Exceptions for underflow, precision, and
7
denormalized operations are masked, and are therefore handled internally by
the FPU. FPUCW may be modified by the user.
As explained above, the machine may be left in an unstable state after
code has been terminated from within an interrupt handler. This is also the
case for the FPU interrupt handler. If an FPU exception occurs under DPMI or
under a VCPI-based multitasker, then the machine may need rebooting. Most
DPMI hosts appear to be restored to normal state by execution of INT 21
function 4CH (DOS termination). However, this approach is not recommended in
the DPMI specifications, and should be particularly suspect under a
multitasker. It is generally safe to continue execution after an FPU
exception when running in a single-task environment under VCPI or when running
in the absence of both DPMI and VCPI. The user may therefore wish to debug
FPU code in these sorts of environments.
Bit 0 of OFLAGS is used by XLIB to simultaneously enable or disable all
of its own interrupt handlers. Setting the bit enables the handlers. XLIB
sets this bit upon calls to CALLPM/ENTERPM and clears the bit upon return.
All interrupts are cascaded to the inherited real-mode handlers when the bit
is clear.
The keyboard interrupt handler may be permanently disabled by setting
HOTKEY to zero. This follows since no key has a zero scan code. With HOTKEY
= 0, all keyboard interrupts are cascaded to the inherited real-mode handler.
The FPU exception handler may be permanently disabled by setting bit 1 in
OFLAGS. If this bit is set, then the FPU interrupt handler simply cascades
the interrupt to the inherited real-mode handler. XLIB will set the bit
during initialization if an FPU is not present; it is otherwise cleared.
Real-mode software interrupts which receive or return values in segment
registers cannot be used within protected mode because the deflection routine
will restore selectors to segment registers upon completion of the interrupt.
To use such software interrupts, one must switch to real mode through CALLRM;
issue the interrupt, and then transfer the segment registers to other
registers before returning to protected mode.
The user may install real-mode interrupt handlers in usual fashion. Such
handlers will also receive interrupts occurring in protected mode provided
that the protected-mode handlers cascade the interrupt. Protected-mode
interrupts will be deflected to real mode either by XLIB or by the DPMI host.
If XLIB deflects the interrupt, then the handler will receive SS = DSEG with
ESP set to 200H free bytes. Stack sizes under DPMI will depend upon the host.
The DOS routines to get and set interrupt vectors (INT 21H functions 35H
and 25H) receive and return values through segment registers; consequently,
they cannot be used in protected mode. Instead, use the XLIB procedures
PMGETRMIV and PMSETRMIV (protected mode - get/set real-mode interrupt vector).
Call PMGETRMIV with the interrupt number in AL. The handler address is
returned in CX:DX. Call PMSETRMIV with the interrupt number in AL and the new
handler address in CX:DX.
The user may install a protected-mode interrupt handler from real mode by
calling SETPMIV (set protected-mode interrupt vector). Call with the
interrupt number in AL and the address of the new handler in CX:EDX (CX is a
selector). This routine returns an error code in EAX (EAX returned as zero if
successful). The current protected-mode interrupt vector may be obtained by
calling GETPMIV. Call with AL equal to the interrupt number. The current
handler address is returned in CX:EDX. This routine is always successful.
These routines should not be used to manage vectors for CPU exceptions when
DPMI is active. Direct calls to DPMI functions should be executed for these
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -