]>
Commit | Line | Data |
---|---|---|
200182a7 SG |
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 | |
16 | cpu_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 | ||
77 | code64: | |
78 | lret_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 | gdt: | |
0bc74ab3 SG |
85 | .word gdt_end - gdt - 1 |
86 | .long gdt /* Fixed up by code above */ | |
200182a7 SG |
87 | .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 */ | |
93 | gdt_end: |