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 *
862306a36Sopenharmony_ci *	This is only used for booting secondary CPUs in SMP machine
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci *	Entry: CS:IP point to the start of our code, we are
1162306a36Sopenharmony_ci *	in real mode with no stack, but the rest of the
1262306a36Sopenharmony_ci *	trampoline page to make our stack and everything else
1362306a36Sopenharmony_ci *	is a mystery.
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci *	We jump into arch/x86/kernel/head_32.S.
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci *	On entry to trampoline_start, the processor is in real mode
1862306a36Sopenharmony_ci *	with 16-bit addressing and 16-bit data.  CS has some value
1962306a36Sopenharmony_ci *	and IP is zero.  Thus, we load CS to the physical segment
2062306a36Sopenharmony_ci *	of the real mode code before doing anything further.
2162306a36Sopenharmony_ci */
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include <linux/linkage.h>
2462306a36Sopenharmony_ci#include <asm/segment.h>
2562306a36Sopenharmony_ci#include <asm/page_types.h>
2662306a36Sopenharmony_ci#include "realmode.h"
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	.text
2962306a36Sopenharmony_ci	.code16
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	.balign	PAGE_SIZE
3262306a36Sopenharmony_ciSYM_CODE_START(trampoline_start)
3362306a36Sopenharmony_ci	wbinvd			# Needed for NUMA-Q should be harmless for others
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	LJMPW_RM(1f)
3662306a36Sopenharmony_ci1:
3762306a36Sopenharmony_ci	mov	%cs, %ax	# Code and data in the same place
3862306a36Sopenharmony_ci	mov	%ax, %ds
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	cli			# We should be safe anyway
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	movl	tr_start, %eax	# where we need to go
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	/*
4562306a36Sopenharmony_ci	 * GDT tables in non default location kernel can be beyond 16MB and
4662306a36Sopenharmony_ci	 * lgdt will not be able to load the address as in real mode default
4762306a36Sopenharmony_ci	 * operand size is 16bit. Use lgdtl instead to force operand size
4862306a36Sopenharmony_ci	 * to 32 bit.
4962306a36Sopenharmony_ci	 */
5062306a36Sopenharmony_ci	lidtl	tr_idt			# load idt with 0, 0
5162306a36Sopenharmony_ci	lgdtl	tr_gdt			# load gdt with whatever is appropriate
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	movw	$1, %dx			# protected mode (PE) bit
5462306a36Sopenharmony_ci	lmsw	%dx			# into protected mode
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	ljmpl	$__BOOT_CS, $pa_startup_32
5762306a36Sopenharmony_ciSYM_CODE_END(trampoline_start)
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	.section ".text32","ax"
6062306a36Sopenharmony_ci	.code32
6162306a36Sopenharmony_ciSYM_CODE_START(startup_32)			# note: also used from wakeup_asm.S
6262306a36Sopenharmony_ci	jmp	*%eax
6362306a36Sopenharmony_ciSYM_CODE_END(startup_32)
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	.bss
6662306a36Sopenharmony_ci	.balign 8
6762306a36Sopenharmony_ciSYM_DATA_START(trampoline_header)
6862306a36Sopenharmony_ci	SYM_DATA_LOCAL(tr_start,	.space 4)
6962306a36Sopenharmony_ci	SYM_DATA_LOCAL(tr_gdt_pad,	.space 2)
7062306a36Sopenharmony_ci	SYM_DATA_LOCAL(tr_gdt,		.space 6)
7162306a36Sopenharmony_ciSYM_DATA_END(trampoline_header)
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci#include "trampoline_common.S"
74