diff options
Diffstat (limited to 'efi')
-rw-r--r-- | efi/x86_64/linux.S | 61 |
1 files changed, 41 insertions, 20 deletions
diff --git a/efi/x86_64/linux.S b/efi/x86_64/linux.S index 0a0e9965..972c0b2c 100644 --- a/efi/x86_64/linux.S +++ b/efi/x86_64/linux.S @@ -10,8 +10,9 @@ * * ----------------------------------------------------------------------- */ -#define CR0_PG_FLAG 0x80000000 -#define MSR_EFER 0xc0000080 +#define CR0_PG_BIT 31 +#define CR4_PAE_BIT 5 +#define MSR_EFER 0xc0000080 .globl kernel_jump .type kernel_jump,@function @@ -19,30 +20,50 @@ kernel_jump: cli - /* - * Setup our segment selector (0x10) and return address (%rdi) - * on the stack in preparation for the far return below. - */ - mov $0x1000000000, %rcx - addq %rcx, %rdi - pushq %rdi + /* save the content of rsi (boot_param argument of kernel_jump function) */ + mov %rsi, %rbx + + call base_address +base_address: + pop %rsi + + /* need to perform a long jump to update cs + + /* load absolute address of pm_code in jmp_address location */ + lea (pm_code - base_address)(%rsi, 1), %rax + mov %eax, (jmp_address - base_address)(%rsi, 1) + + ljmp *(jmp_address - base_address)(%rsi, 1) + +jmp_address: + .long 0 /* address */ + .word 0x10 /* segment */ .code32 pm_code: - /* Disable IA-32e mode by clearing IA32_EFER.LME */ - xorl %eax, %eax - xorl %edx, %edx - movl $MSR_EFER, %ecx - wrmsr + /* cs segment has been updated, now update the rest */ + mov $0x18, %eax + mov %eax, %ds + mov %eax, %es + mov %eax, %fs + mov %eax, %gs + mov %eax, %ss - /* Turn off paging to disable long mode */ - movl %cr0, %eax - andl $~CR0_PG_FLAG, %eax - movl %eax, %cr0 + /* disable paging. */ + mov %cr0, %eax + btr $CR0_PG_BIT, %eax /* PG in CR0 */ + mov %eax, %cr0 + + /* disable long mode. */ + mov $MSR_EFER, %ecx + rdmsr + btr $8, %eax + wrmsr - /* Far return */ - lret + /* kernel jump */ + mov %ebx, %esi + jmp *%edi .code64 .align 4 |