Add code to jump to a 64-bit Linux kernel. We need to set up a flat page table structure, a new GDT and then go through a few hoops in the right order. Signed-off-by: Simon Glass <sjg@chromium.org>master
parent
92cc94a1fe
commit
200182a748
@ -0,0 +1,93 @@ |
||||
/* |
||||
* (C) Copyright 2014 Google, Inc |
||||
* Copyright (C) 1991, 1992, 1993 Linus Torvalds |
||||
* |
||||
* Parts of this copied from Linux arch/x86/boot/compressed/head_64.S |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <asm/global_data.h> |
||||
#include <asm/msr-index.h> |
||||
#include <asm/processor-flags.h> |
||||
|
||||
.code32 |
||||
.globl cpu_call64
|
||||
cpu_call64: |
||||
/* |
||||
* cpu_call64(ulong pgtable, ulong setup_base, ulong target) |
||||
* |
||||
* eax - pgtable |
||||
* edx - setup_base |
||||
* ecx - target |
||||
*/ |
||||
cli |
||||
push %ecx /* arg2 = target */ |
||||
push %edx /* arg1 = setup_base */ |
||||
mov %eax, %ebx |
||||
|
||||
/* Load new GDT with the 64bit segments using 32bit descriptor */ |
||||
leal gdt, %eax |
||||
movl %eax, gdt+2 |
||||
lgdt gdt |
||||
|
||||
/* Enable PAE mode */ |
||||
movl $(X86_CR4_PAE), %eax |
||||
movl %eax, %cr4 |
||||
|
||||
/* Enable the boot page tables */ |
||||
leal (%ebx), %eax |
||||
movl %eax, %cr3 |
||||
|
||||
/* Enable Long mode in EFER (Extended Feature Enable Register) */ |
||||
movl $MSR_EFER, %ecx |
||||
rdmsr |
||||
btsl $_EFER_LME, %eax |
||||
wrmsr |
||||
|
||||
/* After gdt is loaded */ |
||||
xorl %eax, %eax |
||||
lldt %ax |
||||
movl $0x20, %eax |
||||
ltr %ax |
||||
|
||||
/* |
||||
* Setup for the jump to 64bit mode |
||||
* |
||||
* When the jump is performed we will be in long mode but |
||||
* in 32bit compatibility mode with EFER.LME = 1, CS.L = 0, CS.D = 1 |
||||
* (and in turn EFER.LMA = 1). To jump into 64bit mode we use |
||||
* the new gdt/idt that has __KERNEL_CS with CS.L = 1. |
||||
* We place all of the values on our mini stack so lret can |
||||
* used to perform that far jump. See the gdt below. |
||||
*/ |
||||
pop %esi /* setup_base */ |
||||
|
||||
pushl $0x10 |
||||
leal lret_target, %eax |
||||
pushl %eax |
||||
|
||||
/* Enter paged protected Mode, activating Long Mode */ |
||||
movl $(X86_CR0_PG | X86_CR0_PE), %eax |
||||
movl %eax, %cr0 |
||||
|
||||
/* Jump from 32bit compatibility mode into 64bit mode. */ |
||||
lret |
||||
|
||||
code64: |
||||
lret_target: |
||||
pop %eax /* target */ |
||||
mov %eax, %eax /* Clear bits 63:32 */ |
||||
jmp *%eax /* Jump to the 64-bit target */ |
||||
|
||||
.data |
||||
gdt: |
||||
.word gdt_end - gdt |
||||
.long gdt
|
||||
.word 0
|
||||
.quad 0x0000000000000000 /* NULL descriptor */ |
||||
.quad 0x00af9a000000ffff /* __KERNEL_CS */ |
||||
.quad 0x00cf92000000ffff /* __KERNEL_DS */ |
||||
.quad 0x0080890000000000 /* TS descriptor */ |
||||
.quad 0x0000000000000000 /* TS continued */ |
||||
gdt_end: |
Loading…
Reference in new issue