1/* 2 * (C) Copyright 2014 Google, Inc 3 * Copyright (C) 1991, 1992, 1993 Linus Torvalds 4 * 5 * Parts of this copied from Linux arch/x86/boot/compressed/head_64.S 6 * 7 * SPDX-License-Identifier: GPL-2.0+ 8 */ 9 10#include <asm/global_data.h> 11#include <asm/msr-index.h> 12#include <asm/processor-flags.h> 13 14.code32 15.globl cpu_call64 16cpu_call64: 17 /* 18 * cpu_call64(ulong pgtable, ulong setup_base, ulong target) 19 * 20 * eax - pgtable 21 * edx - setup_base 22 * ecx - target 23 */ 24 cli 25 push %ecx /* arg2 = target */ 26 push %edx /* arg1 = setup_base */ 27 mov %eax, %ebx 28 29 /* Load new GDT with the 64bit segments using 32bit descriptor */ 30 leal gdt, %eax 31 movl %eax, gdt+2 32 lgdt gdt 33 34 /* Enable PAE mode */ 35 movl $(X86_CR4_PAE), %eax 36 movl %eax, %cr4 37 38 /* Enable the boot page tables */ 39 leal (%ebx), %eax 40 movl %eax, %cr3 41 42 /* Enable Long mode in EFER (Extended Feature Enable Register) */ 43 movl $MSR_EFER, %ecx 44 rdmsr 45 btsl $_EFER_LME, %eax 46 wrmsr 47 48 /* After gdt is loaded */ 49 xorl %eax, %eax 50 lldt %ax 51 movl $0x20, %eax 52 ltr %ax 53 54 /* 55 * Setup for the jump to 64bit mode 56 * 57 * When the jump is performed we will be in long mode but 58 * in 32bit compatibility mode with EFER.LME = 1, CS.L = 0, CS.D = 1 59 * (and in turn EFER.LMA = 1). To jump into 64bit mode we use 60 * the new gdt/idt that has __KERNEL_CS with CS.L = 1. 61 * We place all of the values on our mini stack so lret can 62 * used to perform that far jump. See the gdt below. 63 */ 64 pop %esi /* setup_base */ 65 66 pushl $0x10 67 leal lret_target, %eax 68 pushl %eax 69 70 /* Enter paged protected Mode, activating Long Mode */ 71 movl $(X86_CR0_PG | X86_CR0_PE), %eax 72 movl %eax, %cr0 73 74 /* Jump from 32bit compatibility mode into 64bit mode. */ 75 lret 76 77code64: 78lret_target: 79 pop %eax /* target */ 80 mov %eax, %eax /* Clear bits 63:32 */ 81 jmp *%eax /* Jump to the 64-bit target */ 82 83 .data 84 .align 16 85 .globl gdt64 86gdt64: 87gdt: 88 .word gdt_end - gdt - 1 89 .long gdt /* Fixed up by code above */ 90 .word 0 91 .quad 0x0000000000000000 /* NULL descriptor */ 92 .quad 0x00af9a000000ffff /* __KERNEL_CS */ 93 .quad 0x00cf92000000ffff /* __KERNEL_DS */ 94 .quad 0x0080890000000000 /* TS descriptor */ 95 .quad 0x0000000000000000 /* TS continued */ 96gdt_end: 97