diff options
Diffstat (limited to 'arch/x86/cpu')
39 files changed, 1062 insertions, 582 deletions
diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile index f5b8c9e..92a9023 100644 --- a/arch/x86/cpu/Makefile +++ b/arch/x86/cpu/Makefile @@ -8,15 +8,22 @@ # SPDX-License-Identifier: GPL-2.0+ # +ifeq ($(CONFIG_$(SPL_)X86_64),y) +extra-y = start64.o +else extra-y = start.o -obj-$(CONFIG_X86_RESET_VECTOR) += resetvec.o start16.o -obj-y += interrupts.o cpu.o cpu_x86.o call64.o setjmp.o +endif +extra-$(CONFIG_$(SPL_)X86_16BIT_INIT) += resetvec.o start16.o +obj-y += cpu.o cpu_x86.o + +ifndef CONFIG_$(SPL_)X86_64 AFLAGS_REMOVE_call32.o := -mregparm=3 \ $(if $(CONFIG_EFI_STUB_64BIT),-march=i386 -m32) AFLAGS_call32.o := -fpic -fshort-wchar extra-y += call32.o +endif obj-y += intel_common/ obj-$(CONFIG_INTEL_BAYTRAIL) += baytrail/ @@ -27,9 +34,20 @@ obj-$(CONFIG_QEMU) += qemu/ obj-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) += ivybridge/ obj-$(CONFIG_INTEL_QUARK) += quark/ obj-$(CONFIG_INTEL_QUEENSBAY) += queensbay/ -obj-y += irq.o lapic.o ioapic.o +obj-y += lapic.o ioapic.o +obj-y += irq.o +ifndef CONFIG_$(SPL_)X86_64 obj-$(CONFIG_SMP) += mp_init.o +endif obj-y += mtrr.o obj-$(CONFIG_PCI) += pci.o +ifndef CONFIG_$(SPL_)X86_64 obj-$(CONFIG_SMP) += sipi_vector.o +endif obj-y += turbo.o + +ifeq ($(CONFIG_$(SPL_)X86_64),y) +obj-y += x86_64/ +else +obj-y += i386/ +endif diff --git a/arch/x86/cpu/broadwell/cpu.c b/arch/x86/cpu/broadwell/cpu.c index 6977e86..1b71d56 100644 --- a/arch/x86/cpu/broadwell/cpu.c +++ b/arch/x86/cpu/broadwell/cpu.c @@ -256,8 +256,8 @@ static void initialize_vr_config(struct udevice *dev) /* Set the slow ramp rate */ msr.hi &= ~(0x3 << (53 - 32)); /* Configure the C-state exit ramp rate */ - ramp = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "intel,slow-ramp", - -1); + ramp = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), + "intel,slow-ramp", -1); if (ramp != -1) { /* Configured slow ramp rate */ msr.hi |= ((ramp & 0x3) << (53 - 32)); @@ -271,8 +271,8 @@ static void initialize_vr_config(struct udevice *dev) } /* Set MIN_VID (31:24) to allow CPU to have full control */ msr.lo &= ~0xff000000; - min_vid = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "intel,min-vid", - 0); + min_vid = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), + "intel,min-vid", 0); msr.lo |= (min_vid & 0xff) << 24; msr_write(MSR_VR_MISC_CONFIG, msr); @@ -562,7 +562,7 @@ static void configure_thermal_target(struct udevice *dev) int tcc_offset; msr_t msr; - tcc_offset = fdtdec_get_int(gd->fdt_blob, dev->of_offset, + tcc_offset = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "intel,tcc-offset", 0); /* Set TCC activaiton offset if supported */ diff --git a/arch/x86/cpu/broadwell/pch.c b/arch/x86/cpu/broadwell/pch.c index 317f57d..16eac3d 100644 --- a/arch/x86/cpu/broadwell/pch.c +++ b/arch/x86/cpu/broadwell/pch.c @@ -190,14 +190,14 @@ static int pch_power_options(struct udevice *dev) debug("Set power %s after power failure.\n", state); /* GPE setup based on device tree configuration */ - ret = fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, + ret = fdtdec_get_int_array(gd->fdt_blob, dev_of_offset(dev), "intel,gpe0-en", enable, ARRAY_SIZE(enable)); if (ret) return -EINVAL; enable_all_gpe(enable[0], enable[1], enable[2], enable[3]); /* SMI setup based on device tree configuration */ - enable_alt_smi(dev, fdtdec_get_int(gd->fdt_blob, dev->of_offset, + enable_alt_smi(dev, fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "intel,alt-gp-smi-enable", 0)); return 0; diff --git a/arch/x86/cpu/broadwell/pinctrl_broadwell.c b/arch/x86/cpu/broadwell/pinctrl_broadwell.c index 2a3fced..881413f 100644 --- a/arch/x86/cpu/broadwell/pinctrl_broadwell.c +++ b/arch/x86/cpu/broadwell/pinctrl_broadwell.c @@ -51,7 +51,7 @@ static int broadwell_pinctrl_read_configs(struct udevice *dev, int node; debug("%s: starting\n", __func__); - for (node = fdt_first_subnode(blob, dev->of_offset); + for (node = fdt_first_subnode(blob, dev_of_offset(dev)); node > 0; node = fdt_next_subnode(blob, node)) { int phandle = fdt_get_phandle(blob, node); @@ -115,7 +115,7 @@ static int broadwell_pinctrl_read_pins(struct udevice *dev, int count = 0; int node; - for (node = fdt_first_subnode(blob, dev->of_offset); + for (node = fdt_first_subnode(blob, dev_of_offset(dev)); node > 0; node = fdt_next_subnode(blob, node)) { int len, i; diff --git a/arch/x86/cpu/broadwell/sata.c b/arch/x86/cpu/broadwell/sata.c index 2e47082..10461d9 100644 --- a/arch/x86/cpu/broadwell/sata.c +++ b/arch/x86/cpu/broadwell/sata.c @@ -235,7 +235,7 @@ static int broadwell_sata_ofdata_to_platdata(struct udevice *dev) { struct sata_platdata *plat = dev_get_platdata(dev); const void *blob = gd->fdt_blob; - int node = dev->of_offset; + int node = dev_of_offset(dev); plat->port_map = fdtdec_get_int(blob, node, "intel,sata-port-map", 0); plat->port0_gen3_tx = fdtdec_get_int(blob, node, diff --git a/arch/x86/cpu/config.mk b/arch/x86/cpu/config.mk index 1263221..b519f43 100644 --- a/arch/x86/cpu/config.mk +++ b/arch/x86/cpu/config.mk @@ -7,11 +7,15 @@ CROSS_COMPILE ?= i386-linux- -PLATFORM_CPPFLAGS += -D__I386__ - # DO NOT MODIFY THE FOLLOWING UNLESS YOU REALLY KNOW WHAT YOU ARE DOING! LDPPFLAGS += -DRESET_SEG_START=$(CONFIG_RESET_SEG_START) LDPPFLAGS += -DRESET_SEG_SIZE=$(CONFIG_RESET_SEG_SIZE) LDPPFLAGS += -DRESET_VEC_LOC=$(CONFIG_RESET_VEC_LOC) LDPPFLAGS += -DSTART_16=$(CONFIG_SYS_X86_START16) LDPPFLAGS += -DRESET_BASE="CONFIG_SYS_TEXT_BASE + (CONFIG_SYS_MONITOR_LEN - RESET_SEG_SIZE)" + +ifdef CONFIG_X86_64 +ifndef CONFIG_SPL_BUILD +LDSCRIPT = $(srctree)/arch/x86/cpu/u-boot-64.lds +endif +endif diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index 7c1d6de..8fa6953 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -43,55 +43,6 @@ DECLARE_GLOBAL_DATA_PTR; -/* - * Constructor for a conventional segment GDT (or LDT) entry - * This is a macro so it can be used in initialisers - */ -#define GDT_ENTRY(flags, base, limit) \ - ((((base) & 0xff000000ULL) << (56-24)) | \ - (((flags) & 0x0000f0ffULL) << 40) | \ - (((limit) & 0x000f0000ULL) << (48-16)) | \ - (((base) & 0x00ffffffULL) << 16) | \ - (((limit) & 0x0000ffffULL))) - -struct gdt_ptr { - u16 len; - u32 ptr; -} __packed; - -struct cpu_device_id { - unsigned vendor; - unsigned device; -}; - -struct cpuinfo_x86 { - uint8_t x86; /* CPU family */ - uint8_t x86_vendor; /* CPU vendor */ - uint8_t x86_model; - uint8_t x86_mask; -}; - -/* - * List of cpu vendor strings along with their normalized - * id values. - */ -static const struct { - int vendor; - const char *name; -} x86_vendors[] = { - { X86_VENDOR_INTEL, "GenuineIntel", }, - { X86_VENDOR_CYRIX, "CyrixInstead", }, - { X86_VENDOR_AMD, "AuthenticAMD", }, - { X86_VENDOR_UMC, "UMC UMC UMC ", }, - { X86_VENDOR_NEXGEN, "NexGenDriven", }, - { X86_VENDOR_CENTAUR, "CentaurHauls", }, - { X86_VENDOR_RISE, "RiseRiseRise", }, - { X86_VENDOR_TRANSMETA, "GenuineTMx86", }, - { X86_VENDOR_TRANSMETA, "TransmetaCPU", }, - { X86_VENDOR_NSC, "Geode by NSC", }, - { X86_VENDOR_SIS, "SiS SiS SiS ", }, -}; - static const char *const x86_vendor_name[] = { [X86_VENDOR_INTEL] = "Intel", [X86_VENDOR_CYRIX] = "Cyrix", @@ -105,100 +56,6 @@ static const char *const x86_vendor_name[] = { [X86_VENDOR_SIS] = "SiS", }; -static void load_ds(u32 segment) -{ - asm volatile("movl %0, %%ds" : : "r" (segment * X86_GDT_ENTRY_SIZE)); -} - -static void load_es(u32 segment) -{ - asm volatile("movl %0, %%es" : : "r" (segment * X86_GDT_ENTRY_SIZE)); -} - -static void load_fs(u32 segment) -{ - asm volatile("movl %0, %%fs" : : "r" (segment * X86_GDT_ENTRY_SIZE)); -} - -static void load_gs(u32 segment) -{ - asm volatile("movl %0, %%gs" : : "r" (segment * X86_GDT_ENTRY_SIZE)); -} - -static void load_ss(u32 segment) -{ - asm volatile("movl %0, %%ss" : : "r" (segment * X86_GDT_ENTRY_SIZE)); -} - -static void load_gdt(const u64 *boot_gdt, u16 num_entries) -{ - struct gdt_ptr gdt; - - gdt.len = (num_entries * X86_GDT_ENTRY_SIZE) - 1; - gdt.ptr = (ulong)boot_gdt; - - asm volatile("lgdtl %0\n" : : "m" (gdt)); -} - -void arch_setup_gd(gd_t *new_gd) -{ - u64 *gdt_addr; - - gdt_addr = new_gd->arch.gdt; - - /* - * CS: code, read/execute, 4 GB, base 0 - * - * Some OS (like VxWorks) requires GDT entry 1 to be the 32-bit CS - */ - gdt_addr[X86_GDT_ENTRY_UNUSED] = GDT_ENTRY(0xc09b, 0, 0xfffff); - gdt_addr[X86_GDT_ENTRY_32BIT_CS] = GDT_ENTRY(0xc09b, 0, 0xfffff); - - /* DS: data, read/write, 4 GB, base 0 */ - gdt_addr[X86_GDT_ENTRY_32BIT_DS] = GDT_ENTRY(0xc093, 0, 0xfffff); - - /* FS: data, read/write, 4 GB, base (Global Data Pointer) */ - new_gd->arch.gd_addr = new_gd; - gdt_addr[X86_GDT_ENTRY_32BIT_FS] = GDT_ENTRY(0xc093, - (ulong)&new_gd->arch.gd_addr, 0xfffff); - - /* 16-bit CS: code, read/execute, 64 kB, base 0 */ - gdt_addr[X86_GDT_ENTRY_16BIT_CS] = GDT_ENTRY(0x009b, 0, 0x0ffff); - - /* 16-bit DS: data, read/write, 64 kB, base 0 */ - gdt_addr[X86_GDT_ENTRY_16BIT_DS] = GDT_ENTRY(0x0093, 0, 0x0ffff); - - 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); - - load_gdt(gdt_addr, X86_GDT_NUM_ENTRIES); - load_ds(X86_GDT_ENTRY_32BIT_DS); - load_es(X86_GDT_ENTRY_32BIT_DS); - load_gs(X86_GDT_ENTRY_32BIT_DS); - load_ss(X86_GDT_ENTRY_32BIT_DS); - load_fs(X86_GDT_ENTRY_32BIT_FS); -} - -#ifdef CONFIG_HAVE_FSP -/* - * Setup FSP execution environment GDT - * - * Per Intel FSP external architecture specification, before calling any FSP - * APIs, we need make sure the system is in flat 32-bit mode and both the code - * and data selectors should have full 4GB access range. Here we reuse the one - * we used in arch/x86/cpu/start16.S, and reload the segement registers. - */ -void setup_fsp_gdt(void) -{ - load_gdt((const u64 *)(gdt_rom + CONFIG_RESET_SEG_START), 4); - load_ds(X86_GDT_ENTRY_32BIT_DS); - load_ss(X86_GDT_ENTRY_32BIT_DS); - load_es(X86_GDT_ENTRY_32BIT_DS); - load_fs(X86_GDT_ENTRY_32BIT_DS); - load_gs(X86_GDT_ENTRY_32BIT_DS); -} -#endif - int __weak x86_cleanup_before_linux(void) { #ifdef CONFIG_BOOTSTAGE_STASH @@ -209,241 +66,6 @@ int __weak x86_cleanup_before_linux(void) return 0; } -/* - * Cyrix CPUs without cpuid or with cpuid not yet enabled can be detected - * by the fact that they preserve the flags across the division of 5/2. - * PII and PPro exhibit this behavior too, but they have cpuid available. - */ - -/* - * Perform the Cyrix 5/2 test. A Cyrix won't change - * the flags, while other 486 chips will. - */ -static inline int test_cyrix_52div(void) -{ - unsigned int test; - - __asm__ __volatile__( - "sahf\n\t" /* clear flags (%eax = 0x0005) */ - "div %b2\n\t" /* divide 5 by 2 */ - "lahf" /* store flags into %ah */ - : "=a" (test) - : "0" (5), "q" (2) - : "cc"); - - /* AH is 0x02 on Cyrix after the divide.. */ - return (unsigned char) (test >> 8) == 0x02; -} - -/* - * Detect a NexGen CPU running without BIOS hypercode new enough - * to have CPUID. (Thanks to Herbert Oppmann) - */ - -static int deep_magic_nexgen_probe(void) -{ - int ret; - - __asm__ __volatile__ ( - " movw $0x5555, %%ax\n" - " xorw %%dx,%%dx\n" - " movw $2, %%cx\n" - " divw %%cx\n" - " movl $0, %%eax\n" - " jnz 1f\n" - " movl $1, %%eax\n" - "1:\n" - : "=a" (ret) : : "cx", "dx"); - return ret; -} - -static bool has_cpuid(void) -{ - return flag_is_changeable_p(X86_EFLAGS_ID); -} - -static bool has_mtrr(void) -{ - return cpuid_edx(0x00000001) & (1 << 12) ? true : false; -} - -static int build_vendor_name(char *vendor_name) -{ - struct cpuid_result result; - result = cpuid(0x00000000); - unsigned int *name_as_ints = (unsigned int *)vendor_name; - - name_as_ints[0] = result.ebx; - name_as_ints[1] = result.edx; - name_as_ints[2] = result.ecx; - - return result.eax; -} - -static void identify_cpu(struct cpu_device_id *cpu) -{ - char vendor_name[16]; - int i; - - vendor_name[0] = '\0'; /* Unset */ - cpu->device = 0; /* fix gcc 4.4.4 warning */ - - /* Find the id and vendor_name */ - if (!has_cpuid()) { - /* Its a 486 if we can modify the AC flag */ - if (flag_is_changeable_p(X86_EFLAGS_AC)) - cpu->device = 0x00000400; /* 486 */ - else - cpu->device = 0x00000300; /* 386 */ - if ((cpu->device == 0x00000400) && test_cyrix_52div()) { - memcpy(vendor_name, "CyrixInstead", 13); - /* If we ever care we can enable cpuid here */ - } - /* Detect NexGen with old hypercode */ - else if (deep_magic_nexgen_probe()) - memcpy(vendor_name, "NexGenDriven", 13); - } - if (has_cpuid()) { - int cpuid_level; - - cpuid_level = build_vendor_name(vendor_name); - vendor_name[12] = '\0'; - - /* Intel-defined flags: level 0x00000001 */ - if (cpuid_level >= 0x00000001) { - cpu->device = cpuid_eax(0x00000001); - } else { - /* Have CPUID level 0 only unheard of */ - cpu->device = 0x00000400; - } - } - cpu->vendor = X86_VENDOR_UNKNOWN; - for (i = 0; i < ARRAY_SIZE(x86_vendors); i++) { - if (memcmp(vendor_name, x86_vendors[i].name, 12) == 0) { - cpu->vendor = x86_vendors[i].vendor; - break; - } - } -} - -static inline void get_fms(struct cpuinfo_x86 *c, uint32_t tfms) -{ - c->x86 = (tfms >> 8) & 0xf; - c->x86_model = (tfms >> 4) & 0xf; - c->x86_mask = tfms & 0xf; - if (c->x86 == 0xf) - c->x86 += (tfms >> 20) & 0xff; - if (c->x86 >= 0x6) - c->x86_model += ((tfms >> 16) & 0xF) << 4; -} - -u32 cpu_get_family_model(void) -{ - return gd->arch.x86_device & 0x0fff0ff0; -} - -u32 cpu_get_stepping(void) -{ - return gd->arch.x86_mask; -} - -int x86_cpu_init_f(void) -{ - const u32 em_rst = ~X86_CR0_EM; - const u32 mp_ne_set = X86_CR0_MP | X86_CR0_NE; - - if (ll_boot_init()) { - /* initialize FPU, reset EM, set MP and NE */ - asm ("fninit\n" \ - "movl %%cr0, %%eax\n" \ - "andl %0, %%eax\n" \ - "orl %1, %%eax\n" \ - "movl %%eax, %%cr0\n" \ - : : "i" (em_rst), "i" (mp_ne_set) : "eax"); - } - - /* identify CPU via cpuid and store the decoded info into gd->arch */ - if (has_cpuid()) { - struct cpu_device_id cpu; - struct cpuinfo_x86 c; - - identify_cpu(&cpu); - get_fms(&c, cpu.device); - gd->arch.x86 = c.x86; - gd->arch.x86_vendor = cpu.vendor; - gd->arch.x86_model = c.x86_model; - gd->arch.x86_mask = c.x86_mask; - gd->arch.x86_device = cpu.device; - - gd->arch.has_mtrr = has_mtrr(); - } - /* Don't allow PCI region 3 to use memory in the 2-4GB memory hole */ - gd->pci_ram_top = 0x80000000U; - - /* Configure fixed range MTRRs for some legacy regions */ - if (gd->arch.has_mtrr) { - u64 mtrr_cap; - - mtrr_cap = native_read_msr(MTRR_CAP_MSR); - if (mtrr_cap & MTRR_CAP_FIX) { - /* Mark the VGA RAM area as uncacheable */ - native_write_msr(MTRR_FIX_16K_A0000_MSR, - MTRR_FIX_TYPE(MTRR_TYPE_UNCACHEABLE), - MTRR_FIX_TYPE(MTRR_TYPE_UNCACHEABLE)); - - /* - * Mark the PCI ROM area as cacheable to improve ROM - * execution performance. - */ - native_write_msr(MTRR_FIX_4K_C0000_MSR, - MTRR_FIX_TYPE(MTRR_TYPE_WRBACK), - MTRR_FIX_TYPE(MTRR_TYPE_WRBACK)); - native_write_msr(MTRR_FIX_4K_C8000_MSR, - MTRR_FIX_TYPE(MTRR_TYPE_WRBACK), - MTRR_FIX_TYPE(MTRR_TYPE_WRBACK)); - native_write_msr(MTRR_FIX_4K_D0000_MSR, - MTRR_FIX_TYPE(MTRR_TYPE_WRBACK), - MTRR_FIX_TYPE(MTRR_TYPE_WRBACK)); - native_write_msr(MTRR_FIX_4K_D8000_MSR, - MTRR_FIX_TYPE(MTRR_TYPE_WRBACK), - MTRR_FIX_TYPE(MTRR_TYPE_WRBACK)); - - /* Enable the fixed range MTRRs */ - msr_setbits_64(MTRR_DEF_TYPE_MSR, MTRR_DEF_TYPE_FIX_EN); - } - } - -#ifdef CONFIG_I8254_TIMER - /* Set up the i8254 timer if required */ - i8254_init(); -#endif - - return 0; -} - -void x86_enable_caches(void) -{ - unsigned long cr0; - - cr0 = read_cr0(); - cr0 &= ~(X86_CR0_NW | X86_CR0_CD); - write_cr0(cr0); - wbinvd(); -} -void enable_caches(void) __attribute__((weak, alias("x86_enable_caches"))); - -void x86_disable_caches(void) -{ - unsigned long cr0; - - cr0 = read_cr0(); - cr0 |= X86_CR0_NW | X86_CR0_CD; - wbinvd(); - write_cr0(cr0); - wbinvd(); -} -void disable_caches(void) __attribute__((weak, alias("x86_disable_caches"))); - int x86_init_cache(void) { enable_caches(); @@ -483,11 +105,6 @@ void x86_full_reset(void) outb(FULL_RST | SYS_RST | RST_CPU, IO_PORT_RESET); } -int dcache_status(void) -{ - return !(read_cr0() & X86_CR0_CD); -} - /* Define these functions to allow ehch-hcd to function */ void flush_dcache_range(unsigned long start, unsigned long stop) { @@ -520,57 +137,6 @@ int icache_status(void) return 1; } -void cpu_enable_paging_pae(ulong cr3) -{ - __asm__ __volatile__( - /* Load the page table address */ - "movl %0, %%cr3\n" - /* Enable pae */ - "movl %%cr4, %%eax\n" - "orl $0x00000020, %%eax\n" - "movl %%eax, %%cr4\n" - /* Enable paging */ - "movl %%cr0, %%eax\n" - "orl $0x80000000, %%eax\n" - "movl %%eax, %%cr0\n" - : - : "r" (cr3) - : "eax"); -} - -void cpu_disable_paging_pae(void) -{ - /* Turn off paging */ - __asm__ __volatile__ ( - /* Disable paging */ - "movl %%cr0, %%eax\n" - "andl $0x7fffffff, %%eax\n" - "movl %%eax, %%cr0\n" - /* Disable pae */ - "movl %%cr4, %%eax\n" - "andl $0xffffffdf, %%eax\n" - "movl %%eax, %%cr4\n" - : - : - : "eax"); -} - -static bool can_detect_long_mode(void) -{ - return cpuid_eax(0x80000000) > 0x80000000UL; -} - -static bool has_long_mode(void) -{ - return cpuid_edx(0x80000001) & (1 << 29) ? true : false; -} - -int cpu_has_64bit(void) -{ - return has_cpuid() && can_detect_long_mode() && - has_long_mode(); -} - const char *cpu_vendor_name(int vendor) { const char *name; @@ -616,46 +182,6 @@ int default_print_cpuinfo(void) return 0; } -#define PAGETABLE_SIZE (6 * 4096) - -/** - * build_pagetable() - build a flat 4GiB page table structure for 64-bti mode - * - * @pgtable: Pointer to a 24iKB block of memory - */ -static void build_pagetable(uint32_t *pgtable) -{ - uint i; - - memset(pgtable, '\0', PAGETABLE_SIZE); - - /* Level 4 needs a single entry */ - pgtable[0] = (ulong)&pgtable[1024] + 7; - - /* 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; - - /* Level 2 has 2048 64-bit entries, each repesenting 2MiB */ - for (i = 0; i < 2048; i++) - pgtable[2048 + i * 2] = 0x183 + (i << 21UL); -} - -int cpu_jump_to_64bit(ulong setup_base, ulong target) -{ - uint32_t *pgtable; - - pgtable = memalign(4096, PAGETABLE_SIZE); - if (!pgtable) - return -ENOMEM; - - build_pagetable(pgtable); - cpu_call64((ulong)pgtable, setup_base, target); - free(pgtable); - - return -EFAULT; -} - void show_boot_progress(int val) { outb(val, POST_PORT); @@ -680,36 +206,6 @@ int last_stage_init(void) } #endif -#ifdef CONFIG_SMP -static int enable_smis(struct udevice *cpu, void *unused) -{ - return 0; -} - -static struct mp_flight_record mp_steps[] = { - MP_FR_BLOCK_APS(mp_init_cpu, NULL, mp_init_cpu, NULL), - /* Wait for APs to finish initialization before proceeding */ - MP_FR_BLOCK_APS(NULL, NULL, enable_smis, NULL), -}; - -static int x86_mp_init(void) -{ - struct mp_params mp_params; - - mp_params.parallel_microcode_load = 0, - mp_params.flight_plan = &mp_steps[0]; - mp_params.num_records = ARRAY_SIZE(mp_steps); - mp_params.microcode_pointer = 0; - - if (mp_init(&mp_params)) { - printf("Warning: MP init failure\n"); - return -EIO; - } - - return 0; -} -#endif - static int x86_init_cpus(void) { #ifdef CONFIG_SMP diff --git a/arch/x86/cpu/cpu_x86.c b/arch/x86/cpu/cpu_x86.c index 157f3de..8be14b5 100644 --- a/arch/x86/cpu/cpu_x86.c +++ b/arch/x86/cpu/cpu_x86.c @@ -17,7 +17,7 @@ int cpu_x86_bind(struct udevice *dev) struct cpu_platdata *plat = dev_get_parent_platdata(dev); struct cpuid_result res; - plat->cpu_id = fdtdec_get_int(gd->fdt_blob, dev->of_offset, + plat->cpu_id = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "intel,apic-id", -1); plat->family = gd->arch.x86; res = cpuid(1); diff --git a/arch/x86/cpu/i386/Makefile b/arch/x86/cpu/i386/Makefile new file mode 100644 index 0000000..0c47252 --- /dev/null +++ b/arch/x86/cpu/i386/Makefile @@ -0,0 +1,9 @@ +# +# (C) Copyright 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# + +obj-y += call64.o +obj-y += cpu.o +obj-y += interrupt.o +obj-y += setjmp.o diff --git a/arch/x86/cpu/call64.S b/arch/x86/cpu/i386/call64.S index 08dc473..970c461 100644 --- a/arch/x86/cpu/call64.S +++ b/arch/x86/cpu/i386/call64.S @@ -81,6 +81,9 @@ lret_target: jmp *%eax /* Jump to the 64-bit target */ .data + .align 16 + .globl gdt64 +gdt64: gdt: .word gdt_end - gdt - 1 .long gdt /* Fixed up by code above */ diff --git a/arch/x86/cpu/i386/cpu.c b/arch/x86/cpu/i386/cpu.c new file mode 100644 index 0000000..aabdc94 --- /dev/null +++ b/arch/x86/cpu/i386/cpu.c @@ -0,0 +1,598 @@ +/* + * (C) Copyright 2008-2011 + * Graeme Russ, <graeme.russ@gmail.com> + * + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Alex Zuepke <azu@sysgo.de> + * + * Part of this file is adapted from coreboot + * src/arch/x86/lib/cpu.c + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <malloc.h> +#include <asm/control_regs.h> +#include <asm/cpu.h> +#include <asm/mp.h> +#include <asm/msr.h> +#include <asm/mtrr.h> +#include <asm/processor-flags.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* + * Constructor for a conventional segment GDT (or LDT) entry + * This is a macro so it can be used in initialisers + */ +#define GDT_ENTRY(flags, base, limit) \ + ((((base) & 0xff000000ULL) << (56-24)) | \ + (((flags) & 0x0000f0ffULL) << 40) | \ + (((limit) & 0x000f0000ULL) << (48-16)) | \ + (((base) & 0x00ffffffULL) << 16) | \ + (((limit) & 0x0000ffffULL))) + +struct gdt_ptr { + u16 len; + u32 ptr; +} __packed; + +struct cpu_device_id { + unsigned vendor; + unsigned device; +}; + +struct cpuinfo_x86 { + uint8_t x86; /* CPU family */ + uint8_t x86_vendor; /* CPU vendor */ + uint8_t x86_model; + uint8_t x86_mask; +}; + +/* + * List of cpu vendor strings along with their normalized + * id values. + */ +static const struct { + int vendor; + const char *name; +} x86_vendors[] = { + { X86_VENDOR_INTEL, "GenuineIntel", }, + { X86_VENDOR_CYRIX, "CyrixInstead", }, + { X86_VENDOR_AMD, "AuthenticAMD", }, + { X86_VENDOR_UMC, "UMC UMC UMC ", }, + { X86_VENDOR_NEXGEN, "NexGenDriven", }, + { X86_VENDOR_CENTAUR, "CentaurHauls", }, + { X86_VENDOR_RISE, "RiseRiseRise", }, + { X86_VENDOR_TRANSMETA, "GenuineTMx86", }, + { X86_VENDOR_TRANSMETA, "TransmetaCPU", }, + { X86_VENDOR_NSC, "Geode by NSC", }, + { X86_VENDOR_SIS, "SiS SiS SiS ", }, +}; + +static void load_ds(u32 segment) +{ + asm volatile("movl %0, %%ds" : : "r" (segment * X86_GDT_ENTRY_SIZE)); +} + +static void load_es(u32 segment) +{ + asm volatile("movl %0, %%es" : : "r" (segment * X86_GDT_ENTRY_SIZE)); +} + +static void load_fs(u32 segment) +{ + asm volatile("movl %0, %%fs" : : "r" (segment * X86_GDT_ENTRY_SIZE)); +} + +static void load_gs(u32 segment) +{ + asm volatile("movl %0, %%gs" : : "r" (segment * X86_GDT_ENTRY_SIZE)); +} + +static void load_ss(u32 segment) +{ + asm volatile("movl %0, %%ss" : : "r" (segment * X86_GDT_ENTRY_SIZE)); +} + +static void load_gdt(const u64 *boot_gdt, u16 num_entries) +{ + struct gdt_ptr gdt; + + gdt.len = (num_entries * X86_GDT_ENTRY_SIZE) - 1; + gdt.ptr = (ulong)boot_gdt; + + asm volatile("lgdtl %0\n" : : "m" (gdt)); +} + +void arch_setup_gd(gd_t *new_gd) +{ + u64 *gdt_addr; + + gdt_addr = new_gd->arch.gdt; + + /* + * CS: code, read/execute, 4 GB, base 0 + * + * Some OS (like VxWorks) requires GDT entry 1 to be the 32-bit CS + */ + gdt_addr[X86_GDT_ENTRY_UNUSED] = GDT_ENTRY(0xc09b, 0, 0xfffff); + gdt_addr[X86_GDT_ENTRY_32BIT_CS] = GDT_ENTRY(0xc09b, 0, 0xfffff); + + /* DS: data, read/write, 4 GB, base 0 */ + gdt_addr[X86_GDT_ENTRY_32BIT_DS] = GDT_ENTRY(0xc093, 0, 0xfffff); + + /* FS: data, read/write, 4 GB, base (Global Data Pointer) */ + new_gd->arch.gd_addr = new_gd; + gdt_addr[X86_GDT_ENTRY_32BIT_FS] = GDT_ENTRY(0xc093, + (ulong)&new_gd->arch.gd_addr, 0xfffff); + + /* 16-bit CS: code, read/execute, 64 kB, base 0 */ + gdt_addr[X86_GDT_ENTRY_16BIT_CS] = GDT_ENTRY(0x009b, 0, 0x0ffff); + + /* 16-bit DS: data, read/write, 64 kB, base 0 */ + gdt_addr[X86_GDT_ENTRY_16BIT_DS] = GDT_ENTRY(0x0093, 0, 0x0ffff); + + 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); + + load_gdt(gdt_addr, X86_GDT_NUM_ENTRIES); + load_ds(X86_GDT_ENTRY_32BIT_DS); + load_es(X86_GDT_ENTRY_32BIT_DS); + load_gs(X86_GDT_ENTRY_32BIT_DS); + load_ss(X86_GDT_ENTRY_32BIT_DS); + load_fs(X86_GDT_ENTRY_32BIT_FS); +} + +#ifdef CONFIG_HAVE_FSP +/* + * Setup FSP execution environment GDT + * + * Per Intel FSP external architecture specification, before calling any FSP + * APIs, we need make sure the system is in flat 32-bit mode and both the code + * and data selectors should have full 4GB access range. Here we reuse the one + * we used in arch/x86/cpu/start16.S, and reload the segement registers. + */ +void setup_fsp_gdt(void) +{ + load_gdt((const u64 *)(gdt_rom + CONFIG_RESET_SEG_START), 4); + load_ds(X86_GDT_ENTRY_32BIT_DS); + load_ss(X86_GDT_ENTRY_32BIT_DS); + load_es(X86_GDT_ENTRY_32BIT_DS); + load_fs(X86_GDT_ENTRY_32BIT_DS); + load_gs(X86_GDT_ENTRY_32BIT_DS); +} +#endif + +/* + * Cyrix CPUs without cpuid or with cpuid not yet enabled can be detected + * by the fact that they preserve the flags across the division of 5/2. + * PII and PPro exhibit this behavior too, but they have cpuid available. + */ + +/* + * Perform the Cyrix 5/2 test. A Cyrix won't change + * the flags, while other 486 chips will. + */ +static inline int test_cyrix_52div(void) +{ + unsigned int test; + + __asm__ __volatile__( + "sahf\n\t" /* clear flags (%eax = 0x0005) */ + "div %b2\n\t" /* divide 5 by 2 */ + "lahf" /* store flags into %ah */ + : "=a" (test) + : "0" (5), "q" (2) + : "cc"); + + /* AH is 0x02 on Cyrix after the divide.. */ + return (unsigned char) (test >> 8) == 0x02; +} + +/* + * Detect a NexGen CPU running without BIOS hypercode new enough + * to have CPUID. (Thanks to Herbert Oppmann) + */ +static int deep_magic_nexgen_probe(void) +{ + int ret; + + __asm__ __volatile__ ( + " movw $0x5555, %%ax\n" + " xorw %%dx,%%dx\n" + " movw $2, %%cx\n" + " divw %%cx\n" + " movl $0, %%eax\n" + " jnz 1f\n" + " movl $1, %%eax\n" + "1:\n" + : "=a" (ret) : : "cx", "dx"); + return ret; +} + +static bool has_cpuid(void) +{ + return flag_is_changeable_p(X86_EFLAGS_ID); +} + +static bool has_mtrr(void) +{ + return cpuid_edx(0x00000001) & (1 << 12) ? true : false; +} + +static int build_vendor_name(char *vendor_name) +{ + struct cpuid_result result; + result = cpuid(0x00000000); + unsigned int *name_as_ints = (unsigned int *)vendor_name; + + name_as_ints[0] = result.ebx; + name_as_ints[1] = result.edx; + name_as_ints[2] = result.ecx; + + return result.eax; +} + +static void identify_cpu(struct cpu_device_id *cpu) +{ + char vendor_name[16]; + int i; + + vendor_name[0] = '\0'; /* Unset */ + cpu->device = 0; /* fix gcc 4.4.4 warning */ + + /* Find the id and vendor_name */ + if (!has_cpuid()) { + /* Its a 486 if we can modify the AC flag */ + if (flag_is_changeable_p(X86_EFLAGS_AC)) + cpu->device = 0x00000400; /* 486 */ + else + cpu->device = 0x00000300; /* 386 */ + if ((cpu->device == 0x00000400) && test_cyrix_52div()) { + memcpy(vendor_name, "CyrixInstead", 13); + /* If we ever care we can enable cpuid here */ + } + /* Detect NexGen with old hypercode */ + else if (deep_magic_nexgen_probe()) + memcpy(vendor_name, "NexGenDriven", 13); + } + if (has_cpuid()) { + int cpuid_level; + + cpuid_level = build_vendor_name(vendor_name); + vendor_name[12] = '\0'; + + /* Intel-defined flags: level 0x00000001 */ + if (cpuid_level >= 0x00000001) { + cpu->device = cpuid_eax(0x00000001); + } else { + /* Have CPUID level 0 only unheard of */ + cpu->device = 0x00000400; + } + } + cpu->vendor = X86_VENDOR_UNKNOWN; + for (i = 0; i < ARRAY_SIZE(x86_vendors); i++) { + if (memcmp(vendor_name, x86_vendors[i].name, 12) == 0) { + cpu->vendor = x86_vendors[i].vendor; + break; + } + } +} + +static inline void get_fms(struct cpuinfo_x86 *c, uint32_t tfms) +{ + c->x86 = (tfms >> 8) & 0xf; + c->x86_model = (tfms >> 4) & 0xf; + c->x86_mask = tfms & 0xf; + if (c->x86 == 0xf) + c->x86 += (tfms >> 20) & 0xff; + if (c->x86 >= 0x6) + c->x86_model += ((tfms >> 16) & 0xF) << 4; +} + +u32 cpu_get_family_model(void) +{ + return gd->arch.x86_device & 0x0fff0ff0; +} + +u32 cpu_get_stepping(void) +{ + return gd->arch.x86_mask; +} + +int x86_cpu_init_f(void) +{ + const u32 em_rst = ~X86_CR0_EM; + const u32 mp_ne_set = X86_CR0_MP | X86_CR0_NE; + + if (ll_boot_init()) { + /* initialize FPU, reset EM, set MP and NE */ + asm ("fninit\n" \ + "movl %%cr0, %%eax\n" \ + "andl %0, %%eax\n" \ + "orl %1, %%eax\n" \ + "movl %%eax, %%cr0\n" \ + : : "i" (em_rst), "i" (mp_ne_set) : "eax"); + } + + /* identify CPU via cpuid and store the decoded info into gd->arch */ + if (has_cpuid()) { + struct cpu_device_id cpu; + struct cpuinfo_x86 c; + + identify_cpu(&cpu); + get_fms(&c, cpu.device); + gd->arch.x86 = c.x86; + gd->arch.x86_vendor = cpu.vendor; + gd->arch.x86_model = c.x86_model; + gd->arch.x86_mask = c.x86_mask; + gd->arch.x86_device = cpu.device; + + gd->arch.has_mtrr = has_mtrr(); + } + /* Don't allow PCI region 3 to use memory in the 2-4GB memory hole */ + gd->pci_ram_top = 0x80000000U; + + /* Configure fixed range MTRRs for some legacy regions */ + if (gd->arch.has_mtrr) { + u64 mtrr_cap; + + mtrr_cap = native_read_msr(MTRR_CAP_MSR); + if (mtrr_cap & MTRR_CAP_FIX) { + /* Mark the VGA RAM area as uncacheable */ + native_write_msr(MTRR_FIX_16K_A0000_MSR, + MTRR_FIX_TYPE(MTRR_TYPE_UNCACHEABLE), + MTRR_FIX_TYPE(MTRR_TYPE_UNCACHEABLE)); + + /* + * Mark the PCI ROM area as cacheable to improve ROM + * execution performance. + */ + native_write_msr(MTRR_FIX_4K_C0000_MSR, + MTRR_FIX_TYPE(MTRR_TYPE_WRBACK), + MTRR_FIX_TYPE(MTRR_TYPE_WRBACK)); + native_write_msr(MTRR_FIX_4K_C8000_MSR, + MTRR_FIX_TYPE(MTRR_TYPE_WRBACK), + MTRR_FIX_TYPE(MTRR_TYPE_WRBACK)); + native_write_msr(MTRR_FIX_4K_D0000_MSR, + MTRR_FIX_TYPE(MTRR_TYPE_WRBACK), + MTRR_FIX_TYPE(MTRR_TYPE_WRBACK)); + native_write_msr(MTRR_FIX_4K_D8000_MSR, + MTRR_FIX_TYPE(MTRR_TYPE_WRBACK), + MTRR_FIX_TYPE(MTRR_TYPE_WRBACK)); + + /* Enable the fixed range MTRRs */ + msr_setbits_64(MTRR_DEF_TYPE_MSR, MTRR_DEF_TYPE_FIX_EN); + } + } + +#ifdef CONFIG_I8254_TIMER + /* Set up the i8254 timer if required */ + i8254_init(); +#endif + + return 0; +} + +void x86_enable_caches(void) +{ + unsigned long cr0; + + cr0 = read_cr0(); + cr0 &= ~(X86_CR0_NW | X86_CR0_CD); + write_cr0(cr0); + wbinvd(); +} +void enable_caches(void) __attribute__((weak, alias("x86_enable_caches"))); + +void x86_disable_caches(void) +{ + unsigned long cr0; + + cr0 = read_cr0(); + cr0 |= X86_CR0_NW | X86_CR0_CD; + wbinvd(); + write_cr0(cr0); + wbinvd(); +} +void disable_caches(void) __attribute__((weak, alias("x86_disable_caches"))); + +int dcache_status(void) +{ + return !(read_cr0() & X86_CR0_CD); +} + +void cpu_enable_paging_pae(ulong cr3) +{ + __asm__ __volatile__( + /* Load the page table address */ + "movl %0, %%cr3\n" + /* Enable pae */ + "movl %%cr4, %%eax\n" + "orl $0x00000020, %%eax\n" + "movl %%eax, %%cr4\n" + /* Enable paging */ + "movl %%cr0, %%eax\n" + "orl $0x80000000, %%eax\n" + "movl %%eax, %%cr0\n" + : + : "r" (cr3) + : "eax"); +} + +void cpu_disable_paging_pae(void) +{ + /* Turn off paging */ + __asm__ __volatile__ ( + /* Disable paging */ + "movl %%cr0, %%eax\n" + "andl $0x7fffffff, %%eax\n" + "movl %%eax, %%cr0\n" + /* Disable pae */ + "movl %%cr4, %%eax\n" + "andl $0xffffffdf, %%eax\n" + "movl %%eax, %%cr4\n" + : + : + : "eax"); +} + +static bool can_detect_long_mode(void) +{ + return cpuid_eax(0x80000000) > 0x80000000UL; +} + +static bool has_long_mode(void) +{ + return cpuid_edx(0x80000001) & (1 << 29) ? true : false; +} + +int cpu_has_64bit(void) +{ + return has_cpuid() && can_detect_long_mode() && + has_long_mode(); +} + +#define PAGETABLE_SIZE (6 * 4096) + +/** + * build_pagetable() - build a flat 4GiB page table structure for 64-bti mode + * + * @pgtable: Pointer to a 24iKB block of memory + */ +static void build_pagetable(uint32_t *pgtable) +{ + uint i; + + memset(pgtable, '\0', PAGETABLE_SIZE); + + /* Level 4 needs a single entry */ + pgtable[0] = (ulong)&pgtable[1024] + 7; + + /* 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; + + /* Level 2 has 2048 64-bit entries, each repesenting 2MiB */ + for (i = 0; i < 2048; i++) + pgtable[2048 + i * 2] = 0x183 + (i << 21UL); +} + +int cpu_jump_to_64bit(ulong setup_base, ulong target) +{ + uint32_t *pgtable; + + pgtable = memalign(4096, PAGETABLE_SIZE); + if (!pgtable) + return -ENOMEM; + + build_pagetable(pgtable); + cpu_call64((ulong)pgtable, setup_base, target); + free(pgtable); + + return -EFAULT; +} + +/* + * Jump from SPL to U-Boot + * + * This function is work-in-progress with many issues to resolve. + * + * It works by setting up several regions: + * ptr - a place to put the code that jumps into 64-bit mode + * gdt - a place to put the global descriptor table + * pgtable - a place to put the page tables + * + * The cpu_call64() code is copied from ROM and then manually patched so that + * it has the correct GDT address in RAM. U-Boot is copied from ROM into + * its pre-relocation address. Then we jump to the cpu_call64() code in RAM, + * which changes to 64-bit mode and starts U-Boot. + */ +int cpu_jump_to_64bit_uboot(ulong target) +{ + typedef void (*func_t)(ulong pgtable, ulong setup_base, ulong target); + uint32_t *pgtable; + func_t func; + + /* TODO(sjg@chromium.org): Find a better place for this */ + pgtable = (uint32_t *)0x1000000; + if (!pgtable) + return -ENOMEM; + + build_pagetable(pgtable); + + /* TODO(sjg@chromium.org): Find a better place for this */ + char *ptr = (char *)0x3000000; + char *gdt = (char *)0x3100000; + + extern char gdt64[]; + + memcpy(ptr, cpu_call64, 0x1000); + memcpy(gdt, gdt64, 0x100); + + /* + * TODO(sjg@chromium.org): This manually inserts the pointers into + * the code. Tidy this up to avoid this. + */ + func = (func_t)ptr; + ulong ofs = (ulong)cpu_call64 - (ulong)ptr; + *(ulong *)(ptr + 7) = (ulong)gdt; + *(ulong *)(ptr + 0xc) = (ulong)gdt + 2; + *(ulong *)(ptr + 0x13) = (ulong)gdt; + *(ulong *)(ptr + 0x117 - 0xd4) -= ofs; + + /* + * Copy U-Boot from ROM + * TODO(sjg@chromium.org): Figure out a way to get the text base + * correctly here, and in the device-tree binman definition. + * + * Also consider using FIT so we get the correct image length and + * parameters. + */ + memcpy((char *)target, (char *)0xfff00000, 0x100000); + + /* Jump to U-Boot */ + func((ulong)pgtable, 0, (ulong)target); + + return -EFAULT; +} + +#ifdef CONFIG_SMP +static int enable_smis(struct udevice *cpu, void *unused) +{ + return 0; +} + +static struct mp_flight_record mp_steps[] = { + MP_FR_BLOCK_APS(mp_init_cpu, NULL, mp_init_cpu, NULL), + /* Wait for APs to finish initialization before proceeding */ + MP_FR_BLOCK_APS(NULL, NULL, enable_smis, NULL), +}; + +int x86_mp_init(void) +{ + struct mp_params mp_params; + + mp_params.parallel_microcode_load = 0, + mp_params.flight_plan = &mp_steps[0]; + mp_params.num_records = ARRAY_SIZE(mp_steps); + mp_params.microcode_pointer = 0; + + if (mp_init(&mp_params)) { + printf("Warning: MP init failure\n"); + return -EIO; + } + + return 0; +} +#endif diff --git a/arch/x86/cpu/interrupts.c b/arch/x86/cpu/i386/interrupt.c index 5f6cdd3..a058303 100644 --- a/arch/x86/cpu/interrupts.c +++ b/arch/x86/cpu/i386/interrupt.c @@ -13,16 +13,12 @@ #include <common.h> #include <dm.h> -#include <asm/cache.h> #include <asm/control_regs.h> #include <asm/i8259.h> #include <asm/interrupt.h> #include <asm/io.h> #include <asm/lapic.h> -#include <asm/msr.h> #include <asm/processor-flags.h> -#include <asm/processor.h> -#include <asm/u-boot-x86.h> DECLARE_GLOBAL_DATA_PTR; @@ -238,7 +234,7 @@ int disable_interrupts(void) { long flags; -#ifdef CONFIG_X86_64 +#if CONFIG_IS_ENABLED(X86_64) asm volatile ("pushfq ; popq %0 ; cli\n" : "=g" (flags) : ); #else asm volatile ("pushfl ; popl %0 ; cli\n" : "=g" (flags) : ); diff --git a/arch/x86/cpu/setjmp.S b/arch/x86/cpu/i386/setjmp.S index 2ea1c6c..2ea1c6c 100644 --- a/arch/x86/cpu/setjmp.S +++ b/arch/x86/cpu/i386/setjmp.S diff --git a/arch/x86/cpu/intel_common/Makefile b/arch/x86/cpu/intel_common/Makefile index 804c539..1145e78 100644 --- a/arch/x86/cpu/intel_common/Makefile +++ b/arch/x86/cpu/intel_common/Makefile @@ -4,13 +4,15 @@ # SPDX-License-Identifier: GPL-2.0+ # -obj-$(CONFIG_HAVE_MRC) += car.o +ifdef CONFIG_HAVE_MRC +obj-$(CONFIG_$(SPL_)X86_32BIT_INIT) += car.o +obj-$(CONFIG_$(SPL_)X86_32BIT_INIT) += me_status.o +obj-$(CONFIG_$(SPL_)X86_32BIT_INIT) += report_platform.o +obj-$(CONFIG_$(SPL_)X86_32BIT_INIT) += mrc.o +endif obj-y += cpu.o obj-y += lpc.o -obj-$(CONFIG_HAVE_MRC) += me_status.o ifndef CONFIG_TARGET_EFI obj-y += microcode.o endif obj-y += pch.o -obj-$(CONFIG_HAVE_MRC) += report_platform.o -obj-$(CONFIG_HAVE_MRC) += mrc.o diff --git a/arch/x86/cpu/intel_common/lpc.c b/arch/x86/cpu/intel_common/lpc.c index 03cb45b..696b630 100644 --- a/arch/x86/cpu/intel_common/lpc.c +++ b/arch/x86/cpu/intel_common/lpc.c @@ -50,7 +50,7 @@ int lpc_common_early_init(struct udevice *dev) int count; int i; - count = fdtdec_get_int_array_count(gd->fdt_blob, dev->of_offset, + count = fdtdec_get_int_array_count(gd->fdt_blob, dev_of_offset(dev), "intel,gen-dec", (u32 *)values, sizeof(values) / sizeof(u32)); if (count < 0) diff --git a/arch/x86/cpu/intel_common/mrc.c b/arch/x86/cpu/intel_common/mrc.c index 01b6e86..f1a249a 100644 --- a/arch/x86/cpu/intel_common/mrc.c +++ b/arch/x86/cpu/intel_common/mrc.c @@ -149,7 +149,7 @@ int mrc_locate_spd(struct udevice *dev, int size, const void **spd_datap) spd_index = dm_gpio_get_values_as_int(desc, ret); debug("spd index %d\n", spd_index); - node = fdt_first_subnode(blob, dev->of_offset); + node = fdt_first_subnode(blob, dev_of_offset(dev)); if (node < 0) return -EINVAL; for (spd_node = fdt_first_subnode(blob, node); diff --git a/arch/x86/cpu/irq.c b/arch/x86/cpu/irq.c index 9364410..f5654eb 100644 --- a/arch/x86/cpu/irq.c +++ b/arch/x86/cpu/irq.c @@ -17,8 +17,6 @@ DECLARE_GLOBAL_DATA_PTR; -static struct irq_routing_table *pirq_routing_table; - bool pirq_check_irq_routed(struct udevice *dev, int link, u8 irq) { struct irq_router *priv = dev_get_priv(dev); @@ -28,7 +26,7 @@ bool pirq_check_irq_routed(struct udevice *dev, int link, u8 irq) if (priv->config == PIRQ_VIA_PCI) dm_pci_read_config8(dev->parent, LINK_N2V(link, base), &pirq); else - pirq = readb(priv->ibase + LINK_N2V(link, base)); + pirq = readb((uintptr_t)priv->ibase + LINK_N2V(link, base)); pirq &= 0xf; @@ -58,7 +56,7 @@ void pirq_assign_irq(struct udevice *dev, int link, u8 irq) if (priv->config == PIRQ_VIA_PCI) dm_pci_write_config8(dev->parent, LINK_N2V(link, base), irq); else - writeb(irq, priv->ibase + LINK_N2V(link, base)); + writeb(irq, (uintptr_t)priv->ibase + LINK_N2V(link, base)); } static struct irq_info *check_dup_entry(struct irq_info *slot_base, @@ -98,7 +96,7 @@ static int create_pirq_routing_table(struct udevice *dev) int i; int ret; - node = dev->of_offset; + node = dev_of_offset(dev); /* extract the bdf from fdt_pci_addr */ priv->bdf = dm_pci_get_bdf(dev->parent); @@ -219,7 +217,7 @@ static int create_pirq_routing_table(struct udevice *dev) /* Fix up the table checksum */ rt->checksum = table_compute_checksum(rt, rt->size); - pirq_routing_table = rt; + gd->arch.pirq_routing_table = rt; return 0; } @@ -236,7 +234,7 @@ static void irq_enable_sci(struct udevice *dev) if (priv->config == PIRQ_VIA_PCI) dm_pci_write_config32(dev->parent, priv->actl_addr, 0); else - writel(0, priv->ibase + priv->actl_addr); + writel(0, (uintptr_t)priv->ibase + priv->actl_addr); } } @@ -250,8 +248,8 @@ int irq_router_common_init(struct udevice *dev) return ret; } /* Route PIRQ */ - pirq_route_irqs(dev, pirq_routing_table->slots, - get_irq_slot_count(pirq_routing_table)); + pirq_route_irqs(dev, gd->arch.pirq_routing_table->slots, + get_irq_slot_count(gd->arch.pirq_routing_table)); if (IS_ENABLED(CONFIG_GENERATE_ACPI_TABLE)) irq_enable_sci(dev); @@ -264,12 +262,12 @@ int irq_router_probe(struct udevice *dev) return irq_router_common_init(dev); } -u32 write_pirq_routing_table(u32 addr) +ulong write_pirq_routing_table(ulong addr) { - if (!pirq_routing_table) + if (!gd->arch.pirq_routing_table) return addr; - return copy_pirq_routing_table(addr, pirq_routing_table); + return copy_pirq_routing_table(addr, gd->arch.pirq_routing_table); } static const struct udevice_id irq_router_ids[] = { diff --git a/arch/x86/cpu/ivybridge/Makefile b/arch/x86/cpu/ivybridge/Makefile index 498e71a..25fbd59 100644 --- a/arch/x86/cpu/ivybridge/Makefile +++ b/arch/x86/cpu/ivybridge/Makefile @@ -7,12 +7,17 @@ ifdef CONFIG_HAVE_FSP obj-y += fsp_configs.o ivybridge.o else -obj-y += cpu.o +obj-$(CONFIG_$(SPL_)X86_32BIT_INIT) += cpu.o obj-y += early_me.o obj-y += lpc.o obj-y += model_206ax.o obj-y += northbridge.o +ifndef CONFIG_SPL_BUILD obj-y += sata.o -obj-y += sdram.o +endif +obj-$(CONFIG_$(SPL_)X86_32BIT_INIT) += sdram.o +ifndef CONFIG_$(SPL_)X86_32BIT_INIT +obj-y += sdram_nop.o +endif endif obj-y += bd82x6x.o diff --git a/arch/x86/cpu/ivybridge/bd82x6x.c b/arch/x86/cpu/ivybridge/bd82x6x.c index e63ea6b..e3eff69 100644 --- a/arch/x86/cpu/ivybridge/bd82x6x.c +++ b/arch/x86/cpu/ivybridge/bd82x6x.c @@ -19,6 +19,8 @@ #include <asm/arch/pch.h> #include <asm/arch/sandybridge.h> +DECLARE_GLOBAL_DATA_PTR; + #define GPIO_BASE 0x48 #define BIOS_CTRL 0xdc diff --git a/arch/x86/cpu/ivybridge/cpu.c b/arch/x86/cpu/ivybridge/cpu.c index 85e361a..c4aca08 100644 --- a/arch/x86/cpu/ivybridge/cpu.c +++ b/arch/x86/cpu/ivybridge/cpu.c @@ -169,8 +169,10 @@ int print_cpuinfo(void) /* Enable SPD ROMs and DDR-III DRAM */ ret = uclass_first_device_err(UCLASS_I2C, &dev); - if (ret) + if (ret) { + debug("%s: Failed to get I2C (ret=%d)\n", __func__, ret); return ret; + } /* Prepare USB controller early in S3 resume */ if (boot_mode == PEI_BOOT_RESUME) { diff --git a/arch/x86/cpu/ivybridge/lpc.c b/arch/x86/cpu/ivybridge/lpc.c index 4af89b3..4e254b3 100644 --- a/arch/x86/cpu/ivybridge/lpc.c +++ b/arch/x86/cpu/ivybridge/lpc.c @@ -20,6 +20,8 @@ #include <asm/pci.h> #include <asm/arch/pch.h> +DECLARE_GLOBAL_DATA_PTR; + #define NMI_OFF 0 #define ENABLE_ACPI_MODE_IN_COREBOOT 0 @@ -84,7 +86,7 @@ static int pch_pirq_init(struct udevice *pch) { uint8_t route[8], *ptr; - if (fdtdec_get_byte_array(gd->fdt_blob, pch->of_offset, + if (fdtdec_get_byte_array(gd->fdt_blob, dev_of_offset(pch), "intel,pirq-routing", route, sizeof(route))) return -EINVAL; ptr = route; @@ -111,7 +113,7 @@ static int pch_gpi_routing(struct udevice *pch) u32 reg; int gpi; - if (fdtdec_get_byte_array(gd->fdt_blob, pch->of_offset, + if (fdtdec_get_byte_array(gd->fdt_blob, dev_of_offset(pch), "intel,gpi-routing", route, sizeof(route))) return -EINVAL; @@ -126,7 +128,7 @@ static int pch_gpi_routing(struct udevice *pch) static int pch_power_options(struct udevice *pch) { const void *blob = gd->fdt_blob; - int node = pch->of_offset; + int node = dev_of_offset(pch); u8 reg8; u16 reg16, pmbase; u32 reg32; diff --git a/arch/x86/cpu/ivybridge/model_206ax.c b/arch/x86/cpu/ivybridge/model_206ax.c index 09b5342..81dedee 100644 --- a/arch/x86/cpu/ivybridge/model_206ax.c +++ b/arch/x86/cpu/ivybridge/model_206ax.c @@ -22,6 +22,8 @@ #include <asm/turbo.h> #include <asm/arch/model_206ax.h> +DECLARE_GLOBAL_DATA_PTR; + static void enable_vmx(void) { struct cpuid_result regs; @@ -286,8 +288,8 @@ static int configure_thermal_target(struct udevice *dev) int tcc_offset; msr_t msr; - tcc_offset = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "tcc-offset", - 0); + tcc_offset = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), + "tcc-offset", 0); /* Set TCC activaiton offset if supported */ msr = msr_read(MSR_PLATFORM_INFO); diff --git a/arch/x86/cpu/ivybridge/northbridge.c b/arch/x86/cpu/ivybridge/northbridge.c index 491f289..94f31c4 100644 --- a/arch/x86/cpu/ivybridge/northbridge.c +++ b/arch/x86/cpu/ivybridge/northbridge.c @@ -19,6 +19,8 @@ #include <asm/arch/model_206ax.h> #include <asm/arch/sandybridge.h> +DECLARE_GLOBAL_DATA_PTR; + int bridge_silicon_revision(struct udevice *dev) { struct cpuid_result result; diff --git a/arch/x86/cpu/ivybridge/sata.c b/arch/x86/cpu/ivybridge/sata.c index 87ff872..0f5e190 100644 --- a/arch/x86/cpu/ivybridge/sata.c +++ b/arch/x86/cpu/ivybridge/sata.c @@ -39,7 +39,7 @@ static void bd82x6x_sata_init(struct udevice *dev, struct udevice *pch) { unsigned int port_map, speed_support, port_tx; const void *blob = gd->fdt_blob; - int node = dev->of_offset; + int node = dev_of_offset(dev); const char *mode; u32 reg32; u16 reg16; @@ -53,7 +53,7 @@ static void bd82x6x_sata_init(struct udevice *dev, struct udevice *pch) mode = fdt_getprop(blob, node, "intel,sata-mode", NULL); if (!mode || !strcmp(mode, "ahci")) { - u32 abar; + ulong abar; debug("SATA: Controller in AHCI mode\n"); @@ -72,7 +72,7 @@ static void bd82x6x_sata_init(struct udevice *dev, struct udevice *pch) /* Initialize AHCI memory-mapped space */ abar = dm_pci_read_bar32(dev, 5); - debug("ABAR: %08X\n", abar); + debug("ABAR: %08lx\n", abar); /* CAP (HBA Capabilities) : enable power management */ reg32 = readl(abar + 0x00); reg32 |= 0x0c006000; /* set PSC+SSC+SALP+SSS */ @@ -190,7 +190,7 @@ static void bd82x6x_sata_init(struct udevice *dev, struct udevice *pch) static void bd82x6x_sata_enable(struct udevice *dev) { const void *blob = gd->fdt_blob; - int node = dev->of_offset; + int node = dev_of_offset(dev); unsigned port_map; const char *mode; u16 map = 0; diff --git a/arch/x86/cpu/ivybridge/sdram.c b/arch/x86/cpu/ivybridge/sdram.c index e0b06b5..201368c 100644 --- a/arch/x86/cpu/ivybridge/sdram.c +++ b/arch/x86/cpu/ivybridge/sdram.c @@ -207,8 +207,10 @@ static int copy_spd(struct udevice *dev, struct pei_data *peid) int ret; ret = mrc_locate_spd(dev, sizeof(peid->spd_data[0]), &data); - if (ret) + if (ret) { + debug("%s: Could not locate SPD (ret=%d)\n", __func__, ret); return ret; + } memcpy(peid->spd_data[0], data, sizeof(peid->spd_data[0])); @@ -460,18 +462,27 @@ int dram_init(void) /* We need the pinctrl set up early */ ret = syscon_get_by_driver_data(X86_SYSCON_PINCONF, &dev); - if (ret) + if (ret) { + debug("%s: Could not get pinconf (ret=%d)\n", __func__, ret); return ret; + } ret = uclass_first_device_err(UCLASS_NORTHBRIDGE, &dev); - if (ret) + if (ret) { + debug("%s: Could not get northbridge (ret=%d)\n", __func__, + ret); return ret; + } ret = syscon_get_by_driver_data(X86_SYSCON_ME, &me_dev); - if (ret) + if (ret) { + debug("%s: Could not get ME (ret=%d)\n", __func__, ret); return ret; + } ret = copy_spd(dev, pei_data); - if (ret) + if (ret) { + debug("%s: Could not get SPD (ret=%d)\n", __func__, ret); return ret; + } pei_data->boot_mode = gd->arch.pei_boot_mode; debug("Boot mode %d\n", gd->arch.pei_boot_mode); debug("mrc_input %p\n", pei_data->mrc_input); @@ -498,19 +509,27 @@ int dram_init(void) /* Wait for ME to be ready */ ret = intel_early_me_init(me_dev); - if (ret) + if (ret) { + debug("%s: Could not init ME (ret=%d)\n", __func__, ret); return ret; + } ret = intel_early_me_uma_size(me_dev); - if (ret < 0) + if (ret < 0) { + debug("%s: Could not get UMA size (ret=%d)\n", __func__, ret); return ret; + } ret = mrc_common_init(dev, pei_data, false); - if (ret) + if (ret) { + debug("%s: mrc_common_init() failed (ret=%d)\n", __func__, ret); return ret; + } ret = sdram_find(dev); - if (ret) + if (ret) { + debug("%s: sdram_find() failed (ret=%d)\n", __func__, ret); return ret; + } gd->ram_size = gd->arch.meminfo.total_32bit_memory; debug("MRC output data length %#x at %p\n", pei_data->mrc_output_len, diff --git a/arch/x86/cpu/ivybridge/sdram_nop.c b/arch/x86/cpu/ivybridge/sdram_nop.c new file mode 100644 index 0000000..bd1189e --- /dev/null +++ b/arch/x86/cpu/ivybridge/sdram_nop.c @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2016 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> + +DECLARE_GLOBAL_DATA_PTR; + +int dram_init(void) +{ + gd->ram_size = 1ULL << 31; + gd->bd->bi_dram[0].start = 0; + gd->bd->bi_dram[0].size = gd->ram_size; + + return 0; +} diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c index 2b6b3bd..988073c 100644 --- a/arch/x86/cpu/mp_init.c +++ b/arch/x86/cpu/mp_init.c @@ -568,7 +568,8 @@ int mp_init_cpu(struct udevice *cpu, void *unused) * seq num in the uclass_resolve_seq() during device_probe(). To avoid * this, set req_seq to the reg number in the device tree in advance. */ - cpu->req_seq = fdtdec_get_int(gd->fdt_blob, cpu->of_offset, "reg", -1); + cpu->req_seq = fdtdec_get_int(gd->fdt_blob, dev_of_offset(cpu), "reg", + -1); plat->ucode_version = microcode_read_rev(); plat->device_id = gd->arch.x86_device; diff --git a/arch/x86/cpu/qemu/e820.c b/arch/x86/cpu/qemu/e820.c index 63853e4..c1c9b89 100644 --- a/arch/x86/cpu/qemu/e820.c +++ b/arch/x86/cpu/qemu/e820.c @@ -7,6 +7,8 @@ #include <common.h> #include <asm/e820.h> +DECLARE_GLOBAL_DATA_PTR; + unsigned install_e820_map(unsigned max_entries, struct e820entry *entries) { entries[0].addr = 0; diff --git a/arch/x86/cpu/qemu/qemu.c b/arch/x86/cpu/qemu/qemu.c index c3092f2..7153eb2 100644 --- a/arch/x86/cpu/qemu/qemu.c +++ b/arch/x86/cpu/qemu/qemu.c @@ -47,7 +47,7 @@ static void qemu_x86_fwcfg_read_entry_pio(uint16_t entry, static void qemu_x86_fwcfg_read_entry_dma(struct fw_cfg_dma_access *dma) { /* the DMA address register is big endian */ - outl(cpu_to_be32((uint32_t)dma), FW_DMA_PORT_HIGH); + outl(cpu_to_be32((uintptr_t)dma), FW_DMA_PORT_HIGH); while (be32_to_cpu(dma->control) & ~FW_CFG_DMA_ERROR) __asm__ __volatile__ ("pause"); @@ -137,14 +137,17 @@ static void qemu_chipset_init(void) #endif } +#if !CONFIG_IS_ENABLED(SPL_X86_32BIT_INIT) int arch_cpu_init(void) { post_code(POST_CPU_INIT); return x86_cpu_init_f(); } +#endif -#ifndef CONFIG_EFI_STUB +#if !CONFIG_IS_ENABLED(EFI_STUB) && \ + !CONFIG_IS_ENABLED(SPL_X86_32BIT_INIT) int print_cpuinfo(void) { post_code(POST_CPU_INFO); diff --git a/arch/x86/cpu/start.S b/arch/x86/cpu/start.S index a5cba1c..8de55a0 100644 --- a/arch/x86/cpu/start.S +++ b/arch/x86/cpu/start.S @@ -18,14 +18,6 @@ #include <generated/generic-asm-offsets.h> #include <generated/asm-offsets.h> -/* - * Define this to boot U-Boot from a 32-bit program which sets the GDT - * differently. This can be used to boot directly from any stage of coreboot, - * for example, bypassing the normal payload-loading feature. - * This is only useful for development. - */ -#undef LOAD_FROM_32_BIT - .section .text .code32 .globl _start @@ -76,7 +68,7 @@ _start: /* Save table pointer */ movl %ecx, %esi -#ifdef LOAD_FROM_32_BIT +#ifdef CONFIG_X86_LOAD_FROM_32_BIT lgdt gdt_ptr2 #endif @@ -233,7 +225,7 @@ multiboot_header: /* entry addr */ .long CONFIG_SYS_TEXT_BASE -#ifdef LOAD_FROM_32_BIT +#ifdef CONFIG_X86_LOAD_FROM_32_BIT /* * The following Global Descriptor Table is just enough to get us into * 'Flat Protected Mode' - It will be discarded as soon as the final diff --git a/arch/x86/cpu/start64.S b/arch/x86/cpu/start64.S new file mode 100644 index 0000000..651f16a --- /dev/null +++ b/arch/x86/cpu/start64.S @@ -0,0 +1,28 @@ +/* + * 64-bit x86 Startup Code + * + * (C) Copyright 216 Google, Inc + * Written by Simon Glass <sjg@chromium.org> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <config.h> + +.section .text +.code64 +.globl _start +.type _start, @function +_start: + /* Set up memory using the existing stack */ + mov %rsp, %rdi + call board_init_f_alloc_reserve + mov %rax, %rsp + + call board_init_f_init_reserve + + call board_init_f + call board_init_f_r + + /* Should not return here */ + jmp . diff --git a/arch/x86/cpu/turbo.c b/arch/x86/cpu/turbo.c index 254d0de..bbd255e 100644 --- a/arch/x86/cpu/turbo.c +++ b/arch/x86/cpu/turbo.c @@ -12,6 +12,8 @@ #include <asm/processor.h> #include <asm/turbo.h> +DECLARE_GLOBAL_DATA_PTR; + #if CONFIG_CPU_INTEL_TURBO_NOT_PACKAGE_SCOPED static inline int get_global_turbo_state(void) { @@ -22,16 +24,14 @@ static inline void set_global_turbo_state(int state) { } #else -static int g_turbo_state = TURBO_UNKNOWN; - static inline int get_global_turbo_state(void) { - return g_turbo_state; + return gd->arch.turbo_state; } static inline void set_global_turbo_state(int state) { - g_turbo_state = state; + gd->arch.turbo_state = state; } #endif diff --git a/arch/x86/cpu/u-boot-64.lds b/arch/x86/cpu/u-boot-64.lds new file mode 100644 index 0000000..718790c --- /dev/null +++ b/arch/x86/cpu/u-boot-64.lds @@ -0,0 +1,76 @@ +/* + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB, daniel@omicron.se. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <config.h> +OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") +OUTPUT_ARCH(i386:x86-64) +ENTRY(_start) + +SECTIONS +{ +#ifndef CONFIG_CMDLINE + /DISCARD/ : { *(.u_boot_list_2_cmd_*) } +#endif + + . = CONFIG_SYS_TEXT_BASE; /* Location of bootcode in flash */ + __text_start = .; + .text : { *(.text*); } + + . = ALIGN(4); + + . = ALIGN(4); + .u_boot_list : { + KEEP(*(SORT(.u_boot_list*))); + } + + . = ALIGN(4); + .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } + + . = ALIGN(4); + .data : { *(.data*) } + + . = ALIGN(4); + .hash : { *(.hash*) } + + . = ALIGN(4); + .got : { *(.got*) } + + . = ALIGN(4); + __data_end = .; + __init_end = .; + + . = ALIGN(4); + .dynsym : { *(.dynsym*) } + + . = ALIGN(4); + __rel_dyn_start = .; + .rela.dyn : { + *(.rela*) + } + __rel_dyn_end = .; + . = ALIGN(4); + + .dynamic : { *(.dynamic) } + + . = ALIGN(4); + _end = .; + + .bss __rel_dyn_start (OVERLAY) : { + __bss_start = .; + *(.bss) + *(COM*) + . = ALIGN(4); + __bss_end = .; + } + + /DISCARD/ : { *(.dynsym) } + /DISCARD/ : { *(.dynstr*) } + /DISCARD/ : { *(.dynamic*) } + /DISCARD/ : { *(.plt*) } + /DISCARD/ : { *(.interp*) } + /DISCARD/ : { *(.gnu*) } +} diff --git a/arch/x86/cpu/u-boot-spl.lds b/arch/x86/cpu/u-boot-spl.lds new file mode 100644 index 0000000..8a38d58 --- /dev/null +++ b/arch/x86/cpu/u-boot-spl.lds @@ -0,0 +1,74 @@ +/* + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB, daniel@omicron.se. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <config.h> +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) + +SECTIONS +{ +#ifndef CONFIG_CMDLINE + /DISCARD/ : { *(.u_boot_list_2_cmd_*) } +#endif + + . = CONFIG_SPL_TEXT_BASE; /* Location of bootcode in flash */ + __text_start = .; + .text : { *(.text*); } + + . = ALIGN(4); + + . = ALIGN(4); + .u_boot_list : { + KEEP(*(SORT(.u_boot_list*))); + } + + . = ALIGN(4); + .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } + + . = ALIGN(4); + .data : { *(.data*) } + + . = ALIGN(4); + __data_end = .; + __init_end = .; + + _image_binary_end = .; + + . = 0x120000; + .bss (OVERLAY) : { + __bss_start = .; + *(.bss*) + *(COM*) + . = ALIGN(4); + __bss_end = .; + } + __bss_size = __bss_end - __bss_start; + + /DISCARD/ : { *(.dynstr*) } + /DISCARD/ : { *(.dynamic*) } + /DISCARD/ : { *(.plt*) } + /DISCARD/ : { *(.interp*) } + /DISCARD/ : { *(.gnu*) } + +#ifdef CONFIG_SPL_X86_16BIT_INIT + /* + * The following expressions place the 16-bit Real-Mode code and + * Reset Vector at the end of the Flash ROM + */ + . = START_16 - RESET_SEG_START; + .start16 : AT (START_16) { + KEEP(*(.start16)); + } + + . = RESET_VEC_LOC - RESET_SEG_START; + .resetvec : AT (RESET_VEC_LOC) { + KEEP(*(.resetvec)); + } +#endif + +} diff --git a/arch/x86/cpu/u-boot.lds b/arch/x86/cpu/u-boot.lds index cca536b..186718d 100644 --- a/arch/x86/cpu/u-boot.lds +++ b/arch/x86/cpu/u-boot.lds @@ -103,7 +103,7 @@ SECTIONS /DISCARD/ : { *(.interp*) } /DISCARD/ : { *(.gnu*) } -#ifdef CONFIG_X86_RESET_VECTOR +#ifdef CONFIG_X86_16BIT_INIT /* * The following expressions place the 16-bit Real-Mode code and * Reset Vector at the end of the Flash ROM diff --git a/arch/x86/cpu/x86_64/Makefile b/arch/x86/cpu/x86_64/Makefile new file mode 100644 index 0000000..400f0ff --- /dev/null +++ b/arch/x86/cpu/x86_64/Makefile @@ -0,0 +1,6 @@ +# +# (C) Copyright 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# + +obj-y += cpu.o interrupts.o setjmp.o diff --git a/arch/x86/cpu/x86_64/cpu.c b/arch/x86/cpu/x86_64/cpu.c new file mode 100644 index 0000000..db171f7 --- /dev/null +++ b/arch/x86/cpu/x86_64/cpu.c @@ -0,0 +1,73 @@ +/* + * (C) Copyright 2016 Google, Inc + * Written by Simon Glass <sjg@chromium.org> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <debug_uart.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* Global declaration of gd */ +struct global_data *global_data_ptr; + +void arch_setup_gd(gd_t *new_gd) +{ + global_data_ptr = new_gd; + + /* + * TODO(sjg@chromium.org): For some reason U-Boot does not boot + * without this line. It fails to start up U-Boot proper and instead + * restarts SPL. Need to figure out why: + * + * U-Boot SPL 2017.01 + * + * U-Boot SPL 2017.01 + * CPU: Intel(R) Core(TM) i5-3427U CPU @ 1.80GHz + * Trying to boot from SPIJumping to 64-bit U-Boot: Note many + * features are missing + * + * U-Boot SPL 2017.01 + */ +#ifdef CONFIG_DEBUG_UART + printch(' '); +#endif +} + +int cpu_has_64bit(void) +{ + return true; +} + +void enable_caches(void) +{ + /* Not implemented */ +} + +void disable_caches(void) +{ + /* Not implemented */ +} + +int dcache_status(void) +{ + return true; +} + +int x86_mp_init(void) +{ + /* Not implemented */ + return 0; +} + +int misc_init_r(void) +{ + return 0; +} + +int print_cpuinfo(void) +{ + return 0; +} diff --git a/arch/x86/cpu/x86_64/interrupts.c b/arch/x86/cpu/x86_64/interrupts.c new file mode 100644 index 0000000..3e06173 --- /dev/null +++ b/arch/x86/cpu/x86_64/interrupts.c @@ -0,0 +1,29 @@ +/* + * (C) Copyright 2016 Google, Inc + * Written by Simon Glass <sjg@chromium.org> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/processor-flags.h> + +void enable_interrupts(void) +{ + asm("sti\n"); +} + +int disable_interrupts(void) +{ + long flags; + + asm volatile ("pushfq ; popq %0 ; cli\n" : "=g" (flags) : ); + + return flags & X86_EFLAGS_IF; +} + +int interrupt_init(void) +{ + /* Nothing to do - this was already done in SPL */ + return 0; +} diff --git a/arch/x86/cpu/x86_64/setjmp.c b/arch/x86/cpu/x86_64/setjmp.c new file mode 100644 index 0000000..25f8d28 --- /dev/null +++ b/arch/x86/cpu/x86_64/setjmp.c @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2016 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/setjmp.h> + +int setjmp(struct jmp_buf_data *jmp_buf) +{ + printf("WARNING: setjmp() is not supported\n"); + + return 0; +} + +void longjmp(struct jmp_buf_data *jmp_buf, int val) +{ + printf("WARNING: longjmp() is not supported\n"); +} |