Page 1 of 1

0x7C00 to RING 3

Posted: Mon Nov 29, 2010 2:30 am
by ecco
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 :D

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

Re: 0x7C00 to RING 3

Posted: Mon Nov 29, 2010 4:42 am
by Dario
Finding out that LGDT instruction was using DS kept me busy for a while.
Actually, LGDT is using linear address...it doesn't care what is in DS, but that address is easier to get when DS=0x0000.
Otherwise if your DS was something like this: DS:0x07C0, then you would do this to obtain linear address:

Code: Select all

lgdtr (0x07C0<<4)+gdtr
from Intel 2a:
The source operand specifies a 6-byte memory location that contains the base address (a linear address) and
the limit (size of table in bytes) of the global descriptor table (GDT) or the interrupt
descriptor table (IDT).

Re: 0x7C00 to RING 3

Posted: Mon Nov 29, 2010 6:21 am
by gerryg400
Actually, LGDT is using linear address...it doesn't care what is in DS, but that address is easier to get when DS=0x0000.
Otherwise if your DS was something like this: DS:0x07C0, then you would do this to obtain linear address:
Are you sure ? I understood that the operand uses segmented addressing as usual but the value that is loaded is linear. In other words, DS is relevant when LGDT is executed.

Re: 0x7C00 to RING 3

Posted: Mon Nov 29, 2010 7:14 am
by Dario
Are you sure ? I understood that the operand uses segmented addressing as usual but the value that is loaded is linear. In other words, DS is relevant when LGDT is executed.
I just wanted to point out that he could use what ever segment was specified in DS, but transform it to linear address before using it as an operand.

Re: 0x7C00 to RING 3

Posted: Mon Nov 29, 2010 7:22 am
by gerryg400
I just wanted to point out that he could use what ever segment was specified in DS, but transform it to linear address before using it as an operand.
No that's not correct. The operand is segmented. But the operand points to a linear address.

Re: 0x7C00 to RING 3

Posted: Mon Nov 29, 2010 8:10 am
by Dario
gerryg400 wrote:The operand is segmented.
Then why don't we use DS:OFFSET in instruction?

Re: 0x7C00 to RING 3

Posted: Mon Nov 29, 2010 8:23 am
by gerryg400
As is mostly the case, DS is the default seg for data. But you can use a segment override.

Re: 0x7C00 to RING 3

Posted: Mon Nov 29, 2010 11:42 am
by ecco
LGDT(DS:Offset) is implied if no other segment is specified... apparently :P. It worked fine if I loaded it using some other bootloader but not when I booted it directly because I wasn't clearing DS and my computer boots with DS=0x9FC0.

Re: 0x7C00 to RING 3

Posted: Tue Nov 30, 2010 1:40 am
by ecco
Well now I've got a task scheduler in place and can trigger GPFs and DIV0 errors that merely cause that particular RING 3 task to be removed from the scheduling queue. My setup now has a kernel stack and user stack allocated to each process. I'm thinking that theoretically I can leave interrupts enabled full time except for the part where I switch contexts...

Re: 0x7C00 to RING 3

Posted: Tue Nov 30, 2010 3:52 pm
by TylerH
Dario wrote:Actually, LGDT is using linear address...it doesn't care what is in DS, but that address is easier to get when DS=0x0000.
Otherwise if your DS was something like this: DS:0x07C0, then you would do this to obtain linear address:

Code: Select all

lgdtr (0x07C0<<4)+gdtr
from Intel 2a:
The source operand specifies a 6-byte memory location that contains the base address (a linear address) and
the limit (size of table in bytes) of the global descriptor table (GDT) or the interrupt
descriptor table (IDT).
It says that the base part of the 6 byte structure, usually called the GDTR, at the memory location is linear; not that the pointer specifying the address of the structure has to be linear.

Re: 0x7C00 to RING 3

Posted: Wed Dec 01, 2010 2:30 am
by ecco
Agreed, when the processor uses the 6-byte pointer stored in GDTR to access the segment descriptors DS nor any other segment register is used (i.e. linear). However when executing the LGDT instruction the operand is defaulted to [DS:value] but can be overridden with any of the other segment registers.