Entering Protected Mode from x86 Assembly

Intel’s 8086 chip was in no small part responsible for launching the personal computer revolution, but its 20-bit address bus could only access one megabyte of memory, and only half of that was available to user programs. As programs got bigger, Intel’s new chips started offering something called “protected mode”. Protected mode not only provided support for preemptive multitasking, which made operating system engineers happy, but it also made it possible to address whole gigabytes of memory, which made almost everyone happy, and almost made up for how complicated it was to get it to actually work in the first place.

1. Follow the steps in a previous tutorial, but replace the text of the assembly language source file with the code given below.

use16
org 0x7C00 ; boot sector address

Boot:
	;
	mov ah,0x00	; reset disk
	mov dl,0	; drive number
	int 0x13
	;
	mov ah,0x02	; read sectors into memory
	mov al,0x10	; number of sectors to read (16)
	mov dl,0	; drive number
	mov ch,0	; cylinder number
	mov dh,0	; head number
	mov cl,2	; starting sector number
	mov bx,Main	; address to load to
	int 0x13	; call the interrupt routine
	;
	jmp Main
	;

PreviousLabel:

PadOutWithZeroesSectorOne:
	times ((0x200 - 2) - ($ - $$)) db 0x00

BootSectorSignature:
	dw 0xAA55

;===========================================

Main:
	;
	; set the display to VGA text mode now
	; because interrupts must be disabled
	;
	mov ax,3
	int 0x10    ; set VGA text mode 3
	;
	; set up data for entering protected mode
	;
        xor edx,edx ; edx = 0
        mov dx,ds   ; get the data segment
        shl edx,4   ; shift it left a nibble
        add [GlobalDescriptorTable+2],edx ; GDT's base addr = edx
	;
        lgdt [GlobalDescriptorTable] ; load the GDT  
        mov eax,cr0 ; eax = machine status word (MSW)
        or al,1     ; set the protection enable bit of the MSW to 1
	;
        cli         ; disable interrupts
        mov cr0,eax ; start protected mode
	;
        mov bx,0x08 ; the size of a GDT descriptor is 8 bytes
        mov fs,bx   ; fs = the 2nd GDT descriptor, a 4 GB data seg
	;
	; write a status message
	;
	mov ebx,0xB8000 ; address of first char for VGA mode 3
	;
	mov si,TextProtectedMode ; si = message text
	;
	ForEachChar:
		;
		lodsb		; get next char	
		cmp al,0x00	; if it's null, break 	
		je EndForEachChar
		;
		mov [fs:ebx],al	; write char to display memory
		;
		inc ebx		; 2 bytes per char
		inc ebx		; so increment twice
		;
	jmp ForEachChar
	EndForEachChar:
	;
	LoopForever: jmp LoopForever
	;
	ret
	;
	TextProtectedMode: db 'The processor is in protected mode.',0

GlobalDescriptorTable:   

	; the global descriptor table is the heart of protected mode
	; entries are used to map virtual to physical memory
	; among other things
	;
	; each descriptor contains 8 bytes, "organized" as follows:
	;
	; |----------------------2 bytes--------------------|
	;
	; +-------------------------------------------------+
	; | segment address 24-31  | flags #2  | len 16-19  | +6
	; +-------------------------------------------------+
	; | flags #1               | segment address 16-23  | +4
	; +-------------------------------------------------+
	; | segment address bits 0-15                       | +2
	; +-------------------------------------------------+
	; | segment length bits 0-15                        | +0
	; +-------------------------------------------------+

	; the high-order bit of flags #2 controls "granularity"
	; setting it to 1 multiplies the segment length by 4096

	;======================================================

	; create two descriptors:
	; one for the GDT itself, plus a 4 gibabyte data segment

	dw GlobalDescriptorTableEnd - GlobalDescriptorTable - 1 
	; segment address bits 0-15, 16-23
	dw GlobalDescriptorTable 
	db 0	
	; flags 1, segment length 16-19 + flags 2
	db 0, 0
	; segment address bits 24-31
	db 0 

	; a data segment based at address 0, 4 gibabytes long
	; 
        dw 0xFFFF 	; segment length 0-15
	db 0, 0, 0 	; segment address 0-15, 16-23
	db 0x91 	; flags 1
	db 0xCF 	; flags 2, segment length 16-19
	db 0		; segment address 24-31
	;
GlobalDescriptorTableEnd:

;===========================================

PadOutWithZeroesSectorsAll:
	times (0x2000 - ($ - $$)) db 0x00

Notes

  • This code is cobbled together from multiple, very confusing sources, and was executed successfully for the first time only a short time before this tutorial was posted. Based on recent research, though, I fear that it may still be the best protected mode tutorial on the internet. Like the man says: prove me wrong, kids, prove me wrong.
This entry was posted in Uncategorized and tagged , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s