blob: f979f9e5f0edf4f89e5ad6307e492b406fe99307 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001/* SPDX-License-Identifier: GPL-2.0+ */
Simon Glass463fac22014-10-10 08:21:55 -06002/*
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
Simon Glass463fac22014-10-10 08:21:55 -06007 */
8
Simon Glass463fac22014-10-10 08:21:55 -06009#include <asm/msr-index.h>
10#include <asm/processor-flags.h>
11
12.code32
Sam Edwards7cc2ef92025-03-15 15:18:05 -070013.section .text_call64, "ax"
Simon Glass463fac22014-10-10 08:21:55 -060014.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
Simon Glass46faeea2025-03-15 14:25:37 +000028 # disable paging
29 movl %cr0, %eax
30 andl $~X86_CR0_PG, %eax
31 movl %eax, %cr0
32
Simon Glass463fac22014-10-10 08:21:55 -060033 /* Load new GDT with the 64bit segments using 32bit descriptor */
34 leal gdt, %eax
35 movl %eax, gdt+2
36 lgdt gdt
37
38 /* Enable PAE mode */
39 movl $(X86_CR4_PAE), %eax
40 movl %eax, %cr4
41
42 /* Enable the boot page tables */
43 leal (%ebx), %eax
44 movl %eax, %cr3
45
46 /* Enable Long mode in EFER (Extended Feature Enable Register) */
47 movl $MSR_EFER, %ecx
48 rdmsr
49 btsl $_EFER_LME, %eax
50 wrmsr
51
52 /* After gdt is loaded */
53 xorl %eax, %eax
54 lldt %ax
55 movl $0x20, %eax
56 ltr %ax
57
58 /*
59 * Setup for the jump to 64bit mode
60 *
61 * When the jump is performed we will be in long mode but
62 * in 32bit compatibility mode with EFER.LME = 1, CS.L = 0, CS.D = 1
63 * (and in turn EFER.LMA = 1). To jump into 64bit mode we use
64 * the new gdt/idt that has __KERNEL_CS with CS.L = 1.
65 * We place all of the values on our mini stack so lret can
66 * used to perform that far jump. See the gdt below.
67 */
68 pop %esi /* setup_base */
69
70 pushl $0x10
71 leal lret_target, %eax
72 pushl %eax
73
74 /* Enter paged protected Mode, activating Long Mode */
Simon Glass46faeea2025-03-15 14:25:37 +000075 movl %cr0, %eax
76 orl $X86_CR0_PG, %eax
Simon Glass463fac22014-10-10 08:21:55 -060077 movl %eax, %cr0
78
79 /* Jump from 32bit compatibility mode into 64bit mode. */
80 lret
81
82code64:
83lret_target:
84 pop %eax /* target */
85 mov %eax, %eax /* Clear bits 63:32 */
86 jmp *%eax /* Jump to the 64-bit target */
87
Bin Meng17b7b602019-01-31 08:22:13 -080088.globl call64_stub_size
89call64_stub_size:
90 .long . - cpu_call64
91
Simon Glass463fac22014-10-10 08:21:55 -060092 .data
Simon Glass1e32ede2017-01-16 07:04:15 -070093 .align 16
94 .globl gdt64
95gdt64:
Simon Glass463fac22014-10-10 08:21:55 -060096gdt:
Simon Glassf2d1a112015-07-31 09:31:30 -060097 .word gdt_end - gdt - 1
98 .long gdt /* Fixed up by code above */
Simon Glass463fac22014-10-10 08:21:55 -060099 .word 0
100 .quad 0x0000000000000000 /* NULL descriptor */
101 .quad 0x00af9a000000ffff /* __KERNEL_CS */
102 .quad 0x00cf92000000ffff /* __KERNEL_DS */
103 .quad 0x0080890000000000 /* TS descriptor */
104 .quad 0x0000000000000000 /* TS continued */
105gdt_end: