Protected Mode Tutorial
Protected Mode Tutorial
Protected Mode Tutorial
http://prodebug.sourceforge.net/pmtut.html
Table of Contents
Contents 1 Introduction to Protected Mode 1.1 A Brief Introduction to Protected Mode 1.2 The Benets of Using Protected Mode 2 Addressing in Real Mode 3 Registers in the 80386 4 The Real Mode Vector Table 5 Hardware Interrupts 6 Keyboard and the A20 Line 7 Segment Selectors and Descriptors 7.1 Segment Selectors 7.2 Tables Required in Protected Mode 7.3 Descriptors 8 Protected Mode Privileges 8.1 Data Access 9 How Multitasking Works 10 Exceptions on the 80386 Processor 11 Memory Management Unit (MMU) 12 Virtual 8086 (V86/VM86) Mode 13 Interrupt Handling in Protected Mode 14 Working in Protected Mode Node:Top, Next:Introduction,
Contents
This documentation was written as a part of the CSD course project in which I had build a protected mode bootable debugger.I found a lot of information on the web and in the intel manuals.This is my attempt to collate it so as to be useful to a beginner. The document is designed as a tutorial and is intended to be a starting reference. The documentation contains detailed information about protected mode. Starters who wish to merely touch upon "protected mode programming" should generally read only the introduction, while others who require more information can get into the depths. If you have other questions, you can mail me. Introduction: Introduction to Protected Mode RM Addressing: Real Mode Addressing
1 of 20
16/02/12 10:08 PM
http://prodebug.sourceforge.net/pmtut.html
80386 Registers: The 80386 Registers RM Vector Table: The Real Mode Interrupt Vector Table Hardware Interrupts: Hardware Interrupts Keyboard: The Keyboard and the A20 Line Selectors and Descriptors: Segment Selectors and Descriptors Protected Mode Privileges: Protected Mode Privileges Multitasking: How Multitasking Works Exceptions: Exceptions on the 80386 Processor MMU: Memory Management Unit V86 Mode: Virtual 8086 Mode Interrupt Handling: Interrupt Handling in Protected Mode Working in Protected Mode: Working in Protected Mode Node:Introduction, Next:RM Addressing, Previous:Top, Up:Top
2 of 20
16/02/12 10:08 PM
http://prodebug.sourceforge.net/pmtut.html
3 of 20
16/02/12 10:08 PM
http://prodebug.sourceforge.net/pmtut.html
protects programs against bugs that would crash the computer. Process protection - In a similar fashion to memory protection, different programs (or parts of a program) can be protected from each other. One program might not have access to another program's data, while the operating system might have access to everyone's data. Conversely, user programs may have only limited access to the operating system's data. This is actually implemented using the page protection mechanism provided by the MMU. 32-bit registers - All general-purpose registers on the 386 are 32-bits wide. Except for the E prex (ex: EAX instead of AX), these registers have the same names as in the 8086. Two new segment registers (FS and GS) are also available; they are accessible from all modes but are most useful in protected mode programs. Real-mode programs can also access these 32-bit registeres, but they won't use them for indexing purposes. And using 32-bit registers in protected mode (32-bit protected mode) will cut down the size of the code generally. Improved addressing modes - In real mode, programs can only form addresses with constant values, the BX or BP register, and the SI or DI register. In protected mode programs, any register can form addresses. An index can include a scale factor of two, four or eight. This allows you to write instructions like MOV EBX, [EDI][EAX*8]+2. Multitasking support - The 386 has special provisions to save the current processor state and switch to a new task (known as context switch). A single instruction can switch contexts rapidly. This has important ramications for operating systems and real-time processing. The 386 also supports nested tasks. A task can return to its original task using a back-link. Hardware debugging - The 386 has special hardware for implementing single-step code and data breakpoints. This hardware is available in real mode with some special techniques. Node:RM Addressing, Next:80386 Registers, Previous:Introduction, Up:Top
4 of 20
16/02/12 10:08 PM
http://prodebug.sourceforge.net/pmtut.html
The gure below shows most of these registers and their signicance. As you can see, the 386+ have a variety of special registers. They usually aren't useful under DOS, but we'll see some of them when we look at protected mode extensions to DOS.
5 of 20
16/02/12 10:08 PM
http://prodebug.sourceforge.net/pmtut.html
5 Hardware Interrupts
6 of 20 16/02/12 10:08 PM
http://prodebug.sourceforge.net/pmtut.html
A hardware interrupt is a special signal from an I/O device to the computer. This signal informs the computer that the I/O device requires attention. The processor will normally stop whatever it is doing to service the interrupt. When the interrupt completes, the processor resumes execution where it left off. Hardware interrupts can come from various sources. For example, every time you press or release a key, you generate an interrupt. Other interrupts originate from the clock, printer, serial port, disk drives and so on. The processor itself causes some interrupts. INT 0 for instance, occurs when a program attempts to divide by zero. These are all hardware interrupts. Hardware interrupt handling is perhaps one of the most important functions in protected mode. Badly written hardware interrupt handlers can cause disasters. The 8259 Programmable Interrupt Controller (PIC) on the motherboard manages all hardware interruptrs. These controllers take interrupt signals from various devices and convert them to specic interrupts for the processor. Tha table below shows the hardware interrupts in real mode with their corresponding PIC interrupt request inputs (known as IRQ lines). Do not confuse IRQ numbers with interrupt numbers. For example, the keyboard connects to IRQ1, which sends INT 9 to the CPU. The PICs can be reprogrammed to generate different interrupt numbers for each IRQ. This technique is generally used by screen trapping programs and also by DOS Extenders such as go32. The PICs also control the priority of interrupts. For example, the clock (on IRQ 0) has a higher priority than the keyboard (IRQ 1). If the processor is servicing a clock interrupt, the PIC won't generate an interrupt for the keyboard until the clock's ISR resets the PIC. On the other hand, the clock can interrupt the keyboard's ISR. The PICs can be programmed to use a variety of priority schemes, but this is rarely, if ever, seen in PC programming. The AT's extra PIC connects to the IRQ 2 of the rst PIC. Therefore, the extra PIC's IRQs (8 through 15) have the same priority as IRQ 2. Disabling IRQ 2 disabled all of the second PICs interrupts. Interrupt IRQ Number Description 00H Divide by zero or divide overow 02H NMI (Non-maskable Interrupt) 04H Overow (generated by INTO) 08H 0 System timer 09H 1 Keyboard 0AH 2 Interrupt from second PIC 0BH 3 COM2 0CH 4 COM1 0DH 5 LPT2 0EH 6 Floppy Disk 0FH 7 LPT1 70H 8 Real Time Clock 71H 9 General I/O 72H 10 General I/O
7 of 20
16/02/12 10:08 PM
http://prodebug.sourceforge.net/pmtut.html
11 12 13 14 15
You can stop interrupts from disturbing an important section of code in several ways. The CLI instruction disables all interrupts except the nonmaskable interrupt NMI since the NMI, which does not go through a PIC cannot be disabled this way2. In addition, PICs can be reprogrammed to turn off specic interrupts. Node:Keyboard, Next:Selectors and Descriptors, Previous:Hardware Interrupts, Up:Top
8 of 20
16/02/12 10:08 PM
http://prodebug.sourceforge.net/pmtut.html
The selector contains three elds. The lowest two bits (RPL) pertain to the 386's protection mechanism which is explained shortly. The next bit, TI, determines which table of descriptors denes the segment. There are three segment descriptor tables: 1. The Global Descriptor Table (GDT) 2. The Interrupt Descriptor Table (IDT) 3. The Local Descriptor Table (LDT) Segment selectors never refer to the IDT. If TI is zero, the segment's denition is in the GDT. If it is one, the LDT contains the denition. Node:Tables, Next:Descriptors, Previous:Segment Selectors, Up:Selectors and Descriptors
9 of 20
16/02/12 10:08 PM
http://prodebug.sourceforge.net/pmtut.html
10 of 20
16/02/12 10:08 PM
http://prodebug.sourceforge.net/pmtut.html
7.3 Descriptors
Two elds in the segment descriptor are particularly interesting. The P bit (bit 47) determines whether the segment is present. An operating system can clear this bit to create a virtual segment. When a program tries to use a virtual segment, the 386 generates an error. The operating system can then load the segment from the disk and try again. When P is clear, bits 0 through 39 and 48 through 63 can contain any values. The operating system could store a disk address here, for example. But this is unsuitable is the segment size is large. Fortunately, the 386 provides a better way to use virtual memory. The other interesting eld is the A bit (bit 40). The 386 sets this bit when any program writes to the segment. Our crude virtual memory system might use this bit to decide whether it should write a segment to disk before making it absent and reusing its space. Another question is how a descriptor can specify a segment from one byte to 4GB long. The limit eld given is only 20 bits. This is where the G bit (bit 55) comes into play. If G is zero, the limit eld corresponds to one segment's maximum legal offset (one less than its length). If G is one, however, the 386 shifts the limit eld 12 places left to make a 32-bit limit. The 386 lls the bottom
11 of 20
16/02/12 10:08 PM
http://prodebug.sourceforge.net/pmtut.html
This scheme allows us to specify a segment with a length of less than 1 Mbyte or a multiple of 4 Kbytes. When G is zero, the segment can range from one byte to 1 Mbyte long. When G is one, the segment can range from 4 Kbytes to 4 Gbytes in length (in 4 Kbytes steps). It is possible to create two or more descriptors that point to the same area of memory. An operating system, for example, might load a le into a data segment and jump to a code segment that starts in the same place. This process is known as aliasing. The operating system must have some way of loading the GDT and other tables. Therefore, it will usually have a data segment alias to the GDT. Some systems set up a data segment that covers all 4GB of memory. Tables can then be written directly with that data sgement. Operating systems rarely allow user programs to access the GDT, IDT and other system tables directly. The processor reserves the rst slot of the GDT. The selector for this slot is the null selector, and using it always causes an error. The null selector's descriptors should be all zeros. Non-zero values work but you never know ;-). Node:Protected Mode Privileges, Next:Multitasking, Previous:Selectors and Descriptors, Up:Top
12 of 20
16/02/12 10:08 PM
http://prodebug.sourceforge.net/pmtut.html
The IOPL eld 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 ags. When other programs modify the ags, 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 eld 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.
13 of 20
16/02/12 10:08 PM
http://prodebug.sourceforge.net/pmtut.html
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 ll in certain entries in the TSS buffer. Notice the slots for stack segments and pointers for PL0, PL1 and PL2 near the top of the TSS. A program must maintain separate tasks for each privilege ring it may use. In particular the PL0 stack segments and pointers are a must. Otherwise, the processor may shut down due to a double fault in case of an interrupt. 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" eld 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 instruction4. The TSS aren't reentrant. Whenever a task is running, the 386 sets the BUSY bit in the TSS selector to indicate this. This is done to prevent recurive calling of tasks. 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 eld. 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.
14 of 20
16/02/12 10:08 PM
http://prodebug.sourceforge.net/pmtut.html
15 of 20
16/02/12 10:08 PM
http://prodebug.sourceforge.net/pmtut.html
system. Slightest errors in these interrupt handlers may result in disasters and blue screens ;-). The processor generated 386 exceptions can be classied 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.5 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. The table below shows the various exceptions with their classications: Exception (#num) Type Divide Error (0) Fault Debug (1) F/Trap Breakpoint (3) Trap Overow (4) Trap Bounds Check (5) Fault Bad Opcode (6) Fault No Coprocessor (7) Fault Double Fault (8) Abort Coprocessor Overrun (9) Abort Invalid TSS Segment (0A) Fault Segment not Present (0B) Fault Stack Fault (0C) Fault General Protection Fault (0D) Fault Page Fault (0E) Fault Coprocessor Error (10) Fault Node:MMU, Next:V86 Mode, Previous:Exceptions, Up:Top
16 of 20
16/02/12 10:08 PM
http://prodebug.sourceforge.net/pmtut.html
systems today. CWSDPMI, the ofcial DJGPP DPMI server, uses this too. The advantage of using the paging mechanism is that you can restrict access to specic 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. See Advantages. 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. See Advantages. As with most other functionality, only PL0 programs can activate the MMU. User programs never know that an MMU exists! The pages are classied 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". 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 coressponding pgae 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 nds 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)6
http://prodebug.sourceforge.net/pmtut.html
As mentioned earlier in this document, the 80386 has a third mode called the V86 mode. In this mode, the 80386 behaves exactly like an 8086 with a few minor exceptions. In V86 mode, the CPU may not issue any of the privileged instructions such as LGDT, LIDT, LLDT, SLDT, ARPL, LAR, LSL, LTR, VERR, VERW, INVD, WBINVD, WRMSR, RDMSR, etc. However, unlike the real mode, the MMU is active in the V86 mode. Therefore, the operating system still has control over a V86 task, although it runs just like in real mode. Since privileged instructions cannot be executed, the OS can prevent system crashes or malicious programs from destroying any data. A task is said to be a V86 task when the VM bit in the EFLAGS register is set. Only a PL0 program can set this bit. The bit can also be set in the TSS before the task is executed. The advantage of a having a V86 task rather than a real mode task is obvious - it's due to security reasons. The other reason is that the time taken by the CPU to switch from protected mode to real mode is considerable and greatly slows down the program. By running the program in V86 mode, the program is actually executed faster. A V86 task, just like a real mode program, uses segments and offsets rather than a selector:offset pair. It can access 1MB of memory. A V86 task always runs at PL3. They can do I/O only if the IOPL is 3 or if the TSS bitmap allows them to do so. If IOPL is less than 3, then the CPU generates a General Protection Fault whenever the V86 task attempts to execute the following instructions - CLI, STI, INT, IRET, LOCK, PUSHF and POPF. Node:Interrupt Handling, Next:Working in Protected Mode, Previous:V86 Mode, Up:Top
18 of 20
16/02/12 10:08 PM
http://prodebug.sourceforge.net/pmtut.html
When the General Protection Fault occurs, it can be either due to the fact that a V86 task was interrupted or it could be due to an interrupt in a true protected mode program. To differentiate between the two, the handler can look at the EFLAGS register to check if a V86 task was running. If a V86 task generated the interrupt, the interrupt handler can look at the offending instruction. Once the cause of interrupt is known, the operating system can choose to emulate the instruction (instructions like CLI, STI, etc.). or simply terminate the program or take any other action. Node:Working in Protected Mode, Next:Protected Mode Tutorial, Previous:Interrupt Handling, Up:Top
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.
19 of 20
16/02/12 10:08 PM
http://prodebug.sourceforge.net/pmtut.html
Footnotes 1. In reality, this hardly happens. Most BIOSes and even DOS, sometimes, use instructions like RETF 2, making this INT-IRET sequence unreliable enough for simulating interrupts in V86 mode. A work-around is to use a special VM86 stack-frame which is takes care of all this. 2. By denition the 8086 can't mask the NMI. On the PC, the motherboard, however, does have the ciruitary to prevent an NMI from occurring. You will rarely need to disable the NMI. On the ATs, the motherboard controls it with port 70H. Clearing bit 7 of this port will cut off NMI. 3. Many programs get access to memory beyond the 1 MB limit by simply enabling the A20. With the A20 enabled, the addresses won't wrap around, so they can access around 64K of memory above the 1MB limit without getting to real mode. But then, this can cause several problems with memory managers, so it must be carefully done 4. The IRET instruction in the 386's protected mode has a much different meaning than what it has in real mode. To return from an interrupt handler in protected mode, IRETD is used. 5. Traps have nothing to do with trap gates. A trap can be handled using an interrupt gate or a trap gate. 6. Note that the PDE and all PTEs must lie on the beginning of a 4K block.
20 of 20
16/02/12 10:08 PM