0x7C00 to RING 3
Posted: Mon Nov 29, 2010 2:30 am
Just thought I'd share some code. Was able to go from 0x7C00 to ring 3 in 102 bytes (including gdt but not the boot magic). Finding out that LGDT instruction was using DS kept me busy for a while. The best part is that it works on my native hardware too! Now I just need to find a way back
Code: Select all
; Boot sector offset in memory
ORG 0x7C00
; Initially in 16 bit Real Mode
BITS 16
; Keep interrupts for crashing the mode switch
cli
; LGDT uses the DS register offset
xor ax,ax
mov ds,ax
lgdt[gdtr]
; Set the PE bit in CR0 which enables Protected Mode
mov eax, cr0
or al, 1
mov cr0, eax
; According the the Intel Architectures Software Developer's Manual
; the following will clear the prefetch cache that will contain
; invalid information in 32 bit mode.
jmp long code_segment:pmode
; This is the entry point into 32 bit Protected Mode
BITS 32
pmode:
; Load a valid SS register
mov ax, data_segment
mov ss, ax
; Set the RING 0 stack
mov esp, 0x7C00
; Here we setup a stack from for the IRET instruction
; which will pop the following SS / ESP / EFLAGS / CS / EIP
; since RPL > CPL
push dword udata_segment | 3
push dword 0x8000
pushf
push dword ucode_segment | 3
push ring3
; Switch to RING 3
iret
; At this point we are running under the rules of RING 3
ring3:
.loop:
inc byte [ss:0xB8001]
jmp .loop
; Global Descriptor Table
gdt:
; null descriptor / GDTR
gdt_null:
; Global Descriptor Table Register
gdtr:
dw gdt_end-gdt-1
dd gdt
dw 0
; code
gdt_cs:
; RING 0 Code Segment
code_segment equ $-gdt
dd 0x0000FFFF
dd 0x00CF9A00
; data
gdt_ds:
; RING 0 Data Segment
data_segment equ $-gdt
dd 0x0000FFFF
dd 0x00CF9200
; code
gdt_ucs:
; RING 3 Code Segment
ucode_segment equ $-gdt
dd 0x0000FFFF
dd 0x00CFFA00
; data
gdt_uds:
; RING 3 Data Segment
udata_segment equ $-gdt
dd 0x0000FFFF
dd 0x00CFF200
gdt_end:
; Skip to end of MBR and insert the boot magic
TIMES 510-($-$$) db 0
dw 0xAA55