diff options
Diffstat (limited to 'arch/x86/cpu')
-rw-r--r-- | arch/x86/cpu/coreboot/Kconfig | 2 | ||||
-rw-r--r-- | arch/x86/cpu/coreboot/coreboot.c | 2 | ||||
-rw-r--r-- | arch/x86/cpu/cpu.c | 24 | ||||
-rw-r--r-- | arch/x86/cpu/i386/call64.S | 37 | ||||
-rw-r--r-- | arch/x86/cpu/i386/cpu.c | 41 | ||||
-rw-r--r-- | arch/x86/cpu/mtrr.c | 115 | ||||
-rw-r--r-- | arch/x86/cpu/qemu/dram.c | 18 | ||||
-rw-r--r-- | arch/x86/cpu/qemu/e820.c | 62 | ||||
-rw-r--r-- | arch/x86/cpu/qemu/qemu.c | 20 | ||||
-rw-r--r-- | arch/x86/cpu/start.S | 4 | ||||
-rw-r--r-- | arch/x86/cpu/start16.S | 3 | ||||
-rw-r--r-- | arch/x86/cpu/x86_64/cpu.c | 5 |
12 files changed, 208 insertions, 125 deletions
diff --git a/arch/x86/cpu/coreboot/Kconfig b/arch/x86/cpu/coreboot/Kconfig index 085302c0482..66f25533b97 100644 --- a/arch/x86/cpu/coreboot/Kconfig +++ b/arch/x86/cpu/coreboot/Kconfig @@ -26,7 +26,7 @@ config SYS_COREBOOT imply CBMEM_CONSOLE imply X86_TSC_READ_BASE imply USE_PREBOOT - select BINMAN if X86_64 + select BINMAN if X86_RUN_64BIT select SYSINFO imply SYSINFO_EXTRA diff --git a/arch/x86/cpu/coreboot/coreboot.c b/arch/x86/cpu/coreboot/coreboot.c index fa7430b436f..d0719d1a405 100644 --- a/arch/x86/cpu/coreboot/coreboot.c +++ b/arch/x86/cpu/coreboot/coreboot.c @@ -22,7 +22,7 @@ int arch_cpu_init(void) { int ret; - ret = IS_ENABLED(CONFIG_X86_RUN_64BIT) ? x86_cpu_reinit_f() : + ret = IS_ENABLED(CONFIG_X86_64) ? x86_cpu_reinit_f() : x86_cpu_init_f(); if (ret) return ret; diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index a8b21406ac0..c373b14df30 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -364,3 +364,27 @@ long locate_coreboot_table(void) return addr; } + +static bool has_cpuid(void) +{ + return flag_is_changeable_p(X86_EFLAGS_ID); +} + +static uint cpu_cpuid_extended_level(void) +{ + return cpuid_eax(0x80000000); +} + +int cpu_phys_address_size(void) +{ + if (!has_cpuid()) + return 32; + + if (cpu_cpuid_extended_level() >= 0x80000008) + return cpuid_eax(0x80000008) & 0xff; + + if (cpuid_edx(1) & (CPUID_FEATURE_PAE | CPUID_FEATURE_PSE36)) + return 36; + + return 32; +} diff --git a/arch/x86/cpu/i386/call64.S b/arch/x86/cpu/i386/call64.S index d81bcc6f8f4..a9d3f16a6ad 100644 --- a/arch/x86/cpu/i386/call64.S +++ b/arch/x86/cpu/i386/call64.S @@ -7,10 +7,11 @@ */ #include <asm/msr-index.h> +#include <asm/processor.h> #include <asm/processor-flags.h> .code32 -.section .text_call64 +.section .text_call64, "ax" .globl cpu_call64 cpu_call64: /* @@ -21,17 +22,19 @@ cpu_call64: * ecx - target */ cli + pushl $0 /* top 64-bits of target */ push %ecx /* arg2 = target */ push %edx /* arg1 = setup_base */ mov %eax, %ebx - /* Load new GDT with the 64bit segments using 32bit descriptor */ - leal gdt, %eax - movl %eax, gdt+2 - lgdt gdt + # disable paging + movl %cr0, %eax + andl $~X86_CR0_PG, %eax + movl %eax, %cr0 /* Enable PAE mode */ - movl $(X86_CR4_PAE), %eax + movl %cr4, %eax + orl $X86_CR4_PAE, %eax movl %eax, %cr4 /* Enable the boot page tables */ @@ -44,12 +47,6 @@ cpu_call64: btsl $_EFER_LME, %eax wrmsr - /* After gdt is loaded */ - xorl %eax, %eax - lldt %ax - movl $0x20, %eax - ltr %ax - /* * Setup for the jump to 64bit mode * @@ -62,22 +59,18 @@ cpu_call64: */ pop %esi /* setup_base */ - pushl $0x10 - leal lret_target, %eax - pushl %eax - /* Enter paged protected Mode, activating Long Mode */ - movl $(X86_CR0_PG | X86_CR0_PE), %eax + movl %cr0, %eax + orl $X86_CR0_PG, %eax movl %eax, %cr0 /* Jump from 32bit compatibility mode into 64bit mode. */ - lret + ljmp $(X86_GDT_ENTRY_64BIT_CS * X86_GDT_ENTRY_SIZE), $lret_target -code64: +.code64 lret_target: - pop %eax /* target */ - mov %eax, %eax /* Clear bits 63:32 */ - jmp *%eax /* Jump to the 64-bit target */ + pop %rax /* target */ + jmp *%rax /* Jump to the 64-bit target */ .globl call64_stub_size call64_stub_size: diff --git a/arch/x86/cpu/i386/cpu.c b/arch/x86/cpu/i386/cpu.c index a51a24498a7..ee6dbeb5c48 100644 --- a/arch/x86/cpu/i386/cpu.c +++ b/arch/x86/cpu/i386/cpu.c @@ -35,10 +35,6 @@ DECLARE_GLOBAL_DATA_PTR; -#define CPUID_FEATURE_PAE BIT(6) -#define CPUID_FEATURE_PSE36 BIT(17) -#define CPUID_FEAURE_HTT BIT(28) - /* * Constructor for a conventional segment GDT (or LDT) entry * This is a macro so it can be used in initialisers @@ -160,6 +156,9 @@ void arch_setup_gd(gd_t *new_gd) gdt_addr[X86_GDT_ENTRY_16BIT_FLAT_CS] = GDT_ENTRY(0x809b, 0, 0xfffff); gdt_addr[X86_GDT_ENTRY_16BIT_FLAT_DS] = GDT_ENTRY(0x8093, 0, 0xfffff); + gdt_addr[X86_GDT_ENTRY_64BIT_CS] = GDT_ENTRY(0xaf9b, 0, 0xfffff); + gdt_addr[X86_GDT_ENTRY_64BIT_TS1] = GDT_ENTRY(0x8980, 0, 0xfffff); + gdt_addr[X86_GDT_ENTRY_64BIT_TS2] = 0; load_gdt(gdt_addr, X86_GDT_NUM_ENTRIES); load_ds(X86_GDT_ENTRY_32BIT_DS); @@ -409,25 +408,6 @@ static void setup_identity(void) } } -static uint cpu_cpuid_extended_level(void) -{ - return cpuid_eax(0x80000000); -} - -int cpu_phys_address_size(void) -{ - if (!has_cpuid()) - return 32; - - if (cpu_cpuid_extended_level() >= 0x80000008) - return cpuid_eax(0x80000008) & 0xff; - - if (cpuid_edx(1) & (CPUID_FEATURE_PAE | CPUID_FEATURE_PSE36)) - return 36; - - return 32; -} - static void setup_mtrr(void) { u64 mtrr_cap; @@ -589,6 +569,13 @@ int cpu_has_64bit(void) #define PAGETABLE_BASE 0x80000 #define PAGETABLE_SIZE (6 * 4096) +#define _PRES BIT(0) /* present */ +#define _RW BIT(1) /* write allowed */ +#define _US BIT(2) /* user-access allowed */ +#define _A BIT(5) /* has been accessed */ +#define _DT BIT(6) /* has been written to */ +#define _PS BIT(7) /* indicates 2MB page size here */ + /** * build_pagetable() - build a flat 4GiB page table structure for 64-bti mode * @@ -601,15 +588,17 @@ static void build_pagetable(uint32_t *pgtable) memset(pgtable, '\0', PAGETABLE_SIZE); /* Level 4 needs a single entry */ - pgtable[0] = (ulong)&pgtable[1024] + 7; + pgtable[0] = (ulong)&pgtable[1024] + _PRES + _RW + _US + _A; /* Level 3 has one 64-bit entry for each GiB of memory */ for (i = 0; i < 4; i++) - pgtable[1024 + i * 2] = (ulong)&pgtable[2048] + 0x1000 * i + 7; + pgtable[1024 + i * 2] = (ulong)&pgtable[2048] + 0x1000 * i + + _PRES + _RW + _US + _A; /* Level 2 has 2048 64-bit entries, each repesenting 2MiB */ for (i = 0; i < 2048; i++) - pgtable[2048 + i * 2] = 0x183 + (i << 21UL); + pgtable[2048 + i * 2] = _PRES + _RW + _US + _PS + _A + _DT + + (i << 21UL); } int cpu_jump_to_64bit(ulong setup_base, ulong target) diff --git a/arch/x86/cpu/mtrr.c b/arch/x86/cpu/mtrr.c index 07ea89162de..7a0f00b9b8f 100644 --- a/arch/x86/cpu/mtrr.c +++ b/arch/x86/cpu/mtrr.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ /* * (C) Copyright 2014 Google, Inc + * Portions added from coreboot * * Memory Type Range Regsters - these are used to tell the CPU whether * memory is cacheable and if so the cache write mode to use. @@ -16,6 +17,7 @@ * since the MTRR registers are sometimes in flux. */ +#include <cpu.h> #include <cpu_func.h> #include <log.h> #include <sort.h> @@ -39,6 +41,27 @@ static const char *const mtrr_type_name[MTRR_TYPE_COUNT] = { "Back", }; +u64 mtrr_to_size(u64 mask) +{ + u64 size; + + size = ~mask & ((1ULL << cpu_phys_address_size()) - 1); + size |= (1 << 12) - 1; + size += 1; + + return size; +} + +u64 mtrr_to_mask(u64 size) +{ + u64 mask; + + mask = ~(size - 1); + mask &= (1ull << cpu_phys_address_size()) - 1; + + return mask; +} + /* Prepare to adjust MTRRs */ void mtrr_open(struct mtrr_state *state, bool do_caches) { @@ -68,11 +91,9 @@ void mtrr_close(struct mtrr_state *state, bool do_caches) static void set_var_mtrr(uint reg, uint type, uint64_t start, uint64_t size) { - u64 mask; + u64 mask = mtrr_to_mask(size); wrmsrl(MTRR_PHYS_BASE_MSR(reg), start | type); - mask = ~(size - 1); - mask &= (1ULL << CONFIG_CPU_ADDR_BITS) - 1; wrmsrl(MTRR_PHYS_MASK_MSR(reg), mask | MTRR_PHYS_MASK_VALID); } @@ -184,30 +205,80 @@ int mtrr_commit(bool do_caches) return 0; } -int mtrr_add_request(int type, uint64_t start, uint64_t size) +/* fms: find most significant bit set (from Linux) */ +static inline uint fms(uint val) +{ + uint ret; + + __asm__("bsrl %1,%0\n\t" + "jnz 1f\n\t" + "movl $0,%0\n" + "1:" : "=r" (ret) : "mr" (val)); + + return ret; +} + +/* + * fms64: find most significant bit set in a 64-bit word + * As samples, fms64(0x0) = 0; fms64(0x4400) = 14; + * fms64(0x40400000000) = 42. + */ +static uint fms64(uint64_t val) +{ + u32 hi = (u32)(val >> 32); + + if (!hi) + return fms((u32)val); + + return fms(hi) + 32; +} + +int mtrr_add_request(int type, u64 base, uint64_t size) { struct mtrr_request *req; - uint64_t mask; + u64 mask; debug("%s: count=%d\n", __func__, gd->arch.mtrr_req_count); if (!gd->arch.has_mtrr) return -ENOSYS; - if (!is_power_of_2(size)) - return -EINVAL; - - if (gd->arch.mtrr_req_count == MAX_MTRR_REQUESTS) - return -ENOSPC; - req = &gd->arch.mtrr_req[gd->arch.mtrr_req_count++]; - req->type = type; - req->start = start; - req->size = size; - debug("%d: type=%d, %08llx %08llx\n", gd->arch.mtrr_req_count - 1, - req->type, req->start, req->size); - mask = ~(req->size - 1); - mask &= (1ULL << CONFIG_CPU_ADDR_BITS) - 1; - mask |= MTRR_PHYS_MASK_VALID; - debug(" %016llx %016llx\n", req->start | req->type, mask); + while (size) { + uint addr_lsb; + uint size_msb; + u64 mtrr_size; + + addr_lsb = fls64(base); + size_msb = fms64(size); + + /* + * All MTRR entries need to have their base aligned to the + * mask size. The maximum size is calculated by a function of + * the min base bit set and maximum size bit set. + * Algorithm is from coreboot + */ + if (!addr_lsb || addr_lsb > size_msb) + mtrr_size = 1ull << size_msb; + else + mtrr_size = 1ull << addr_lsb; + log_debug("addr_lsb %x size_msb %x mtrr_size %llx\n", + addr_lsb, size_msb, mtrr_size); + + if (gd->arch.mtrr_req_count == MAX_MTRR_REQUESTS) + return -ENOSPC; + req = &gd->arch.mtrr_req[gd->arch.mtrr_req_count++]; + req->type = type; + req->start = base; + req->size = mtrr_size; + log_debug("%d: type=%d, %08llx %08llx ", + gd->arch.mtrr_req_count - 1, req->type, req->start, + req->size); + mask = mtrr_to_mask(req->size); + mask |= MTRR_PHYS_MASK_VALID; + log_debug(" %016llx %016llx\n", req->start | req->type, mask); + + size -= mtrr_size; + base += mtrr_size; + } return 0; } @@ -360,9 +431,7 @@ int mtrr_list(int reg_count, int cpu_select) base = info.mtrr[i].base; mask = info.mtrr[i].mask; - size = ~mask & ((1ULL << CONFIG_CPU_ADDR_BITS) - 1); - size |= (1 << 12) - 1; - size += 1; + size = mtrr_to_size(mask); valid = mask & MTRR_PHYS_MASK_VALID; type = mtrr_type_name[base & MTRR_BASE_TYPE_MASK]; printf("%d %-5s %-12s %016llx %016llx %016llx\n", i, diff --git a/arch/x86/cpu/qemu/dram.c b/arch/x86/cpu/qemu/dram.c index 62a301c0fd3..ba3638e6acc 100644 --- a/arch/x86/cpu/qemu/dram.c +++ b/arch/x86/cpu/qemu/dram.c @@ -4,7 +4,9 @@ */ #include <init.h> +#include <spl.h> #include <asm/global_data.h> +#include <asm/mtrr.h> #include <asm/post.h> #include <asm/arch/qemu.h> #include <linux/sizes.h> @@ -44,6 +46,22 @@ int dram_init(void) gd->ram_size += qemu_get_high_memory_size(); post_code(POST_DRAM); + if (xpl_phase() == PHASE_BOARD_F) { + u64 total = gd->ram_size; + int ret; + + if (total > SZ_2G + SZ_1G) + total += SZ_1G; + ret = mtrr_add_request(MTRR_TYPE_WRBACK, 0, total); + if (ret != -ENOSYS) { + if (ret) + return log_msg_ret("mta", ret); + ret = mtrr_commit(false); + if (ret) + return log_msg_ret("mtc", ret); + } + } + return 0; } diff --git a/arch/x86/cpu/qemu/e820.c b/arch/x86/cpu/qemu/e820.c index 17a04f86479..078d1d86b02 100644 --- a/arch/x86/cpu/qemu/e820.c +++ b/arch/x86/cpu/qemu/e820.c @@ -6,6 +6,7 @@ * (C) Copyright 2019 Bin Meng <bmeng.cn@gmail.com> */ +#include <bloblist.h> #include <env_internal.h> #include <malloc.h> #include <asm/e820.h> @@ -19,51 +20,34 @@ unsigned int install_e820_map(unsigned int max_entries, struct e820_entry *entries) { u64 high_mem_size; - int n = 0; + struct e820_ctx ctx; - entries[n].addr = 0; - entries[n].size = ISA_START_ADDRESS; - entries[n].type = E820_RAM; - n++; + e820_init(&ctx, entries, max_entries); - entries[n].addr = ISA_START_ADDRESS; - entries[n].size = ISA_END_ADDRESS - ISA_START_ADDRESS; - entries[n].type = E820_RESERVED; - n++; + e820_next(&ctx, E820_RAM, ISA_START_ADDRESS); + e820_next(&ctx, E820_RESERVED, ISA_END_ADDRESS); /* - * since we use memalign(malloc) to allocate high memory for - * storing ACPI tables, we need to reserve them in e820 tables, - * otherwise kernel will reclaim them and data will be corrupted + * if we use bloblist to allocate high memory for storing ACPI tables, + * we need to reserve that region in e820 tables, otherwise the kernel + * will reclaim them and data will be corrupted. The ACPI tables may not + * have been written yet, so use the whole bloblist size */ - entries[n].addr = ISA_END_ADDRESS; - entries[n].size = gd->relocaddr - TOTAL_MALLOC_LEN - ISA_END_ADDRESS; - entries[n].type = E820_RAM; - n++; - - /* for simplicity, reserve entire malloc space */ - entries[n].addr = gd->relocaddr - TOTAL_MALLOC_LEN; - entries[n].size = TOTAL_MALLOC_LEN; - entries[n].type = E820_RESERVED; - n++; - - entries[n].addr = gd->relocaddr; - entries[n].size = qemu_get_low_memory_size() - gd->relocaddr; - entries[n].type = E820_RESERVED; - n++; - - entries[n].addr = CONFIG_PCIE_ECAM_BASE; - entries[n].size = CONFIG_PCIE_ECAM_SIZE; - entries[n].type = E820_RESERVED; - n++; + if (IS_ENABLED(CONFIG_BLOBLIST_TABLES)) { + e820_to_addr(&ctx, E820_RAM, (ulong)gd->bloblist); + e820_next(&ctx, E820_ACPI, bloblist_get_total_size()); + } else { + /* If using memalign() reserve that whole region instead */ + e820_to_addr(&ctx, E820_RAM, gd->relocaddr - TOTAL_MALLOC_LEN); + e820_next(&ctx, E820_ACPI, TOTAL_MALLOC_LEN); + } + e820_to_addr(&ctx, E820_RAM, qemu_get_low_memory_size()); + e820_add(&ctx, E820_RESERVED, CONFIG_PCIE_ECAM_BASE, + CONFIG_PCIE_ECAM_SIZE); high_mem_size = qemu_get_high_memory_size(); - if (high_mem_size) { - entries[n].addr = SZ_4G; - entries[n].size = high_mem_size; - entries[n].type = E820_RAM; - n++; - } + if (high_mem_size) + e820_add(&ctx, E820_RAM, SZ_4G, high_mem_size); - return n; + return e820_finish(&ctx); } diff --git a/arch/x86/cpu/qemu/qemu.c b/arch/x86/cpu/qemu/qemu.c index 563f63e2bc8..e846ccd44aa 100644 --- a/arch/x86/cpu/qemu/qemu.c +++ b/arch/x86/cpu/qemu/qemu.c @@ -15,14 +15,21 @@ #include <asm/arch/qemu.h> #include <asm/u-boot-x86.h> -static bool i440fx; - #if CONFIG_IS_ENABLED(QFW_PIO) U_BOOT_DRVINFO(x86_qfw_pio) = { .name = "qfw_pio", }; #endif +static bool is_i440fx(void) +{ + u16 device; + + pci_read_config16(PCI_BDF(0, 0, 0), PCI_DEVICE_ID, &device); + + return device == PCI_DEVICE_ID_INTEL_82441; +} + static void enable_pm_piix(void) { u8 en; @@ -50,16 +57,17 @@ static void enable_pm_ich9(void) void qemu_chipset_init(void) { - u16 device, xbcs; + bool i440fx; + u16 xbcs; int pam, i; + i440fx = is_i440fx(); + /* * i440FX and Q35 chipset have different PAM register offset, but with * the same bitfield layout. Here we determine the offset based on its * PCI device ID. */ - pci_read_config16(PCI_BDF(0, 0, 0), PCI_DEVICE_ID, &device); - i440fx = (device == PCI_DEVICE_ID_INTEL_82441); pam = i440fx ? I440FX_PAM : Q35_PAM; /* @@ -123,7 +131,7 @@ int mp_determine_pci_dstirq(int bus, int dev, int func, int pirq) { u8 irq; - if (i440fx) { + if (is_i440fx()) { /* * Not like most x86 platforms, the PIRQ[A-D] on PIIX3 are not * connected to I/O APIC INTPIN#16-19. Instead they are routed diff --git a/arch/x86/cpu/start.S b/arch/x86/cpu/start.S index 0ef27cc5a00..385a691265e 100644 --- a/arch/x86/cpu/start.S +++ b/arch/x86/cpu/start.S @@ -254,7 +254,7 @@ multiboot_header: * GDT is setup in a safe location in RAM */ gdt_ptr2: - .word 0x1f /* limit (31 bytes = 4 GDT entries - 1) */ + .word gdt2_end - gdt_ptr2 - 1 .long gdt_rom2 /* base */ /* Some CPUs are picky about GDT alignment... */ @@ -313,4 +313,6 @@ gdt_rom2: .byte 0x93 /* access */ .byte 0xcf /* flags + limit_high */ .byte 0x00 /* base_high */ +gdt2_end: + #endif diff --git a/arch/x86/cpu/start16.S b/arch/x86/cpu/start16.S index 865a49731e5..8d9acb193e0 100644 --- a/arch/x86/cpu/start16.S +++ b/arch/x86/cpu/start16.S @@ -61,7 +61,7 @@ idt_ptr: * GDT is setup in a safe location in RAM */ gdt_ptr: - .word 0x1f /* limit (31 bytes = 4 GDT entries - 1) */ + .word gdt_end - gdt_rom - 1 .long BOOT_SEG + gdt_rom /* base */ /* Some CPUs are picky about GDT alignment... */ @@ -120,3 +120,4 @@ gdt_rom: .byte 0x93 /* access */ .byte 0xcf /* flags + limit_high */ .byte 0x00 /* base_high */ +gdt_end: diff --git a/arch/x86/cpu/x86_64/cpu.c b/arch/x86/cpu/x86_64/cpu.c index 71bc07f872a..25ae92c702f 100644 --- a/arch/x86/cpu/x86_64/cpu.c +++ b/arch/x86/cpu/x86_64/cpu.c @@ -59,11 +59,6 @@ int x86_cpu_reinit_f(void) return 0; } -int cpu_phys_address_size(void) -{ - return CONFIG_CPU_ADDR_BITS; -} - int x86_cpu_init_f(void) { return 0; |