0ffc1006bbf79110dcaa262429f3f904ce704388
[platform/kernel/u-boot.git] / arch / x86 / cpu / i386 / call64.S
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 .section .text_call64
15 .globl cpu_call64
16 cpu_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
77 code64:
78 lret_target:
79         pop     %eax                    /* target */
80         mov     %eax, %eax              /* Clear bits 63:32 */
81         jmp     *%eax                   /* Jump to the 64-bit target */
82
83 .globl call64_stub_size
84 call64_stub_size:
85         .long   . - cpu_call64
86
87         .data
88         .align  16
89         .globl  gdt64
90 gdt64:
91 gdt:
92         .word   gdt_end - gdt - 1
93         .long   gdt                     /* Fixed up by code above */
94         .word   0
95         .quad   0x0000000000000000      /* NULL descriptor */
96         .quad   0x00af9a000000ffff      /* __KERNEL_CS */
97         .quad   0x00cf92000000ffff      /* __KERNEL_DS */
98         .quad   0x0080890000000000      /* TS descriptor */
99         .quad   0x0000000000000000      /* TS continued */
100 gdt_end: