[ Usenet FAQs | Web FAQs | Documents | RFC Index ]
Part1 - Part2 - Part3 - Single Page
Top Document: x86 Assembly Language FAQ - General Part 2/3
Previous Document: News Headers
Next Document: 16. What Is Available at developer.intel.com
-
Search the FAQ Archives
Part1 - Part2 - Part3 - Single Page
Top Document: x86 Assembly Language FAQ - General Part 2/3
Previous Document: News Headers
Next Document: 16. What Is Available at developer.intel.com
15. Accessing 4 Gigs of Memory in Real Mode
Flat real mode is a popular name for a technique used to access up to 4
GB of memory, while remaining in real mode. This technique requires a
80386 or higher processor. The address space really is not flat.
Actually, this technique allows you treat one or more segments as large
(32-bit) segments, thereby accessing memory above 1 MB.
When the CPU accesses memory, the base address of the segment used is
not described by the value currently in the appropriate register. The
value is stored internally in a structure known as the descriptor cache.
Changing the value of a segment register results in that segment's entry
in the descriptor cache being recalculated according to the rules of the
current mode. In real mode, the value of the segment register is
shifted left four bits to find the base address of the segment, and the
size of the segment is always 64k. In protected mode, the value in the
segment register is used as an index into a descriptor table located in
memory, and the base address and size (which may be as small as 4 KB, or
as large as 4 GB) from the descriptor table are loaded into the
descriptor cache.
When the processor changes modes, the contents of the processor's
internal descriptor cache are not changed. The reason is because
changing them would result in (at the very least) the code segment being
recalculated according to the new mode's rules, most likely causing your
program to crash. Thus the program must load the segment registers with
sensible values after the mode switch occurs. Consider an example where
real mode code is located in segment 1000h. If switching modes caused
an immediate recalculation of the descriptor cache, the processor would
attempt to read entry 1000h of the descriptor table immediately upon
switching to protected mode. Even if this were a valid descriptor
(unlikely), it would have to have a base address identical to real mode
segment 1000h (i.e., 10000h), and a size limit of 64 KB to prevent a
probable crash. An invalid descriptor would cause an immediate
processor exception.
Normally, aside from preventing situations like that in the above
example, there is little to be said about this feature. After all, as
soon as you reload new values into the segment register, the descriptor
cache entry for that segment will be reset according to the rules of the
current mode. After switching from protected mode to real mode,
however, when you load the segment registers with their new values, the
segment's base address is recalculated according to real mode rules, but
the size limit is not changed. After setting the 4 GB limit (which must
be done in protected mode), it will stay in place until changed by
another protected mode program, regardless of what values are loaded in
the segment register in real mode.
So, the steps to using this technique are as follows:
1. Set up a bare bones global descriptor table, with a null entry,
and a single entry for a 4 GB segment. The base address of this segment
is not important.
2. If you don't wish to define an interrupt descriptor table (IDT),
you must disable interrupts before switching to protected mode. You do
not need a full-fledged protected mode environment for this, so it is
easiest just to disable interrupts and not worry about the IDT.
3. Switch to protected mode.
4. Load the segment registers you wish to change with the selector
for the 4 GB segment. I recommend using FS and/or GS for this purpose,
for reasons I'll describe below.
5. Return to real mode.
6. Re-enable interrupts.
After these steps, you can then load your segment registers with any
value you wish. Keep in mind that the base address will be calculated
according to real mode rules. Loading a value of 0 into a segment
register will result in a 4 GB segment beginning at physical address 0.
You can use any of the usual 32-bit registers to generate offsets into
this segment.
Some points to keep in mind:
1. Some software depends on 64 KB segment wrap-around. While rare,
it is possible that you will encounter software that crashes if the
older segments (DS or ES) are 4 GB in size. For that reason, I
recommend only using FS and/or GS for this purpose, as they are not used
as widely as the others.
2. You should never change the limit of the code segment. The
processor uses IP (not EIP) to generate offsets into the code segment in
real mode; any code beyond the 64 KB mark would be inaccessible,
regardless of the segment size.
3. You should never change the limit of the stack segment. This is
similar to the above; the processor uses SP in real mode, rather than
ESP.
4. Because of the necessity of switching to protected mode, this
technique will not work in a virtual 8086 mode "DOS box" from Windows,
OS/2, or any other protected mode environment. It only works when you
start from plain, real mode DOS. Many memory managers also run DOS in
V86 mode, and prevent the switch to protected mode. It is possible to
use VCPI to work around this, but if you go to that length you will
probably find that you have implemented a complete protected mode
environment, and would not need to return to real mode anyway.
5. This technique will not work in the presence of any protected
mode software that changes segment size limits. When that software
returns control to your real mode program, the limits will be the values
to which the protected mode code set them. If these limits are
different that what your program used, problems can result. At the very
least, your program will return incorrect results when accessing data
stored in extended memory. At worst, your program will crash and burn.
The benefits of this technique are many. Most importantly, you can
access extended memory without resorting to slow BIOS calls or having to
implement a complete DOS extender. If your program uses interrupts
extensively (timer interrupts for animation or sound, for example), real
mode is a better choice because protected mode handles interrupts
slower. DOS itself uses this technique in HIMEM.SYS as a fast,
practical method of providing access to extended memory.
Code demonstrating this technique is available:
ftp://x2ftp.oulu.fi/pub/msdos/programming/memory/realmem.zip
For further reading on this topic, I suggest "DOS Internals," by Geoff
Chappell. It is published by Addison-Wesley as part of the Andrew
Schulman Programming Series. The ISBN number is 0-201-60835-9.
Contributor: Sherm Pendley, grinch@access.mountain.net
Last changed: 15 Jan 95
Top Document: x86 Assembly Language FAQ - General Part 2/3
Previous Document: News Headers
Next Document: 16. What Is Available at developer.intel.com
Part1 - Part2 - Part3 - Single Page
[ Usenet FAQs | Web FAQs | Documents | RFC Index ]
Send corrections/additions to the FAQ Maintainer:
raymoon@moonware.dgsys.com
Last Update October 22 2009 @ 05:22 AM