Entering 64bit Mode.

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
manlyman
Posts: 4
Joined: Sun Oct 24, 2010 10:25 am

Entering 64bit Mode.

Post by manlyman »

I've recently decided to go 64bit with my kernel. After finding that i was spending a lot of my time writing code that does the same thing just using different features of the processor: interupts/syscall/sysenter, fsave/fxsave/osxsave and PIC/APIC for example.

With long mode i can assume support for a lot of features and be able to support much larger address spaces and ram. And with hobby OS's taking 5-10 years to develop into something useable it seems silly to build a 32bit kernel when typical pc's will be running programs that want far more than 4GB address space. Making my OS obsolete.

I've been looking at http://wiki.osdev.org/User:Stephanvansc ... _Long_Mode which has proved very useful. I've stubbed out the beginning of a kernel that can enter long mode.

At the moment i have 2 GDT's. One is 32bit and one is 64bit each with their own register structure.

What i've figured is that i could use one GDT and just use a different register. Like this:

Code: Select all

;----------
; GDT
;----------
gdt32Register:               
    dw gdtEnd-gdt-1
    dd gdt
gdt64Register:
    dw gdtEnd-gdt-1
    dq gdt
gdt:
    .null:
        dq 0             ;Reserved
    .kernelCode:         ;Flat DPL=0 code selector
        dw 0xFFFF        ;Limit  0-15
        dw 0             ;Base   0-15
        db 0             ;Base  16-23
        db 10011010b     ;Access
        db 11101111b     ;Limit 16-19, Flags 0-3 (granularity set to 4kb, size set to 32bit, 64bit flag set)
        db 0             ;Base  24-31
    .kernelData:         ;Flat DPL=0 data selector
        dw 0xFFFF
        dw 0
        db 0
        db 10010010b
        db 11101111b
        db 0
gdtEnd:            
This works in QEMU-system-x86-64. Is there anything wrong with doing this? Is it ok to have the 64bit flag set when in 32bit mode. If this was run on a 32bit cpu where this flag was reserved would it triple fault? It it considered wrong (qemu allows it though) that the 32bit and 64bit flags are set when in 64 bit mode?

Also as a sidenote from what i know all 64bit instructions have a REX prefix and the immediate and memory operands are twice as big and hence slower. Should all of my code be 32bit where possible and just 64bit operands for pointers and very large numbers?

Thanks.
User avatar
Owen
Member
Member
Posts: 1700
Joined: Fri Jun 13, 2008 3:21 pm
Location: Cambridge, United Kingdom
Contact:

Re: Entering 64bit Mode.

Post by Owen »

Setting a reserved bit is always illegal and will likely cause issues on some processors. However, you need 32-bit segments in your 64-bit GDT anyway (SYSCALL/SYSRET assume their presence)

Long mode only has 32-bit sign extended immediates, except for a couple of instructions which take 64-bit immediates. All instructions operating on 64-bit data, or using r8-r15, require a REX prefix. You cannot address ?H and r?b in the same instruction.
gerryg400
Member
Member
Posts: 1801
Joined: Thu Mar 25, 2010 11:26 pm
Location: Melbourne, Australia

Re: Entering 64bit Mode.

Post by gerryg400 »

Intel 3A is very clear in section 3.4.5
If L-bit is set, then D-bit must be cleared.
If a trainstation is where trains stop, what is a workstation ?
manlyman
Posts: 4
Joined: Sun Oct 24, 2010 10:25 am

Re: Entering 64bit Mode.

Post by manlyman »

After some time on IRC, i believe i've come to the solution. I'm now only using the long bit on the k64code descriptor (thanks gerry) and i've organized my descriptors in such a way that it should be compatible with syscall and sysret in both modes (thanks to owen and xgf for helping me here).

Code: Select all

;----------
; GDT
;----------
gdt32Register:                  ;Global descriptor table
    dw gdtEnd-gdt-1
    dd gdt
gdt64Register:
    dw gdtEnd-gdt-1
    dq gdt
gdt:
    .null:
        dq 0
    .k32Code:          ;syscall uses this as the first selector set in STAR MSR
        dw 0xFFFF
        dw 0
        db 0
        db 10011010b   ;access byte
        db 11001111b   ;top 4 bits are flags, bottom 4 are part of limit
        db 0
    .kData:            ;needs to be after k32code, SS is loaded with STAR+8
        dw 0xFFFF
        dw 0
        db 0
        db 10010010b
        db 11001111b
        db 0
    .k64code:          ;when in 64bit mode, syscall loads STAR+16 so this needs to be here
        dw 0
        dw 0
        db 0
        db 10011000b
        db 00100000b
        db 0
    .u32code:          ;sysret needs uses this as the base selector in the MSR
        dw 0xFFFF
        dw 0
        db 0
        db 11111010b
        db 11001111b
        db 0
    .u32data:         ;needs be after u32code as it sysret asks for MSR+8 for this
        dw 0xFFFF
        dw 0
        db 0
        db 11110010b
        db 11001111b
        db 0
    .u64code:         ;needs be 2 selectors after u32code as it sysret asks for MSR+16 in 64bit mode
        dw 0
        dw 0
        db 0
        db 11111000b
        db 00100000b
gdtEnd:     
Post Reply