Haill!
Once you wrote to me:
JW>>>> mov ax,0
JW>>>> mov ds,ax ;DS =
JW>>>> mov word ptr [ds:0b8142h],8403h
DG>>> Out of idle curiosity, what happens if you try this without
DG>>> himem.sys loaded?
SS>> #GP will be generated.
DG> No kidding.
I'm serious -- it'll cause #GP (int 0Dh) even in real mode.
DG>>> I ask, because I have been reading Intel specs for years,
DG>>> and haven't got a clue what this "Big Real" mode is
DG>>> supposed to be.
SS>> It is still undocumented by Intel of course. :)
DG> I'm from Missouri. What is the opcode mnemonic to switch to this mode?
_Opcodes_ you mean. There's no special opcodes, just plain vanilla ones.
)
Here's the short example (with my comments in []):
- - - - 8<- - - - - 8<- - - - - 8<- - - - - 8<- - - - - 8<- - - - - 8<- - - -
-
.model tiny
.code
org 100h
.386p
;
; How to setup the BIG REAL MODE
; Copyright (C) Aleksandr K. Konosevich, 1997, V 0.2
; Note : this example sets 4Gb limit _for_all_segment_registers_
;
start:
dd 0E0010F66h ;)
; [this is the SMSW EAX
; instruction, using it isn't
; necessary but there's smth
; interesting about the way
t
; works :)]
test al, 01h ; [CR0.PE=1?]
jnz exit ; [forget it, we're in V86]
mov edx, cs ;)
; [MOV Reg32,SegReg clears
he
; high word of Reg32]
push ss ;(
shl edx, 4
add dword ptr GDT_base, edx ; [adjust GDT base]
or dword ptr CS_base, edx ;)
; [and flat segment's base
too]
inc ax ; [set CR0.PE]
cli
lgdt qword ptr GDT_base-2 ;)
; [dirty trick (: GDT limit
; will be set to 21CDh (int
21h
; opcode) which is quite
enough
; for us]
mov cr0, eax ; [enter PM]
mov dx, 08h ; [GDT descriptor 1: flat 4G
; data segment]
mov ds, dx ; [load it into
DS,ES,FS,GS,SS]
mov es, dx
mov gs, dx
mov fs, dx
mov ss, dx
or byte ptr CS_base+3, dl ;)
; [now turn the data segment
; into the code segment]
db 0EAh ; [and do a FAR jump]
dw offset set_CS ; [to load CS from 4G flat]
dw 8 ; [segment descriptor]
set_CS:
dec ax ; [clear CR0.PE]
mov cr0, eax ; [enter RM again]
pop ss ;(
; [SS needs to be restored,
; remember: CPU even in RM
uses
; the segment base from the
; segment descriptor caches,
; and ignores the segment
; registers' contents, so POP
; as well as any other memory
; reference works relative to
; the program load address, ;
not 80h as you may judge ; by
the current segment
; registers' contents ;) ]
exit:
mov ah, 4Ch ; [we did it! but CS!=PSP, so
; we can't use INT 20h or
ETN
; to exit]
int 21h
GDT_base dd offset GDT_base-4 ;)
; [those -4 is for the "null
; descriptor -- it's contents
; is irrelevant to the CPU]
dw 0FFFFh ; [low word of the
descriptor's
; limit]
CS_base dd 92000000h ; [writeable data segment]
dw 008Fh ; [with 4K granularity]
end start
- - - - 8<- - - - - 8<- - - - - 8<- - - - - 8<- - - - - 8<- - - - - 8<- - - -
-
Well, about that SMSW EAX thing: on Intel CPUs it functions just like MOV
EAX,CR0 except it doesn't generate #GP when executed not on the CPL0 (and in
V86 mode) -- it returns not only low word of CR0 (i.e. 286's MSW) but its
high word too, including CR0.PG and other 386+ bits. On Intel clones like AMD
this bug has been fixed, so the high word is always 0. BTW, when you check
for V86 from a DOS program, always use SMSW and never MOV Reg32,CR0 beacuse
the latter will generate #GP which some VM monitors (e.g. Win3.x/Win'95)
handle rather improperly -- the just skips the whole instruction not changing
Reg32 contents!
DG>>> There are 2 modes on Intel 32-bit CPUs, 16 and 32. The
DG>>> former has one flavour only, and looks basically like one
DG>>> big DOS machine,
SS>> Plain RM but not BRM: first, the segment limits may be
SS>> set to 4G (or anything you like); second, you can change
SS>> B-bit in the segment descriptor caches so you segments can
SS>> be 32-bit even in RM (and AFAIK this can be done even with
SS>> CS though requires some tricks for correct interrupt
SS>> entering/ exitting)!
DG> No kidding, particularly since descriptors don't exist in "real" mode.
Actually they do: the "descriptor caches" are still here and working.
Reloading the segment register in RM usually reloads only the segment's base
address in those caches, leaving segment limits unchanged; the other fiels
could be changed by entering PM and loading the segment registers with
appropriate selectors, and the exiting to RM as in the above example. Well,
here's some stuff about those things by Robert Collins:
- - - - 8<- - - - - 8<- - - - - 8<- - - - - 8<- - - - - 8<- - - - - 8<- - - -
-
Page 60,132
Title Descriptor Cache Anomalies
;-----------------------------------------------------------------------------
;
; DESC32.ASM
;
; Copyright (c) 1991, 1995-Present Robert Collins
;
; You have my permission to copy and distribute this software for
; non-commercial purposes. Any commercial use of this software or
; source code is allowed, so long as the appropriate copyright
; attributions (to me) are intact, *AND* my email address is properly
; displayed.
;
; Basically, give me credit, where credit is due, and show my email
; address.
;
;-----------------------------------------------------------------------------
;
; Robert R. Collins email: rcollins@x86.org
;
;-----------------------------------------------------------------------------
; DESCRIPT.ASM -- Prove that anomalies exist in the real mode definition of
; the descriptor cache registers. Intel states that all of
; these registers get default, fixed values when loaded in
; real mode. This is not the case, and this source code
; will attempt to prove that.
;
; Unfortunately, most of these cases are impossible to prove
; under software control -- and can only be proven using an
; Intel ICE.
;
;-----------------------------------------------------------------------------
;
; +-----------------------------------------------+
; | Descriptor Cache contents: Real-Mode |
; | |
; | Operand size(*)-------------------------+ |
; | Granularity(*)------------------------+ | |
; | Accessed----------------------------+ | | |
; | Read/Write------------------------+ | | | |
; | Expansion direction-------------+ | | | | |
; | Executable--------------------+ | | | | | |
; | Code/Data Segment?----------+ | | | | | | |
; | Privilege level----------++ | | | | | | | |
; | Present----------------+ || | | | | | | | |
; | | || | | | | | | | |
; | Base Addr Limit | || | | | | | | | |
; | ---+------------+---------+-+--+-+-+-+-+-+-+-+|
; | CS |16xSeg. Reg.| Honored |Y| H|Y|H|H|Y|Y|-|H||
; | ---+------------+---------+-+--+-+-+-+-+-+-+-+|
; | SS |16xSeg. Reg.| Honored |H| H|Y|H|H|H|Y|-|-||
; | ---+------------+---------+-+--+-+-+-+-+-+-+-+|
; | DS |16xSeg. Reg.| Honored |H| H|Y|H|H|H|Y|-|-||
; | ---+------------+---------+-+--+-+-+-+-+-+-+-+|
; | ES |16xSeg. Reg.| Honored |H| H|Y|H|H|H|Y|-|-||
; | ===+============+=========+=+==+=+=+=+=+=+=+=+|
; | FS |16xSeg. Reg.| Honored |H| H|Y|H|H|H|Y|-|-||
; | ---+------------+---------+-+--+-+-+-+-+-+-+-+|
; | GS |16xSeg. Reg.| Honored |H| H|Y|H|H|H|Y|-|-||
; | ---+------------+---------+-+--+-+-+-+-+-+-+-+|
; | |
; | Y=Yes (1) |
; | N=No (0) |
; | U=Up (0) |
; | B=Byte (0) (*)=386 and 486 only |
; | S=16-bit (0) (*)=386 and 486 only |
; | H=Honored. Whenever the segment gets loaded, |
; | the contents of this field don't |
; | change. |
; | -=Not applicable |
; | |
; +-----------------------------------------------+
;
- - - - 8<- - - - - 8<- - - - - 8<- - - - - 8<- - - - - 8<- - - - - 8<- - - -
-
The whole source is available at ftp.x86.org (or I could post it here).
DG>>> If you try this code in 16-bit mode, you will definitely
DG>>> get a CPU exception,
SS>> You won't, if you use those BRM tricks. :)
DG> Show me the opcodes.
Well, after executing the above exapmle in RM (not in V86 mode, of course)
you'll be able to access the data beyond 64K segment limits using any segment
prefix.
DG>>> I can't recall the number, but it will be a segment
DG>>> boundary violation.
SS>> Int 13 - GP fault (#GP).
DG> General protection fault in native mode; in "real" mode, only a segment
DG> boundary violation generates the interrupt.
But it's the same #GP, isn't it? :)
DG>>> It is possible that Himem.sys traps that exception... kicks the
DG>>> system into 32-bit mode,
SS>> No, it "kicks the system" to PM,
DG> "Protected" mode = native mode = 32-bit mode.
It uses 16-bit mode as it just doesn't need 32-bit mode to load DS/ES with
the flat segment's descriptor and exit PM.
SS>> then loads DS/ES with 4G
SS>> segment selector, then returns to RM. The new segment
SS>> limits are honored in RM
DG> Selectors do not even exist in "real" mode.
1) don't confuse the selectors and the descriptors;
2) don't confuse segment descriptrs in the GDT/LDT, and their "mirrors" in
the segment "shadow registers" (AKA descriptor caches), the latter do exist
even in RM.
SS>> -- segment reg. re-loads doesnt'
SS>> change them. That's why it all works after HiMem does a
SS>> block move.
DG> Time to disassemble himem.sys, I think.. more likely the INT D trap in
DG> himem performs the block move, then returns to "real" mode.
Well, try this. I'm posting XM386.ASM (HiMem 386+ memory move part) in the
next message(s)...
Farewell!
--- GoldED 2.50+
---------------
* Origin: Six To Go (FidoNet 2:5020/157.59)
|