Real Mode: Difference between revisions
[unchecked revision] | [unchecked revision] |
(Fixed pseudocode (it was totally broken), added a note to the example code.) |
|||
Line 146: | Line 146: | ||
=== External Links === |
=== External Links === |
||
* [http://www.osdever.net/tutorials/rm_addressing.php?the_id=50 The Workings of: x86-16/32 RealMode Addressing] |
* [http://www.osdever.net/tutorials/rm_addressing.php?the_id=50 The Workings of: x86-16/32 RealMode Addressing] (2003) / [http://therx.sourceforge.net/osdev/files/ia32_rm_addr.pdf The workings of IA32 real mode addressing and the a20 line] (2004) |
||
[[Category:X86 CPU]] |
[[Category:X86 CPU]] |
Revision as of 05:57, 8 February 2009
Real mode is the initial 16 bit operating mode of all x86 Intel processors (and clones). Its presence in modern x86 CPUs is required for backwards compatibility with pre-80386 processors and applications.
"negatives"
- less than 1M of RAM is available for use
- there is no hardware based memory protection (GDT), or virtual memory
- there is no way to restrict the instructions that any user program can execute
- the default CPU operand length is only 16 bits
- AX, CX, and DX are no longer "general purpose" registers -- they cannot be used for addresses
- the memory addressing modes are different and more complicated
- modern compilers cannot generate code that is compatible with Real mode
- (so you either have to find a very old compiler, or use Assembly)
"positives"
- the BIOS functions implemented in the system's BIOS all work
- the BIOS has drivers to handle all the hardware for you
All modern operating systems (Windows, Linux) run in Protected Mode, due to the many limitations and problems that Real mode presents. Older OSes (DOS) and programs ran in Real mode because it was the only operating mode available at the time. For information on switching from Real mode to Protected mode, see the Protected Mode article.
Note: There is a mode called Virtual 8086 Mode which allows OSes running in Protected mode to emulate the Real mode segmented model for individual applications. This can be used to allow a Protected mode OS to still have access to BIOS functions, when needed.
Real Mode Memory Addressing
In Real mode, there is a little over 1M of "addressable" memory (including the High Memory Area). See Detecting Memory (x86) and Memory Map (x86) to determine how much is actually usable. The usable amount will be much less than 1M. Memory access is done using segmentation via a segment:offset system.
There are six 16 bit segment registers: CS, DS, ES, FS, GS, and SS. When using segment registers, addresses are given with the following notation, where Segment is a value in a segment register, and Offset is a value in a valid address register (ie. not AX, CX, or DX):
12F3:4B27 ^ ^ Segment Offset
Segments and Offsets are related to physical addresses by the equation:
PhysicalAddress = Segment * 16 + Offset
Thus, 12F3:4B27 corresponds to the physical address 0x17A57. Any physical address can be represented in multiple ways, with different Segments and Offsets. For example, physical address 0x210 can be 0020:0010, 0000:0210, or 0021:0000.
The Real Mode Stack
SS and SP are 16-bit segment:offset registers that specify a 20-bit physical address (described above), which is the current "top" of the stack. The stack stores 16 bit words, grows downward, and must be aligned on a word boundary. It is used every time a program does a PUSH, POP, CALL, INT, or RET opcode, and also when the BIOS handles any hardware interrupt (which happens 18 times a second, at least).
High Memory Area
If you set DS (or any segment register) to a value of 0xffff, it points to an address that is 16 bytes below 1M. If you then use that segment register as a base, with an offset of 0x10 to 0xffff, you can access physical memory addresses from 0x100000 to 0x10ffef. This (almost 64K) area above 1Mb is called the High Memory Area, in Real mode.
SIB Modes
In Assembly language, SIB modes are the complicated memory addressing modes, such as [ES:ecx + eax*8 - 0x1000000]. In Real mode, the selection of "encodable" SIB modes is much more limited than in Protected Mode:
- [BX + val]
- [SI + val]
- [DI + val]
- [BP + val]
- [BX + SI + val]
- [BX + DI + val]
- [BP + SI + val]
- [BP + DI + val]
- [val]
Notes: You can still specify any segment for each mode. -32768 <= val <= 32767
Switching from Protected to Real mode
As noted above, it is possible for a Protected mode OS to use "V86" (Virtual 8086) mode to access BIOS functions. However, V86 mode has its own complications and difficulties. Some OS designers think that it is simpler and cleaner to temporarily return to Real mode on those occasions when it becomes necessary to access a BIOS function. This requires creating a special Ring 0 program, and placing it in a physical memory address that can be accessed in Real mode.
The OS needs to pass an information packet about which BIOS function to execute, with specified data.
The program needs to:
- turn off interrupts,
- turn off paging
- perform a "far jump" to set CS with real-mode like values
- reload the other segment registers with real-mode values
- turn off protected mode
- point IDTR to the real mode IVT
- set up a Real mode stack,
- set up the the registers needed for the bios call
- execute the requested BIOS function,
- save all the "return values" from the BIOS function in memory somewhere
- turn Protected mode back on,
- do a "far jump" to set CS to a legal value,
- if needed (depending on your kernel):
- reload segment registers
- re-enable paging
- point IDTR back to the protected mode IDT and enable interrupts
- get back the return values
- and "exit"
x86 Examples
[bits 16] idt_real: dw 0x3ff ; 256 entries, 4b each = 1K dd 0 ; Real mode IVT @ 0x0000 savcr0: dd 0 ; storage location for pmode CR0 Entry16: ; we are already in 16-bit mode here! cli ;Disable interrupts ; Need 16bit pmode gdt entries! mov eax, DATASEL16 ;16 bit pmode data selector mov ds, eax mov es, eax mov fs, eax mov gs, eax ;Disable paging works because it must be a 1:1 mapping mov eax, cr0 mov [savcr0], eax ; save pmode CR0 and eax, 0x7FFFFFFe ; Disable paging bit & enable 16-bit pmode mov cr0, eax jump 0:GoRMode ; Perform Far jump to set CS GoRMode: mov sp, 0x8000 ; pick a stack pointer mov ax, 0 ; Reset segment registers to 0 mov ds, ax mov es, ax mov fs, ax mov gs, ax lidt [idt_real] sti ; Restore interrupts -- be careful, unhandled int's will kill it