2 * (C) Copyright 2008-2011
3 * Graeme Russ, <graeme.russ@gmail.com>
6 * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se>
9 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
10 * Marius Groeger <mgroeger@sysgo.de>
13 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
14 * Alex Zuepke <azu@sysgo.de>
16 * Part of this file is adapted from coreboot
17 * src/arch/x86/lib/cpu.c
19 * SPDX-License-Identifier: GPL-2.0+
27 #include <asm/control_regs.h>
29 #include <asm/lapic.h>
30 #include <asm/microcode.h>
35 #include <asm/processor.h>
36 #include <asm/processor-flags.h>
37 #include <asm/interrupt.h>
38 #include <asm/tables.h>
39 #include <linux/compiler.h>
41 DECLARE_GLOBAL_DATA_PTR
;
44 * Constructor for a conventional segment GDT (or LDT) entry
45 * This is a macro so it can be used in initialisers
47 #define GDT_ENTRY(flags, base, limit) \
48 ((((base) & 0xff000000ULL) << (56-24)) | \
49 (((flags) & 0x0000f0ffULL) << 40) | \
50 (((limit) & 0x000f0000ULL) << (48-16)) | \
51 (((base) & 0x00ffffffULL) << 16) | \
52 (((limit) & 0x0000ffffULL)))
59 struct cpu_device_id
{
65 uint8_t x86
; /* CPU family */
66 uint8_t x86_vendor
; /* CPU vendor */
72 * List of cpu vendor strings along with their normalized
79 { X86_VENDOR_INTEL
, "GenuineIntel", },
80 { X86_VENDOR_CYRIX
, "CyrixInstead", },
81 { X86_VENDOR_AMD
, "AuthenticAMD", },
82 { X86_VENDOR_UMC
, "UMC UMC UMC ", },
83 { X86_VENDOR_NEXGEN
, "NexGenDriven", },
84 { X86_VENDOR_CENTAUR
, "CentaurHauls", },
85 { X86_VENDOR_RISE
, "RiseRiseRise", },
86 { X86_VENDOR_TRANSMETA
, "GenuineTMx86", },
87 { X86_VENDOR_TRANSMETA
, "TransmetaCPU", },
88 { X86_VENDOR_NSC
, "Geode by NSC", },
89 { X86_VENDOR_SIS
, "SiS SiS SiS ", },
92 static const char *const x86_vendor_name
[] = {
93 [X86_VENDOR_INTEL
] = "Intel",
94 [X86_VENDOR_CYRIX
] = "Cyrix",
95 [X86_VENDOR_AMD
] = "AMD",
96 [X86_VENDOR_UMC
] = "UMC",
97 [X86_VENDOR_NEXGEN
] = "NexGen",
98 [X86_VENDOR_CENTAUR
] = "Centaur",
99 [X86_VENDOR_RISE
] = "Rise",
100 [X86_VENDOR_TRANSMETA
] = "Transmeta",
101 [X86_VENDOR_NSC
] = "NSC",
102 [X86_VENDOR_SIS
] = "SiS",
105 static void load_ds(u32 segment
)
107 asm volatile("movl %0, %%ds" : : "r" (segment
* X86_GDT_ENTRY_SIZE
));
110 static void load_es(u32 segment
)
112 asm volatile("movl %0, %%es" : : "r" (segment
* X86_GDT_ENTRY_SIZE
));
115 static void load_fs(u32 segment
)
117 asm volatile("movl %0, %%fs" : : "r" (segment
* X86_GDT_ENTRY_SIZE
));
120 static void load_gs(u32 segment
)
122 asm volatile("movl %0, %%gs" : : "r" (segment
* X86_GDT_ENTRY_SIZE
));
125 static void load_ss(u32 segment
)
127 asm volatile("movl %0, %%ss" : : "r" (segment
* X86_GDT_ENTRY_SIZE
));
130 static void load_gdt(const u64
*boot_gdt
, u16 num_entries
)
134 gdt
.len
= (num_entries
* X86_GDT_ENTRY_SIZE
) - 1;
135 gdt
.ptr
= (u32
)boot_gdt
;
137 asm volatile("lgdtl %0\n" : : "m" (gdt
));
140 void arch_setup_gd(gd_t
*new_gd
)
144 gdt_addr
= new_gd
->arch
.gdt
;
147 * CS: code, read/execute, 4 GB, base 0
149 * Some OS (like VxWorks) requires GDT entry 1 to be the 32-bit CS
151 gdt_addr
[X86_GDT_ENTRY_UNUSED
] = GDT_ENTRY(0xc09b, 0, 0xfffff);
152 gdt_addr
[X86_GDT_ENTRY_32BIT_CS
] = GDT_ENTRY(0xc09b, 0, 0xfffff);
154 /* DS: data, read/write, 4 GB, base 0 */
155 gdt_addr
[X86_GDT_ENTRY_32BIT_DS
] = GDT_ENTRY(0xc093, 0, 0xfffff);
157 /* FS: data, read/write, 4 GB, base (Global Data Pointer) */
158 new_gd
->arch
.gd_addr
= new_gd
;
159 gdt_addr
[X86_GDT_ENTRY_32BIT_FS
] = GDT_ENTRY(0xc093,
160 (ulong
)&new_gd
->arch
.gd_addr
, 0xfffff);
162 /* 16-bit CS: code, read/execute, 64 kB, base 0 */
163 gdt_addr
[X86_GDT_ENTRY_16BIT_CS
] = GDT_ENTRY(0x009b, 0, 0x0ffff);
165 /* 16-bit DS: data, read/write, 64 kB, base 0 */
166 gdt_addr
[X86_GDT_ENTRY_16BIT_DS
] = GDT_ENTRY(0x0093, 0, 0x0ffff);
168 gdt_addr
[X86_GDT_ENTRY_16BIT_FLAT_CS
] = GDT_ENTRY(0x809b, 0, 0xfffff);
169 gdt_addr
[X86_GDT_ENTRY_16BIT_FLAT_DS
] = GDT_ENTRY(0x8093, 0, 0xfffff);
171 load_gdt(gdt_addr
, X86_GDT_NUM_ENTRIES
);
172 load_ds(X86_GDT_ENTRY_32BIT_DS
);
173 load_es(X86_GDT_ENTRY_32BIT_DS
);
174 load_gs(X86_GDT_ENTRY_32BIT_DS
);
175 load_ss(X86_GDT_ENTRY_32BIT_DS
);
176 load_fs(X86_GDT_ENTRY_32BIT_FS
);
179 #ifdef CONFIG_HAVE_FSP
181 * Setup FSP execution environment GDT
183 * Per Intel FSP external architecture specification, before calling any FSP
184 * APIs, we need make sure the system is in flat 32-bit mode and both the code
185 * and data selectors should have full 4GB access range. Here we reuse the one
186 * we used in arch/x86/cpu/start16.S, and reload the segement registers.
188 void setup_fsp_gdt(void)
190 load_gdt((const u64
*)(gdt_rom
+ CONFIG_RESET_SEG_START
), 4);
191 load_ds(X86_GDT_ENTRY_32BIT_DS
);
192 load_ss(X86_GDT_ENTRY_32BIT_DS
);
193 load_es(X86_GDT_ENTRY_32BIT_DS
);
194 load_fs(X86_GDT_ENTRY_32BIT_DS
);
195 load_gs(X86_GDT_ENTRY_32BIT_DS
);
199 int __weak
x86_cleanup_before_linux(void)
201 #ifdef CONFIG_BOOTSTAGE_STASH
202 bootstage_stash((void *)CONFIG_BOOTSTAGE_STASH_ADDR
,
203 CONFIG_BOOTSTAGE_STASH_SIZE
);
210 * Cyrix CPUs without cpuid or with cpuid not yet enabled can be detected
211 * by the fact that they preserve the flags across the division of 5/2.
212 * PII and PPro exhibit this behavior too, but they have cpuid available.
216 * Perform the Cyrix 5/2 test. A Cyrix won't change
217 * the flags, while other 486 chips will.
219 static inline int test_cyrix_52div(void)
223 __asm__
__volatile__(
224 "sahf\n\t" /* clear flags (%eax = 0x0005) */
225 "div %b2\n\t" /* divide 5 by 2 */
226 "lahf" /* store flags into %ah */
231 /* AH is 0x02 on Cyrix after the divide.. */
232 return (unsigned char) (test
>> 8) == 0x02;
236 * Detect a NexGen CPU running without BIOS hypercode new enough
237 * to have CPUID. (Thanks to Herbert Oppmann)
240 static int deep_magic_nexgen_probe(void)
244 __asm__
__volatile__ (
245 " movw $0x5555, %%ax\n"
253 : "=a" (ret
) : : "cx", "dx");
257 static bool has_cpuid(void)
259 return flag_is_changeable_p(X86_EFLAGS_ID
);
262 static bool has_mtrr(void)
264 return cpuid_edx(0x00000001) & (1 << 12) ? true : false;
267 static int build_vendor_name(char *vendor_name
)
269 struct cpuid_result result
;
270 result
= cpuid(0x00000000);
271 unsigned int *name_as_ints
= (unsigned int *)vendor_name
;
273 name_as_ints
[0] = result
.ebx
;
274 name_as_ints
[1] = result
.edx
;
275 name_as_ints
[2] = result
.ecx
;
280 static void identify_cpu(struct cpu_device_id
*cpu
)
282 char vendor_name
[16];
285 vendor_name
[0] = '\0'; /* Unset */
286 cpu
->device
= 0; /* fix gcc 4.4.4 warning */
288 /* Find the id and vendor_name */
290 /* Its a 486 if we can modify the AC flag */
291 if (flag_is_changeable_p(X86_EFLAGS_AC
))
292 cpu
->device
= 0x00000400; /* 486 */
294 cpu
->device
= 0x00000300; /* 386 */
295 if ((cpu
->device
== 0x00000400) && test_cyrix_52div()) {
296 memcpy(vendor_name
, "CyrixInstead", 13);
297 /* If we ever care we can enable cpuid here */
299 /* Detect NexGen with old hypercode */
300 else if (deep_magic_nexgen_probe())
301 memcpy(vendor_name
, "NexGenDriven", 13);
306 cpuid_level
= build_vendor_name(vendor_name
);
307 vendor_name
[12] = '\0';
309 /* Intel-defined flags: level 0x00000001 */
310 if (cpuid_level
>= 0x00000001) {
311 cpu
->device
= cpuid_eax(0x00000001);
313 /* Have CPUID level 0 only unheard of */
314 cpu
->device
= 0x00000400;
317 cpu
->vendor
= X86_VENDOR_UNKNOWN
;
318 for (i
= 0; i
< ARRAY_SIZE(x86_vendors
); i
++) {
319 if (memcmp(vendor_name
, x86_vendors
[i
].name
, 12) == 0) {
320 cpu
->vendor
= x86_vendors
[i
].vendor
;
326 static inline void get_fms(struct cpuinfo_x86
*c
, uint32_t tfms
)
328 c
->x86
= (tfms
>> 8) & 0xf;
329 c
->x86_model
= (tfms
>> 4) & 0xf;
330 c
->x86_mask
= tfms
& 0xf;
332 c
->x86
+= (tfms
>> 20) & 0xff;
334 c
->x86_model
+= ((tfms
>> 16) & 0xF) << 4;
337 u32
cpu_get_family_model(void)
339 return gd
->arch
.x86_device
& 0x0fff0ff0;
342 u32
cpu_get_stepping(void)
344 return gd
->arch
.x86_mask
;
347 int x86_cpu_init_f(void)
349 const u32 em_rst
= ~X86_CR0_EM
;
350 const u32 mp_ne_set
= X86_CR0_MP
| X86_CR0_NE
;
352 if (ll_boot_init()) {
353 /* initialize FPU, reset EM, set MP and NE */
355 "movl %%cr0, %%eax\n" \
358 "movl %%eax, %%cr0\n" \
359 : : "i" (em_rst
), "i" (mp_ne_set
) : "eax");
362 /* identify CPU via cpuid and store the decoded info into gd->arch */
364 struct cpu_device_id cpu
;
365 struct cpuinfo_x86 c
;
368 get_fms(&c
, cpu
.device
);
369 gd
->arch
.x86
= c
.x86
;
370 gd
->arch
.x86_vendor
= cpu
.vendor
;
371 gd
->arch
.x86_model
= c
.x86_model
;
372 gd
->arch
.x86_mask
= c
.x86_mask
;
373 gd
->arch
.x86_device
= cpu
.device
;
375 gd
->arch
.has_mtrr
= has_mtrr();
377 /* Don't allow PCI region 3 to use memory in the 2-4GB memory hole */
378 gd
->pci_ram_top
= 0x80000000U
;
380 /* Configure fixed range MTRRs for some legacy regions */
381 if (gd
->arch
.has_mtrr
) {
384 mtrr_cap
= native_read_msr(MTRR_CAP_MSR
);
385 if (mtrr_cap
& MTRR_CAP_FIX
) {
386 /* Mark the VGA RAM area as uncacheable */
387 native_write_msr(MTRR_FIX_16K_A0000_MSR
,
388 MTRR_FIX_TYPE(MTRR_TYPE_UNCACHEABLE
),
389 MTRR_FIX_TYPE(MTRR_TYPE_UNCACHEABLE
));
392 * Mark the PCI ROM area as cacheable to improve ROM
393 * execution performance.
395 native_write_msr(MTRR_FIX_4K_C0000_MSR
,
396 MTRR_FIX_TYPE(MTRR_TYPE_WRBACK
),
397 MTRR_FIX_TYPE(MTRR_TYPE_WRBACK
));
398 native_write_msr(MTRR_FIX_4K_C8000_MSR
,
399 MTRR_FIX_TYPE(MTRR_TYPE_WRBACK
),
400 MTRR_FIX_TYPE(MTRR_TYPE_WRBACK
));
401 native_write_msr(MTRR_FIX_4K_D0000_MSR
,
402 MTRR_FIX_TYPE(MTRR_TYPE_WRBACK
),
403 MTRR_FIX_TYPE(MTRR_TYPE_WRBACK
));
404 native_write_msr(MTRR_FIX_4K_D8000_MSR
,
405 MTRR_FIX_TYPE(MTRR_TYPE_WRBACK
),
406 MTRR_FIX_TYPE(MTRR_TYPE_WRBACK
));
408 /* Enable the fixed range MTRRs */
409 msr_setbits_64(MTRR_DEF_TYPE_MSR
, MTRR_DEF_TYPE_FIX_EN
);
413 #ifdef CONFIG_I8254_TIMER
414 /* Set up the i8254 timer if required */
421 void x86_enable_caches(void)
426 cr0
&= ~(X86_CR0_NW
| X86_CR0_CD
);
430 void enable_caches(void) __attribute__((weak
, alias("x86_enable_caches")));
432 void x86_disable_caches(void)
437 cr0
|= X86_CR0_NW
| X86_CR0_CD
;
442 void disable_caches(void) __attribute__((weak
, alias("x86_disable_caches")));
444 int x86_init_cache(void)
450 int init_cache(void) __attribute__((weak
, alias("x86_init_cache")));
452 int do_reset(cmd_tbl_t
*cmdtp
, int flag
, int argc
, char * const argv
[])
454 printf("resetting ...\n");
458 disable_interrupts();
465 void flush_cache(unsigned long dummy1
, unsigned long dummy2
)
470 __weak
void reset_cpu(ulong addr
)
472 /* Do a hard reset through the chipset's reset control register */
473 outb(SYS_RST
| RST_CPU
, IO_PORT_RESET
);
478 void x86_full_reset(void)
480 outb(FULL_RST
| SYS_RST
| RST_CPU
, IO_PORT_RESET
);
483 int dcache_status(void)
485 return !(read_cr0() & X86_CR0_CD
);
488 /* Define these functions to allow ehch-hcd to function */
489 void flush_dcache_range(unsigned long start
, unsigned long stop
)
493 void invalidate_dcache_range(unsigned long start
, unsigned long stop
)
497 void dcache_enable(void)
502 void dcache_disable(void)
507 void icache_enable(void)
511 void icache_disable(void)
515 int icache_status(void)
520 void cpu_enable_paging_pae(ulong cr3
)
522 __asm__
__volatile__(
523 /* Load the page table address */
526 "movl %%cr4, %%eax\n"
527 "orl $0x00000020, %%eax\n"
528 "movl %%eax, %%cr4\n"
530 "movl %%cr0, %%eax\n"
531 "orl $0x80000000, %%eax\n"
532 "movl %%eax, %%cr0\n"
538 void cpu_disable_paging_pae(void)
540 /* Turn off paging */
541 __asm__
__volatile__ (
543 "movl %%cr0, %%eax\n"
544 "andl $0x7fffffff, %%eax\n"
545 "movl %%eax, %%cr0\n"
547 "movl %%cr4, %%eax\n"
548 "andl $0xffffffdf, %%eax\n"
549 "movl %%eax, %%cr4\n"
555 static bool can_detect_long_mode(void)
557 return cpuid_eax(0x80000000) > 0x80000000UL
;
560 static bool has_long_mode(void)
562 return cpuid_edx(0x80000001) & (1 << 29) ? true : false;
565 int cpu_has_64bit(void)
567 return has_cpuid() && can_detect_long_mode() &&
571 const char *cpu_vendor_name(int vendor
)
574 name
= "<invalid cpu vendor>";
575 if ((vendor
< (ARRAY_SIZE(x86_vendor_name
))) &&
576 (x86_vendor_name
[vendor
] != 0))
577 name
= x86_vendor_name
[vendor
];
582 char *cpu_get_name(char *name
)
584 unsigned int *name_as_ints
= (unsigned int *)name
;
585 struct cpuid_result regs
;
589 /* This bit adds up to 48 bytes */
590 for (i
= 0; i
< 3; i
++) {
591 regs
= cpuid(0x80000002 + i
);
592 name_as_ints
[i
* 4 + 0] = regs
.eax
;
593 name_as_ints
[i
* 4 + 1] = regs
.ebx
;
594 name_as_ints
[i
* 4 + 2] = regs
.ecx
;
595 name_as_ints
[i
* 4 + 3] = regs
.edx
;
597 name
[CPU_MAX_NAME_LEN
- 1] = '\0';
599 /* Skip leading spaces. */
607 int default_print_cpuinfo(void)
609 printf("CPU: %s, vendor %s, device %xh\n",
610 cpu_has_64bit() ? "x86_64" : "x86",
611 cpu_vendor_name(gd
->arch
.x86_vendor
), gd
->arch
.x86_device
);
616 #define PAGETABLE_SIZE (6 * 4096)
619 * build_pagetable() - build a flat 4GiB page table structure for 64-bti mode
621 * @pgtable: Pointer to a 24iKB block of memory
623 static void build_pagetable(uint32_t *pgtable
)
627 memset(pgtable
, '\0', PAGETABLE_SIZE
);
629 /* Level 4 needs a single entry */
630 pgtable
[0] = (uint32_t)&pgtable
[1024] + 7;
632 /* Level 3 has one 64-bit entry for each GiB of memory */
633 for (i
= 0; i
< 4; i
++) {
634 pgtable
[1024 + i
* 2] = (uint32_t)&pgtable
[2048] +
638 /* Level 2 has 2048 64-bit entries, each repesenting 2MiB */
639 for (i
= 0; i
< 2048; i
++)
640 pgtable
[2048 + i
* 2] = 0x183 + (i
<< 21UL);
643 int cpu_jump_to_64bit(ulong setup_base
, ulong target
)
647 pgtable
= memalign(4096, PAGETABLE_SIZE
);
651 build_pagetable(pgtable
);
652 cpu_call64((ulong
)pgtable
, setup_base
, target
);
658 void show_boot_progress(int val
)
660 outb(val
, POST_PORT
);
663 #ifndef CONFIG_SYS_COREBOOT
664 int last_stage_init(void)
673 static int enable_smis(struct udevice
*cpu
, void *unused
)
678 static struct mp_flight_record mp_steps
[] = {
679 MP_FR_BLOCK_APS(mp_init_cpu
, NULL
, mp_init_cpu
, NULL
),
680 /* Wait for APs to finish initialization before proceeding */
681 MP_FR_BLOCK_APS(NULL
, NULL
, enable_smis
, NULL
),
684 static int x86_mp_init(void)
686 struct mp_params mp_params
;
688 mp_params
.parallel_microcode_load
= 0,
689 mp_params
.flight_plan
= &mp_steps
[0];
690 mp_params
.num_records
= ARRAY_SIZE(mp_steps
);
691 mp_params
.microcode_pointer
= 0;
693 if (mp_init(&mp_params
)) {
694 printf("Warning: MP init failure\n");
702 static int x86_init_cpus(void)
705 debug("Init additional CPUs\n");
711 * This causes the cpu-x86 driver to be probed.
712 * We don't check return value here as we want to allow boards
713 * which have not been converted to use cpu uclass driver to boot.
715 uclass_first_device(UCLASS_CPU
, &dev
);
729 ret
= x86_init_cpus();
734 * Set up the northbridge, PCH and LPC if available. Note that these
735 * may have had some limited pre-relocation init if they were probed
736 * before relocation, but this is post relocation.
738 uclass_first_device(UCLASS_NORTHBRIDGE
, &dev
);
739 uclass_first_device(UCLASS_PCH
, &dev
);
740 uclass_first_device(UCLASS_LPC
, &dev
);