162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Trampoline.S Derived from Setup.S by Linus Torvalds 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * 4 Jan 1997 Michael Chastain: changed to gnu as. 762306a36Sopenharmony_ci * 15 Sept 2005 Eric Biederman: 64bit PIC support 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Entry: CS:IP point to the start of our code, we are 1062306a36Sopenharmony_ci * in real mode with no stack, but the rest of the 1162306a36Sopenharmony_ci * trampoline page to make our stack and everything else 1262306a36Sopenharmony_ci * is a mystery. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * On entry to trampoline_start, the processor is in real mode 1562306a36Sopenharmony_ci * with 16-bit addressing and 16-bit data. CS has some value 1662306a36Sopenharmony_ci * and IP is zero. Thus, data addresses need to be absolute 1762306a36Sopenharmony_ci * (no relocation) and are taken with regard to r_base. 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * With the addition of trampoline_level4_pgt this code can 2062306a36Sopenharmony_ci * now enter a 64bit kernel that lives at arbitrary 64bit 2162306a36Sopenharmony_ci * physical addresses. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * If you work on this file, check the object module with objdump 2462306a36Sopenharmony_ci * --full-contents --reloc to make sure there are no relocation 2562306a36Sopenharmony_ci * entries. 2662306a36Sopenharmony_ci */ 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#include <linux/linkage.h> 2962306a36Sopenharmony_ci#include <asm/pgtable_types.h> 3062306a36Sopenharmony_ci#include <asm/page_types.h> 3162306a36Sopenharmony_ci#include <asm/msr.h> 3262306a36Sopenharmony_ci#include <asm/segment.h> 3362306a36Sopenharmony_ci#include <asm/processor-flags.h> 3462306a36Sopenharmony_ci#include <asm/realmode.h> 3562306a36Sopenharmony_ci#include "realmode.h" 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci .text 3862306a36Sopenharmony_ci .code16 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci.macro LOCK_AND_LOAD_REALMODE_ESP lock_pa=0 4162306a36Sopenharmony_ci /* 4262306a36Sopenharmony_ci * Make sure only one CPU fiddles with the realmode stack 4362306a36Sopenharmony_ci */ 4462306a36Sopenharmony_ci.Llock_rm\@: 4562306a36Sopenharmony_ci .if \lock_pa 4662306a36Sopenharmony_ci lock btsl $0, pa_tr_lock 4762306a36Sopenharmony_ci .else 4862306a36Sopenharmony_ci lock btsl $0, tr_lock 4962306a36Sopenharmony_ci .endif 5062306a36Sopenharmony_ci jnc 2f 5162306a36Sopenharmony_ci pause 5262306a36Sopenharmony_ci jmp .Llock_rm\@ 5362306a36Sopenharmony_ci2: 5462306a36Sopenharmony_ci # Setup stack 5562306a36Sopenharmony_ci movl $rm_stack_end, %esp 5662306a36Sopenharmony_ci.endm 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci .balign PAGE_SIZE 5962306a36Sopenharmony_ciSYM_CODE_START(trampoline_start) 6062306a36Sopenharmony_ci cli # We should be safe anyway 6162306a36Sopenharmony_ci wbinvd 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci LJMPW_RM(1f) 6462306a36Sopenharmony_ci1: 6562306a36Sopenharmony_ci mov %cs, %ax # Code and data in the same place 6662306a36Sopenharmony_ci mov %ax, %ds 6762306a36Sopenharmony_ci mov %ax, %es 6862306a36Sopenharmony_ci mov %ax, %ss 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci LOCK_AND_LOAD_REALMODE_ESP 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci call verify_cpu # Verify the cpu supports long mode 7362306a36Sopenharmony_ci testl %eax, %eax # Check for return code 7462306a36Sopenharmony_ci jnz no_longmode 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci.Lswitch_to_protected: 7762306a36Sopenharmony_ci /* 7862306a36Sopenharmony_ci * GDT tables in non default location kernel can be beyond 16MB and 7962306a36Sopenharmony_ci * lgdt will not be able to load the address as in real mode default 8062306a36Sopenharmony_ci * operand size is 16bit. Use lgdtl instead to force operand size 8162306a36Sopenharmony_ci * to 32 bit. 8262306a36Sopenharmony_ci */ 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci lidtl tr_idt # load idt with 0, 0 8562306a36Sopenharmony_ci lgdtl tr_gdt # load gdt with whatever is appropriate 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci movw $__KERNEL_DS, %dx # Data segment descriptor 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci # Enable protected mode 9062306a36Sopenharmony_ci movl $(CR0_STATE & ~X86_CR0_PG), %eax 9162306a36Sopenharmony_ci movl %eax, %cr0 # into protected mode 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci # flush prefetch and jump to startup_32 9462306a36Sopenharmony_ci ljmpl $__KERNEL32_CS, $pa_startup_32 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cino_longmode: 9762306a36Sopenharmony_ci hlt 9862306a36Sopenharmony_ci jmp no_longmode 9962306a36Sopenharmony_ciSYM_CODE_END(trampoline_start) 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci#ifdef CONFIG_AMD_MEM_ENCRYPT 10262306a36Sopenharmony_ci/* SEV-ES supports non-zero IP for entry points - no alignment needed */ 10362306a36Sopenharmony_ciSYM_CODE_START(sev_es_trampoline_start) 10462306a36Sopenharmony_ci cli # We should be safe anyway 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci LJMPW_RM(1f) 10762306a36Sopenharmony_ci1: 10862306a36Sopenharmony_ci mov %cs, %ax # Code and data in the same place 10962306a36Sopenharmony_ci mov %ax, %ds 11062306a36Sopenharmony_ci mov %ax, %es 11162306a36Sopenharmony_ci mov %ax, %ss 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci LOCK_AND_LOAD_REALMODE_ESP 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci jmp .Lswitch_to_protected 11662306a36Sopenharmony_ciSYM_CODE_END(sev_es_trampoline_start) 11762306a36Sopenharmony_ci#endif /* CONFIG_AMD_MEM_ENCRYPT */ 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci#include "../kernel/verify_cpu.S" 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci .section ".text32","ax" 12262306a36Sopenharmony_ci .code32 12362306a36Sopenharmony_ci .balign 4 12462306a36Sopenharmony_ciSYM_CODE_START(startup_32) 12562306a36Sopenharmony_ci movl %edx, %ss 12662306a36Sopenharmony_ci addl $pa_real_mode_base, %esp 12762306a36Sopenharmony_ci movl %edx, %ds 12862306a36Sopenharmony_ci movl %edx, %es 12962306a36Sopenharmony_ci movl %edx, %fs 13062306a36Sopenharmony_ci movl %edx, %gs 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci /* 13362306a36Sopenharmony_ci * Check for memory encryption support. This is a safety net in 13462306a36Sopenharmony_ci * case BIOS hasn't done the necessary step of setting the bit in 13562306a36Sopenharmony_ci * the MSR for this AP. If SME is active and we've gotten this far 13662306a36Sopenharmony_ci * then it is safe for us to set the MSR bit and continue. If we 13762306a36Sopenharmony_ci * don't we'll eventually crash trying to execute encrypted 13862306a36Sopenharmony_ci * instructions. 13962306a36Sopenharmony_ci */ 14062306a36Sopenharmony_ci btl $TH_FLAGS_SME_ACTIVE_BIT, pa_tr_flags 14162306a36Sopenharmony_ci jnc .Ldone 14262306a36Sopenharmony_ci movl $MSR_AMD64_SYSCFG, %ecx 14362306a36Sopenharmony_ci rdmsr 14462306a36Sopenharmony_ci bts $MSR_AMD64_SYSCFG_MEM_ENCRYPT_BIT, %eax 14562306a36Sopenharmony_ci jc .Ldone 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci /* 14862306a36Sopenharmony_ci * Memory encryption is enabled but the SME enable bit for this 14962306a36Sopenharmony_ci * CPU has has not been set. It is safe to set it, so do so. 15062306a36Sopenharmony_ci */ 15162306a36Sopenharmony_ci wrmsr 15262306a36Sopenharmony_ci.Ldone: 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci movl pa_tr_cr4, %eax 15562306a36Sopenharmony_ci movl %eax, %cr4 # Enable PAE mode 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci # Setup trampoline 4 level pagetables 15862306a36Sopenharmony_ci movl $pa_trampoline_pgd, %eax 15962306a36Sopenharmony_ci movl %eax, %cr3 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci # Set up EFER 16262306a36Sopenharmony_ci movl $MSR_EFER, %ecx 16362306a36Sopenharmony_ci rdmsr 16462306a36Sopenharmony_ci /* 16562306a36Sopenharmony_ci * Skip writing to EFER if the register already has desired 16662306a36Sopenharmony_ci * value (to avoid #VE for the TDX guest). 16762306a36Sopenharmony_ci */ 16862306a36Sopenharmony_ci cmp pa_tr_efer, %eax 16962306a36Sopenharmony_ci jne .Lwrite_efer 17062306a36Sopenharmony_ci cmp pa_tr_efer + 4, %edx 17162306a36Sopenharmony_ci je .Ldone_efer 17262306a36Sopenharmony_ci.Lwrite_efer: 17362306a36Sopenharmony_ci movl pa_tr_efer, %eax 17462306a36Sopenharmony_ci movl pa_tr_efer + 4, %edx 17562306a36Sopenharmony_ci wrmsr 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci.Ldone_efer: 17862306a36Sopenharmony_ci # Enable paging and in turn activate Long Mode. 17962306a36Sopenharmony_ci movl $CR0_STATE, %eax 18062306a36Sopenharmony_ci movl %eax, %cr0 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci /* 18362306a36Sopenharmony_ci * At this point we're in long mode but in 32bit compatibility mode 18462306a36Sopenharmony_ci * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn 18562306a36Sopenharmony_ci * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we use 18662306a36Sopenharmony_ci * the new gdt/idt that has __KERNEL_CS with CS.L = 1. 18762306a36Sopenharmony_ci */ 18862306a36Sopenharmony_ci ljmpl $__KERNEL_CS, $pa_startup_64 18962306a36Sopenharmony_ciSYM_CODE_END(startup_32) 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ciSYM_CODE_START(pa_trampoline_compat) 19262306a36Sopenharmony_ci /* 19362306a36Sopenharmony_ci * In compatibility mode. Prep ESP and DX for startup_32, then disable 19462306a36Sopenharmony_ci * paging and complete the switch to legacy 32-bit mode. 19562306a36Sopenharmony_ci */ 19662306a36Sopenharmony_ci LOCK_AND_LOAD_REALMODE_ESP lock_pa=1 19762306a36Sopenharmony_ci movw $__KERNEL_DS, %dx 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci movl $(CR0_STATE & ~X86_CR0_PG), %eax 20062306a36Sopenharmony_ci movl %eax, %cr0 20162306a36Sopenharmony_ci ljmpl $__KERNEL32_CS, $pa_startup_32 20262306a36Sopenharmony_ciSYM_CODE_END(pa_trampoline_compat) 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci .section ".text64","ax" 20562306a36Sopenharmony_ci .code64 20662306a36Sopenharmony_ci .balign 4 20762306a36Sopenharmony_ciSYM_CODE_START(startup_64) 20862306a36Sopenharmony_ci # Now jump into the kernel using virtual addresses 20962306a36Sopenharmony_ci jmpq *tr_start(%rip) 21062306a36Sopenharmony_ciSYM_CODE_END(startup_64) 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ciSYM_CODE_START(trampoline_start64) 21362306a36Sopenharmony_ci /* 21462306a36Sopenharmony_ci * APs start here on a direct transfer from 64-bit BIOS with identity 21562306a36Sopenharmony_ci * mapped page tables. Load the kernel's GDT in order to gear down to 21662306a36Sopenharmony_ci * 32-bit mode (to handle 4-level vs. 5-level paging), and to (re)load 21762306a36Sopenharmony_ci * segment registers. Load the zero IDT so any fault triggers a 21862306a36Sopenharmony_ci * shutdown instead of jumping back into BIOS. 21962306a36Sopenharmony_ci */ 22062306a36Sopenharmony_ci lidt tr_idt(%rip) 22162306a36Sopenharmony_ci lgdt tr_gdt64(%rip) 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci ljmpl *tr_compat(%rip) 22462306a36Sopenharmony_ciSYM_CODE_END(trampoline_start64) 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci .section ".rodata","a" 22762306a36Sopenharmony_ci # Duplicate the global descriptor table 22862306a36Sopenharmony_ci # so the kernel can live anywhere 22962306a36Sopenharmony_ci .balign 16 23062306a36Sopenharmony_ciSYM_DATA_START(tr_gdt) 23162306a36Sopenharmony_ci .short tr_gdt_end - tr_gdt - 1 # gdt limit 23262306a36Sopenharmony_ci .long pa_tr_gdt 23362306a36Sopenharmony_ci .short 0 23462306a36Sopenharmony_ci .quad 0x00cf9b000000ffff # __KERNEL32_CS 23562306a36Sopenharmony_ci .quad 0x00af9b000000ffff # __KERNEL_CS 23662306a36Sopenharmony_ci .quad 0x00cf93000000ffff # __KERNEL_DS 23762306a36Sopenharmony_ciSYM_DATA_END_LABEL(tr_gdt, SYM_L_LOCAL, tr_gdt_end) 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ciSYM_DATA_START(tr_gdt64) 24062306a36Sopenharmony_ci .short tr_gdt_end - tr_gdt - 1 # gdt limit 24162306a36Sopenharmony_ci .long pa_tr_gdt 24262306a36Sopenharmony_ci .long 0 24362306a36Sopenharmony_ciSYM_DATA_END(tr_gdt64) 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ciSYM_DATA_START(tr_compat) 24662306a36Sopenharmony_ci .long pa_trampoline_compat 24762306a36Sopenharmony_ci .short __KERNEL32_CS 24862306a36Sopenharmony_ciSYM_DATA_END(tr_compat) 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci .bss 25162306a36Sopenharmony_ci .balign PAGE_SIZE 25262306a36Sopenharmony_ciSYM_DATA(trampoline_pgd, .space PAGE_SIZE) 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci .balign 8 25562306a36Sopenharmony_ciSYM_DATA_START(trampoline_header) 25662306a36Sopenharmony_ci SYM_DATA_LOCAL(tr_start, .space 8) 25762306a36Sopenharmony_ci SYM_DATA(tr_efer, .space 8) 25862306a36Sopenharmony_ci SYM_DATA(tr_cr4, .space 4) 25962306a36Sopenharmony_ci SYM_DATA(tr_flags, .space 4) 26062306a36Sopenharmony_ci SYM_DATA(tr_lock, .space 4) 26162306a36Sopenharmony_ciSYM_DATA_END(trampoline_header) 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci#include "trampoline_common.S" 264