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