Module 6
Module 6
ng
2
Protected mode privileges
• Protected mode gets its name from the 386's privilege
protection. Each program has a privilege level, or PL,
from zero to three (i.e. 00-11).
• Programs at PL0 can execute any instruction and access
any data. Programs at PL3 can't execute certain
instructions; they also can't access data that belong to
more privileged programs.
• Each segment descriptor has a Descriptor Privilege Level
(DPL) that the 386 uses for protection. The 386 also
controls which programs can execute I/O instructions.
3
Protected mode privileges
• A privilege hierarchy is important for supporting modern
operating systems. In a typical operating system, the
main kernel runs at PL0.
• Other parts of the operating system might run at PL1.
Device drivers can run at PL2; they need to do direct
device I/O. User programs in this system would run at
PL3.
• This scheme has many advantages. In particular, a
malicious program can't damage the operating system
or other user programs.
4
Cont’d
PL0 programs alone can execute the following instructions: HLT, CLTS,
LGDT, LIDT, LLDT, LTR, LMSW, MOV (to/from control/debug/test
registers).
On 486 systems:
•INVD
•WBINVD
•INVLPG
On Pentium and above:
•RDMSR
•WRMSR
•RDTSC
5
Cont’d
• The IOPL field in the EFLAGS register allows the operating system to
control who can do I/O. These two bits determine the minimum privilege
level a program must have to execute I/O instructions (CLI, STI, IN, INS,
OUT and OUTS). If IOPL is zero, only PL0 programs can do I/O. If IOPL is
3, all programs can execute I/O instructions. Only a PL0 program can
modify the IOPL flags. When other programs modify the flags, IOPL
doesn't change! Leaving IOPL=3 makes life easy for DOS Extenders, but
it can cause major problems since real-mode programs mostly use direct
I/O.
• A program's privilege level is equal to the RPL field of the selector in the
CS register. This is the current privilege level or CPL. You can't directly
modify the CS register so that it has a different RPL. The same holds
true for SS as well.
6
Data Access
Programs can't load a segment register with just any selector. When a data
segment register (DS, ES, FS or GS) is loaded, the 386 checks the DPL against the
program's CPL and the selector's RPL. The 386 first compares the CPL to the RPL.
The largest one becomes the effective privilege level (EPL). If the DPL is greater
than ot equal to the EPL, the 386 loads the sgment register; otherwise an error
occurs.
The SS register must be loaded with a segment whose DPL and CPL are equal. The
386 also checks to make sure a stack segment is readable, writeable and present.
The 386 provides a special stack segment type. You can also use a plain data
segment for a stack, if you wish. A stack segment's limit field indicates the lowest
legal offset in the segment.
It is always valid to load a null selector (0 through 3) into a segment register.
However, any attempt to access memory via the selector will cause an error as
expected.
7
Control Transfer Instructions
• Unconditional Transfer Instructions
JMP, CALL, RET, INT and IRET instructions transfer control
from one code segment location to another. These
locations can be within the same code segment (near
control transfers) or in different code segments (far control
transfers).
• Conditional Transfer Instructions
The conditional transfer instructions are jumps that may or
may not transfer control, depending on the state of the
CPU flags when the instruction executes.
8
Conditional Jump Instructions
The Table below shows the conditional transfer mnemonics and their
interpretations. Conditional jump instructions contain a displacement which
is added to the EIP register if the condition is true. The displacement may be
a byte, a word, or a double-word. The displacement is signed; therefore, it
can be used to jump forward or backward.
Interpretation of Conditional Transfers
Unsigned Conditional Transfers
Mnemonic Condition Tested "Jump If..."
JA/JNBE (CF or ZF) = 0 above/not below nor equal
JAE/JNB CF = 0 above or equal/not below
JB/JNAE CF = 1 below/not above nor equal
JBE/JNA (CF or ZF) = 1 below or equal/not above
9
Unsigned Conditional Jumps
JC CF = 1 carry
JE/JZ ZF = 1 equal/zero
JNC CF = 0 not carry
JNE/JNZ ZF = 0 not equal/not zero
JNP/JPO PF = 0 not parity/parity odd
JP/JPE PF = 1 parity/parity even
10
Signed Conditional Transfers
Mnemonic Condition Tested "Jump If..."
JG/JNLE ((SF xor OF) or ZF) = 0 greater/not less nor equal
JGE/JNL (SF xor OF) = 0 greater or equal/not less
JL/JNGE (SF xor OF) = 1 less/not greater nor equal
JLE/JNG ((SF xor OF) or ZF) = 1 less or equal/not greater
JNO OF = 0 not overflow
JNS SF = 0 not sign (positive, including 0)
JO OF = 1 overflow
JS SF = 1 sign (negative)
11
Loop Instructions
The loop instructions are conditional jumps that use a value placed in ECX
to specify the number of repetitions of a software loop. All loop instructions
automatically decrement ECX and terminate the loop when ECX=0. Four of
the five loop instructions specify a condition involving ZF that terminates
the loop before ECX reaches zero. LOOP (Loop While ECX Not Zero) is a
conditional transfer that automatically decrements the ECX register before
testing ECX for the branch condition.
If ECX is non-zero, the program branches to the target label specified in the
instruction. The LOOP instruction causes the repetition of a code section
until the operation of the LOOP instruction decrements ECX to a value of
zero. If LOOP finds ECX=0, control transfers to the instruction immediately
following the LOOP instruction. If the value of ECX is initially zero, then the
LOOP executes 2^(32) times.
12
Loop Instruction
LOOPE (Loop While Equal) and LOOPZ (Loop While Zero) are synonyms for
the same instruction. These instructions automatically decrement the ECX
register before testing ECX and ZF for the branch conditions. If ECX is non-
zero and ZF=1, the program branches to the target label specified in the
instruction. If LOOPE or LOOPZ finds that ECX=0 or ZF=0, control transfers
to the instruction immediately following the LOOPE or LOOPZ instruction.
LOOPNE (Loop While Not Equal) and LOOPNZ (Loop While Not Zero) are
synonyms for the same instruction. These instructions automatically
decrement the ECX register before testing ECX and ZF for the branch
conditions. If ECX is non-zero and ZF=0, the program branches to the target
label specified in the instruction. If LOOPNE or LOOPNZ finds that ECX=0 or
ZF=1, control transfers to the instruction immediately following the LOOPNE
or LOOPNZ instruction.
13
Executing a Loop or Repeat Zero Times
JCXZ (Jump if ECX Zero) branches to the label specified in the instruction if it
finds a value of zero in ECX. JCXZ is useful in combination with the LOOP
instruction and with the string scan and compare instructions, all of which
decrement ECX. Sometimes, it is desirable to design a loop that executes
zero times if the count variable in ECX is initialized to zero. Because the
LOOP instructions (and repeat prefixes) decrement ECX before they test it, a
loop will execute 2^(32) times if the program enters the loop with a zero
value in ECX.
A programmer may conveniently overcome this problem with JCXZ, which
enables the program to branch around the code within the loop if ECX is zero
when JCXZ executes. When used with repeated string scan and compare
instructions, JCXZ can determine whether the repetitions terminated due to
zero in ECX or due to satisfaction of the scan or compare conditions.
14
Software-Generated Interrupts
• The INT n, , and BOUND instructions allow the programmer to specify a
transfer to an interrupt service routine from within a program. INT n
(Software Interrupt) activates the interrupt service routine that
corresponds to the number coded within the instruction. The INT
instruction may specify any interrupt type. Programmers may use this
flexibility to implement multiple types of internal interrupts or to test the
operation of interrupt service routines. (Interrupts 0-31 are reserved by
Intel.) The interrupt service routine terminates with an IRET instruction
that returns control to the instruction that follows INT n.
• INTO (Interrupt on Overflow) invokes interrupt 4 if OF is set. Interrupt 4
is reserved for this purpose. OF is set by several arithmetic, logical, and
string instructions.
15
Software-Generated Interrupts
BOUND (Detect Value Out of Range) verifies that the signed value contained in the specified
register lies within specified limits. An interrupt (INT 5) occurs if the value contained in the
register is less than the lower bound or greater than the upper bound.
The BOUND instruction includes two operands. The first operand specifies the register being
tested. The second operand contains the effective relative address of the two signed BOUND
limit values. The BOUND instruction assumes that the upper limit and lower limit are in adjacent
memory locations. These limit values cannot be register operands; if they are, an invalid op-code
exception occurs.
BOUND is useful for checking array bounds before using a new index value to access an
element within the array. BOUND provides a simple way to check the value of an index register
before the program overwrites information in a location beyond the limit of the array.
The block of memory that specifies the lower and upper limits of an array might typically reside
just before the array itself. This makes the array bounds accessible at a constant offset from the
beginning of the array. Because the address of the array will already be present in a register, this
practice avoids extra calculations to obtain the effective address of the array bounds.
The upper and lower limit values may each be a word or a double-word.
16
Multi-tasking
• The 386 uses the Task State Segments (TSSs) to support multitasking. The TSS
descriptor points to a buffer which must be at least 104 bytes long. In addition
to multitasking, TSSs can also be used for hardware interrupt handling (using
task gates in the IDT). The TSS selector is neither readable nor writeable.
Generally, a TSS alias is created, which is nothing but a "data type" segment
pointing to the TSS buffer. TSS selectors always appear in the GDT, never in LDT
or IDT. However, as mentioned above, task gates may appear in the IDT. The
processor uses the TSS selector internally.
• Since a multitasking switch requires the processor state to be saved, the buffer
mostly contains the contents of the hardware registers. When a task switch
occurs, the processor saves various details in the TSS buffer automatically. This
process is very quick and hence not many CPU cycles are wasted in switching to
a new task. Before a task is initially started, the operating system has to fill in
certain entries in the TSS buffer.
17
Multi-tasking
• A task switch may occur during a "far jump" or a "far call". The offset of the call or
jump is simply ignored. The values in the TSS are loaded into the registers and the
new task beings to execute. The selector referred by the jump or call must be a
TSS selector or a task gate. The task gate contains the TSS selector. But unlike the
TSS selector, the task gate may occur in the GDT, IDT or LDT. The EPL must always
be less than or equal to the TSS's DPL as in case of the normal segment selectors.
• The 386 also supports nested tasks. It handles nested tasks using the NT bit in the
EFLAGS register. Whenever a task "calls" another task, the 386 stores the old
task's TSS selector in the "back-link" field of the new TSS. Also, the NT bit in the
EFLAGS register is set. When the new task wishes to return to the old one, it issues
an IRET instruction.
• The TSS aren't re-entrant. Whenever a task is running, the 386 sets the BUSY bit
in the TSS selector to indicate this. This is done to prevent recursive calling of
tasks.
18
Multi-Tasking
19
Multi-Tasking
As mentioned earlier, the TSS must be at least 104 bytes long. The
size of the TSS may extend to any size. The 386 contains a pointer
to an I/O bitmap in the last field. The size of this bitmap is usually
8K, but may be lesser. The I/O bitmap is optional. If the size of the
I/O bitmap is lesser, entries past the end of this bitmap are
considered as "1s".
Each bit in the I/O bitmap corresponds to one I/O port. If a task tries
to do I/O, the 386 checks the task's CPL against the IOPL. If the CPL
is less than or equal to the IOPL, access is granted, otherwise the
386 checks the I/O bitmap. If the bit corresponding to the I/O port
used is zero, the 386 allows access, otherwise it denies access. A
bitmap should always end with 0FFh.
20
Exceptions
The 386 has support for 256 interrupts (or exceptions)
just as in the 8086. The Interrupt Descriptor table (IDT)
contains the definition for each of these interrupts. The
IDT can have 8192 entries. But if more than 256 of
these entries are present, they simply remain unused.
The IDT may contain trap gates, interrupt gates or task
gates. A trap gate is one that does not clear interrupts
before entering the exception handler. However, an
interrupt gates disables all interrupts before entering
the handler.
21
Faults, Aborts and Traps
The processor generated 386 exceptions can be classified into faults, traps
and aborts.
A fault is a correctable error. Most invalid operations result in faults. When
a fault occurs, the CS:EIP points to the instruction that caused the fault.
Faults are considered to be the least serious exceptions. The most common
of these faults is the "General Protection Fault (GPF)".
Traps accur whenever a software interrupt occurs. Software interrupts are
caused due to the execution of INT and INTO instructions. When a trap
occurs, the CS:EIP points to the instruction following the actual instruction
that caused the trap. The system cannot restart traps.
Aborts are serious errors that indicate that there may be a severe problem
with the operating system itself. The Double Fault and FPU Overrun are
considered as aborts.
22
Classifications and Examples of Exceptions
The 386 has at least two facilities to support memory management. They are:
1. Segmentation
2. Paging
Among the two types, use of the segmentation mechanism is a must, while
paging is optional to the user. Paging provides a mechanism to implement
virtual memory used by almost all operating systems today. CWSDPMI, the
official DJGPP DPMI server, uses this too. The advantage of using the paging
mechanism is that you can restrict access to specific portions of the memory,
while that would be hard to do with a segmentation scheme. You can enable
paging using the CR0 register. Segments are used to keep track of data, code
and the stack a certain program is using. However, an operating system might
also use a single selector that covers the entire 4GB of addressable space and
described earlier in this document.
25
Paging
• Enabling paging, however isn't as simple as setting bit 31 of CR0.
You need to set up the Page Directory Entries and the Page Table
Entries, the PDEs and PTEs. The PDEs and PTEs are actually tables
which are used to convert the logical address into the physical
address.
• As with most other functionality, only PL0 programs can activate
the MMU. User programs never know that an MMU exists! The
pages are classified as User/System. PL0 programs can access any
page. PL3 programs can access a "User" page, but not a system
page. Since 4GB of memory is often not available on most
systems, the page tables for these aren't usually setup. The
corresponsding entries in the PDEs are marked as "not present".
26
PDE register
27
Memory Management Unit
The MMU uses two types of tables to translate addresses - the Page Directory
Entry and the Page table Entries. Each PDE corresponds to 4 Megabytes of
contiguous memory. The PDE contains a pointer to the starting of the
corresponding page tables. These PTEs can be used to set permissions for 4K
blocks within the PDEs 4M area. The PTEs also contain the actual physical
address. Note that the PDE contains the Physical Address of the page tables.
To translate a linear address into a physical address, the MMU looks at bits
31-22 of the linear address. This is used to select the PDE in concern. Bits 21-
12 are used to select one of the 1024 PTEs in the page table selected. The
lower 12 bits form the lower 12-bits of the physical address.
Now, the question is how the MMU finds where the Page Directories are
present. The CR3 register holds the base address of the PDEs. Hence, it is
also known as the PDBR (Page Directory Base Register).
28
Conclusion
Working in Protected Mode requires that you first switch to protected mode. To switch
to protected mode and do some real work, you need to follow these steps:
1. Setup the Global Descriptor Table (GDT)
2. Setup the Interrupt Descriptor Table (IDT)
3. Reprogram the PICs so that they generate different interrupts
4. Setup the TSS
5. Setup Page Tables and CR3 (perhaps you may not require this)
6. Set bit 0 of CR0
7. Load the Task Register (TR)
8. Jump to the TSS selector
Setting up the GDT and IDT should be easy. Create the descriptors and then load
GDTR with the address and length of the table. Setting up the TSS can be easy, too, if
you follow a neat procedure. Finally, do a far jump to the TSS and that should do it.
29
References
1.https://pdos.csail.mit.edu/6.828/2014/
readings/i386/s03_05.htm
2.http://www.internals.com/articles/
protmode/introduction.htm
3.http://prodebug.sourceforge.net/
pmtut.html
30