blob: 08dc473d6af40e528f574c19f26fae07cb658778 [file] [log] [blame]
Simon Glass463fac22014-10-10 08:21:55 -06001/*
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
84gdt:
Simon Glassf2d1a112015-07-31 09:31:30 -060085 .word gdt_end - gdt - 1
86 .long gdt /* Fixed up by code above */
Simon Glass463fac22014-10-10 08:21:55 -060087 .word 0
88 .quad 0x0000000000000000 /* NULL descriptor */
89 .quad 0x00af9a000000ffff /* __KERNEL_CS */
90 .quad 0x00cf92000000ffff /* __KERNEL_DS */
91 .quad 0x0080890000000000 /* TS descriptor */
92 .quad 0x0000000000000000 /* TS continued */
93gdt_end: