x86: Add a way to call 32-bit code from 64-bit mode
[oweals/u-boot.git] / arch / x86 / include / asm / cpu.h
1 /*
2  * Copyright (c) 2014 The Chromium OS Authors.
3  *
4  * Part of this file is adapted from coreboot
5  * src/arch/x86/include/arch/cpu.h and
6  * src/arch/x86/lib/cpu.c
7  *
8  * SPDX-License-Identifier:     GPL-2.0+
9  */
10
11 #ifndef _ASM_CPU_H
12 #define _ASM_CPU_H
13
14 enum {
15         X86_VENDOR_INVALID = 0,
16         X86_VENDOR_INTEL,
17         X86_VENDOR_CYRIX,
18         X86_VENDOR_AMD,
19         X86_VENDOR_UMC,
20         X86_VENDOR_NEXGEN,
21         X86_VENDOR_CENTAUR,
22         X86_VENDOR_RISE,
23         X86_VENDOR_TRANSMETA,
24         X86_VENDOR_NSC,
25         X86_VENDOR_SIS,
26         X86_VENDOR_ANY = 0xfe,
27         X86_VENDOR_UNKNOWN = 0xff
28 };
29
30 /* Global descriptor table (GDT) bits */
31 enum {
32         GDT_4KB                 = 1ULL << 55,
33         GDT_32BIT               = 1ULL << 54,
34         GDT_LONG                = 1ULL << 53,
35         GDT_PRESENT             = 1ULL << 47,
36         GDT_NOTSYS              = 1ULL << 44,
37         GDT_CODE                = 1ULL << 43,
38         GDT_LIMIT_LOW_SHIFT     = 0,
39         GDT_LIMIT_LOW_MASK      = 0xffff,
40         GDT_LIMIT_HIGH_SHIFT    = 48,
41         GDT_LIMIT_HIGH_MASK     = 0xf,
42         GDT_BASE_LOW_SHIFT      = 16,
43         GDT_BASE_LOW_MASK       = 0xffff,
44         GDT_BASE_HIGH_SHIFT     = 56,
45         GDT_BASE_HIGH_MASK      = 0xf,
46 };
47
48 struct cpuid_result {
49         uint32_t eax;
50         uint32_t ebx;
51         uint32_t ecx;
52         uint32_t edx;
53 };
54
55 /*
56  * Generic CPUID function
57  */
58 static inline struct cpuid_result cpuid(int op)
59 {
60         struct cpuid_result result;
61         asm volatile(
62                 "mov %%ebx, %%edi;"
63                 "cpuid;"
64                 "mov %%ebx, %%esi;"
65                 "mov %%edi, %%ebx;"
66                 : "=a" (result.eax),
67                   "=S" (result.ebx),
68                   "=c" (result.ecx),
69                   "=d" (result.edx)
70                 : "0" (op)
71                 : "edi");
72         return result;
73 }
74
75 /*
76  * Generic Extended CPUID function
77  */
78 static inline struct cpuid_result cpuid_ext(int op, unsigned ecx)
79 {
80         struct cpuid_result result;
81         asm volatile(
82                 "mov %%ebx, %%edi;"
83                 "cpuid;"
84                 "mov %%ebx, %%esi;"
85                 "mov %%edi, %%ebx;"
86                 : "=a" (result.eax),
87                   "=S" (result.ebx),
88                   "=c" (result.ecx),
89                   "=d" (result.edx)
90                 : "0" (op), "2" (ecx)
91                 : "edi");
92         return result;
93 }
94
95 /*
96  * CPUID functions returning a single datum
97  */
98 static inline unsigned int cpuid_eax(unsigned int op)
99 {
100         unsigned int eax;
101
102         __asm__("mov %%ebx, %%edi;"
103                 "cpuid;"
104                 "mov %%edi, %%ebx;"
105                 : "=a" (eax)
106                 : "0" (op)
107                 : "ecx", "edx", "edi");
108         return eax;
109 }
110
111 static inline unsigned int cpuid_ebx(unsigned int op)
112 {
113         unsigned int eax, ebx;
114
115         __asm__("mov %%ebx, %%edi;"
116                 "cpuid;"
117                 "mov %%ebx, %%esi;"
118                 "mov %%edi, %%ebx;"
119                 : "=a" (eax), "=S" (ebx)
120                 : "0" (op)
121                 : "ecx", "edx", "edi");
122         return ebx;
123 }
124
125 static inline unsigned int cpuid_ecx(unsigned int op)
126 {
127         unsigned int eax, ecx;
128
129         __asm__("mov %%ebx, %%edi;"
130                 "cpuid;"
131                 "mov %%edi, %%ebx;"
132                 : "=a" (eax), "=c" (ecx)
133                 : "0" (op)
134                 : "edx", "edi");
135         return ecx;
136 }
137
138 static inline unsigned int cpuid_edx(unsigned int op)
139 {
140         unsigned int eax, edx;
141
142         __asm__("mov %%ebx, %%edi;"
143                 "cpuid;"
144                 "mov %%edi, %%ebx;"
145                 : "=a" (eax), "=d" (edx)
146                 : "0" (op)
147                 : "ecx", "edi");
148         return edx;
149 }
150
151 /* Standard macro to see if a specific flag is changeable */
152 static inline int flag_is_changeable_p(uint32_t flag)
153 {
154         uint32_t f1, f2;
155
156         asm(
157                 "pushfl\n\t"
158                 "pushfl\n\t"
159                 "popl %0\n\t"
160                 "movl %0,%1\n\t"
161                 "xorl %2,%0\n\t"
162                 "pushl %0\n\t"
163                 "popfl\n\t"
164                 "pushfl\n\t"
165                 "popl %0\n\t"
166                 "popfl\n\t"
167                 : "=&r" (f1), "=&r" (f2)
168                 : "ir" (flag));
169         return ((f1^f2) & flag) != 0;
170 }
171
172 static inline void mfence(void)
173 {
174         __asm__ __volatile__("mfence" : : : "memory");
175 }
176
177 /**
178  * cpu_enable_paging_pae() - Enable PAE-paging
179  *
180  * @cr3:        Value to set in cr3 (PDPT or PML4T)
181  */
182 void cpu_enable_paging_pae(ulong cr3);
183
184 /**
185  * cpu_disable_paging_pae() - Disable paging and PAE
186  */
187 void cpu_disable_paging_pae(void);
188
189 /**
190  * cpu_has_64bit() - Check if the CPU has 64-bit support
191  *
192  * @return 1 if this CPU supports long mode (64-bit), 0 if not
193  */
194 int cpu_has_64bit(void);
195
196 /**
197  * cpu_vendor_name() - Get CPU vendor name
198  *
199  * @vendor:     CPU vendor enumeration number
200  *
201  * @return:     Address to hold the CPU vendor name string
202  */
203 const char *cpu_vendor_name(int vendor);
204
205 #define CPU_MAX_NAME_LEN        49
206
207 /**
208  * cpu_get_name() - Get the name of the current cpu
209  *
210  * @name: Place to put name, which must be CPU_MAX_NAME_LEN bytes including
211  * @return pointer to name, which will likely be a few bytes after the start
212  * of @name
213  * \0 terminator
214  */
215 char *cpu_get_name(char *name);
216
217 /**
218  * cpu_call64() - Jump to a 64-bit Linux kernel (internal function)
219  *
220  * The kernel is uncompressed and the 64-bit entry point is expected to be
221  * at @target.
222  *
223  * This function is used internally - see cpu_jump_to_64bit() for a more
224  * useful function.
225  *
226  * @pgtable:    Address of 24KB area containing the page table
227  * @setup_base: Pointer to the setup.bin information for the kernel
228  * @target:     Pointer to the start of the kernel image
229  */
230 void cpu_call64(ulong pgtable, ulong setup_base, ulong target);
231
232 /**
233  * cpu_call32() - Jump to a 32-bit entry point
234  *
235  * @code_seg32: 32-bit code segment to use (GDT offset, e.g. 0x20)
236  * @target:     Pointer to the start of the 32-bit U-Boot image/entry point
237  * @table:      Pointer to start of info table to pass to U-Boot
238  */
239 void cpu_call32(ulong code_seg32, ulong target, ulong table);
240
241 /**
242  * cpu_jump_to_64bit() - Jump to a 64-bit Linux kernel
243  *
244  * The kernel is uncompressed and the 64-bit entry point is expected to be
245  * at @target.
246  *
247  * @setup_base: Pointer to the setup.bin information for the kernel
248  * @target:     Pointer to the start of the kernel image
249  */
250 int cpu_jump_to_64bit(ulong setup_base, ulong target);
251
252 #endif