|
@@ -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:
|