]>
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 |
f37240f1 | 41 | ENTRY(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 | ||
52 | movl $0xA5A5A5A5, trampoline_status | |
53 | # write marker for master knows we're running | |
54 | ||
55 | # Setup stack | |
8e029fcd | 56 | movl $rm_stack_end, %esp |
48927bbb JS |
57 | |
58 | call verify_cpu # Verify the cpu supports long mode | |
59 | testl %eax, %eax # Check for return code | |
60 | jnz no_longmode | |
61 | ||
62 | /* | |
63 | * GDT tables in non default location kernel can be beyond 16MB and | |
64 | * lgdt will not be able to load the address as in real mode default | |
65 | * operand size is 16bit. Use lgdtl instead to force operand size | |
66 | * to 32 bit. | |
67 | */ | |
68 | ||
cda846f1 JS |
69 | lidtl tr_idt # load idt with 0, 0 |
70 | lgdtl tr_gdt # load gdt with whatever is appropriate | |
48927bbb | 71 | |
8e029fcd JS |
72 | movw $__KERNEL_DS, %dx # Data segment descriptor |
73 | ||
74 | # Enable protected mode | |
75 | movl $X86_CR0_PE, %eax # protected mode (PE) bit | |
76 | movl %eax, %cr0 # into protected mode | |
48927bbb JS |
77 | |
78 | # flush prefetch and jump to startup_32 | |
056a43a6 | 79 | ljmpl $__KERNEL32_CS, $pa_startup_32 |
48927bbb JS |
80 | |
81 | no_longmode: | |
82 | hlt | |
83 | jmp no_longmode | |
84 | #include "../kernel/verify_cpu.S" | |
85 | ||
02474286 | 86 | .section ".text32","ax" |
48927bbb JS |
87 | .code32 |
88 | .balign 4 | |
89 | ENTRY(startup_32) | |
8e029fcd JS |
90 | movl %edx, %ss |
91 | addl $pa_real_mode_base, %esp | |
92 | movl %edx, %ds | |
93 | movl %edx, %es | |
94 | movl %edx, %fs | |
95 | movl %edx, %gs | |
48927bbb | 96 | |
46d010e0 TL |
97 | /* |
98 | * Check for memory encryption support. This is a safety net in | |
99 | * case BIOS hasn't done the necessary step of setting the bit in | |
100 | * the MSR for this AP. If SME is active and we've gotten this far | |
101 | * then it is safe for us to set the MSR bit and continue. If we | |
102 | * don't we'll eventually crash trying to execute encrypted | |
103 | * instructions. | |
104 | */ | |
105 | bt $TH_FLAGS_SME_ACTIVE_BIT, pa_tr_flags | |
106 | jnc .Ldone | |
107 | movl $MSR_K8_SYSCFG, %ecx | |
108 | rdmsr | |
109 | bts $MSR_K8_SYSCFG_MEM_ENCRYPT_BIT, %eax | |
110 | jc .Ldone | |
111 | ||
112 | /* | |
113 | * Memory encryption is enabled but the SME enable bit for this | |
114 | * CPU has has not been set. It is safe to set it, so do so. | |
115 | */ | |
116 | wrmsr | |
117 | .Ldone: | |
118 | ||
cda846f1 | 119 | movl pa_tr_cr4, %eax |
48927bbb JS |
120 | movl %eax, %cr4 # Enable PAE mode |
121 | ||
8e029fcd | 122 | # Setup trampoline 4 level pagetables |
f37240f1 | 123 | movl $pa_trampoline_pgd, %eax |
48927bbb JS |
124 | movl %eax, %cr3 |
125 | ||
cda846f1 JS |
126 | # Set up EFER |
127 | movl pa_tr_efer, %eax | |
128 | movl pa_tr_efer + 4, %edx | |
48927bbb | 129 | movl $MSR_EFER, %ecx |
48927bbb JS |
130 | wrmsr |
131 | ||
132 | # Enable paging and in turn activate Long Mode | |
8e029fcd | 133 | movl $(X86_CR0_PG | X86_CR0_WP | X86_CR0_PE), %eax |
48927bbb JS |
134 | movl %eax, %cr0 |
135 | ||
136 | /* | |
137 | * At this point we're in long mode but in 32bit compatibility mode | |
138 | * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn | |
139 | * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we use | |
140 | * the new gdt/idt that has __KERNEL_CS with CS.L = 1. | |
141 | */ | |
056a43a6 | 142 | ljmpl $__KERNEL_CS, $pa_startup_64 |
48927bbb | 143 | |
02474286 | 144 | .section ".text64","ax" |
48927bbb JS |
145 | .code64 |
146 | .balign 4 | |
147 | ENTRY(startup_64) | |
148 | # Now jump into the kernel using virtual addresses | |
f37240f1 | 149 | jmpq *tr_start(%rip) |
48927bbb | 150 | |
51edbe6a PA |
151 | .section ".rodata","a" |
152 | # Duplicate the global descriptor table | |
153 | # so the kernel can live anywhere | |
154 | .balign 16 | |
155 | .globl tr_gdt | |
156 | tr_gdt: | |
157 | .short tr_gdt_end - tr_gdt - 1 # gdt limit | |
158 | .long pa_tr_gdt | |
159 | .short 0 | |
160 | .quad 0x00cf9b000000ffff # __KERNEL32_CS | |
161 | .quad 0x00af9b000000ffff # __KERNEL_CS | |
162 | .quad 0x00cf93000000ffff # __KERNEL_DS | |
163 | tr_gdt_end: | |
164 | ||
165 | .bss | |
166 | .balign PAGE_SIZE | |
167 | GLOBAL(trampoline_pgd) .space PAGE_SIZE | |
168 | ||
169 | .balign 8 | |
170 | GLOBAL(trampoline_header) | |
171 | tr_start: .space 8 | |
51edbe6a | 172 | GLOBAL(tr_efer) .space 8 |
638d957b | 173 | GLOBAL(tr_cr4) .space 4 |
46d010e0 | 174 | GLOBAL(tr_flags) .space 4 |
51edbe6a PA |
175 | END(trampoline_header) |
176 | ||
f37240f1 | 177 | #include "trampoline_common.S" |