]> asedeno.scripts.mit.edu Git - linux.git/blob - arch/x86/boot/compressed/head_64.S
x86/boot/compressed/64: Detect and handle 5-level paging at boot-time
[linux.git] / arch / x86 / boot / compressed / head_64.S
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  *  linux/boot/head.S
4  *
5  *  Copyright (C) 1991, 1992, 1993  Linus Torvalds
6  */
7
8 /*
9  *  head.S contains the 32-bit startup code.
10  *
11  * NOTE!!! Startup happens at absolute address 0x00001000, which is also where
12  * the page directory will exist. The startup code will be overwritten by
13  * the page directory. [According to comments etc elsewhere on a compressed
14  * kernel it will end up at 0x1000 + 1Mb I hope so as I assume this. - AC]
15  *
16  * Page 0 is deliberately kept safe, since System Management Mode code in 
17  * laptops may need to access the BIOS data stored there.  This is also
18  * useful for future device drivers that either access the BIOS via VM86 
19  * mode.
20  */
21
22 /*
23  * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
24  */
25         .code32
26         .text
27
28 #include <linux/init.h>
29 #include <linux/linkage.h>
30 #include <asm/segment.h>
31 #include <asm/boot.h>
32 #include <asm/msr.h>
33 #include <asm/processor-flags.h>
34 #include <asm/asm-offsets.h>
35 #include <asm/bootparam.h>
36
37 /*
38  * Locally defined symbols should be marked hidden:
39  */
40         .hidden _bss
41         .hidden _ebss
42         .hidden _got
43         .hidden _egot
44
45         __HEAD
46         .code32
47 ENTRY(startup_32)
48         /*
49          * 32bit entry is 0 and it is ABI so immutable!
50          * If we come here directly from a bootloader,
51          * kernel(text+data+bss+brk) ramdisk, zero_page, command line
52          * all need to be under the 4G limit.
53          */
54         cld
55         /*
56          * Test KEEP_SEGMENTS flag to see if the bootloader is asking
57          * us to not reload segments
58          */
59         testb $KEEP_SEGMENTS, BP_loadflags(%esi)
60         jnz 1f
61
62         cli
63         movl    $(__BOOT_DS), %eax
64         movl    %eax, %ds
65         movl    %eax, %es
66         movl    %eax, %ss
67 1:
68
69 /*
70  * Calculate the delta between where we were compiled to run
71  * at and where we were actually loaded at.  This can only be done
72  * with a short local call on x86.  Nothing  else will tell us what
73  * address we are running at.  The reserved chunk of the real-mode
74  * data at 0x1e4 (defined as a scratch field) are used as the stack
75  * for this calculation. Only 4 bytes are needed.
76  */
77         leal    (BP_scratch+4)(%esi), %esp
78         call    1f
79 1:      popl    %ebp
80         subl    $1b, %ebp
81
82 /* setup a stack and make sure cpu supports long mode. */
83         movl    $boot_stack_end, %eax
84         addl    %ebp, %eax
85         movl    %eax, %esp
86
87         call    verify_cpu
88         testl   %eax, %eax
89         jnz     no_longmode
90
91 /*
92  * Compute the delta between where we were compiled to run at
93  * and where the code will actually run at.
94  *
95  * %ebp contains the address we are loaded at by the boot loader and %ebx
96  * contains the address where we should move the kernel image temporarily
97  * for safe in-place decompression.
98  */
99
100 #ifdef CONFIG_RELOCATABLE
101         movl    %ebp, %ebx
102         movl    BP_kernel_alignment(%esi), %eax
103         decl    %eax
104         addl    %eax, %ebx
105         notl    %eax
106         andl    %eax, %ebx
107         cmpl    $LOAD_PHYSICAL_ADDR, %ebx
108         jge     1f
109 #endif
110         movl    $LOAD_PHYSICAL_ADDR, %ebx
111 1:
112
113         /* Target address to relocate to for decompression */
114         movl    BP_init_size(%esi), %eax
115         subl    $_end, %eax
116         addl    %eax, %ebx
117
118 /*
119  * Prepare for entering 64 bit mode
120  */
121
122         /* Load new GDT with the 64bit segments using 32bit descriptor */
123         addl    %ebp, gdt+2(%ebp)
124         lgdt    gdt(%ebp)
125
126         /* Enable PAE mode */
127         movl    %cr4, %eax
128         orl     $X86_CR4_PAE, %eax
129         movl    %eax, %cr4
130
131  /*
132   * Build early 4G boot pagetable
133   */
134         /*
135          * If SEV is active then set the encryption mask in the page tables.
136          * This will insure that when the kernel is copied and decompressed
137          * it will be done so encrypted.
138          */
139         call    get_sev_encryption_bit
140         xorl    %edx, %edx
141         testl   %eax, %eax
142         jz      1f
143         subl    $32, %eax       /* Encryption bit is always above bit 31 */
144         bts     %eax, %edx      /* Set encryption mask for page tables */
145 1:
146
147         /* Initialize Page tables to 0 */
148         leal    pgtable(%ebx), %edi
149         xorl    %eax, %eax
150         movl    $(BOOT_INIT_PGT_SIZE/4), %ecx
151         rep     stosl
152
153         /* Build Level 4 */
154         leal    pgtable + 0(%ebx), %edi
155         leal    0x1007 (%edi), %eax
156         movl    %eax, 0(%edi)
157         addl    %edx, 4(%edi)
158
159         /* Build Level 3 */
160         leal    pgtable + 0x1000(%ebx), %edi
161         leal    0x1007(%edi), %eax
162         movl    $4, %ecx
163 1:      movl    %eax, 0x00(%edi)
164         addl    %edx, 0x04(%edi)
165         addl    $0x00001000, %eax
166         addl    $8, %edi
167         decl    %ecx
168         jnz     1b
169
170         /* Build Level 2 */
171         leal    pgtable + 0x2000(%ebx), %edi
172         movl    $0x00000183, %eax
173         movl    $2048, %ecx
174 1:      movl    %eax, 0(%edi)
175         addl    %edx, 4(%edi)
176         addl    $0x00200000, %eax
177         addl    $8, %edi
178         decl    %ecx
179         jnz     1b
180
181         /* Enable the boot page tables */
182         leal    pgtable(%ebx), %eax
183         movl    %eax, %cr3
184
185         /* Enable Long mode in EFER (Extended Feature Enable Register) */
186         movl    $MSR_EFER, %ecx
187         rdmsr
188         btsl    $_EFER_LME, %eax
189         wrmsr
190
191         /* After gdt is loaded */
192         xorl    %eax, %eax
193         lldt    %ax
194         movl    $__BOOT_TSS, %eax
195         ltr     %ax
196
197         /*
198          * Setup for the jump to 64bit mode
199          *
200          * When the jump is performend we will be in long mode but
201          * in 32bit compatibility mode with EFER.LME = 1, CS.L = 0, CS.D = 1
202          * (and in turn EFER.LMA = 1).  To jump into 64bit mode we use
203          * the new gdt/idt that has __KERNEL_CS with CS.L = 1.
204          * We place all of the values on our mini stack so lret can
205          * used to perform that far jump.
206          */
207         pushl   $__KERNEL_CS
208         leal    startup_64(%ebp), %eax
209 #ifdef CONFIG_EFI_MIXED
210         movl    efi32_config(%ebp), %ebx
211         cmp     $0, %ebx
212         jz      1f
213         leal    handover_entry(%ebp), %eax
214 1:
215 #endif
216         pushl   %eax
217
218         /* Enter paged protected Mode, activating Long Mode */
219         movl    $(X86_CR0_PG | X86_CR0_PE), %eax /* Enable Paging and Protected mode */
220         movl    %eax, %cr0
221
222         /* Jump from 32bit compatibility mode into 64bit mode. */
223         lret
224 ENDPROC(startup_32)
225
226 #ifdef CONFIG_EFI_MIXED
227         .org 0x190
228 ENTRY(efi32_stub_entry)
229         add     $0x4, %esp              /* Discard return address */
230         popl    %ecx
231         popl    %edx
232         popl    %esi
233
234         leal    (BP_scratch+4)(%esi), %esp
235         call    1f
236 1:      pop     %ebp
237         subl    $1b, %ebp
238
239         movl    %ecx, efi32_config(%ebp)
240         movl    %edx, efi32_config+8(%ebp)
241         sgdtl   efi32_boot_gdt(%ebp)
242
243         leal    efi32_config(%ebp), %eax
244         movl    %eax, efi_config(%ebp)
245
246         jmp     startup_32
247 ENDPROC(efi32_stub_entry)
248 #endif
249
250         .code64
251         .org 0x200
252 ENTRY(startup_64)
253         /*
254          * 64bit entry is 0x200 and it is ABI so immutable!
255          * We come here either from startup_32 or directly from a
256          * 64bit bootloader.
257          * If we come here from a bootloader, kernel(text+data+bss+brk),
258          * ramdisk, zero_page, command line could be above 4G.
259          * We depend on an identity mapped page table being provided
260          * that maps our entire kernel(text+data+bss+brk), zero page
261          * and command line.
262          */
263
264         /* Setup data segments. */
265         xorl    %eax, %eax
266         movl    %eax, %ds
267         movl    %eax, %es
268         movl    %eax, %ss
269         movl    %eax, %fs
270         movl    %eax, %gs
271
272         /*
273          * Compute the decompressed kernel start address.  It is where
274          * we were loaded at aligned to a 2M boundary. %rbp contains the
275          * decompressed kernel start address.
276          *
277          * If it is a relocatable kernel then decompress and run the kernel
278          * from load address aligned to 2MB addr, otherwise decompress and
279          * run the kernel from LOAD_PHYSICAL_ADDR
280          *
281          * We cannot rely on the calculation done in 32-bit mode, since we
282          * may have been invoked via the 64-bit entry point.
283          */
284
285         /* Start with the delta to where the kernel will run at. */
286 #ifdef CONFIG_RELOCATABLE
287         leaq    startup_32(%rip) /* - $startup_32 */, %rbp
288         movl    BP_kernel_alignment(%rsi), %eax
289         decl    %eax
290         addq    %rax, %rbp
291         notq    %rax
292         andq    %rax, %rbp
293         cmpq    $LOAD_PHYSICAL_ADDR, %rbp
294         jge     1f
295 #endif
296         movq    $LOAD_PHYSICAL_ADDR, %rbp
297 1:
298
299         /* Target address to relocate to for decompression */
300         movl    BP_init_size(%rsi), %ebx
301         subl    $_end, %ebx
302         addq    %rbp, %rbx
303
304         /* Set up the stack */
305         leaq    boot_stack_end(%rbx), %rsp
306
307 #ifdef CONFIG_X86_5LEVEL
308         /*
309          * Check if we need to enable 5-level paging.
310          * RSI holds real mode data and need to be preserved across
311          * a function call.
312          */
313         pushq   %rsi
314         call    l5_paging_required
315         popq    %rsi
316
317         /* If l5_paging_required() returned zero, we're done here. */
318         cmpq    $0, %rax
319         je      lvl5
320
321         /*
322          * At this point we are in long mode with 4-level paging enabled,
323          * but we want to enable 5-level paging.
324          *
325          * The problem is that we cannot do it directly. Setting LA57 in
326          * long mode would trigger #GP. So we need to switch off long mode
327          * first.
328          *
329          * NOTE: This is not going to work if bootloader put us above 4G
330          * limit.
331          *
332          * The first step is go into compatibility mode.
333          */
334
335         /* Clear additional page table */
336         leaq    lvl5_pgtable(%rbx), %rdi
337         xorq    %rax, %rax
338         movq    $(PAGE_SIZE/8), %rcx
339         rep     stosq
340
341         /*
342          * Setup current CR3 as the first and only entry in a new top level
343          * page table.
344          */
345         movq    %cr3, %rdi
346         leaq    0x7 (%rdi), %rax
347         movq    %rax, lvl5_pgtable(%rbx)
348
349         /* Switch to compatibility mode (CS.L = 0 CS.D = 1) via far return */
350         pushq   $__KERNEL32_CS
351         leaq    compatible_mode(%rip), %rax
352         pushq   %rax
353         lretq
354 lvl5:
355 #endif
356
357         /* Zero EFLAGS */
358         pushq   $0
359         popfq
360
361 /*
362  * Copy the compressed kernel to the end of our buffer
363  * where decompression in place becomes safe.
364  */
365         pushq   %rsi
366         leaq    (_bss-8)(%rip), %rsi
367         leaq    (_bss-8)(%rbx), %rdi
368         movq    $_bss /* - $startup_32 */, %rcx
369         shrq    $3, %rcx
370         std
371         rep     movsq
372         cld
373         popq    %rsi
374
375 /*
376  * Jump to the relocated address.
377  */
378         leaq    relocated(%rbx), %rax
379         jmp     *%rax
380
381 #ifdef CONFIG_EFI_STUB
382
383 /* The entry point for the PE/COFF executable is efi_pe_entry. */
384 ENTRY(efi_pe_entry)
385         movq    %rcx, efi64_config(%rip)        /* Handle */
386         movq    %rdx, efi64_config+8(%rip) /* EFI System table pointer */
387
388         leaq    efi64_config(%rip), %rax
389         movq    %rax, efi_config(%rip)
390
391         call    1f
392 1:      popq    %rbp
393         subq    $1b, %rbp
394
395         /*
396          * Relocate efi_config->call().
397          */
398         addq    %rbp, efi64_config+40(%rip)
399
400         movq    %rax, %rdi
401         call    make_boot_params
402         cmpq    $0,%rax
403         je      fail
404         mov     %rax, %rsi
405         leaq    startup_32(%rip), %rax
406         movl    %eax, BP_code32_start(%rsi)
407         jmp     2f              /* Skip the relocation */
408
409 handover_entry:
410         call    1f
411 1:      popq    %rbp
412         subq    $1b, %rbp
413
414         /*
415          * Relocate efi_config->call().
416          */
417         movq    efi_config(%rip), %rax
418         addq    %rbp, 40(%rax)
419 2:
420         movq    efi_config(%rip), %rdi
421         call    efi_main
422         movq    %rax,%rsi
423         cmpq    $0,%rax
424         jne     2f
425 fail:
426         /* EFI init failed, so hang. */
427         hlt
428         jmp     fail
429 2:
430         movl    BP_code32_start(%esi), %eax
431         leaq    startup_64(%rax), %rax
432         jmp     *%rax
433 ENDPROC(efi_pe_entry)
434
435         .org 0x390
436 ENTRY(efi64_stub_entry)
437         movq    %rdi, efi64_config(%rip)        /* Handle */
438         movq    %rsi, efi64_config+8(%rip) /* EFI System table pointer */
439
440         leaq    efi64_config(%rip), %rax
441         movq    %rax, efi_config(%rip)
442
443         movq    %rdx, %rsi
444         jmp     handover_entry
445 ENDPROC(efi64_stub_entry)
446 #endif
447
448         .text
449 relocated:
450
451 /*
452  * Clear BSS (stack is currently empty)
453  */
454         xorl    %eax, %eax
455         leaq    _bss(%rip), %rdi
456         leaq    _ebss(%rip), %rcx
457         subq    %rdi, %rcx
458         shrq    $3, %rcx
459         rep     stosq
460
461 /*
462  * Adjust our own GOT
463  */
464         leaq    _got(%rip), %rdx
465         leaq    _egot(%rip), %rcx
466 1:
467         cmpq    %rcx, %rdx
468         jae     2f
469         addq    %rbx, (%rdx)
470         addq    $8, %rdx
471         jmp     1b
472 2:
473         
474 /*
475  * Do the extraction, and jump to the new kernel..
476  */
477         pushq   %rsi                    /* Save the real mode argument */
478         movq    %rsi, %rdi              /* real mode address */
479         leaq    boot_heap(%rip), %rsi   /* malloc area for uncompression */
480         leaq    input_data(%rip), %rdx  /* input_data */
481         movl    $z_input_len, %ecx      /* input_len */
482         movq    %rbp, %r8               /* output target address */
483         movq    $z_output_len, %r9      /* decompressed length, end of relocs */
484         call    extract_kernel          /* returns kernel location in %rax */
485         popq    %rsi
486
487 /*
488  * Jump to the decompressed kernel.
489  */
490         jmp     *%rax
491
492         .code32
493 #ifdef CONFIG_X86_5LEVEL
494 compatible_mode:
495         /* Setup data and stack segments */
496         movl    $__KERNEL_DS, %eax
497         movl    %eax, %ds
498         movl    %eax, %ss
499
500         /* Disable paging */
501         movl    %cr0, %eax
502         btrl    $X86_CR0_PG_BIT, %eax
503         movl    %eax, %cr0
504
505         /* Point CR3 to 5-level paging */
506         leal    lvl5_pgtable(%ebx), %eax
507         movl    %eax, %cr3
508
509         /* Enable PAE and LA57 mode */
510         movl    %cr4, %eax
511         orl     $(X86_CR4_PAE | X86_CR4_LA57), %eax
512         movl    %eax, %cr4
513
514         /* Calculate address we are running at */
515         call    1f
516 1:      popl    %edi
517         subl    $1b, %edi
518
519         /* Prepare stack for far return to Long Mode */
520         pushl   $__KERNEL_CS
521         leal    lvl5(%edi), %eax
522         push    %eax
523
524         /* Enable paging back */
525         movl    $(X86_CR0_PG | X86_CR0_PE), %eax
526         movl    %eax, %cr0
527
528         lret
529 #endif
530
531 no_longmode:
532         /* This isn't an x86-64 CPU so hang */
533 1:
534         hlt
535         jmp     1b
536
537 #include "../../kernel/verify_cpu.S"
538
539         .data
540 gdt:
541         .word   gdt_end - gdt
542         .long   gdt
543         .word   0
544         .quad   0x00cf9a000000ffff      /* __KERNEL32_CS */
545         .quad   0x00af9a000000ffff      /* __KERNEL_CS */
546         .quad   0x00cf92000000ffff      /* __KERNEL_DS */
547         .quad   0x0080890000000000      /* TS descriptor */
548         .quad   0x0000000000000000      /* TS continued */
549 gdt_end:
550
551 #ifdef CONFIG_EFI_STUB
552 efi_config:
553         .quad   0
554
555 #ifdef CONFIG_EFI_MIXED
556         .global efi32_config
557 efi32_config:
558         .fill   5,8,0
559         .quad   efi64_thunk
560         .byte   0
561 #endif
562
563         .global efi64_config
564 efi64_config:
565         .fill   5,8,0
566         .quad   efi_call
567         .byte   1
568 #endif /* CONFIG_EFI_STUB */
569
570 /*
571  * Stack and heap for uncompression
572  */
573         .bss
574         .balign 4
575 boot_heap:
576         .fill BOOT_HEAP_SIZE, 1, 0
577 boot_stack:
578         .fill BOOT_STACK_SIZE, 1, 0
579 boot_stack_end:
580
581 /*
582  * Space for page tables (not in .bss so not zeroed)
583  */
584         .section ".pgtable","a",@nobits
585         .balign 4096
586 pgtable:
587         .fill BOOT_PGT_SIZE, 1, 0
588 #ifdef CONFIG_X86_5LEVEL
589 lvl5_pgtable:
590         .fill PAGE_SIZE, 1, 0
591 #endif