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