1, Concepts:
CS.L
L (long) flag in Code Segment entry of GDT or LDT, indicating long mode
CS.D
D (doubleword) flag in Code Segment entry of GDT or LDT, indicating protected mode
.code32
Indicating a 32bit code segment
.code64
Indicating a 64bit code segment
EFER
Extended Feature Enable Register, a special configuration register for 64bit machine.
EFER.LME
Long Mode Enable flag in EFER, when enabled, the CPU works in either compatibility
mode or long mode.
Disabling paging also disables EFER.LME.
EFER.LMA
Long Mode Activity flag in EFER, when enabled, the CPU works in long mode.
Setting CS.L=1 also sets EFER.LMA=1, and clearing CS.L also clears EFER.LMA.
PAE
Page Address Extension, a flag in cr4, when enabled, the CPU can access more than 4GB
memory, it is required by compatibility mode and long mode.
PGE
Page Global Enable, a flag in cr4, when enabled, a page can have Global Page attribute
so that it will stay in cache as long as the cache size is allow.
This flag is only available in 64 bit machine.
Compatibility Mode
When a CPU runs in .code32, has EFER.LME=1 and CS.L=0 (CS.D=1), it works in
compatibility mode. This is a transition mode that can execute both 64 bit instructions
32 bit ones.
Long Mode
When a CPU runs in .code64, has EFER.LME=1 and CS.L=1 (CS.D=0), it works in Long mode.
In this mode, all instructions and addressings are interpreted as 64 bit long.
Identity Mapping
A page mapping that maps a virtual address to the same physical address, this mapping is
required in mode switching that involves paging.
2, Registers
In 64 bit mode (compatibility mode or long mode), all accessible registers include:
64 bit registers:
rax, rbx, rcx, rdx, r8, r9, r10, r11, r12, r13, r14, r15, rsi, rdi, rsp, rbp
All config registers become 64 bits:
cr0~cr4, cr8 (64bit mode only, Task Priority Register (TPR))
32 bit registers:
eax, ebx, ecx, edx, esi, edi, esp, ebp
All segment registers are also 32 bits, but their content has no effect,
note that they should not be used to prefix an address in long mode.
cs, ds, es, ss, fs, gs
16 bit registers:
ax, bx, cx, dx, si, di, sp, bp
8 bit registers:
ah, al, bh, bl, ch, cl, dh, dl
Among them,
rax, rbx, rcx, rdx, rsi, rdi, rsp, rbp
are extended from
eax, ebx, ecx, edx, esi, edi, esp, ebp
respectively.
But everytime when the lower 32bit register is loaded with a new value, the higher
32bit will be cleared, this is very important in programming.
3, 64 bit parameter passing in GCC
All parameters are extended to 64 bit before passing, the order is:
rdi, rsi, rdx, rcx, r8, r9, r10, ...
For example, in assembly code, one can call a C function this way:
This is the prototype of a C function:
void printk_at(int x, int y, int color, int attr, char *fmt, ...);
This is the method to call that function in NASM format:
extern printk_at
teststr db 'The value of EDI is %d/n', 0
call printk_at in function code:
push_all ; a macro to push all common registers
mov eax, edi
mov edi, 0 ; x
mov esi, 21 ; y
mov edx, 7 ; white color
mov ecx, 0 ; black background
mov r8, teststr ; display string
mov r9, rax ; value, only eax will be used
call printk_at
pop_all ; a macro to pop all common registers
4, Alignment issue
In assembly code, all 64 bit data should be aligned to 64 bit boundary, or else a
write to it (with MOV instruction) will cause the machine to reboot.
In C, all data are aligned automatically by compiler.
5, Switching from protected mode to long mode
1) Enable PAE and PGE in cr4
xorl %eax, %eax
btsl $5, %eax # PAE: Page Address Extension
btsl $7, %eax # PGE: Page Global Enable
movl %eax, %cr4
2) Load pagetable in cr3, the page mapping must be an identity mapping.
movl $pgtable, %eax # address of 4 level page table
movl %eax, %cr3
3) Setup EFER, so that when paging is enabled,
we will be in compatibility mode
movl $MSR_EFER, %ecx # MSR_EFER = 0xc0000080
rdmsr
/* Fool rdmsr and reset %eax to avoid dependences */
xorl %eax, %eax
btsl $_EFER_LME, %eax # _EFER_LME = 8, Enable Long Mode
btsl $_EFER_SCE, %eax # _EFER_SCE = 0, Enable System Call
btl $20,%edi
jnc 1f
btsl $_EFER_NX, %eax /* _EFER_NX = 11, No Execute supported? */
1:
wrmsr /* Make changes effective */
4) Enable paging and other flags in cr0
xorl %eax, %eax
btsl $31, %eax # Enable paging
btsl $0, %eax # Enable protected mode
btsl $1, %eax # Enable MP
btsl $4, %eax # Enable ET
btsl $5, %eax # Enable NE
btsl $16, %eax # Enable WP
btsl $18, %eax # Enable AM
movl %eax, %cr0 # Make changes effective
5) Use a long jump to make flags effective, now we are in compatibility mode
6) Load 64 bit GDT and IDT and long-jump to 64 bit long mode in .code64 segment
lgdt pGDT64 # CS.L = 1, CS.D = 0
lidt pIDT64
/* set up data segments. actually 0 would do too */
movl $KERNEL_DS,%eax
movl %eax,%ds
movl %eax,%ss
movl %eax,%es
movl $long_mode_ptr, %eax # located in .code64 segment
ljmp *(%eax) # Finally jump in 64bit long mode
6, Switching back from long mode to protected mode
1) Disable interrupt and MNI
cli # no interrupts allowed !
movb $0x80, %al # disable NMI
outb %al, $0x70
2) Use a long jump to jump into .code32 segment
movl $reach_code32_ptr, %eax
ljmp *(%eax) # Jump in .code32 segment
3) Load 32bit GDT and IDT, and long jump to compatibility mode
/*
* MUST load GDT with CS.L=0 and ljmp before clearing cr0.PG
*/
movl $idt_32, %eax
lidt (%eax) # load idt with 0,0
movl $gdt_32, %eax
lgdt (%eax) # load 32 bit gdt, CS.L=0, CS.D=1
/* Jump to compatibility mode */
movl $reach_compat_ptr, %eax
ljmp *(%eax) # EFER.LMA is automatically cleared
4) Clear page flag in cr0 to disable paging, and jump to protected mode
/* Reload 32 bit segment reigsters */
movl $KERNEL_DS, %eax
movl %eax, %ds
movl %eax, %es
movl %eax, %ss
movl %cr0, %eax
andl $0x7fffffff, %eax # set cr0.PG=0
movl %eax, %cr0
/* Disable Long Mode in EFER.
* According to Intel menual, this is not necessary,
* but I need to be more assured
*/
movl $MSR_EFER, %ecx # MSR_EFER = 0xc0000080
rdmsr
btrl $_EFER_LME, %eax # EFER_LME = bit 8
btrl $_EFER_LMA, %eax # EFER_LMA = bit 10
wrmsr # Make changes effective
/* Jump in protected mode with paging off */
movl $reach_prot_ptr, %eax
ljmp *(%eax) # EFER.LME will be automatically cleared
5) Now we are in protected mode with paging off
References:
* IA 32 Intel Architecture Software Developer's Manual
http://developer.intel.com/design/pentium4/manuals/
Refer to Vol 3A, page 69 for details of control registers.
Refer to Vol 3A, page 140 for GDT entry description.
Refer to Vol 3A, page 180 for details of EFER description.
Yu Zhenshen
August, 27th, 2009 in Shenzhen