18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Trampoline.S Derived from Setup.S by Linus Torvalds 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * 4 Jan 1997 Michael Chastain: changed to gnu as. 78c2ecf20Sopenharmony_ci * 15 Sept 2005 Eric Biederman: 64bit PIC support 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Entry: CS:IP point to the start of our code, we are 108c2ecf20Sopenharmony_ci * in real mode with no stack, but the rest of the 118c2ecf20Sopenharmony_ci * trampoline page to make our stack and everything else 128c2ecf20Sopenharmony_ci * is a mystery. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * On entry to trampoline_start, the processor is in real mode 158c2ecf20Sopenharmony_ci * with 16-bit addressing and 16-bit data. CS has some value 168c2ecf20Sopenharmony_ci * and IP is zero. Thus, data addresses need to be absolute 178c2ecf20Sopenharmony_ci * (no relocation) and are taken with regard to r_base. 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * With the addition of trampoline_level4_pgt this code can 208c2ecf20Sopenharmony_ci * now enter a 64bit kernel that lives at arbitrary 64bit 218c2ecf20Sopenharmony_ci * physical addresses. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * If you work on this file, check the object module with objdump 248c2ecf20Sopenharmony_ci * --full-contents --reloc to make sure there are no relocation 258c2ecf20Sopenharmony_ci * entries. 268c2ecf20Sopenharmony_ci */ 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include <linux/linkage.h> 298c2ecf20Sopenharmony_ci#include <asm/pgtable_types.h> 308c2ecf20Sopenharmony_ci#include <asm/page_types.h> 318c2ecf20Sopenharmony_ci#include <asm/msr.h> 328c2ecf20Sopenharmony_ci#include <asm/segment.h> 338c2ecf20Sopenharmony_ci#include <asm/processor-flags.h> 348c2ecf20Sopenharmony_ci#include <asm/realmode.h> 358c2ecf20Sopenharmony_ci#include "realmode.h" 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci .text 388c2ecf20Sopenharmony_ci .code16 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci .balign PAGE_SIZE 418c2ecf20Sopenharmony_ciSYM_CODE_START(trampoline_start) 428c2ecf20Sopenharmony_ci cli # We should be safe anyway 438c2ecf20Sopenharmony_ci wbinvd 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci LJMPW_RM(1f) 468c2ecf20Sopenharmony_ci1: 478c2ecf20Sopenharmony_ci mov %cs, %ax # Code and data in the same place 488c2ecf20Sopenharmony_ci mov %ax, %ds 498c2ecf20Sopenharmony_ci mov %ax, %es 508c2ecf20Sopenharmony_ci mov %ax, %ss 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci # Setup stack 538c2ecf20Sopenharmony_ci movl $rm_stack_end, %esp 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci call verify_cpu # Verify the cpu supports long mode 568c2ecf20Sopenharmony_ci testl %eax, %eax # Check for return code 578c2ecf20Sopenharmony_ci jnz no_longmode 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci.Lswitch_to_protected: 608c2ecf20Sopenharmony_ci /* 618c2ecf20Sopenharmony_ci * GDT tables in non default location kernel can be beyond 16MB and 628c2ecf20Sopenharmony_ci * lgdt will not be able to load the address as in real mode default 638c2ecf20Sopenharmony_ci * operand size is 16bit. Use lgdtl instead to force operand size 648c2ecf20Sopenharmony_ci * to 32 bit. 658c2ecf20Sopenharmony_ci */ 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci lidtl tr_idt # load idt with 0, 0 688c2ecf20Sopenharmony_ci lgdtl tr_gdt # load gdt with whatever is appropriate 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci movw $__KERNEL_DS, %dx # Data segment descriptor 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci # Enable protected mode 738c2ecf20Sopenharmony_ci movl $X86_CR0_PE, %eax # protected mode (PE) bit 748c2ecf20Sopenharmony_ci movl %eax, %cr0 # into protected mode 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci # flush prefetch and jump to startup_32 778c2ecf20Sopenharmony_ci ljmpl $__KERNEL32_CS, $pa_startup_32 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cino_longmode: 808c2ecf20Sopenharmony_ci hlt 818c2ecf20Sopenharmony_ci jmp no_longmode 828c2ecf20Sopenharmony_ciSYM_CODE_END(trampoline_start) 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci#ifdef CONFIG_AMD_MEM_ENCRYPT 858c2ecf20Sopenharmony_ci/* SEV-ES supports non-zero IP for entry points - no alignment needed */ 868c2ecf20Sopenharmony_ciSYM_CODE_START(sev_es_trampoline_start) 878c2ecf20Sopenharmony_ci cli # We should be safe anyway 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci LJMPW_RM(1f) 908c2ecf20Sopenharmony_ci1: 918c2ecf20Sopenharmony_ci mov %cs, %ax # Code and data in the same place 928c2ecf20Sopenharmony_ci mov %ax, %ds 938c2ecf20Sopenharmony_ci mov %ax, %es 948c2ecf20Sopenharmony_ci mov %ax, %ss 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci # Setup stack 978c2ecf20Sopenharmony_ci movl $rm_stack_end, %esp 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci jmp .Lswitch_to_protected 1008c2ecf20Sopenharmony_ciSYM_CODE_END(sev_es_trampoline_start) 1018c2ecf20Sopenharmony_ci#endif /* CONFIG_AMD_MEM_ENCRYPT */ 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci#include "../kernel/verify_cpu.S" 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci .section ".text32","ax" 1068c2ecf20Sopenharmony_ci .code32 1078c2ecf20Sopenharmony_ci .balign 4 1088c2ecf20Sopenharmony_ciSYM_CODE_START(startup_32) 1098c2ecf20Sopenharmony_ci movl %edx, %ss 1108c2ecf20Sopenharmony_ci addl $pa_real_mode_base, %esp 1118c2ecf20Sopenharmony_ci movl %edx, %ds 1128c2ecf20Sopenharmony_ci movl %edx, %es 1138c2ecf20Sopenharmony_ci movl %edx, %fs 1148c2ecf20Sopenharmony_ci movl %edx, %gs 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci /* 1178c2ecf20Sopenharmony_ci * Check for memory encryption support. This is a safety net in 1188c2ecf20Sopenharmony_ci * case BIOS hasn't done the necessary step of setting the bit in 1198c2ecf20Sopenharmony_ci * the MSR for this AP. If SME is active and we've gotten this far 1208c2ecf20Sopenharmony_ci * then it is safe for us to set the MSR bit and continue. If we 1218c2ecf20Sopenharmony_ci * don't we'll eventually crash trying to execute encrypted 1228c2ecf20Sopenharmony_ci * instructions. 1238c2ecf20Sopenharmony_ci */ 1248c2ecf20Sopenharmony_ci btl $TH_FLAGS_SME_ACTIVE_BIT, pa_tr_flags 1258c2ecf20Sopenharmony_ci jnc .Ldone 1268c2ecf20Sopenharmony_ci movl $MSR_K8_SYSCFG, %ecx 1278c2ecf20Sopenharmony_ci rdmsr 1288c2ecf20Sopenharmony_ci bts $MSR_K8_SYSCFG_MEM_ENCRYPT_BIT, %eax 1298c2ecf20Sopenharmony_ci jc .Ldone 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci /* 1328c2ecf20Sopenharmony_ci * Memory encryption is enabled but the SME enable bit for this 1338c2ecf20Sopenharmony_ci * CPU has has not been set. It is safe to set it, so do so. 1348c2ecf20Sopenharmony_ci */ 1358c2ecf20Sopenharmony_ci wrmsr 1368c2ecf20Sopenharmony_ci.Ldone: 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci movl pa_tr_cr4, %eax 1398c2ecf20Sopenharmony_ci movl %eax, %cr4 # Enable PAE mode 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci # Setup trampoline 4 level pagetables 1428c2ecf20Sopenharmony_ci movl $pa_trampoline_pgd, %eax 1438c2ecf20Sopenharmony_ci movl %eax, %cr3 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci # Set up EFER 1468c2ecf20Sopenharmony_ci movl pa_tr_efer, %eax 1478c2ecf20Sopenharmony_ci movl pa_tr_efer + 4, %edx 1488c2ecf20Sopenharmony_ci movl $MSR_EFER, %ecx 1498c2ecf20Sopenharmony_ci wrmsr 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci # Enable paging and in turn activate Long Mode 1528c2ecf20Sopenharmony_ci movl $(X86_CR0_PG | X86_CR0_WP | X86_CR0_PE), %eax 1538c2ecf20Sopenharmony_ci movl %eax, %cr0 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci /* 1568c2ecf20Sopenharmony_ci * At this point we're in long mode but in 32bit compatibility mode 1578c2ecf20Sopenharmony_ci * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn 1588c2ecf20Sopenharmony_ci * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we use 1598c2ecf20Sopenharmony_ci * the new gdt/idt that has __KERNEL_CS with CS.L = 1. 1608c2ecf20Sopenharmony_ci */ 1618c2ecf20Sopenharmony_ci ljmpl $__KERNEL_CS, $pa_startup_64 1628c2ecf20Sopenharmony_ciSYM_CODE_END(startup_32) 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci .section ".text64","ax" 1658c2ecf20Sopenharmony_ci .code64 1668c2ecf20Sopenharmony_ci .balign 4 1678c2ecf20Sopenharmony_ciSYM_CODE_START(startup_64) 1688c2ecf20Sopenharmony_ci # Now jump into the kernel using virtual addresses 1698c2ecf20Sopenharmony_ci jmpq *tr_start(%rip) 1708c2ecf20Sopenharmony_ciSYM_CODE_END(startup_64) 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci .section ".rodata","a" 1738c2ecf20Sopenharmony_ci # Duplicate the global descriptor table 1748c2ecf20Sopenharmony_ci # so the kernel can live anywhere 1758c2ecf20Sopenharmony_ci .balign 16 1768c2ecf20Sopenharmony_ciSYM_DATA_START(tr_gdt) 1778c2ecf20Sopenharmony_ci .short tr_gdt_end - tr_gdt - 1 # gdt limit 1788c2ecf20Sopenharmony_ci .long pa_tr_gdt 1798c2ecf20Sopenharmony_ci .short 0 1808c2ecf20Sopenharmony_ci .quad 0x00cf9b000000ffff # __KERNEL32_CS 1818c2ecf20Sopenharmony_ci .quad 0x00af9b000000ffff # __KERNEL_CS 1828c2ecf20Sopenharmony_ci .quad 0x00cf93000000ffff # __KERNEL_DS 1838c2ecf20Sopenharmony_ciSYM_DATA_END_LABEL(tr_gdt, SYM_L_LOCAL, tr_gdt_end) 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci .bss 1868c2ecf20Sopenharmony_ci .balign PAGE_SIZE 1878c2ecf20Sopenharmony_ciSYM_DATA(trampoline_pgd, .space PAGE_SIZE) 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci .balign 8 1908c2ecf20Sopenharmony_ciSYM_DATA_START(trampoline_header) 1918c2ecf20Sopenharmony_ci SYM_DATA_LOCAL(tr_start, .space 8) 1928c2ecf20Sopenharmony_ci SYM_DATA(tr_efer, .space 8) 1938c2ecf20Sopenharmony_ci SYM_DATA(tr_cr4, .space 4) 1948c2ecf20Sopenharmony_ci SYM_DATA(tr_flags, .space 4) 1958c2ecf20Sopenharmony_ciSYM_DATA_END(trampoline_header) 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci#include "trampoline_common.S" 198