1/* SPDX-License-Identifier: GPL-2.0+ */
2/*
3 * (C) Copyright 2014 Google, Inc
4 * Copyright (C) 1991, 1992, 1993  Linus Torvalds
5 *
6 * Parts of this copied from Linux arch/x86/boot/compressed/head_64.S
7 */
8
9#include <asm/msr-index.h>
10#include <asm/processor-flags.h>
11
12.code32
13.section .text_call64
14.globl cpu_call64
15cpu_call64:
16	/*
17	 * cpu_call64(ulong pgtable, ulong setup_base, ulong target)
18	 *
19	 * eax - pgtable
20	 * edx - setup_base
21	 * ecx - target
22	 */
23	cli
24	push	%ecx		/* arg2 = target */
25	push	%edx		/* arg1 = setup_base */
26	mov	%eax, %ebx
27
28	/* Load new GDT with the 64bit segments using 32bit descriptor */
29	leal	gdt, %eax
30	movl	%eax, gdt+2
31	lgdt	gdt
32
33	/* Enable PAE mode */
34	movl	$(X86_CR4_PAE), %eax
35	movl	%eax, %cr4
36
37	/* Enable the boot page tables */
38	leal	(%ebx), %eax
39	movl	%eax, %cr3
40
41	/* Enable Long mode in EFER (Extended Feature Enable Register) */
42	movl	$MSR_EFER, %ecx
43	rdmsr
44	btsl	$_EFER_LME, %eax
45	wrmsr
46
47	/* After gdt is loaded */
48	xorl	%eax, %eax
49	lldt	%ax
50	movl    $0x20, %eax
51	ltr	%ax
52
53	/*
54	 * Setup for the jump to 64bit mode
55	 *
56	 * When the jump is performed we will be in long mode but
57	 * in 32bit compatibility mode with EFER.LME = 1, CS.L = 0, CS.D = 1
58	 * (and in turn EFER.LMA = 1). To jump into 64bit mode we use
59	 * the new gdt/idt that has __KERNEL_CS with CS.L = 1.
60	 * We place all of the values on our mini stack so lret can
61	 * used to perform that far jump. See the gdt below.
62	 */
63	pop	%esi			/* setup_base */
64
65	pushl	$0x10
66	leal	lret_target, %eax
67	pushl	%eax
68
69	/* Enter paged protected Mode, activating Long Mode */
70	movl	$(X86_CR0_PG | X86_CR0_PE), %eax
71	movl	%eax, %cr0
72
73	/* Jump from 32bit compatibility mode into 64bit mode. */
74	lret
75
76code64:
77lret_target:
78	pop	%eax			/* target */
79	mov	%eax, %eax		/* Clear bits 63:32 */
80	jmp	*%eax			/* Jump to the 64-bit target */
81
82.globl call64_stub_size
83call64_stub_size:
84	.long	. - cpu_call64
85
86	.data
87	.align	16
88	.globl	gdt64
89gdt64:
90gdt:
91	.word	gdt_end - gdt - 1
92	.long	gdt			/* Fixed up by code above */
93	.word	0
94	.quad	0x0000000000000000	/* NULL descriptor */
95	.quad	0x00af9a000000ffff	/* __KERNEL_CS */
96	.quad	0x00cf92000000ffff	/* __KERNEL_DS */
97	.quad	0x0080890000000000	/* TS descriptor */
98	.quad   0x0000000000000000	/* TS continued */
99gdt_end:
100