Download presentation
Presentation is loading. Please wait.
Published bySamson Parsons Modified over 9 years ago
1
3. 32-Bits Protected Mode ENGI 3655 Lab Sessions
2
Richard Khoury2 Textbook Readings Segmentation ◦ Section 8.6 Pentium Segmentation ◦ Section 8.7.1
3
Richard Khoury3 16 Bits We have this line at the beginning of our bootloaders [BITS 16] Why? ◦ Obviously, because our code is 16 bits ◦ But our processors are 32 bits, so again, why? ◦ Because our CPU is in 16-bits Real Mode
4
Richard Khoury4 A Bit of History In real mode, any program has direct access to the computer resources ◦ Including all addresses in memory, the hardware and the BIOS interrupts, no protection whatsoever The slightest mistake in a program causes the computer to crash That’s the way all user programs were done originally
5
Richard Khoury5 A Bit of History Soon, people realised that programmers cannot be trusted with that power Needed some control ◦ Memory protection ◦ Multitasking while keeping all programs safe from each other ◦ Hardware-enforced protection and limits on what user programs can do CPU Protected Mode ◦ As opposed to Real Mode
6
Richard Khoury6 A Bit of History In the mean time, memory was becoming cheaper and cheaper, while programs needed more and more of it 8086 CPU was connected to 20 bit memory address bus ◦ 2 20 ≈ 1 MB main memory (conventional memory) ◦ But with 16-bit registers, only the first 64k were easily accessible directly ◦ Higher memory regions required awkwardly adjusting the segment registers ◦ That was another limitation in real mode
7
Richard Khoury7 A Bit of History Over time, memory address bus was expanded to 24 bits, then 32 bits (today 64 bits) ◦ 2 32 ≈ 4 GB (extended memory) ◦ New 32-bit CPU extended registers allowed programs to access the entire 4GB range in one operation 16 bits8 bits ahal ax eax
8
Richard Khoury8 A Bit of History Intel 8086/80186 ◦ 1979/1982 ◦ 16 bits with a 20-bit bus, real mode only Intel 80286 ◦ 1982 ◦ 16 bits with a 24-bit bus ◦ Protected mode, but with too many limitations Intel 80386 ◦ 1986 ◦ 32 bits ◦ Fully-functional protected mode ◦ Still used in many aerospace systems Intel 80486 ◦ 1989 ◦ Internal cache Intel Pentium (80586) ◦ 1993 ◦ 32 bits with a 64-bit bus
9
Richard Khoury9 16 Bits Operating systems ◦ Runs in 32 bits protected mode to benefit from up to 4GB of main memory, virtual memory, paging, safe multitasking, and hardware-enforced user/kernel protection rings However, Intel designed its 80x86 to be backward compatible ◦ They all start in 16-bit real mode, like the 8086 ◦ Therefore, our bootloader runs in 16-bit real mode ◦ It is part of the stage-2 bootloader’s function to switch the CPU to 32-bit protected mode
10
Enable memory protection & segmentation ◦ Set up the Global Descriptor Table Enable 32-bit memory addressing ◦ Activate Gate A20 Read the Kernel into memory ◦ I’ll give you a free one Enter Protected Mode ◦ Switch the CPU to Protected Mode and jump to the Kernel In This Lab Richard Khoury10
11
Richard Khoury11 Memory Protection In protected mode, our program cannot access memory directly like it did in real mode Instead, memory will be divided in segments ◦ Each segment has clear boundaries and a privilege setting Information on the segments is kept in the Global Descriptor Table (GDT) ◦ Your program accesses memory through the GDT ◦ The OS double-checks in the CPU’s GDT that the program has the correct privileges and that the address is in the segment
12
Richard Khoury12 Global Descriptor Table Bootloader must set it up before entering protected mode Descriptor is a 64-bit (8 bytes) data structure Null Descriptor ◦ All zeros Code Descriptor ◦ This memory area contains executable code Data Descriptor ◦ This memory area contains data
13
Richard Khoury13 Descriptors Bits 0-15: Segment limit (low 16 bits) Bits 16-39: Base address, start of segment (low 24 bits) Bit 40: Access bit for virtual memory Bits 41-43: Descriptor type ◦ Bit 41: Read/Write bit 0: Read only (Data Segments); Execute only (Code Segments) 1: Read and write (Data Segments); Read and Execute (Code Segments) ◦ Bit 42: Expansion direction (Data segments), conforming (Code Segments) ◦ Bit 43: Executable segment 0: Data Segment 1: Code Segment
14
Richard Khoury14 Descriptors Bit 44: Descriptor Bit ◦ 0: System Descriptor ◦ 1: Code or Data Descriptor Bits 45-46: Descriptor Privilege Level ◦ 00: Ring 0, Highest (kernel) ◦ 01: Ring 1 ◦ 10: Ring 2 ◦ 11: Ring 3, Lowest (user) Bit 47: Segment is in memory (Virtual Memory)
15
Richard Khoury15 Descriptors Bits 48-51: Segment limit (high 4 bits) Bits 52-53: Reserved (should be 0) Bit 54: Segment type ◦ 0: 16 bit ◦ 1: 32 bit Bit 55: Granularity of the segment ◦ 0: Byte (1 byte) ◦ 1: Page (4kB) (that is 4096B, or 1000h) Bits 56-63: Base address (high 8 bits)
16
Descriptor Implementation Eventually, we can divide the memory into segments for each program ◦ Each memory access will be checked against the segment base, size, and priority level But to begin, the 80x86 requires a flat memory model ◦ Null descriptor (all zeros) ◦ Kernel-mode code descriptor ◦ Kernel-mode data descriptor ◦ User-mode code descriptor ◦ User-mode data descriptor
17
Our initial segments ◦ Cover entire 4GB memory range Base 0x0, limit 0xFFFFF, granularity 4kB Note: Size of a segment is: base + (limit + 1)*granularity = 1 0000 0000 Note: Final limit address is: size – 1 = FFFF FFFF ◦ Do not use virtual memory VM access bit = 0; VM segment in memory bit = 1 ◦ Not read-only ◦ 32-bit segments types ◦ Expansion direction bit = 0 Descriptor Implementation Richard Khoury17
18
You cannot define 64 bits at once But you can define bytes (8 bits) and words (16 bits) You can write in hex or binary Order matters! ◦ The first word (16 bits) are before the next byte ◦ The right-hand bits of the byte are before the left- hand bits Descriptor Implementation Richard Khoury18 dw FFFFh db 11001111b
19
Lab, Part 1 Write the five descriptors we need ◦ In GDT.inc Later, our OS will switch between user and kernel mode by changing which memory segment we point to
20
Richard Khoury20 Global Descriptor Table To load the GDT into a CPU register, we need to define pointers to it ◦ Put labels gdt_data: and end_of_gdt: at the beginning and end of the GDT ◦ Define a pointer with the size minus one and the start of the GDT toc: dw end_of_gdt - gdt_data - 1 dd gdt_data ; base of GDT The GDT is loaded into a special register in the CPU, the GDTR, using a special “load GDT” instruction lgdt [toc]
21
Richard Khoury21 More History The original 8086 had a 20-line address bus ◦ Lines A0 to A19 The bus was expanded to 24 lines on the 80286, then 32 lines on the 80386 ◦ Adding lines A20 to A23/A31 To maintain backward compatibility, these have to be deactivated at boot-up ◦ Intel added a logic gate on line A20 to control it ◦ We’ll have to activate Gate A20 to be able to use all available memory
22
Richard Khoury22 Enabling Gate A20 Intel needed to add a hardware gate and a pin somewhere to control it The keyboard controller happened to have a free pin Therefore, the way to control Gate A20 and enable higher memory is through the keyboard ◦ I’m not even kidding here
23
Richard Khoury23 Keyboard Controller Our bootloader will need to send commands to the keyboard controller The keyboard controller uses two 8-bit ports in either read or write mode 0x60 data input/output port ◦ Read output buffer ◦ Write input buffer 0x64 command/status port ◦ Read status register ◦ Send command to controller
24
Keyboard Controller 0x64 read mode: Status register Bit 0: Output Buffer Status ◦ 0: Output buffer empty, don’t read ◦ 1: Output buffer full, ready to read Bit 1: Input Buffer Status ◦ 0: Input buffer empty, can be written ◦ 1: Input buffer full, don’t write Bit 2: System flag ◦ 0 on power on, 1 after keyboard self test Bit 3: Command Data ◦ 0/1 = last write was data/command Bit 4: Keyboard Locked ◦ 0/1 = locked/not locked Bit 5: Auxiliary Output buffer full ◦ 0/1 = OK/timeout Bit 6: Timeout ◦ 0/1 = OK/timeout Bit 7: Parity error ◦ 0/1 = OK/parity error
25
Keyboard Controller 0x64 write mode: send command to controller 0xAD ◦ Disable Keyboard 0xAE ◦ Enable Keyboard 0xD0 ◦ Read Output Port 0xD1 ◦ Write Input Port
26
Keyboard Controller 0x60 input/output port: 8 bits Bit 0: System Reset Bit 1: A20 ◦ 0: A20 disabled ◦ 1: A20 enabled Bits 2-3: Undefined Bit 4: Input buffer full Bit 5: Output buffer empty Bit 6: Keyboard Clock Bit 7: Keyboard Data
27
Enabling Gate A20 Activating A20 can be done through four commands to the keyboard controller ◦ Disable keyboard ◦ Read output port ◦ (Set bit #1 to 1) ◦ Write input port ◦ Enable keyboard Lab, part 2: do this
28
Useful Functions IN ◦ Transfer byte from a controller port to the AL register ◦ IN al, port# OUT ◦ Transfer byte from the AL register to a controller port ◦ OUT port#, al TEST ◦ Compare a register to a given value without changing either of them ◦ TEST al, # ◦ Will clear the CF flag if they are different, or set it if they are identical ◦ Can then be followed by a jump, like JNZ or JZ
29
Useful Functions Before each write, you should check that the input buffer is empty and can be written ◦ Read 0x64 and test input buffer status All other bits will be 0 ◦ Loop if not ready to write Before each read, you should check that the output buffer is full and ready to read ◦ Read 0x64 and test output buffer status All other bits will be 0 ◦ Loop if not ready to read
30
Richard Khoury30 Entering Protected Mode Now the GDT is loaded and Gate A20 is activated We can finally switch to Protected Mode
31
Richard Khoury31 Entering Protected Mode Protected Mode is a mode of operation of the processor Behaviour of processor is controlled by the Control Registers (CR) There are five CR in the 80x86 ◦ CR0 controls a number of general behaviours ◦ CR1 is reserved by Intel ◦ CR2 controls the Page Fault Linear Address ◦ CR3 controls memory paging, and includes the Page Directory Base Register ◦ CR4 controls behaviour while in protected mode Which one should we look at?
32
Richard Khoury32 CR0 32-bit register primary control register Bit 0: Protected Mode Enable (PE) ◦ 0/1 = Real mode/Protected mode Bit 1: Monitor co-processor (MP) ◦ Controls the operation of the WAIT & FWAIT instructions Bit 2: Emulation (EM) ◦ 0/1 = floating point units activated/deactivated Bit 3: Task Switched (TS) ◦ Set to 1 when processor switches to another task, to allow saving context Bit 4: Extension Type (ET) ◦ 0/1 = coprocessor is 80287/80387
33
Richard Khoury33 CR0 Bit 5: Numeric Error (NE) ◦ 0 - Enable standard error reporting ◦ 1 - Enable internal x87 FPU error reporting Bits 6-15 : Unused Bit 16: Write Protect (WP) Bit 17: Unused Bit 18: Alignment Mask (AM) ◦ 0/1 = Alignment Check Disabled/Enabled Bits 19-28: Unused Bit 29: Not Write-Through (NW) Bit 30: Cache Disable (CD) Bit 31: Paging (PG) ◦ 0/1 = Memory Paging Disabled/Enabled ◦ When enabled, CR3 is used
34
Richard Khoury34 Entering Protected Mode Bit 0: Protected Mode Enable (PE) ◦ 0/1 = Real mode/Protected mode ◦ At booting, that bit is 0, it needs to be switched to 1 to enter protected mode mov eax, cr0 or eax, 1 mov cr0, eax Before we do, we need to disable interrupts cli ◦ We cannot re-enable them after; protected mode does not allow BIOS interrupts
35
Richard Khoury35 Reading the Kernel The final task of the bootloader is to read the OS kernel into memory and jump to it We will write the kernel next week ◦ For now, use “kernel.bin” from the website
36
Richard Khoury36 Reading the Kernel We already know how to find files on a FAT12 disk and how to read them into memory ◦ BIOS Interrupt 13h We’ll need to add this ability to our second- stage bootloader However, BIOS interrupts are not usable from protected mode ◦ We’ll do it in real mode
37
Richard Khoury37 Reading the Kernel Next, we want to put the kernel at 1MB in memory ◦ Right after the end of conventional memory accessible by 20-bit real mode ◦ Beginning of extended memory ◦ But that area is not accessible in real mode! ◦ We’ll have to do that in protected mode So we have a problem ◦ We can only read the disk in real mode and access the memory in protected mode
38
Richard Khoury38 Stage 2 Bootloader Structure Install GDT Enable Gate A20 Read Kernel into Lower Memory Enter Protected Mode Copy Kernel to 1MB in Memory Jump to Kernel
39
Richard Khoury39 Reading the Kernel Reading the Kernel from disk to lower memory is done as before ◦ Use FAT-handling functions from lab 2 included in “FAT12.inc” ◦ Notice that our LoadFile function kept a count of sectors read popecx incecx pushecx Copy “kernel.bin” to 0x3000 (unused region of conventional memory)
40
Richard Khoury40 Reading the Kernel After we’re in Protected Mode, we want to copy it to 1MB in memory (address 0x100000) moveax, dword [ImageSize] movzxebx, word [bpbBytesPerSector] mulebx movebx, 4 divebx cld movesi, IMAGE_RMODE_BASE movedi, IMAGE_PMODE_BASE movecx, eax repmovsd
41
Richard Khoury41 Reading the Kernel Compute size to copy (in double-words) in ECX ◦ The size of the kernel in sectors is stored in ImageSize after our FAT12 function ◦ The size of a sector in bytes is known from the BPB ◦ A double-word is two words, or four bytes ◦ CX=(size of kernel in sectors) * (bytes per sector) / 4 ◦ MOVZX : copy a 16-bit source to a 32-bit destination, fill with 0
42
Richard Khoury42 Reading the Kernel Copy! ◦ Set copy direction from left to right ◦ Move origin in DS:SI and destination in ES:DI ◦ movsd moves double-words from DS:SI to ES:DI ◦ rep repeats it for CX times
43
Richard Khoury43 Reading the Kernel Once the copying is done, simply jump to the kernel’s memory position Only jump allowed in Protected Mode is Descriptor:Address far jump jmp CODE_DESC:0x100000 And that’s the end of the bootloader!
44
Lab Assignment New files: ◦ Gdt.inc, which contains the declaration of the GDT and the function to load it ◦ A20.inc, which contains the function to enable the A20 line ◦ Stage-2 Bootloader that calls these functions ◦ A compiled Kernel
45
Richard Khoury45 Lab Assignment Write the five GDT descriptors Write the function to make the keyboard controller activate line A20 With this, our second-stage bootloader is complete!
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.