]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
48927bbb JS |
2 | /* |
3 | * | |
4 | * Trampoline.S Derived from Setup.S by Linus Torvalds | |
5 | * | |
6 | * 4 Jan 1997 Michael Chastain: changed to gnu as. | |
7 | * 15 Sept 2005 Eric Biederman: 64bit PIC support | |
8 | * | |
9 | * Entry: CS:IP point to the start of our code, we are | |
10 | * in real mode with no stack, but the rest of the | |
11 | * trampoline page to make our stack and everything else | |
12 | * is a mystery. | |
13 | * | |
f37240f1 | 14 | * On entry to trampoline_start, the processor is in real mode |
48927bbb JS |
15 | * with 16-bit addressing and 16-bit data. CS has some value |
16 | * and IP is zero. Thus, data addresses need to be absolute | |
17 | * (no relocation) and are taken with regard to r_base. | |
18 | * | |
19 | * With the addition of trampoline_level4_pgt this code can | |
20 | * now enter a 64bit kernel that lives at arbitrary 64bit | |
21 | * physical addresses. | |
22 | * | |
23 | * If you work on this file, check the object module with objdump | |
24 | * --full-contents --reloc to make sure there are no relocation | |
25 | * entries. | |
26 | */ | |
27 | ||
28 | #include <linux/linkage.h> | |
48927bbb JS |
29 | #include <asm/pgtable_types.h> |
30 | #include <asm/page_types.h> | |
31 | #include <asm/msr.h> | |
32 | #include <asm/segment.h> | |
33 | #include <asm/processor-flags.h> | |
46d010e0 | 34 | #include <asm/realmode.h> |
e5684ec4 | 35 | #include "realmode.h" |
48927bbb JS |
36 | |
37 | .text | |
48927bbb JS |
38 | .code16 |
39 | ||
cda846f1 | 40 | .balign PAGE_SIZE |
4aec216b | 41 | SYM_CODE_START(trampoline_start) |
48927bbb JS |
42 | cli # We should be safe anyway |
43 | wbinvd | |
44 | ||
e5684ec4 | 45 | LJMPW_RM(1f) |
48927bbb JS |
46 | 1: |
47 | mov %cs, %ax # Code and data in the same place | |
48 | mov %ax, %ds | |
49 | mov %ax, %es | |
50 | mov %ax, %ss | |
51 | ||
48927bbb | 52 | # Setup stack |
8e029fcd | 53 | movl $rm_stack_end, %esp |
48927bbb JS |
54 | |
55 | call verify_cpu # Verify the cpu supports long mode | |
56 | testl %eax, %eax # Check for return code | |
57 | jnz no_longmode | |
58 | ||
bf5ff276 | 59 | .Lswitch_to_protected: |
48927bbb JS |
60 | /* |
61 | * GDT tables in non default location kernel can be beyond 16MB and | |
62 | * lgdt will not be able to load the address as in real mode default | |
63 | * operand size is 16bit. Use lgdtl instead to force operand size | |
64 | * to 32 bit. | |
65 | */ | |
66 | ||
cda846f1 JS |
67 | lidtl tr_idt # load idt with 0, 0 |
68 | lgdtl tr_gdt # load gdt with whatever is appropriate | |
48927bbb | 69 | |
8e029fcd JS |
70 | movw $__KERNEL_DS, %dx # Data segment descriptor |
71 | ||
72 | # Enable protected mode | |
73 | movl $X86_CR0_PE, %eax # protected mode (PE) bit | |
74 | movl %eax, %cr0 # into protected mode | |
48927bbb JS |
75 | |
76 | # flush prefetch and jump to startup_32 | |
056a43a6 | 77 | ljmpl $__KERNEL32_CS, $pa_startup_32 |
48927bbb JS |
78 | |
79 | no_longmode: | |
80 | hlt | |
81 | jmp no_longmode | |
4aec216b JS |
82 | SYM_CODE_END(trampoline_start) |
83 | ||
bf5ff276 JR |
84 | #ifdef CONFIG_AMD_MEM_ENCRYPT |
85 | /* SEV-ES supports non-zero IP for entry points - no alignment needed */ | |
86 | SYM_CODE_START(sev_es_trampoline_start) | |
87 | cli # We should be safe anyway | |
88 | ||
89 | LJMPW_RM(1f) | |
90 | 1: | |
91 | mov %cs, %ax # Code and data in the same place | |
92 | mov %ax, %ds | |
93 | mov %ax, %es | |
94 | mov %ax, %ss | |
95 | ||
96 | # Setup stack | |
97 | movl $rm_stack_end, %esp | |
98 | ||
99 | jmp .Lswitch_to_protected | |
100 | SYM_CODE_END(sev_es_trampoline_start) | |
101 | #endif /* CONFIG_AMD_MEM_ENCRYPT */ | |
102 | ||
48927bbb JS |
103 | #include "../kernel/verify_cpu.S" |
104 | ||
02474286 | 105 | .section ".text32","ax" |
48927bbb JS |
106 | .code32 |
107 | .balign 4 | |
4aec216b | 108 | SYM_CODE_START(startup_32) |
8e029fcd JS |
109 | movl %edx, %ss |
110 | addl $pa_real_mode_base, %esp | |
111 | movl %edx, %ds | |
112 | movl %edx, %es | |
113 | movl %edx, %fs | |
114 | movl %edx, %gs | |
48927bbb | 115 | |
46d010e0 TL |
116 | /* |
117 | * Check for memory encryption support. This is a safety net in | |
118 | * case BIOS hasn't done the necessary step of setting the bit in | |
119 | * the MSR for this AP. If SME is active and we've gotten this far | |
120 | * then it is safe for us to set the MSR bit and continue. If we | |
121 | * don't we'll eventually crash trying to execute encrypted | |
122 | * instructions. | |
123 | */ | |
8554004a | 124 | btl $TH_FLAGS_SME_ACTIVE_BIT, pa_tr_flags |
46d010e0 | 125 | jnc .Ldone |
059e5c32 | 126 | movl $MSR_AMD64_SYSCFG, %ecx |
46d010e0 | 127 | rdmsr |
059e5c32 | 128 | bts $MSR_AMD64_SYSCFG_MEM_ENCRYPT_BIT, %eax |
46d010e0 TL |
129 | jc .Ldone |
130 | ||
131 | /* | |
132 | * Memory encryption is enabled but the SME enable bit for this | |
133 | * CPU has has not been set. It is safe to set it, so do so. | |
134 | */ | |
135 | wrmsr | |
136 | .Ldone: | |
137 | ||
cda846f1 | 138 | movl pa_tr_cr4, %eax |
48927bbb JS |
139 | movl %eax, %cr4 # Enable PAE mode |
140 | ||
8e029fcd | 141 | # Setup trampoline 4 level pagetables |
f37240f1 | 142 | movl $pa_trampoline_pgd, %eax |
48927bbb JS |
143 | movl %eax, %cr3 |
144 | ||
cda846f1 JS |
145 | # Set up EFER |
146 | movl pa_tr_efer, %eax | |
147 | movl pa_tr_efer + 4, %edx | |
48927bbb | 148 | movl $MSR_EFER, %ecx |
48927bbb JS |
149 | wrmsr |
150 | ||
151 | # Enable paging and in turn activate Long Mode | |
8e029fcd | 152 | movl $(X86_CR0_PG | X86_CR0_WP | X86_CR0_PE), %eax |
48927bbb JS |
153 | movl %eax, %cr0 |
154 | ||
155 | /* | |
156 | * At this point we're in long mode but in 32bit compatibility mode | |
157 | * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn | |
158 | * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we use | |
159 | * the new gdt/idt that has __KERNEL_CS with CS.L = 1. | |
160 | */ | |
056a43a6 | 161 | ljmpl $__KERNEL_CS, $pa_startup_64 |
4aec216b | 162 | SYM_CODE_END(startup_32) |
48927bbb | 163 | |
02474286 | 164 | .section ".text64","ax" |
48927bbb JS |
165 | .code64 |
166 | .balign 4 | |
4aec216b | 167 | SYM_CODE_START(startup_64) |
48927bbb | 168 | # Now jump into the kernel using virtual addresses |
f37240f1 | 169 | jmpq *tr_start(%rip) |
4aec216b | 170 | SYM_CODE_END(startup_64) |
48927bbb | 171 | |
51edbe6a PA |
172 | .section ".rodata","a" |
173 | # Duplicate the global descriptor table | |
174 | # so the kernel can live anywhere | |
175 | .balign 16 | |
78f44330 | 176 | SYM_DATA_START(tr_gdt) |
51edbe6a PA |
177 | .short tr_gdt_end - tr_gdt - 1 # gdt limit |
178 | .long pa_tr_gdt | |
179 | .short 0 | |
180 | .quad 0x00cf9b000000ffff # __KERNEL32_CS | |
181 | .quad 0x00af9b000000ffff # __KERNEL_CS | |
182 | .quad 0x00cf93000000ffff # __KERNEL_DS | |
78f44330 | 183 | SYM_DATA_END_LABEL(tr_gdt, SYM_L_LOCAL, tr_gdt_end) |
51edbe6a PA |
184 | |
185 | .bss | |
186 | .balign PAGE_SIZE | |
78f44330 | 187 | SYM_DATA(trampoline_pgd, .space PAGE_SIZE) |
51edbe6a PA |
188 | |
189 | .balign 8 | |
78f44330 JS |
190 | SYM_DATA_START(trampoline_header) |
191 | SYM_DATA_LOCAL(tr_start, .space 8) | |
192 | SYM_DATA(tr_efer, .space 8) | |
193 | SYM_DATA(tr_cr4, .space 4) | |
194 | SYM_DATA(tr_flags, .space 4) | |
195 | SYM_DATA_END(trampoline_header) | |
51edbe6a | 196 | |
f37240f1 | 197 | #include "trampoline_common.S" |