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>
34 #include <asm/processor.h>
35 #include <asm/processor-flags.h>
36 #include <asm/interrupt.h>
37 #include <asm/tables.h>
38 #include <linux/compiler.h>
40 DECLARE_GLOBAL_DATA_PTR
;
43 * Constructor for a conventional segment GDT (or LDT) entry
44 * This is a macro so it can be used in initialisers
46 #define GDT_ENTRY(flags, base, limit) \
47 ((((base) & 0xff000000ULL) << (56-24)) | \
48 (((flags) & 0x0000f0ffULL) << 40) | \
49 (((limit) & 0x000f0000ULL) << (48-16)) | \
50 (((base) & 0x00ffffffULL) << 16) | \
51 (((limit) & 0x0000ffffULL)))
58 struct cpu_device_id
{
64 uint8_t x86
; /* CPU family */
65 uint8_t x86_vendor
; /* CPU vendor */
71 * List of cpu vendor strings along with their normalized
78 { X86_VENDOR_INTEL
, "GenuineIntel", },
79 { X86_VENDOR_CYRIX
, "CyrixInstead", },
80 { X86_VENDOR_AMD
, "AuthenticAMD", },
81 { X86_VENDOR_UMC
, "UMC UMC UMC ", },
82 { X86_VENDOR_NEXGEN
, "NexGenDriven", },
83 { X86_VENDOR_CENTAUR
, "CentaurHauls", },
84 { X86_VENDOR_RISE
, "RiseRiseRise", },
85 { X86_VENDOR_TRANSMETA
, "GenuineTMx86", },
86 { X86_VENDOR_TRANSMETA
, "TransmetaCPU", },
87 { X86_VENDOR_NSC
, "Geode by NSC", },
88 { X86_VENDOR_SIS
, "SiS SiS SiS ", },
91 static const char *const x86_vendor_name
[] = {
92 [X86_VENDOR_INTEL
] = "Intel",
93 [X86_VENDOR_CYRIX
] = "Cyrix",
94 [X86_VENDOR_AMD
] = "AMD",
95 [X86_VENDOR_UMC
] = "UMC",
96 [X86_VENDOR_NEXGEN
] = "NexGen",
97 [X86_VENDOR_CENTAUR
] = "Centaur",
98 [X86_VENDOR_RISE
] = "Rise",
99 [X86_VENDOR_TRANSMETA
] = "Transmeta",
100 [X86_VENDOR_NSC
] = "NSC",
101 [X86_VENDOR_SIS
] = "SiS",
104 static void load_ds(u32 segment
)
106 asm volatile("movl %0, %%ds" : : "r" (segment
* X86_GDT_ENTRY_SIZE
));
109 static void load_es(u32 segment
)
111 asm volatile("movl %0, %%es" : : "r" (segment
* X86_GDT_ENTRY_SIZE
));
114 static void load_fs(u32 segment
)
116 asm volatile("movl %0, %%fs" : : "r" (segment
* X86_GDT_ENTRY_SIZE
));
119 static void load_gs(u32 segment
)
121 asm volatile("movl %0, %%gs" : : "r" (segment
* X86_GDT_ENTRY_SIZE
));
124 static void load_ss(u32 segment
)
126 asm volatile("movl %0, %%ss" : : "r" (segment
* X86_GDT_ENTRY_SIZE
));
129 static void load_gdt(const u64
*boot_gdt
, u16 num_entries
)
133 gdt
.len
= (num_entries
* X86_GDT_ENTRY_SIZE
) - 1;
134 gdt
.ptr
= (u32
)boot_gdt
;
136 asm volatile("lgdtl %0\n" : : "m" (gdt
));
139 void arch_setup_gd(gd_t
*new_gd
)
143 gdt_addr
= new_gd
->arch
.gdt
;
146 * CS: code, read/execute, 4 GB, base 0
148 * Some OS (like VxWorks) requires GDT entry 1 to be the 32-bit CS
150 gdt_addr
[X86_GDT_ENTRY_UNUSED
] = GDT_ENTRY(0xc09b, 0, 0xfffff);
151 gdt_addr
[X86_GDT_ENTRY_32BIT_CS
] = GDT_ENTRY(0xc09b, 0, 0xfffff);
153 /* DS: data, read/write, 4 GB, base 0 */
154 gdt_addr
[X86_GDT_ENTRY_32BIT_DS
] = GDT_ENTRY(0xc093, 0, 0xfffff);
156 /* FS: data, read/write, 4 GB, base (Global Data Pointer) */
157 new_gd
->arch
.gd_addr
= new_gd
;
158 gdt_addr
[X86_GDT_ENTRY_32BIT_FS
] = GDT_ENTRY(0xc093,
159 (ulong
)&new_gd
->arch
.gd_addr
, 0xfffff);
161 /* 16-bit CS: code, read/execute, 64 kB, base 0 */
162 gdt_addr
[X86_GDT_ENTRY_16BIT_CS
] = GDT_ENTRY(0x009b, 0, 0x0ffff);
164 /* 16-bit DS: data, read/write, 64 kB, base 0 */
165 gdt_addr
[X86_GDT_ENTRY_16BIT_DS
] = GDT_ENTRY(0x0093, 0, 0x0ffff);
167 gdt_addr
[X86_GDT_ENTRY_16BIT_FLAT_CS
] = GDT_ENTRY(0x809b, 0, 0xfffff);
168 gdt_addr
[X86_GDT_ENTRY_16BIT_FLAT_DS
] = GDT_ENTRY(0x8093, 0, 0xfffff);
170 load_gdt(gdt_addr
, X86_GDT_NUM_ENTRIES
);
171 load_ds(X86_GDT_ENTRY_32BIT_DS
);
172 load_es(X86_GDT_ENTRY_32BIT_DS
);
173 load_gs(X86_GDT_ENTRY_32BIT_DS
);
174 load_ss(X86_GDT_ENTRY_32BIT_DS
);
175 load_fs(X86_GDT_ENTRY_32BIT_FS
);
178 #ifdef CONFIG_HAVE_FSP
180 * Setup FSP execution environment GDT
182 * Per Intel FSP external architecture specification, before calling any FSP
183 * APIs, we need make sure the system is in flat 32-bit mode and both the code
184 * and data selectors should have full 4GB access range. Here we reuse the one
185 * we used in arch/x86/cpu/start16.S, and reload the segement registers.
187 void setup_fsp_gdt(void)
189 load_gdt((const u64
*)(gdt_rom
+ CONFIG_RESET_SEG_START
), 4);
190 load_ds(X86_GDT_ENTRY_32BIT_DS
);
191 load_ss(X86_GDT_ENTRY_32BIT_DS
);
192 load_es(X86_GDT_ENTRY_32BIT_DS
);
193 load_fs(X86_GDT_ENTRY_32BIT_DS
);
194 load_gs(X86_GDT_ENTRY_32BIT_DS
);
198 int __weak
x86_cleanup_before_linux(void)
200 #ifdef CONFIG_BOOTSTAGE_STASH
201 bootstage_stash((void *)CONFIG_BOOTSTAGE_STASH_ADDR
,
202 CONFIG_BOOTSTAGE_STASH_SIZE
);
209 * Cyrix CPUs without cpuid or with cpuid not yet enabled can be detected
210 * by the fact that they preserve the flags across the division of 5/2.
211 * PII and PPro exhibit this behavior too, but they have cpuid available.
215 * Perform the Cyrix 5/2 test. A Cyrix won't change
216 * the flags, while other 486 chips will.
218 static inline int test_cyrix_52div(void)
222 __asm__
__volatile__(
223 "sahf\n\t" /* clear flags (%eax = 0x0005) */
224 "div %b2\n\t" /* divide 5 by 2 */
225 "lahf" /* store flags into %ah */
230 /* AH is 0x02 on Cyrix after the divide.. */
231 return (unsigned char) (test
>> 8) == 0x02;
235 * Detect a NexGen CPU running without BIOS hypercode new enough
236 * to have CPUID. (Thanks to Herbert Oppmann)
239 static int deep_magic_nexgen_probe(void)
243 __asm__
__volatile__ (
244 " movw $0x5555, %%ax\n"
252 : "=a" (ret
) : : "cx", "dx");
256 static bool has_cpuid(void)
258 return flag_is_changeable_p(X86_EFLAGS_ID
);
261 static bool has_mtrr(void)
263 return cpuid_edx(0x00000001) & (1 << 12) ? true : false;
266 static int build_vendor_name(char *vendor_name
)
268 struct cpuid_result result
;
269 result
= cpuid(0x00000000);
270 unsigned int *name_as_ints
= (unsigned int *)vendor_name
;
272 name_as_ints
[0] = result
.ebx
;
273 name_as_ints
[1] = result
.edx
;
274 name_as_ints
[2] = result
.ecx
;
279 static void identify_cpu(struct cpu_device_id
*cpu
)
281 char vendor_name
[16];
284 vendor_name
[0] = '\0'; /* Unset */
285 cpu
->device
= 0; /* fix gcc 4.4.4 warning */
287 /* Find the id and vendor_name */
289 /* Its a 486 if we can modify the AC flag */
290 if (flag_is_changeable_p(X86_EFLAGS_AC
))
291 cpu
->device
= 0x00000400; /* 486 */
293 cpu
->device
= 0x00000300; /* 386 */
294 if ((cpu
->device
== 0x00000400) && test_cyrix_52div()) {
295 memcpy(vendor_name
, "CyrixInstead", 13);
296 /* If we ever care we can enable cpuid here */
298 /* Detect NexGen with old hypercode */
299 else if (deep_magic_nexgen_probe())
300 memcpy(vendor_name
, "NexGenDriven", 13);
305 cpuid_level
= build_vendor_name(vendor_name
);
306 vendor_name
[12] = '\0';
308 /* Intel-defined flags: level 0x00000001 */
309 if (cpuid_level
>= 0x00000001) {
310 cpu
->device
= cpuid_eax(0x00000001);
312 /* Have CPUID level 0 only unheard of */
313 cpu
->device
= 0x00000400;
316 cpu
->vendor
= X86_VENDOR_UNKNOWN
;
317 for (i
= 0; i
< ARRAY_SIZE(x86_vendors
); i
++) {
318 if (memcmp(vendor_name
, x86_vendors
[i
].name
, 12) == 0) {
319 cpu
->vendor
= x86_vendors
[i
].vendor
;
325 static inline void get_fms(struct cpuinfo_x86
*c
, uint32_t tfms
)
327 c
->x86
= (tfms
>> 8) & 0xf;
328 c
->x86_model
= (tfms
>> 4) & 0xf;
329 c
->x86_mask
= tfms
& 0xf;
331 c
->x86
+= (tfms
>> 20) & 0xff;
333 c
->x86_model
+= ((tfms
>> 16) & 0xF) << 4;
336 int x86_cpu_init_f(void)
338 const u32 em_rst
= ~X86_CR0_EM
;
339 const u32 mp_ne_set
= X86_CR0_MP
| X86_CR0_NE
;
341 if (ll_boot_init()) {
342 /* initialize FPU, reset EM, set MP and NE */
344 "movl %%cr0, %%eax\n" \
347 "movl %%eax, %%cr0\n" \
348 : : "i" (em_rst
), "i" (mp_ne_set
) : "eax");
351 /* identify CPU via cpuid and store the decoded info into gd->arch */
353 struct cpu_device_id cpu
;
354 struct cpuinfo_x86 c
;
357 get_fms(&c
, cpu
.device
);
358 gd
->arch
.x86
= c
.x86
;
359 gd
->arch
.x86_vendor
= cpu
.vendor
;
360 gd
->arch
.x86_model
= c
.x86_model
;
361 gd
->arch
.x86_mask
= c
.x86_mask
;
362 gd
->arch
.x86_device
= cpu
.device
;
364 gd
->arch
.has_mtrr
= has_mtrr();
366 /* Don't allow PCI region 3 to use memory in the 2-4GB memory hole */
367 gd
->pci_ram_top
= 0x80000000U
;
369 /* Configure fixed range MTRRs for some legacy regions */
370 if (gd
->arch
.has_mtrr
) {
373 mtrr_cap
= native_read_msr(MTRR_CAP_MSR
);
374 if (mtrr_cap
& MTRR_CAP_FIX
) {
375 /* Mark the VGA RAM area as uncacheable */
376 native_write_msr(MTRR_FIX_16K_A0000_MSR
,
377 MTRR_FIX_TYPE(MTRR_TYPE_UNCACHEABLE
),
378 MTRR_FIX_TYPE(MTRR_TYPE_UNCACHEABLE
));
381 * Mark the PCI ROM area as cacheable to improve ROM
382 * execution performance.
384 native_write_msr(MTRR_FIX_4K_C0000_MSR
,
385 MTRR_FIX_TYPE(MTRR_TYPE_WRBACK
),
386 MTRR_FIX_TYPE(MTRR_TYPE_WRBACK
));
387 native_write_msr(MTRR_FIX_4K_C8000_MSR
,
388 MTRR_FIX_TYPE(MTRR_TYPE_WRBACK
),
389 MTRR_FIX_TYPE(MTRR_TYPE_WRBACK
));
390 native_write_msr(MTRR_FIX_4K_D0000_MSR
,
391 MTRR_FIX_TYPE(MTRR_TYPE_WRBACK
),
392 MTRR_FIX_TYPE(MTRR_TYPE_WRBACK
));
393 native_write_msr(MTRR_FIX_4K_D8000_MSR
,
394 MTRR_FIX_TYPE(MTRR_TYPE_WRBACK
),
395 MTRR_FIX_TYPE(MTRR_TYPE_WRBACK
));
397 /* Enable the fixed range MTRRs */
398 msr_setbits_64(MTRR_DEF_TYPE_MSR
, MTRR_DEF_TYPE_FIX_EN
);
402 #ifdef CONFIG_I8254_TIMER
403 /* Set up the i8254 timer if required */
410 void x86_enable_caches(void)
415 cr0
&= ~(X86_CR0_NW
| X86_CR0_CD
);
419 void enable_caches(void) __attribute__((weak
, alias("x86_enable_caches")));
421 void x86_disable_caches(void)
426 cr0
|= X86_CR0_NW
| X86_CR0_CD
;
431 void disable_caches(void) __attribute__((weak
, alias("x86_disable_caches")));
433 int x86_init_cache(void)
439 int init_cache(void) __attribute__((weak
, alias("x86_init_cache")));
441 int do_reset(cmd_tbl_t
*cmdtp
, int flag
, int argc
, char * const argv
[])
443 printf("resetting ...\n");
447 disable_interrupts();
454 void flush_cache(unsigned long dummy1
, unsigned long dummy2
)
459 __weak
void reset_cpu(ulong addr
)
461 /* Do a hard reset through the chipset's reset control register */
462 outb(SYS_RST
| RST_CPU
, PORT_RESET
);
467 void x86_full_reset(void)
469 outb(FULL_RST
| SYS_RST
| RST_CPU
, PORT_RESET
);
472 int dcache_status(void)
474 return !(read_cr0() & X86_CR0_CD
);
477 /* Define these functions to allow ehch-hcd to function */
478 void flush_dcache_range(unsigned long start
, unsigned long stop
)
482 void invalidate_dcache_range(unsigned long start
, unsigned long stop
)
486 void dcache_enable(void)
491 void dcache_disable(void)
496 void icache_enable(void)
500 void icache_disable(void)
504 int icache_status(void)
509 void cpu_enable_paging_pae(ulong cr3
)
511 __asm__
__volatile__(
512 /* Load the page table address */
515 "movl %%cr4, %%eax\n"
516 "orl $0x00000020, %%eax\n"
517 "movl %%eax, %%cr4\n"
519 "movl %%cr0, %%eax\n"
520 "orl $0x80000000, %%eax\n"
521 "movl %%eax, %%cr0\n"
527 void cpu_disable_paging_pae(void)
529 /* Turn off paging */
530 __asm__
__volatile__ (
532 "movl %%cr0, %%eax\n"
533 "andl $0x7fffffff, %%eax\n"
534 "movl %%eax, %%cr0\n"
536 "movl %%cr4, %%eax\n"
537 "andl $0xffffffdf, %%eax\n"
538 "movl %%eax, %%cr4\n"
544 static bool can_detect_long_mode(void)
546 return cpuid_eax(0x80000000) > 0x80000000UL
;
549 static bool has_long_mode(void)
551 return cpuid_edx(0x80000001) & (1 << 29) ? true : false;
554 int cpu_has_64bit(void)
556 return has_cpuid() && can_detect_long_mode() &&
560 const char *cpu_vendor_name(int vendor
)
563 name
= "<invalid cpu vendor>";
564 if ((vendor
< (ARRAY_SIZE(x86_vendor_name
))) &&
565 (x86_vendor_name
[vendor
] != 0))
566 name
= x86_vendor_name
[vendor
];
571 char *cpu_get_name(char *name
)
573 unsigned int *name_as_ints
= (unsigned int *)name
;
574 struct cpuid_result regs
;
578 /* This bit adds up to 48 bytes */
579 for (i
= 0; i
< 3; i
++) {
580 regs
= cpuid(0x80000002 + i
);
581 name_as_ints
[i
* 4 + 0] = regs
.eax
;
582 name_as_ints
[i
* 4 + 1] = regs
.ebx
;
583 name_as_ints
[i
* 4 + 2] = regs
.ecx
;
584 name_as_ints
[i
* 4 + 3] = regs
.edx
;
586 name
[CPU_MAX_NAME_LEN
- 1] = '\0';
588 /* Skip leading spaces. */
596 int default_print_cpuinfo(void)
598 printf("CPU: %s, vendor %s, device %xh\n",
599 cpu_has_64bit() ? "x86_64" : "x86",
600 cpu_vendor_name(gd
->arch
.x86_vendor
), gd
->arch
.x86_device
);
605 #define PAGETABLE_SIZE (6 * 4096)
608 * build_pagetable() - build a flat 4GiB page table structure for 64-bti mode
610 * @pgtable: Pointer to a 24iKB block of memory
612 static void build_pagetable(uint32_t *pgtable
)
616 memset(pgtable
, '\0', PAGETABLE_SIZE
);
618 /* Level 4 needs a single entry */
619 pgtable
[0] = (uint32_t)&pgtable
[1024] + 7;
621 /* Level 3 has one 64-bit entry for each GiB of memory */
622 for (i
= 0; i
< 4; i
++) {
623 pgtable
[1024 + i
* 2] = (uint32_t)&pgtable
[2048] +
627 /* Level 2 has 2048 64-bit entries, each repesenting 2MiB */
628 for (i
= 0; i
< 2048; i
++)
629 pgtable
[2048 + i
* 2] = 0x183 + (i
<< 21UL);
632 int cpu_jump_to_64bit(ulong setup_base
, ulong target
)
636 pgtable
= memalign(4096, PAGETABLE_SIZE
);
640 build_pagetable(pgtable
);
641 cpu_call64((ulong
)pgtable
, setup_base
, target
);
647 void show_boot_progress(int val
)
649 outb(val
, POST_PORT
);
652 #ifndef CONFIG_SYS_COREBOOT
653 int last_stage_init(void)
662 static int enable_smis(struct udevice
*cpu
, void *unused
)
667 static struct mp_flight_record mp_steps
[] = {
668 MP_FR_BLOCK_APS(mp_init_cpu
, NULL
, mp_init_cpu
, NULL
),
669 /* Wait for APs to finish initialization before proceeding */
670 MP_FR_BLOCK_APS(NULL
, NULL
, enable_smis
, NULL
),
673 static int x86_mp_init(void)
675 struct mp_params mp_params
;
677 mp_params
.parallel_microcode_load
= 0,
678 mp_params
.flight_plan
= &mp_steps
[0];
679 mp_params
.num_records
= ARRAY_SIZE(mp_steps
);
680 mp_params
.microcode_pointer
= 0;
682 if (mp_init(&mp_params
)) {
683 printf("Warning: MP init failure\n");
691 __weak
int x86_init_cpus(void)
694 debug("Init additional CPUs\n");
700 * This causes the cpu-x86 driver to be probed.
701 * We don't check return value here as we want to allow boards
702 * which have not been converted to use cpu uclass driver to boot.
704 uclass_first_device(UCLASS_CPU
, &dev
);
713 return x86_init_cpus();