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