CLOSE

In the real mode, we only worked with register like AX, BX, CX, and DX and segments like CS, DS, ES, and SS, the instruction pointer IP and the stack pointer SP. The 80386+ processors actually brought new registers.

When we switch to 32-bit programming.

The existing register become wider. Like AX (16 bits wide), will soon have access to EAX (32-bits wide), as well as EBX, ECX and EDX. We will have additional segment registers as well (FS and GS). Similarly, the instruction pointer (IP) becomes (EIP) (32 bits) and SP as ESP.

  • Here, E prefix stands for Extended.

However, we gain other registers as well. The Intel 80386 processor comes armed with a set of control registers, and we’ll need one of them to switch to protected mode so we might as well talk about it now. These control registers change or control the behavior of the CPU. This includes interrupt control, switching addressing mode, paging and coprocessor control. The new registers are called CR0, CR1, CR2, CR3 and CR4.

These CR* registers control and modify the behavior of the CPU.

The first control register, CR0, has various control flags that modify the basic operation of the processor.

BitNameFull nameDescription
31PGPagingIf 1, enable paging and use the CR3 register, else disable paging
30CDCache disableGlobally enables/disable the memory cache
29NWNot-write throughGlobally enables/disable write-back caching
18AMAlignment maskAlignment check enabled if AM set, AC flag (in EFLAGS register) set, and privilege level is 3
16WPWrite protectDetermines whether the CPU can write to pages marked read-only
5NENumeric errorEnable internal x87 floating point error reporting when set, else enables PC style x87 error detection
4ETExtension typeOn the 386, it allowed to specify whether the external math coprocessor was an 80287 or 80387
3TSTask switchedAllows saving x87 task context upon a task switch only after x87 instruction used
2EMEmulationIf set, no x87 floating point unit present, if clear, x87 FPU present
1MPMonitor co-processorControls interaction of WAIT/FWAIT instructions with TS flag in CR0
0PEProtected mode enableIf 1, system is in protected mode, else system is in real mode

Some of these bits will become important for us later on, but for now, we are interested in the very first bit: the PE - Protection Enable bit. It enables protected mode.

Switching to Protected Mode

In order to make the switch to protected mode, all we have to do is enable the PE bit in the CR0 register: like so:

	; Read current value of CR0 into EAX
    mov eax, cr0

    ; Set the PE (Protection Enable) bit (bit 0) in CR0
    or eax, 0x00000001

    ; Write the modified value back to CR0
    mov cr0, eax

Setting up the 80386's registers

We’ll set all our data segments (ds, es, fs and gs) as well as the stack segment (ss) to use selector 2 from the global descriptor table, which corresponds to the data segment that we had defined in our GDT:

	; Set up data segment registers
    mov ax, 0x10       ; Data segment selector (GDT index 1)
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
[bits 16]
[org 0x7c00]

kernel16_start:

    xor ax, ax
    mov ss, ax
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov sp, 0xfff

    cli

    lgdt[GDT_DESCRIPTOR]

    mov eax, cr0
    or eax, 1
    mov cr0, eax

    jmp CODE_SEGMENT:kernel32_start


[bits 32]

kernel32_start:

    mov ax, DATA_SEGMENT
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax

    mov ebp, 0x0ffffff
    mov esp, ebp

    mov esi, hello_world
    call print_string

.loopk:
    jmp .loopk


print_string:
    pusha
    mov edx, VIDEO_MEMORY
.loop:
    mov al, [esi]
    cmp al, 0
    je .exit
    mov ah, 0x0f
    mov [edx], ax
    add esi, 1
    add edx, 2
    jmp .loop
.exit:
    popa
    ret


; Global Descriptor Table definition

GDT_START:

; GDT null segment (2 dwords)
GDT_NULL:
    dd 0x0
    dd 0x0

; GDT Code segment (2 dwords)
GDT_CODE:
    dw 0xffff  ; segment limit first 0-15 bits
    dw 0x0  ; base first 0-15 bits
    db 0x0  ; base 16-23 bits
    db 0x9a  ; access byte
    db 11001111b  ; high 4 bits (flags) low 4 bits (limit 4 last bits)(limit is 20 bit wide)
    db 0x0  ; base 24-31 bits

; GDT Data Segment (2 dwords)
GDT_DATA:
    dw 0xffff  ; segment limit first 0-15 bits
    dw 0x0  ; base first 0-15 bits
    db 0x0  ; base 16-23 bits
    db 0x92  ; access byte
    db 11001111b  ; high 4 bits (flags) low 4 bits (limit 4 last bits)(limit is 20 bit wide)
    db 0x0  ; base 24-31 bits

GDT_END:

GDT_DESCRIPTOR:
    dw GDT_END - GDT_START
    dd GDT_START

CODE_SEGMENT equ GDT_CODE + 4
DATA_SEGMENT equ GDT_DATA + 4


hello_world db 'HelloWorld', 0

VIDEO_MEMORY equ 0xB8000


times (510 - ($ - $$)) db 0x00
dw 0AA55h