uboot/arch/x86/cpu/i386/cpu.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2008-2011
   4 * Graeme Russ, <graeme.russ@gmail.com>
   5 *
   6 * (C) Copyright 2002
   7 * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se>
   8 *
   9 * (C) Copyright 2002
  10 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
  11 * Marius Groeger <mgroeger@sysgo.de>
  12 *
  13 * (C) Copyright 2002
  14 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
  15 * Alex Zuepke <azu@sysgo.de>
  16 *
  17 * Part of this file is adapted from coreboot
  18 * src/arch/x86/lib/cpu.c
  19 */
  20
  21#include <common.h>
  22#include <malloc.h>
  23#include <asm/control_regs.h>
  24#include <asm/cpu.h>
  25#include <asm/mp.h>
  26#include <asm/msr.h>
  27#include <asm/mtrr.h>
  28#include <asm/processor-flags.h>
  29
  30DECLARE_GLOBAL_DATA_PTR;
  31
  32/*
  33 * Constructor for a conventional segment GDT (or LDT) entry
  34 * This is a macro so it can be used in initialisers
  35 */
  36#define GDT_ENTRY(flags, base, limit)                   \
  37        ((((base)  & 0xff000000ULL) << (56-24)) |       \
  38         (((flags) & 0x0000f0ffULL) << 40) |            \
  39         (((limit) & 0x000f0000ULL) << (48-16)) |       \
  40         (((base)  & 0x00ffffffULL) << 16) |            \
  41         (((limit) & 0x0000ffffULL)))
  42
  43struct gdt_ptr {
  44        u16 len;
  45        u32 ptr;
  46} __packed;
  47
  48struct cpu_device_id {
  49        unsigned vendor;
  50        unsigned device;
  51};
  52
  53struct cpuinfo_x86 {
  54        uint8_t x86;            /* CPU family */
  55        uint8_t x86_vendor;     /* CPU vendor */
  56        uint8_t x86_model;
  57        uint8_t x86_mask;
  58};
  59
  60/*
  61 * List of cpu vendor strings along with their normalized
  62 * id values.
  63 */
  64static const struct {
  65        int vendor;
  66        const char *name;
  67} x86_vendors[] = {
  68        { X86_VENDOR_INTEL,     "GenuineIntel", },
  69        { X86_VENDOR_CYRIX,     "CyrixInstead", },
  70        { X86_VENDOR_AMD,       "AuthenticAMD", },
  71        { X86_VENDOR_UMC,       "UMC UMC UMC ", },
  72        { X86_VENDOR_NEXGEN,    "NexGenDriven", },
  73        { X86_VENDOR_CENTAUR,   "CentaurHauls", },
  74        { X86_VENDOR_RISE,      "RiseRiseRise", },
  75        { X86_VENDOR_TRANSMETA, "GenuineTMx86", },
  76        { X86_VENDOR_TRANSMETA, "TransmetaCPU", },
  77        { X86_VENDOR_NSC,       "Geode by NSC", },
  78        { X86_VENDOR_SIS,       "SiS SiS SiS ", },
  79};
  80
  81static void load_ds(u32 segment)
  82{
  83        asm volatile("movl %0, %%ds" : : "r" (segment * X86_GDT_ENTRY_SIZE));
  84}
  85
  86static void load_es(u32 segment)
  87{
  88        asm volatile("movl %0, %%es" : : "r" (segment * X86_GDT_ENTRY_SIZE));
  89}
  90
  91static void load_fs(u32 segment)
  92{
  93        asm volatile("movl %0, %%fs" : : "r" (segment * X86_GDT_ENTRY_SIZE));
  94}
  95
  96static void load_gs(u32 segment)
  97{
  98        asm volatile("movl %0, %%gs" : : "r" (segment * X86_GDT_ENTRY_SIZE));
  99}
 100
 101static void load_ss(u32 segment)
 102{
 103        asm volatile("movl %0, %%ss" : : "r" (segment * X86_GDT_ENTRY_SIZE));
 104}
 105
 106static void load_gdt(const u64 *boot_gdt, u16 num_entries)
 107{
 108        struct gdt_ptr gdt;
 109
 110        gdt.len = (num_entries * X86_GDT_ENTRY_SIZE) - 1;
 111        gdt.ptr = (ulong)boot_gdt;
 112
 113        asm volatile("lgdtl %0\n" : : "m" (gdt));
 114}
 115
 116void arch_setup_gd(gd_t *new_gd)
 117{
 118        u64 *gdt_addr;
 119
 120        gdt_addr = new_gd->arch.gdt;
 121
 122        /*
 123         * CS: code, read/execute, 4 GB, base 0
 124         *
 125         * Some OS (like VxWorks) requires GDT entry 1 to be the 32-bit CS
 126         */
 127        gdt_addr[X86_GDT_ENTRY_UNUSED] = GDT_ENTRY(0xc09b, 0, 0xfffff);
 128        gdt_addr[X86_GDT_ENTRY_32BIT_CS] = GDT_ENTRY(0xc09b, 0, 0xfffff);
 129
 130        /* DS: data, read/write, 4 GB, base 0 */
 131        gdt_addr[X86_GDT_ENTRY_32BIT_DS] = GDT_ENTRY(0xc093, 0, 0xfffff);
 132
 133        /* FS: data, read/write, 4 GB, base (Global Data Pointer) */
 134        new_gd->arch.gd_addr = new_gd;
 135        gdt_addr[X86_GDT_ENTRY_32BIT_FS] = GDT_ENTRY(0xc093,
 136                     (ulong)&new_gd->arch.gd_addr, 0xfffff);
 137
 138        /* 16-bit CS: code, read/execute, 64 kB, base 0 */
 139        gdt_addr[X86_GDT_ENTRY_16BIT_CS] = GDT_ENTRY(0x009b, 0, 0x0ffff);
 140
 141        /* 16-bit DS: data, read/write, 64 kB, base 0 */
 142        gdt_addr[X86_GDT_ENTRY_16BIT_DS] = GDT_ENTRY(0x0093, 0, 0x0ffff);
 143
 144        gdt_addr[X86_GDT_ENTRY_16BIT_FLAT_CS] = GDT_ENTRY(0x809b, 0, 0xfffff);
 145        gdt_addr[X86_GDT_ENTRY_16BIT_FLAT_DS] = GDT_ENTRY(0x8093, 0, 0xfffff);
 146
 147        load_gdt(gdt_addr, X86_GDT_NUM_ENTRIES);
 148        load_ds(X86_GDT_ENTRY_32BIT_DS);
 149        load_es(X86_GDT_ENTRY_32BIT_DS);
 150        load_gs(X86_GDT_ENTRY_32BIT_DS);
 151        load_ss(X86_GDT_ENTRY_32BIT_DS);
 152        load_fs(X86_GDT_ENTRY_32BIT_FS);
 153}
 154
 155#ifdef CONFIG_HAVE_FSP
 156/*
 157 * Setup FSP execution environment GDT
 158 *
 159 * Per Intel FSP external architecture specification, before calling any FSP
 160 * APIs, we need make sure the system is in flat 32-bit mode and both the code
 161 * and data selectors should have full 4GB access range. Here we reuse the one
 162 * we used in arch/x86/cpu/start16.S, and reload the segement registers.
 163 */
 164void setup_fsp_gdt(void)
 165{
 166        load_gdt((const u64 *)(gdt_rom + CONFIG_RESET_SEG_START), 4);
 167        load_ds(X86_GDT_ENTRY_32BIT_DS);
 168        load_ss(X86_GDT_ENTRY_32BIT_DS);
 169        load_es(X86_GDT_ENTRY_32BIT_DS);
 170        load_fs(X86_GDT_ENTRY_32BIT_DS);
 171        load_gs(X86_GDT_ENTRY_32BIT_DS);
 172}
 173#endif
 174
 175/*
 176 * Cyrix CPUs without cpuid or with cpuid not yet enabled can be detected
 177 * by the fact that they preserve the flags across the division of 5/2.
 178 * PII and PPro exhibit this behavior too, but they have cpuid available.
 179 */
 180
 181/*
 182 * Perform the Cyrix 5/2 test. A Cyrix won't change
 183 * the flags, while other 486 chips will.
 184 */
 185static inline int test_cyrix_52div(void)
 186{
 187        unsigned int test;
 188
 189        __asm__ __volatile__(
 190             "sahf\n\t"         /* clear flags (%eax = 0x0005) */
 191             "div %b2\n\t"      /* divide 5 by 2 */
 192             "lahf"             /* store flags into %ah */
 193             : "=a" (test)
 194             : "0" (5), "q" (2)
 195             : "cc");
 196
 197        /* AH is 0x02 on Cyrix after the divide.. */
 198        return (unsigned char) (test >> 8) == 0x02;
 199}
 200
 201/*
 202 *      Detect a NexGen CPU running without BIOS hypercode new enough
 203 *      to have CPUID. (Thanks to Herbert Oppmann)
 204 */
 205static int deep_magic_nexgen_probe(void)
 206{
 207        int ret;
 208
 209        __asm__ __volatile__ (
 210                "       movw    $0x5555, %%ax\n"
 211                "       xorw    %%dx,%%dx\n"
 212                "       movw    $2, %%cx\n"
 213                "       divw    %%cx\n"
 214                "       movl    $0, %%eax\n"
 215                "       jnz     1f\n"
 216                "       movl    $1, %%eax\n"
 217                "1:\n"
 218                : "=a" (ret) : : "cx", "dx");
 219        return  ret;
 220}
 221
 222static bool has_cpuid(void)
 223{
 224        return flag_is_changeable_p(X86_EFLAGS_ID);
 225}
 226
 227static bool has_mtrr(void)
 228{
 229        return cpuid_edx(0x00000001) & (1 << 12) ? true : false;
 230}
 231
 232static int build_vendor_name(char *vendor_name)
 233{
 234        struct cpuid_result result;
 235        result = cpuid(0x00000000);
 236        unsigned int *name_as_ints = (unsigned int *)vendor_name;
 237
 238        name_as_ints[0] = result.ebx;
 239        name_as_ints[1] = result.edx;
 240        name_as_ints[2] = result.ecx;
 241
 242        return result.eax;
 243}
 244
 245static void identify_cpu(struct cpu_device_id *cpu)
 246{
 247        char vendor_name[16];
 248        int i;
 249
 250        vendor_name[0] = '\0'; /* Unset */
 251        cpu->device = 0; /* fix gcc 4.4.4 warning */
 252
 253        /* Find the id and vendor_name */
 254        if (!has_cpuid()) {
 255                /* Its a 486 if we can modify the AC flag */
 256                if (flag_is_changeable_p(X86_EFLAGS_AC))
 257                        cpu->device = 0x00000400; /* 486 */
 258                else
 259                        cpu->device = 0x00000300; /* 386 */
 260                if ((cpu->device == 0x00000400) && test_cyrix_52div()) {
 261                        memcpy(vendor_name, "CyrixInstead", 13);
 262                        /* If we ever care we can enable cpuid here */
 263                }
 264                /* Detect NexGen with old hypercode */
 265                else if (deep_magic_nexgen_probe())
 266                        memcpy(vendor_name, "NexGenDriven", 13);
 267        }
 268        if (has_cpuid()) {
 269                int  cpuid_level;
 270
 271                cpuid_level = build_vendor_name(vendor_name);
 272                vendor_name[12] = '\0';
 273
 274                /* Intel-defined flags: level 0x00000001 */
 275                if (cpuid_level >= 0x00000001) {
 276                        cpu->device = cpuid_eax(0x00000001);
 277                } else {
 278                        /* Have CPUID level 0 only unheard of */
 279                        cpu->device = 0x00000400;
 280                }
 281        }
 282        cpu->vendor = X86_VENDOR_UNKNOWN;
 283        for (i = 0; i < ARRAY_SIZE(x86_vendors); i++) {
 284                if (memcmp(vendor_name, x86_vendors[i].name, 12) == 0) {
 285                        cpu->vendor = x86_vendors[i].vendor;
 286                        break;
 287                }
 288        }
 289}
 290
 291static inline void get_fms(struct cpuinfo_x86 *c, uint32_t tfms)
 292{
 293        c->x86 = (tfms >> 8) & 0xf;
 294        c->x86_model = (tfms >> 4) & 0xf;
 295        c->x86_mask = tfms & 0xf;
 296        if (c->x86 == 0xf)
 297                c->x86 += (tfms >> 20) & 0xff;
 298        if (c->x86 >= 0x6)
 299                c->x86_model += ((tfms >> 16) & 0xF) << 4;
 300}
 301
 302u32 cpu_get_family_model(void)
 303{
 304        return gd->arch.x86_device & 0x0fff0ff0;
 305}
 306
 307u32 cpu_get_stepping(void)
 308{
 309        return gd->arch.x86_mask;
 310}
 311
 312/* initialise FPU, reset EM, set MP and NE */
 313static void setup_cpu_features(void)
 314{
 315        const u32 em_rst = ~X86_CR0_EM;
 316        const u32 mp_ne_set = X86_CR0_MP | X86_CR0_NE;
 317
 318        asm ("fninit\n" \
 319        "movl %%cr0, %%eax\n" \
 320        "andl %0, %%eax\n" \
 321        "orl  %1, %%eax\n" \
 322        "movl %%eax, %%cr0\n" \
 323        : : "i" (em_rst), "i" (mp_ne_set) : "eax");
 324}
 325
 326static void setup_identity(void)
 327{
 328        /* identify CPU via cpuid and store the decoded info into gd->arch */
 329        if (has_cpuid()) {
 330                struct cpu_device_id cpu;
 331                struct cpuinfo_x86 c;
 332
 333                identify_cpu(&cpu);
 334                get_fms(&c, cpu.device);
 335                gd->arch.x86 = c.x86;
 336                gd->arch.x86_vendor = cpu.vendor;
 337                gd->arch.x86_model = c.x86_model;
 338                gd->arch.x86_mask = c.x86_mask;
 339                gd->arch.x86_device = cpu.device;
 340
 341                gd->arch.has_mtrr = has_mtrr();
 342        }
 343}
 344
 345/* Don't allow PCI region 3 to use memory in the 2-4GB memory hole */
 346static void setup_pci_ram_top(void)
 347{
 348        gd->pci_ram_top = 0x80000000U;
 349}
 350
 351static void setup_mtrr(void)
 352{
 353        u64 mtrr_cap;
 354
 355        /* Configure fixed range MTRRs for some legacy regions */
 356        if (!gd->arch.has_mtrr)
 357                return;
 358
 359        mtrr_cap = native_read_msr(MTRR_CAP_MSR);
 360        if (mtrr_cap & MTRR_CAP_FIX) {
 361                /* Mark the VGA RAM area as uncacheable */
 362                native_write_msr(MTRR_FIX_16K_A0000_MSR,
 363                                 MTRR_FIX_TYPE(MTRR_TYPE_UNCACHEABLE),
 364                                 MTRR_FIX_TYPE(MTRR_TYPE_UNCACHEABLE));
 365
 366                /*
 367                 * Mark the PCI ROM area as cacheable to improve ROM
 368                 * execution performance.
 369                 */
 370                native_write_msr(MTRR_FIX_4K_C0000_MSR,
 371                                 MTRR_FIX_TYPE(MTRR_TYPE_WRBACK),
 372                                 MTRR_FIX_TYPE(MTRR_TYPE_WRBACK));
 373                native_write_msr(MTRR_FIX_4K_C8000_MSR,
 374                                 MTRR_FIX_TYPE(MTRR_TYPE_WRBACK),
 375                                 MTRR_FIX_TYPE(MTRR_TYPE_WRBACK));
 376                native_write_msr(MTRR_FIX_4K_D0000_MSR,
 377                                 MTRR_FIX_TYPE(MTRR_TYPE_WRBACK),
 378                                 MTRR_FIX_TYPE(MTRR_TYPE_WRBACK));
 379                native_write_msr(MTRR_FIX_4K_D8000_MSR,
 380                                 MTRR_FIX_TYPE(MTRR_TYPE_WRBACK),
 381                                 MTRR_FIX_TYPE(MTRR_TYPE_WRBACK));
 382
 383                /* Enable the fixed range MTRRs */
 384                msr_setbits_64(MTRR_DEF_TYPE_MSR, MTRR_DEF_TYPE_FIX_EN);
 385        }
 386}
 387
 388int x86_cpu_init_f(void)
 389{
 390        if (ll_boot_init())
 391                setup_cpu_features();
 392        setup_identity();
 393        setup_mtrr();
 394        setup_pci_ram_top();
 395
 396        /* Set up the i8254 timer if required */
 397        if (IS_ENABLED(CONFIG_I8254_TIMER))
 398                i8254_init();
 399
 400        return 0;
 401}
 402
 403int x86_cpu_reinit_f(void)
 404{
 405        setup_identity();
 406        setup_pci_ram_top();
 407
 408        return 0;
 409}
 410
 411void x86_enable_caches(void)
 412{
 413        unsigned long cr0;
 414
 415        cr0 = read_cr0();
 416        cr0 &= ~(X86_CR0_NW | X86_CR0_CD);
 417        write_cr0(cr0);
 418        wbinvd();
 419}
 420void enable_caches(void) __attribute__((weak, alias("x86_enable_caches")));
 421
 422void x86_disable_caches(void)
 423{
 424        unsigned long cr0;
 425
 426        cr0 = read_cr0();
 427        cr0 |= X86_CR0_NW | X86_CR0_CD;
 428        wbinvd();
 429        write_cr0(cr0);
 430        wbinvd();
 431}
 432void disable_caches(void) __attribute__((weak, alias("x86_disable_caches")));
 433
 434int dcache_status(void)
 435{
 436        return !(read_cr0() & X86_CR0_CD);
 437}
 438
 439void cpu_enable_paging_pae(ulong cr3)
 440{
 441        __asm__ __volatile__(
 442                /* Load the page table address */
 443                "movl   %0, %%cr3\n"
 444                /* Enable pae */
 445                "movl   %%cr4, %%eax\n"
 446                "orl    $0x00000020, %%eax\n"
 447                "movl   %%eax, %%cr4\n"
 448                /* Enable paging */
 449                "movl   %%cr0, %%eax\n"
 450                "orl    $0x80000000, %%eax\n"
 451                "movl   %%eax, %%cr0\n"
 452                :
 453                : "r" (cr3)
 454                : "eax");
 455}
 456
 457void cpu_disable_paging_pae(void)
 458{
 459        /* Turn off paging */
 460        __asm__ __volatile__ (
 461                /* Disable paging */
 462                "movl   %%cr0, %%eax\n"
 463                "andl   $0x7fffffff, %%eax\n"
 464                "movl   %%eax, %%cr0\n"
 465                /* Disable pae */
 466                "movl   %%cr4, %%eax\n"
 467                "andl   $0xffffffdf, %%eax\n"
 468                "movl   %%eax, %%cr4\n"
 469                :
 470                :
 471                : "eax");
 472}
 473
 474static bool can_detect_long_mode(void)
 475{
 476        return cpuid_eax(0x80000000) > 0x80000000UL;
 477}
 478
 479static bool has_long_mode(void)
 480{
 481        return cpuid_edx(0x80000001) & (1 << 29) ? true : false;
 482}
 483
 484int cpu_has_64bit(void)
 485{
 486        return has_cpuid() && can_detect_long_mode() &&
 487                has_long_mode();
 488}
 489
 490#define PAGETABLE_BASE          0x80000
 491#define PAGETABLE_SIZE          (6 * 4096)
 492
 493/**
 494 * build_pagetable() - build a flat 4GiB page table structure for 64-bti mode
 495 *
 496 * @pgtable: Pointer to a 24iKB block of memory
 497 */
 498static void build_pagetable(uint32_t *pgtable)
 499{
 500        uint i;
 501
 502        memset(pgtable, '\0', PAGETABLE_SIZE);
 503
 504        /* Level 4 needs a single entry */
 505        pgtable[0] = (ulong)&pgtable[1024] + 7;
 506
 507        /* Level 3 has one 64-bit entry for each GiB of memory */
 508        for (i = 0; i < 4; i++)
 509                pgtable[1024 + i * 2] = (ulong)&pgtable[2048] + 0x1000 * i + 7;
 510
 511        /* Level 2 has 2048 64-bit entries, each repesenting 2MiB */
 512        for (i = 0; i < 2048; i++)
 513                pgtable[2048 + i * 2] = 0x183 + (i << 21UL);
 514}
 515
 516int cpu_jump_to_64bit(ulong setup_base, ulong target)
 517{
 518        uint32_t *pgtable;
 519
 520        pgtable = memalign(4096, PAGETABLE_SIZE);
 521        if (!pgtable)
 522                return -ENOMEM;
 523
 524        build_pagetable(pgtable);
 525        cpu_call64((ulong)pgtable, setup_base, target);
 526        free(pgtable);
 527
 528        return -EFAULT;
 529}
 530
 531/*
 532 * Jump from SPL to U-Boot
 533 *
 534 * This function is work-in-progress with many issues to resolve.
 535 *
 536 * It works by setting up several regions:
 537 *   ptr      - a place to put the code that jumps into 64-bit mode
 538 *   gdt      - a place to put the global descriptor table
 539 *   pgtable  - a place to put the page tables
 540 *
 541 * The cpu_call64() code is copied from ROM and then manually patched so that
 542 * it has the correct GDT address in RAM. U-Boot is copied from ROM into
 543 * its pre-relocation address. Then we jump to the cpu_call64() code in RAM,
 544 * which changes to 64-bit mode and starts U-Boot.
 545 */
 546int cpu_jump_to_64bit_uboot(ulong target)
 547{
 548        typedef void (*func_t)(ulong pgtable, ulong setup_base, ulong target);
 549        uint32_t *pgtable;
 550        func_t func;
 551        char *ptr;
 552
 553        pgtable = (uint32_t *)PAGETABLE_BASE;
 554
 555        build_pagetable(pgtable);
 556
 557        extern long call64_stub_size;
 558        ptr = malloc(call64_stub_size);
 559        if (!ptr) {
 560                printf("Failed to allocate the cpu_call64 stub\n");
 561                return -ENOMEM;
 562        }
 563        memcpy(ptr, cpu_call64, call64_stub_size);
 564
 565        func = (func_t)ptr;
 566
 567        /*
 568         * Copy U-Boot from ROM
 569         * TODO(sjg@chromium.org): Figure out a way to get the text base
 570         * correctly here, and in the device-tree binman definition.
 571         *
 572         * Also consider using FIT so we get the correct image length and
 573         * parameters.
 574         */
 575        memcpy((char *)target, (char *)0xfff00000, 0x100000);
 576
 577        /* Jump to U-Boot */
 578        func((ulong)pgtable, 0, (ulong)target);
 579
 580        return -EFAULT;
 581}
 582
 583#ifdef CONFIG_SMP
 584static int enable_smis(struct udevice *cpu, void *unused)
 585{
 586        return 0;
 587}
 588
 589static struct mp_flight_record mp_steps[] = {
 590        MP_FR_BLOCK_APS(mp_init_cpu, NULL, mp_init_cpu, NULL),
 591        /* Wait for APs to finish initialization before proceeding */
 592        MP_FR_BLOCK_APS(NULL, NULL, enable_smis, NULL),
 593};
 594
 595int x86_mp_init(void)
 596{
 597        struct mp_params mp_params;
 598
 599        mp_params.parallel_microcode_load = 0,
 600        mp_params.flight_plan = &mp_steps[0];
 601        mp_params.num_records = ARRAY_SIZE(mp_steps);
 602        mp_params.microcode_pointer = 0;
 603
 604        if (mp_init(&mp_params)) {
 605                printf("Warning: MP init failure\n");
 606                return -EIO;
 607        }
 608
 609        return 0;
 610}
 611#endif
 612