xref: /openbmc/u-boot/arch/x86/cpu/i386/call64.S (revision 49a97162ea573b8646ba29162b71fc2c29e9c5d4)
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/global_data.h>
10 #include <asm/msr-index.h>
11 #include <asm/processor-flags.h>
12 
13 .code32
14 .globl cpu_call64
15 cpu_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 
76 code64:
77 lret_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
83 call64_stub_size:
84 	.long	. - cpu_call64
85 
86 	.data
87 	.align	16
88 	.globl	gdt64
89 gdt64:
90 gdt:
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 */
99 gdt_end:
100