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