GNU Linux-libre 5.4.274-gnu1
[releases.git] / arch / x86 / kernel / relocate_kernel_64.S
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * relocate_kernel.S - put the kernel image in place to boot
4  * Copyright (C) 2002-2005 Eric Biederman  <ebiederm@xmission.com>
5  */
6
7 #include <linux/linkage.h>
8 #include <asm/page_types.h>
9 #include <asm/kexec.h>
10 #include <asm/processor-flags.h>
11 #include <asm/pgtable_types.h>
12
13 /*
14  * Must be relocatable PIC code callable as a C function
15  */
16
17 #define PTR(x) (x << 3)
18 #define PAGE_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
19
20 /*
21  * control_page + KEXEC_CONTROL_CODE_MAX_SIZE
22  * ~ control_page + PAGE_SIZE are used as data storage and stack for
23  * jumping back
24  */
25 #define DATA(offset)            (KEXEC_CONTROL_CODE_MAX_SIZE+(offset))
26
27 /* Minimal CPU state */
28 #define RSP                     DATA(0x0)
29 #define CR0                     DATA(0x8)
30 #define CR3                     DATA(0x10)
31 #define CR4                     DATA(0x18)
32
33 /* other data */
34 #define CP_PA_TABLE_PAGE        DATA(0x20)
35 #define CP_PA_SWAP_PAGE         DATA(0x28)
36 #define CP_PA_BACKUP_PAGES_MAP  DATA(0x30)
37
38         .text
39         .align PAGE_SIZE
40         .code64
41         .globl relocate_kernel
42 relocate_kernel:
43         /*
44          * %rdi indirection_page
45          * %rsi page_list
46          * %rdx start address
47          * %rcx preserve_context
48          * %r8  sme_active
49          */
50
51         /* Save the CPU context, used for jumping back */
52         pushq %rbx
53         pushq %rbp
54         pushq %r12
55         pushq %r13
56         pushq %r14
57         pushq %r15
58         pushf
59
60         movq    PTR(VA_CONTROL_PAGE)(%rsi), %r11
61         movq    %rsp, RSP(%r11)
62         movq    %cr0, %rax
63         movq    %rax, CR0(%r11)
64         movq    %cr3, %rax
65         movq    %rax, CR3(%r11)
66         movq    %cr4, %rax
67         movq    %rax, CR4(%r11)
68
69         /* Save CR4. Required to enable the right paging mode later. */
70         movq    %rax, %r13
71
72         /* zero out flags, and disable interrupts */
73         pushq $0
74         popfq
75
76         /* Save SME active flag */
77         movq    %r8, %r12
78
79         /*
80          * get physical address of control page now
81          * this is impossible after page table switch
82          */
83         movq    PTR(PA_CONTROL_PAGE)(%rsi), %r8
84
85         /* get physical address of page table now too */
86         movq    PTR(PA_TABLE_PAGE)(%rsi), %r9
87
88         /* get physical address of swap page now */
89         movq    PTR(PA_SWAP_PAGE)(%rsi), %r10
90
91         /* save some information for jumping back */
92         movq    %r9, CP_PA_TABLE_PAGE(%r11)
93         movq    %r10, CP_PA_SWAP_PAGE(%r11)
94         movq    %rdi, CP_PA_BACKUP_PAGES_MAP(%r11)
95
96         /* Switch to the identity mapped page tables */
97         movq    %r9, %cr3
98
99         /* setup a new stack at the end of the physical control page */
100         lea     PAGE_SIZE(%r8), %rsp
101
102         /* jump to identity mapped page */
103         addq    $(identity_mapped - relocate_kernel), %r8
104         pushq   %r8
105         ret
106
107 identity_mapped:
108         /* set return address to 0 if not preserving context */
109         pushq   $0
110         /* store the start address on the stack */
111         pushq   %rdx
112
113         /*
114          * Set cr0 to a known state:
115          *  - Paging enabled
116          *  - Alignment check disabled
117          *  - Write protect disabled
118          *  - No task switch
119          *  - Don't do FP software emulation.
120          *  - Proctected mode enabled
121          */
122         movq    %cr0, %rax
123         andq    $~(X86_CR0_AM | X86_CR0_WP | X86_CR0_TS | X86_CR0_EM), %rax
124         orl     $(X86_CR0_PG | X86_CR0_PE), %eax
125         movq    %rax, %cr0
126
127         /*
128          * Set cr4 to a known state:
129          *  - physical address extension enabled
130          *  - 5-level paging, if it was enabled before
131          */
132         movl    $X86_CR4_PAE, %eax
133         testq   $X86_CR4_LA57, %r13
134         jz      1f
135         orl     $X86_CR4_LA57, %eax
136 1:
137         movq    %rax, %cr4
138
139         jmp 1f
140 1:
141
142         /* Flush the TLB (needed?) */
143         movq    %r9, %cr3
144
145         /*
146          * If SME is active, there could be old encrypted cache line
147          * entries that will conflict with the now unencrypted memory
148          * used by kexec. Flush the caches before copying the kernel.
149          */
150         testq   %r12, %r12
151         jz 1f
152         wbinvd
153 1:
154
155         movq    %rcx, %r11
156         call    swap_pages
157
158         /*
159          * To be certain of avoiding problems with self-modifying code
160          * I need to execute a serializing instruction here.
161          * So I flush the TLB by reloading %cr3 here, it's handy,
162          * and not processor dependent.
163          */
164         movq    %cr3, %rax
165         movq    %rax, %cr3
166
167         /*
168          * set all of the registers to known values
169          * leave %rsp alone
170          */
171
172         testq   %r11, %r11
173         jnz 1f
174         xorl    %eax, %eax
175         xorl    %ebx, %ebx
176         xorl    %ecx, %ecx
177         xorl    %edx, %edx
178         xorl    %esi, %esi
179         xorl    %edi, %edi
180         xorl    %ebp, %ebp
181         xorl    %r8d, %r8d
182         xorl    %r9d, %r9d
183         xorl    %r10d, %r10d
184         xorl    %r11d, %r11d
185         xorl    %r12d, %r12d
186         xorl    %r13d, %r13d
187         xorl    %r14d, %r14d
188         xorl    %r15d, %r15d
189
190         ret
191
192 1:
193         popq    %rdx
194         leaq    PAGE_SIZE(%r10), %rsp
195         call    *%rdx
196
197         /* get the re-entry point of the peer system */
198         movq    0(%rsp), %rbp
199         call    1f
200 1:
201         popq    %r8
202         subq    $(1b - relocate_kernel), %r8
203         movq    CP_PA_SWAP_PAGE(%r8), %r10
204         movq    CP_PA_BACKUP_PAGES_MAP(%r8), %rdi
205         movq    CP_PA_TABLE_PAGE(%r8), %rax
206         movq    %rax, %cr3
207         lea     PAGE_SIZE(%r8), %rsp
208         call    swap_pages
209         movq    $virtual_mapped, %rax
210         pushq   %rax
211         ret
212
213 virtual_mapped:
214         movq    RSP(%r8), %rsp
215         movq    CR4(%r8), %rax
216         movq    %rax, %cr4
217         movq    CR3(%r8), %rax
218         movq    CR0(%r8), %r8
219         movq    %rax, %cr3
220         movq    %r8, %cr0
221         movq    %rbp, %rax
222
223         popf
224         popq    %r15
225         popq    %r14
226         popq    %r13
227         popq    %r12
228         popq    %rbp
229         popq    %rbx
230         ret
231
232         /* Do the copies */
233 swap_pages:
234         movq    %rdi, %rcx      /* Put the page_list in %rcx */
235         xorl    %edi, %edi
236         xorl    %esi, %esi
237         jmp     1f
238
239 0:      /* top, read another word for the indirection page */
240
241         movq    (%rbx), %rcx
242         addq    $8,     %rbx
243 1:
244         testb   $0x1,   %cl   /* is it a destination page? */
245         jz      2f
246         movq    %rcx,   %rdi
247         andq    $0xfffffffffffff000, %rdi
248         jmp     0b
249 2:
250         testb   $0x2,   %cl   /* is it an indirection page? */
251         jz      2f
252         movq    %rcx,   %rbx
253         andq    $0xfffffffffffff000, %rbx
254         jmp     0b
255 2:
256         testb   $0x4,   %cl   /* is it the done indicator? */
257         jz      2f
258         jmp     3f
259 2:
260         testb   $0x8,   %cl   /* is it the source indicator? */
261         jz      0b            /* Ignore it otherwise */
262         movq    %rcx,   %rsi  /* For ever source page do a copy */
263         andq    $0xfffffffffffff000, %rsi
264
265         movq    %rdi, %rdx
266         movq    %rsi, %rax
267
268         movq    %r10, %rdi
269         movl    $512, %ecx
270         rep ; movsq
271
272         movq    %rax, %rdi
273         movq    %rdx, %rsi
274         movl    $512, %ecx
275         rep ; movsq
276
277         movq    %rdx, %rdi
278         movq    %r10, %rsi
279         movl    $512, %ecx
280         rep ; movsq
281
282         lea     PAGE_SIZE(%rax), %rsi
283         jmp     0b
284 3:
285         ret
286
287         .globl kexec_control_code_size
288 .set kexec_control_code_size, . - relocate_kernel