/* SPDX-License-Identifier: GPL-2.0 */12#include <linux/linkage.h>3#include <asm/segment.h>4#include <asm/boot.h>5#include <asm/msr.h>6#include <asm/processor-flags.h>78/*9* This is the 32-bit trampoline that will be copied over to low memory. It10* will be called using the ordinary 64-bit calling convention from code11* running in 64-bit mode.12*13* Return address is at the top of the stack (might be above 4G).14* The first argument (EDI) contains the address of the temporary PGD level15* page table in 32-bit addressable memory which will be programmed into16* register CR3.17*/1819.section ".rodata", "a", @progbits20SYM_CODE_START(trampoline_32bit_src)21/*22* Preserve callee save 64-bit registers on the stack: this is23* necessary because the architecture does not guarantee that GPRs will24* retain their full 64-bit values across a 32-bit mode switch.25*/26pushq %r1527pushq %r1428pushq %r1329pushq %r1230pushq %rbp31pushq %rbx3233/* Preserve top half of RSP in a legacy mode GPR to avoid truncation */34movq %rsp, %rbx35shrq $32, %rbx3637/* Switch to compatibility mode (CS.L = 0 CS.D = 1) via far return */38pushq $__KERNEL32_CS39leaq 0f(%rip), %rax40pushq %rax41lretq4243/*44* The 32-bit code below will do a far jump back to long mode and end45* up here after reconfiguring the number of paging levels. First, the46* stack pointer needs to be restored to its full 64-bit value before47* the callee save register contents can be popped from the stack.48*/49.Lret:50shlq $32, %rbx51orq %rbx, %rsp5253/* Restore the preserved 64-bit registers */54popq %rbx55popq %rbp56popq %r1257popq %r1358popq %r1459popq %r1560retq6162.code32630:64/* Disable paging */65movl %cr0, %eax66btrl $X86_CR0_PG_BIT, %eax67movl %eax, %cr06869/* Point CR3 to the trampoline's new top level page table */70movl %edi, %cr37172/* Set EFER.LME=1 as a precaution in case hypervsior pulls the rug */73movl $MSR_EFER, %ecx74rdmsr75btsl $_EFER_LME, %eax76/* Avoid writing EFER if no change was made (for TDX guest) */77jc 1f78wrmsr791:80/* Toggle CR4.LA57 */81movl %cr4, %eax82btcl $X86_CR4_LA57_BIT, %eax83movl %eax, %cr48485/* Enable paging again. */86movl %cr0, %eax87btsl $X86_CR0_PG_BIT, %eax88movl %eax, %cr08990/*91* Return to the 64-bit calling code using LJMP rather than LRET, to92* avoid the need for a 32-bit addressable stack. The destination93* address will be adjusted after the template code is copied into a94* 32-bit addressable buffer.95*/96.Ljmp: ljmpl $__KERNEL_CS, $(.Lret - trampoline_32bit_src)97SYM_CODE_END(trampoline_32bit_src)9899/*100* This symbol is placed right after trampoline_32bit_src() so its address can101* be used to infer the size of the trampoline code.102*/103SYM_DATA(trampoline_ljmp_imm_offset, .word .Ljmp + 1 - trampoline_32bit_src)104105/*106* The trampoline code has a size limit.107* Make sure we fail to compile if the trampoline code grows108* beyond TRAMPOLINE_32BIT_CODE_SIZE bytes.109*/110.org trampoline_32bit_src + TRAMPOLINE_32BIT_CODE_SIZE111112113