-
The
i386 Microprocessor
This section introduces some important properties
of the Intel 386 CPU. The information presented here also applies to
all higher CPUs compatible with the 386 (such as the 486, Pentium,
etc.) and compatible CPUs from other vendors (such as National
Semiconductor, AMD, etc.). RTTarget-32 requires only 32-bit
protected mode. Thus, even CPUs that do not support all the features
described here can be supported by RTTarget-32 (for example, the
NS486SXF from National Semiconductor).
This section only covers some general concepts of
interest to most programmers, mainly to introduce terms used
throughout the rest of this manual. Many subjects are not covered
(e.g., hardware multitasking, gates, etc.). The i386 is a very
complex processor; for a complete description, please refer to the
386TM DX Microprocessor Programmer's Reference Manual
from Intel (order number 230985).
The 386 can operate in
one of three different modes described below; in addition, the basic
mechanisms of address translation, memory protection, and interrupt
handling are discussed.
-
Real
Address Mode
In this mode (also referred to as Real Mode), the
386 behaves like a very fast Intel 8086 CPU with a few new
instructions and wider registers. The accessible address space is
officially limited to 1 megabyte, just like on the 8086 (although
undocumented features of the 386 allow addressing 4GB even in real
mode). For compatibility with earlier CPUs, the 386 starts operating
in this mode after power on or reset.
In real mode, the processor calculates the
physical address of a memory reference by shifting the value of a
segment register to the left by 4 binary digits and then adding the
offset address to this value. Thus, two 16-bit values (segment and
offset) are combined to form a single 20-bit physical address. There
are no linear addresses in real mode.
Under RTTarget-32, this
mode is only used in the boot code. The boot code starts executing
in real mode and carries out most of the initialization.
Subsequently, it switches to 32-bit protected mode and never
switches back.
-
Virtual
8086 Mode
Virtual 8086 mode
emulates the real address mode. However, some protected mode
features of the 386 are in effect. For example, paging is enabled to
allow the virtual 8086 machine to run anywhere in the physical
address space. The IDT is also in effect to route all interrupts to
native protected mode. The GDT and LDT are not used. Address
calculation works just as in real mode; however, instead of physical
addresses, linear addresses subject to paging are generated by
combining segment and offset values.
-
16-Bit
Protected Mode
This is the only protected mode available on
80286 processors. Segments can have any length between 1 and 216
= 64 kilobytes. A segment base has 24 bits on an 80286 CPU, limiting
the available address space to 16 megabytes. On 386 and higher CPUs,
a segment base can have 32 bits. Thus, even in 16-bit protected
mode, the complete 32-bit address space of 4 gigabytes is available
(although many segments are required to use the complete address
space).
Near pointers are 16-bit offsets interpreted
relative to a segment register. Far pointers consist of a 16-bit
selector and a 16-bit offset.
-
32-Bit
Protected Mode
The 386 introduced 32-bit protected mode, the
only mode supported by RTTarget-32. The difference from 16-bit
protected mode is that the size of segments is no longer limited to
64k; rather, a segment can be up to 4 gigabytes in size. Thus, a
single segment can be used to address the complete address space.
Near pointers are 32-bit offsets which are also
interpreted relative to a segment register. Far pointers consist of
a 16-bit selector and a 32-bit offset for a total of 48 bits.
In 32-bit protected mode, the address space is
still segmented. However, since all available memory can be
addressed with a single segment, the CPU can be set up such that
segmentation can (almost) be ignored by the programmer. All segment
descriptors to be used are initialized to refer to a segment
starting at linear address 0 and extend over the complete address
space or at least to the highest address that the system needs to
access. Such an environment is referred to as a flat memory model.
EC32, RTC-32, RTTarget-32 (and Win32) use this flat memory model.
-
Descriptors and Descriptor Tables
The 386 maintains three
different descriptor tables: the Global Descriptor Table (GDT), the
Local Descriptor Table (LDT), and the Interrupt Descriptor Table (IDT).
The IDT can hold up to 256 interrupt, trap, or task gates; GDT and
LDT can hold up to 8191 descriptors. Most GDT and LDT entries hold
segment descriptors, although other descriptors (gates, TSS, etc.)
are possible. Among other things, a segment descriptor contains the
following information:
- the linear start address of the segment (the
Base)
- the size of the segment (the Limit)
- the descriptor privilege level (the
DPL)
- execute, read only, or read/write access
permission
The main purpose of the IDT is to hold
Interrupt or Trap Gates. Basically, these gates simply point to the
entrypoint of an interrupt service routine.
RTTarget-32 manages a GDT with a total of 16
descriptors. The following table summarizes the properties of
RTTarget-32's GDT descriptors:
| Index |
Selector |
DPL |
Description |
| 0h |
0h |
- |
Reserved by Intel (NULL selector) |
| 1h |
8h |
0 |
Ring 0 code segment |
| 2h |
10h |
0 |
Ring 0 data segment |
| 3h |
1Bh |
3 |
Ring 3 code segment |
| 4h |
23h |
3 |
Ring 3 data segment |
| 5h |
28h |
0 |
RTTarget-32 Boot Code TSS |
| 6h |
30h |
0 |
Reserved for RTKernel-32 (LDT) |
| 7h |
3Bh |
3 |
Callgate to call Ring 0 from Ring 3 |
| 8h |
40h |
3 |
BIOS Data Segment (Base == 400h) |
| 9h |
4Bh |
3 |
Win32 main thread TEB segment |
| Ah |
50h | CPL1 |
CPL |
16-bit call stub segment2 |
| Bh |
5Bh |
3 |
16-bit data stub segment12 |
| Ch |
60h | CPL1 |
CPL |
16-bit PnP BIOS code segment12 |
| Dh |
6Bh |
3 |
16-bit PnP BIOS data segment12 |
| Eh |
- |
- |
Reserved |
| Fh |
7Bh |
3 |
Reserved for MetaWINDOW |
RTTarget-32's IDT has 128 entries as follows:
| Index |
Description |
| 0h - 1Fh |
CPU Exceptions |
| 20h |
Reserved |
| 21h |
DOS Emulation |
| 22h - 30h |
Reserved |
| 31h |
DPMI Emulation |
| 32h - 3Fh |
Reserved |
| 40h - 4Fh |
IRQ 0..15 |
| 50h - 5Fh |
Reserved for IRQ 16..31 |
| 60h |
RTTarget-32 Boot Code API |
| 61h |
RTTarget-32 Program Terminate |
| 62h - 6Ch |
Reserved by RTTarget-32 |
| 6Dh - 6Eh |
Reserved by RTTarget-32 Debug Monitor |
| 6Fh |
Reserved by RTTarget-32 (Boot Code Data Base) |
| 70h - 7Fh |
Free for Application Use |
By default, RTTarget-32 does not
maintain an LDT.
-
Privilege
Levels
To provide a higher degree of control for
protection, protected mode defines privilege levels: Descriptor
Privilege Levels (DPL), Current Privilege Levels (CPL), and
Input/Output Privilege Levels (IOPL). Four different levels (0 to 3)
are defined. A higher numerical value implies a lower privilege
level. The DPL has already been introduced, it is stored in each
segment's descriptor. The CPL is the privilege level at which the
CPU is currently running (also frequently referred to as the Ring in
which a program is running). It corresponds to the DPL of the code
segment being executed. The low 2 bits of the CS register hold the
CPL.
In the flat memory model, the application will
usually not reload segment registers and is consequently not
concerned with segment level protection. However, the CPL also
controls access to some privileged instructions. Some instructions
can only be executed at CPL 0. Also, the CPL affects how page-level
protection functions.
The IOPL defines the minimum CPL required to
directly access I/O ports and to execute I/O Sensitive Instructions
(IN, INS, OUT, OUTS, CLI, STI). In addition, the POPF instruction
behaves differently, depending on CPL and IOPL. The IOPL is
maintained by the CPU in the EFLAGS register.
RTTarget-32 can run programs at CPL 0 or
3. IOPL is always initialized to 3, allowing the program to use I/O
ports and I/O sensitive instructions without restrictions at any CPL.
-
Paging
Paging allows regions of memory to be mapped to
different locations in the physical address space. In addition, the
memory access rights can be controlled, much as they can for
segments. However, since the flat memory model uses only one segment,
page level protection is better suited here.
The paging mechanism uses pages (4096 bytes) of
memory as the smallest mappable unit. Each page can have one of the
following access rights: none, system read only, system read/write,
user read only, or user read/write. System access means that only
software running at CPL 0 can access the memory. Write access
checking is not performed at CPL 0. This is important to note, since
it implies that memory cannot be protected if applications run at
CPL 0.
The following table shows the effective page
access privileges enforced by the CPU at run time for code executing
at CPL 0 or 3:
| |
NoAccess |
SysRead |
System |
ReadOnly |
ReadWrite |
| CPL 0 |
NoAccess |
ReadWrite |
ReadWrite |
ReadWrite |
ReadWrite |
| CPL 3 |
NoAccess |
NoAccess |
NoAccess |
ReadOnly |
ReadWrite |
Each column represents a particular access
privilege value for a page set in the page table. The rows show
which privilege actually applies at a particular CPL. Any violation
will trigger exception 14 (page fault) at run-time.
Unlike segmentation,
paging is optional and must be enabled at boot time to become
effective. RTTarget-32 supports running either with or without
paging.
-
Virtual, Linear, and
Physical
Addresses
The 386 memory management can become quite
confusing. Here is a summary of the different types of addresses and
how one type is translated to another:
Virtual addresses are used by an
application program. They consist of a 16-bit selector and a 32-bit
offset. In the flat memory model, the selectors are preloaded into
segment registers CS, DS, SS, and ES, which all refer to the same
linear address. They need not be considered by the application.
Addresses are simply 32-bit near pointers.
Linear addresses are calculated
from virtual addresses by segment translation. The base of the
segment referred to by the selector is added to the virtual offset,
giving a 32-bit linear address. Under RTTarget-32, virtual offsets
are equal to linear addresses since the base of all code and data
segments is 0.
Physical addresses
are calculated from linear addresses through paging. The linear
address is used as an index into the Page Table where the CPU
locates the corresponding physical address. If paging is not enabled,
linear addresses are always equal to physical addresses. Under
RTTarget-32, linear addresses are equal to physical addresses except
for remapped RAM regions.
-
Exceptions and
Interrupts
The 386 supports Exceptions, Software Interrupts,
and Hardware Interrupts, which are summarized by the term Interrupt.
Interrupts are numbered 0 to 255. They are events that transfer
control to an Interrupt Handler (or Interrupt Service Routine, ISR)
which must handle the event. The interrupt handler's address is read
from the IDT. Each descriptor in the IDT contains a pointer to the
corresponding handler (along with some supplemental information).
Exceptions are triggered by the CPU
in case of an error. For example, if a program attempts to write to
a memory location for which it only has read access, the CPU will
trigger an exception. The exception could be handled by an operating
system to abort the misbehaved program or activate a debugger to
allow further investigation of the problem. RTTarget-32's boot code
will initialize all exception vectors to point to a routine that
simply displays a register dump and then stops. If a program wants
to handle such exceptions, it can instruct RTTarget-32 to map CPU
exceptions to Win32 exceptions. The Debug Monitor, RTTarget-32's
debugger interface, will handle all exceptions and allow debugging
the cause of the exception.
Software interrupts are explicitly
triggered by a program using the INT instruction. Actually, this is
similar to a procedure call. However, the address of the procedure
to be called is found in the IDT and a change of privilege level can
occur in the call. RTTarget-32 defines several interrupts for its
API and for emulating subsets of some other APIs such as DOS and
DPMI. The use of interrupts allows the application to run at CPL 0
or 3 while the RTTarget-32 boot code (which handles some API
requests) always runs at CPL 0.
Hardware
interrupts are triggered by some hardware external to the
CPU. The most significant difference from exceptions and software
interrupts is that hardware interrupts can occur at any time and at
any place in the code. Since this may cause problems, the processing
of hardware interrupts can be suspended temporarily using the CLI/STI
instructions. RTTarget-32's boot code installs dummy interrupt
handlers and displays a warning message if an interrupt occurs (exception:
timer and keyboard interrupts on IRQ 0 and 1 are ignored). The
application should install interrupt handlers before any external
hardware will generate interrupts. Interrupt handlers should not
chain to the RTTarget-32 boot code handlers.