From: Simon Glass Date: Mon, 16 Jan 2017 14:03:57 +0000 (-0700) Subject: x86: Move the i386 code into its own directory X-Git-Tag: v2017.03-rc2~83 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=be059e8813082d6c07be5f69cb7febe37411ca47;p=u-boot x86: Move the i386 code into its own directory Much of the cpu and interrupt code cannot be compiled on 64-bit x86. Move it into its own directory and build it only in 32-bit mode. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile index 97b26b0fe7..41ad4818b7 100644 --- a/arch/x86/cpu/Makefile +++ b/arch/x86/cpu/Makefile @@ -14,7 +14,7 @@ else extra-y = start.o endif extra-$(CONFIG_$(SPL_)X86_16BIT_INIT) += resetvec.o start16.o -obj-y += interrupts.o cpu.o cpu_x86.o call64.o setjmp.o +obj-y += cpu.o cpu_x86.o call64.o setjmp.o AFLAGS_REMOVE_call32.o := -mregparm=3 \ $(if $(CONFIG_EFI_STUB_64BIT),-march=i386 -m32) @@ -37,3 +37,7 @@ obj-y += mtrr.o obj-$(CONFIG_PCI) += pci.o obj-$(CONFIG_SMP) += sipi_vector.o obj-y += turbo.o + +ifeq ($(CONFIG_$(SPL_)X86_64),) +obj-y += i386/ +endif diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index 7c1d6deda9..8fa6953588 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/i386/Makefile b/arch/x86/cpu/i386/Makefile new file mode 100644 index 0000000000..d3364955d8 --- /dev/null +++ b/arch/x86/cpu/i386/Makefile @@ -0,0 +1,7 @@ +# +# (C) Copyright 2016 Google, Inc +# Written by Simon Glass +# + +obj-y += cpu.o +obj-y += interrupt.o diff --git a/arch/x86/cpu/i386/cpu.c b/arch/x86/cpu/i386/cpu.c new file mode 100644 index 0000000000..09a5b919e0 --- /dev/null +++ b/arch/x86/cpu/i386/cpu.c @@ -0,0 +1,534 @@ +/* + * (C) Copyright 2008-2011 + * Graeme Russ, + * + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB, + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH + * Marius Groeger + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH + * Alex Zuepke + * + * Part of this file is adapted from coreboot + * src/arch/x86/lib/cpu.c + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +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; +} + +#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/i386/interrupt.c b/arch/x86/cpu/i386/interrupt.c new file mode 100644 index 0000000000..8dfbb4880f --- /dev/null +++ b/arch/x86/cpu/i386/interrupt.c @@ -0,0 +1,615 @@ +/* + * (C) Copyright 2008-2011 + * Graeme Russ, + * + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB, + * + * Portions of this file are derived from the Linux kernel source + * Copyright (C) 1991, 1992 Linus Torvalds + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +#define DECLARE_INTERRUPT(x) \ + ".globl irq_"#x"\n" \ + ".hidden irq_"#x"\n" \ + ".type irq_"#x", @function\n" \ + "irq_"#x":\n" \ + "pushl $"#x"\n" \ + "jmp irq_common_entry\n" + +static char *exceptions[] = { + "Divide Error", + "Debug", + "NMI Interrupt", + "Breakpoint", + "Overflow", + "BOUND Range Exceeded", + "Invalid Opcode (Undefined Opcode)", + "Device Not Avaiable (No Math Coprocessor)", + "Double Fault", + "Coprocessor Segment Overrun", + "Invalid TSS", + "Segment Not Present", + "Stack Segment Fault", + "General Protection", + "Page Fault", + "Reserved", + "x87 FPU Floating-Point Error", + "Alignment Check", + "Machine Check", + "SIMD Floating-Point Exception", + "Virtualization Exception", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved" +}; + +static void dump_regs(struct irq_regs *regs) +{ + unsigned long cs, eip, eflags; + unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L; + unsigned long d0, d1, d2, d3, d6, d7; + unsigned long sp; + + /* + * Some exceptions cause an error code to be saved on the current stack + * after the EIP value. We should extract CS/EIP/EFLAGS from different + * position on the stack based on the exception number. + */ + switch (regs->irq_id) { + case EXC_DF: + case EXC_TS: + case EXC_NP: + case EXC_SS: + case EXC_GP: + case EXC_PF: + case EXC_AC: + cs = regs->context.ctx2.xcs; + eip = regs->context.ctx2.eip; + eflags = regs->context.ctx2.eflags; + /* We should fix up the ESP due to error code */ + regs->esp += 4; + break; + default: + cs = regs->context.ctx1.xcs; + eip = regs->context.ctx1.eip; + eflags = regs->context.ctx1.eflags; + break; + } + + printf("EIP: %04x:[<%08lx>] EFLAGS: %08lx\n", + (u16)cs, eip, eflags); + if (gd->flags & GD_FLG_RELOC) + printf("Original EIP :[<%08lx>]\n", eip - gd->reloc_off); + + printf("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n", + regs->eax, regs->ebx, regs->ecx, regs->edx); + printf("ESI: %08lx EDI: %08lx EBP: %08lx ESP: %08lx\n", + regs->esi, regs->edi, regs->ebp, regs->esp); + printf(" DS: %04x ES: %04x FS: %04x GS: %04x SS: %04x\n", + (u16)regs->xds, (u16)regs->xes, (u16)regs->xfs, + (u16)regs->xgs, (u16)regs->xss); + + cr0 = read_cr0(); + cr2 = read_cr2(); + cr3 = read_cr3(); + cr4 = read_cr4(); + + printf("CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n", + cr0, cr2, cr3, cr4); + + d0 = get_debugreg(0); + d1 = get_debugreg(1); + d2 = get_debugreg(2); + d3 = get_debugreg(3); + + printf("DR0: %08lx DR1: %08lx DR2: %08lx DR3: %08lx\n", + d0, d1, d2, d3); + + d6 = get_debugreg(6); + d7 = get_debugreg(7); + printf("DR6: %08lx DR7: %08lx\n", + d6, d7); + + printf("Stack:\n"); + sp = regs->esp; + + sp += 64; + + while (sp > (regs->esp - 16)) { + if (sp == regs->esp) + printf("--->"); + else + printf(" "); + printf("0x%8.8lx : 0x%8.8lx\n", sp, (ulong)readl(sp)); + sp -= 4; + } +} + +static void do_exception(struct irq_regs *regs) +{ + printf("%s\n", exceptions[regs->irq_id]); + dump_regs(regs); + hang(); +} + +struct idt_entry { + u16 base_low; + u16 selector; + u8 res; + u8 access; + u16 base_high; +} __packed; + +struct desc_ptr { + unsigned short size; + unsigned long address; +} __packed; + +struct idt_entry idt[256] __aligned(16); + +struct desc_ptr idt_ptr; + +static inline void load_idt(const struct desc_ptr *dtr) +{ + asm volatile("cs lidt %0" : : "m" (*dtr)); +} + +void set_vector(u8 intnum, void *routine) +{ + idt[intnum].base_high = (u16)((ulong)(routine) >> 16); + idt[intnum].base_low = (u16)((ulong)(routine) & 0xffff); +} + +/* + * Ideally these would be defined static to avoid a checkpatch warning, but + * the compiler cannot see them in the inline asm and complains that they + * aren't defined + */ +void irq_0(void); +void irq_1(void); + +int cpu_init_interrupts(void) +{ + int i; + + int irq_entry_size = irq_1 - irq_0; + void *irq_entry = (void *)irq_0; + + /* Setup the IDT */ + for (i = 0; i < 256; i++) { + idt[i].access = 0x8e; + idt[i].res = 0; + idt[i].selector = X86_GDT_ENTRY_32BIT_CS * X86_GDT_ENTRY_SIZE; + set_vector(i, irq_entry); + irq_entry += irq_entry_size; + } + + idt_ptr.size = 256 * 8 - 1; + idt_ptr.address = (unsigned long) idt; + + load_idt(&idt_ptr); + + return 0; +} + +void *x86_get_idt(void) +{ + return &idt_ptr; +} + +void __do_irq(int irq) +{ + printf("Unhandled IRQ : %d\n", irq); +} +void do_irq(int irq) __attribute__((weak, alias("__do_irq"))); + +void enable_interrupts(void) +{ + asm("sti\n"); +} + +int disable_interrupts(void) +{ + long flags; + +#ifdef CONFIG_X86_64 + asm volatile ("pushfq ; popq %0 ; cli\n" : "=g" (flags) : ); +#else + asm volatile ("pushfl ; popl %0 ; cli\n" : "=g" (flags) : ); +#endif + return flags & X86_EFLAGS_IF; +} + +int interrupt_init(void) +{ + struct udevice *dev; + int ret; + + /* Try to set up the interrupt router, but don't require one */ + ret = uclass_first_device_err(UCLASS_IRQ, &dev); + if (ret && ret != -ENODEV) + return ret; + + /* + * When running as an EFI application we are not in control of + * interrupts and should leave them alone. + */ +#ifndef CONFIG_EFI_APP + /* Just in case... */ + disable_interrupts(); + +#ifdef CONFIG_I8259_PIC + /* Initialize the master/slave i8259 pic */ + i8259_init(); +#endif + + lapic_setup(); + + /* Initialize core interrupt and exception functionality of CPU */ + cpu_init_interrupts(); + + /* + * It is now safe to enable interrupts. + * + * TODO(sjg@chromium.org): But we don't handle these correctly when + * booted from EFI. + */ + if (ll_boot_init()) + enable_interrupts(); +#endif + + return 0; +} + +/* IRQ Low-Level Service Routine */ +void irq_llsr(struct irq_regs *regs) +{ + /* + * For detailed description of each exception, refer to: + * Intel® 64 and IA-32 Architectures Software Developer's Manual + * Volume 1: Basic Architecture + * Order Number: 253665-029US, November 2008 + * Table 6-1. Exceptions and Interrupts + */ + if (regs->irq_id < 32) { + /* Architecture defined exception */ + do_exception(regs); + } else { + /* Hardware or User IRQ */ + do_irq(regs->irq_id); + } +} + +/* + * OK - This looks really horrible, but it serves a purpose - It helps create + * fully relocatable code. + * - The call to irq_llsr will be a relative jump + * - The IRQ entries will be guaranteed to be in order + * Interrupt entries are now very small (a push and a jump) but they are + * now slower (all registers pushed on stack which provides complete + * crash dumps in the low level handlers + * + * Interrupt Entry Point: + * - Interrupt has caused eflags, CS and EIP to be pushed + * - Interrupt Vector Handler has pushed orig_eax + * - pt_regs.esp needs to be adjusted by 40 bytes: + * 12 bytes pushed by CPU (EFLAGSF, CS, EIP) + * 4 bytes pushed by vector handler (irq_id) + * 24 bytes pushed before SP (SS, GS, FS, ES, DS, EAX) + * NOTE: Only longs are pushed on/popped off the stack! + */ +asm(".globl irq_common_entry\n" \ + ".hidden irq_common_entry\n" \ + ".type irq_common_entry, @function\n" \ + "irq_common_entry:\n" \ + "cld\n" \ + "pushl %ss\n" \ + "pushl %gs\n" \ + "pushl %fs\n" \ + "pushl %es\n" \ + "pushl %ds\n" \ + "pushl %eax\n" \ + "movl %esp, %eax\n" \ + "addl $40, %eax\n" \ + "pushl %eax\n" \ + "pushl %ebp\n" \ + "pushl %edi\n" \ + "pushl %esi\n" \ + "pushl %edx\n" \ + "pushl %ecx\n" \ + "pushl %ebx\n" \ + "mov %esp, %eax\n" \ + "call irq_llsr\n" \ + "popl %ebx\n" \ + "popl %ecx\n" \ + "popl %edx\n" \ + "popl %esi\n" \ + "popl %edi\n" \ + "popl %ebp\n" \ + "popl %eax\n" \ + "popl %eax\n" \ + "popl %ds\n" \ + "popl %es\n" \ + "popl %fs\n" \ + "popl %gs\n" \ + "popl %ss\n" \ + "add $4, %esp\n" \ + "iret\n" \ + DECLARE_INTERRUPT(0) \ + DECLARE_INTERRUPT(1) \ + DECLARE_INTERRUPT(2) \ + DECLARE_INTERRUPT(3) \ + DECLARE_INTERRUPT(4) \ + DECLARE_INTERRUPT(5) \ + DECLARE_INTERRUPT(6) \ + DECLARE_INTERRUPT(7) \ + DECLARE_INTERRUPT(8) \ + DECLARE_INTERRUPT(9) \ + DECLARE_INTERRUPT(10) \ + DECLARE_INTERRUPT(11) \ + DECLARE_INTERRUPT(12) \ + DECLARE_INTERRUPT(13) \ + DECLARE_INTERRUPT(14) \ + DECLARE_INTERRUPT(15) \ + DECLARE_INTERRUPT(16) \ + DECLARE_INTERRUPT(17) \ + DECLARE_INTERRUPT(18) \ + DECLARE_INTERRUPT(19) \ + DECLARE_INTERRUPT(20) \ + DECLARE_INTERRUPT(21) \ + DECLARE_INTERRUPT(22) \ + DECLARE_INTERRUPT(23) \ + DECLARE_INTERRUPT(24) \ + DECLARE_INTERRUPT(25) \ + DECLARE_INTERRUPT(26) \ + DECLARE_INTERRUPT(27) \ + DECLARE_INTERRUPT(28) \ + DECLARE_INTERRUPT(29) \ + DECLARE_INTERRUPT(30) \ + DECLARE_INTERRUPT(31) \ + DECLARE_INTERRUPT(32) \ + DECLARE_INTERRUPT(33) \ + DECLARE_INTERRUPT(34) \ + DECLARE_INTERRUPT(35) \ + DECLARE_INTERRUPT(36) \ + DECLARE_INTERRUPT(37) \ + DECLARE_INTERRUPT(38) \ + DECLARE_INTERRUPT(39) \ + DECLARE_INTERRUPT(40) \ + DECLARE_INTERRUPT(41) \ + DECLARE_INTERRUPT(42) \ + DECLARE_INTERRUPT(43) \ + DECLARE_INTERRUPT(44) \ + DECLARE_INTERRUPT(45) \ + DECLARE_INTERRUPT(46) \ + DECLARE_INTERRUPT(47) \ + DECLARE_INTERRUPT(48) \ + DECLARE_INTERRUPT(49) \ + DECLARE_INTERRUPT(50) \ + DECLARE_INTERRUPT(51) \ + DECLARE_INTERRUPT(52) \ + DECLARE_INTERRUPT(53) \ + DECLARE_INTERRUPT(54) \ + DECLARE_INTERRUPT(55) \ + DECLARE_INTERRUPT(56) \ + DECLARE_INTERRUPT(57) \ + DECLARE_INTERRUPT(58) \ + DECLARE_INTERRUPT(59) \ + DECLARE_INTERRUPT(60) \ + DECLARE_INTERRUPT(61) \ + DECLARE_INTERRUPT(62) \ + DECLARE_INTERRUPT(63) \ + DECLARE_INTERRUPT(64) \ + DECLARE_INTERRUPT(65) \ + DECLARE_INTERRUPT(66) \ + DECLARE_INTERRUPT(67) \ + DECLARE_INTERRUPT(68) \ + DECLARE_INTERRUPT(69) \ + DECLARE_INTERRUPT(70) \ + DECLARE_INTERRUPT(71) \ + DECLARE_INTERRUPT(72) \ + DECLARE_INTERRUPT(73) \ + DECLARE_INTERRUPT(74) \ + DECLARE_INTERRUPT(75) \ + DECLARE_INTERRUPT(76) \ + DECLARE_INTERRUPT(77) \ + DECLARE_INTERRUPT(78) \ + DECLARE_INTERRUPT(79) \ + DECLARE_INTERRUPT(80) \ + DECLARE_INTERRUPT(81) \ + DECLARE_INTERRUPT(82) \ + DECLARE_INTERRUPT(83) \ + DECLARE_INTERRUPT(84) \ + DECLARE_INTERRUPT(85) \ + DECLARE_INTERRUPT(86) \ + DECLARE_INTERRUPT(87) \ + DECLARE_INTERRUPT(88) \ + DECLARE_INTERRUPT(89) \ + DECLARE_INTERRUPT(90) \ + DECLARE_INTERRUPT(91) \ + DECLARE_INTERRUPT(92) \ + DECLARE_INTERRUPT(93) \ + DECLARE_INTERRUPT(94) \ + DECLARE_INTERRUPT(95) \ + DECLARE_INTERRUPT(97) \ + DECLARE_INTERRUPT(96) \ + DECLARE_INTERRUPT(98) \ + DECLARE_INTERRUPT(99) \ + DECLARE_INTERRUPT(100) \ + DECLARE_INTERRUPT(101) \ + DECLARE_INTERRUPT(102) \ + DECLARE_INTERRUPT(103) \ + DECLARE_INTERRUPT(104) \ + DECLARE_INTERRUPT(105) \ + DECLARE_INTERRUPT(106) \ + DECLARE_INTERRUPT(107) \ + DECLARE_INTERRUPT(108) \ + DECLARE_INTERRUPT(109) \ + DECLARE_INTERRUPT(110) \ + DECLARE_INTERRUPT(111) \ + DECLARE_INTERRUPT(112) \ + DECLARE_INTERRUPT(113) \ + DECLARE_INTERRUPT(114) \ + DECLARE_INTERRUPT(115) \ + DECLARE_INTERRUPT(116) \ + DECLARE_INTERRUPT(117) \ + DECLARE_INTERRUPT(118) \ + DECLARE_INTERRUPT(119) \ + DECLARE_INTERRUPT(120) \ + DECLARE_INTERRUPT(121) \ + DECLARE_INTERRUPT(122) \ + DECLARE_INTERRUPT(123) \ + DECLARE_INTERRUPT(124) \ + DECLARE_INTERRUPT(125) \ + DECLARE_INTERRUPT(126) \ + DECLARE_INTERRUPT(127) \ + DECLARE_INTERRUPT(128) \ + DECLARE_INTERRUPT(129) \ + DECLARE_INTERRUPT(130) \ + DECLARE_INTERRUPT(131) \ + DECLARE_INTERRUPT(132) \ + DECLARE_INTERRUPT(133) \ + DECLARE_INTERRUPT(134) \ + DECLARE_INTERRUPT(135) \ + DECLARE_INTERRUPT(136) \ + DECLARE_INTERRUPT(137) \ + DECLARE_INTERRUPT(138) \ + DECLARE_INTERRUPT(139) \ + DECLARE_INTERRUPT(140) \ + DECLARE_INTERRUPT(141) \ + DECLARE_INTERRUPT(142) \ + DECLARE_INTERRUPT(143) \ + DECLARE_INTERRUPT(144) \ + DECLARE_INTERRUPT(145) \ + DECLARE_INTERRUPT(146) \ + DECLARE_INTERRUPT(147) \ + DECLARE_INTERRUPT(148) \ + DECLARE_INTERRUPT(149) \ + DECLARE_INTERRUPT(150) \ + DECLARE_INTERRUPT(151) \ + DECLARE_INTERRUPT(152) \ + DECLARE_INTERRUPT(153) \ + DECLARE_INTERRUPT(154) \ + DECLARE_INTERRUPT(155) \ + DECLARE_INTERRUPT(156) \ + DECLARE_INTERRUPT(157) \ + DECLARE_INTERRUPT(158) \ + DECLARE_INTERRUPT(159) \ + DECLARE_INTERRUPT(160) \ + DECLARE_INTERRUPT(161) \ + DECLARE_INTERRUPT(162) \ + DECLARE_INTERRUPT(163) \ + DECLARE_INTERRUPT(164) \ + DECLARE_INTERRUPT(165) \ + DECLARE_INTERRUPT(166) \ + DECLARE_INTERRUPT(167) \ + DECLARE_INTERRUPT(168) \ + DECLARE_INTERRUPT(169) \ + DECLARE_INTERRUPT(170) \ + DECLARE_INTERRUPT(171) \ + DECLARE_INTERRUPT(172) \ + DECLARE_INTERRUPT(173) \ + DECLARE_INTERRUPT(174) \ + DECLARE_INTERRUPT(175) \ + DECLARE_INTERRUPT(176) \ + DECLARE_INTERRUPT(177) \ + DECLARE_INTERRUPT(178) \ + DECLARE_INTERRUPT(179) \ + DECLARE_INTERRUPT(180) \ + DECLARE_INTERRUPT(181) \ + DECLARE_INTERRUPT(182) \ + DECLARE_INTERRUPT(183) \ + DECLARE_INTERRUPT(184) \ + DECLARE_INTERRUPT(185) \ + DECLARE_INTERRUPT(186) \ + DECLARE_INTERRUPT(187) \ + DECLARE_INTERRUPT(188) \ + DECLARE_INTERRUPT(189) \ + DECLARE_INTERRUPT(190) \ + DECLARE_INTERRUPT(191) \ + DECLARE_INTERRUPT(192) \ + DECLARE_INTERRUPT(193) \ + DECLARE_INTERRUPT(194) \ + DECLARE_INTERRUPT(195) \ + DECLARE_INTERRUPT(196) \ + DECLARE_INTERRUPT(197) \ + DECLARE_INTERRUPT(198) \ + DECLARE_INTERRUPT(199) \ + DECLARE_INTERRUPT(200) \ + DECLARE_INTERRUPT(201) \ + DECLARE_INTERRUPT(202) \ + DECLARE_INTERRUPT(203) \ + DECLARE_INTERRUPT(204) \ + DECLARE_INTERRUPT(205) \ + DECLARE_INTERRUPT(206) \ + DECLARE_INTERRUPT(207) \ + DECLARE_INTERRUPT(208) \ + DECLARE_INTERRUPT(209) \ + DECLARE_INTERRUPT(210) \ + DECLARE_INTERRUPT(211) \ + DECLARE_INTERRUPT(212) \ + DECLARE_INTERRUPT(213) \ + DECLARE_INTERRUPT(214) \ + DECLARE_INTERRUPT(215) \ + DECLARE_INTERRUPT(216) \ + DECLARE_INTERRUPT(217) \ + DECLARE_INTERRUPT(218) \ + DECLARE_INTERRUPT(219) \ + DECLARE_INTERRUPT(220) \ + DECLARE_INTERRUPT(221) \ + DECLARE_INTERRUPT(222) \ + DECLARE_INTERRUPT(223) \ + DECLARE_INTERRUPT(224) \ + DECLARE_INTERRUPT(225) \ + DECLARE_INTERRUPT(226) \ + DECLARE_INTERRUPT(227) \ + DECLARE_INTERRUPT(228) \ + DECLARE_INTERRUPT(229) \ + DECLARE_INTERRUPT(230) \ + DECLARE_INTERRUPT(231) \ + DECLARE_INTERRUPT(232) \ + DECLARE_INTERRUPT(233) \ + DECLARE_INTERRUPT(234) \ + DECLARE_INTERRUPT(235) \ + DECLARE_INTERRUPT(236) \ + DECLARE_INTERRUPT(237) \ + DECLARE_INTERRUPT(238) \ + DECLARE_INTERRUPT(239) \ + DECLARE_INTERRUPT(240) \ + DECLARE_INTERRUPT(241) \ + DECLARE_INTERRUPT(242) \ + DECLARE_INTERRUPT(243) \ + DECLARE_INTERRUPT(244) \ + DECLARE_INTERRUPT(245) \ + DECLARE_INTERRUPT(246) \ + DECLARE_INTERRUPT(247) \ + DECLARE_INTERRUPT(248) \ + DECLARE_INTERRUPT(249) \ + DECLARE_INTERRUPT(250) \ + DECLARE_INTERRUPT(251) \ + DECLARE_INTERRUPT(252) \ + DECLARE_INTERRUPT(253) \ + DECLARE_INTERRUPT(254) \ + DECLARE_INTERRUPT(255)); diff --git a/arch/x86/cpu/interrupts.c b/arch/x86/cpu/interrupts.c deleted file mode 100644 index 5f6cdd36ac..0000000000 --- a/arch/x86/cpu/interrupts.c +++ /dev/null @@ -1,619 +0,0 @@ -/* - * (C) Copyright 2008-2011 - * Graeme Russ, - * - * (C) Copyright 2002 - * Daniel Engström, Omicron Ceti AB, - * - * Portions of this file are derived from the Linux kernel source - * Copyright (C) 1991, 1992 Linus Torvalds - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -DECLARE_GLOBAL_DATA_PTR; - -#define DECLARE_INTERRUPT(x) \ - ".globl irq_"#x"\n" \ - ".hidden irq_"#x"\n" \ - ".type irq_"#x", @function\n" \ - "irq_"#x":\n" \ - "pushl $"#x"\n" \ - "jmp irq_common_entry\n" - -static char *exceptions[] = { - "Divide Error", - "Debug", - "NMI Interrupt", - "Breakpoint", - "Overflow", - "BOUND Range Exceeded", - "Invalid Opcode (Undefined Opcode)", - "Device Not Avaiable (No Math Coprocessor)", - "Double Fault", - "Coprocessor Segment Overrun", - "Invalid TSS", - "Segment Not Present", - "Stack Segment Fault", - "General Protection", - "Page Fault", - "Reserved", - "x87 FPU Floating-Point Error", - "Alignment Check", - "Machine Check", - "SIMD Floating-Point Exception", - "Virtualization Exception", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved" -}; - -static void dump_regs(struct irq_regs *regs) -{ - unsigned long cs, eip, eflags; - unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L; - unsigned long d0, d1, d2, d3, d6, d7; - unsigned long sp; - - /* - * Some exceptions cause an error code to be saved on the current stack - * after the EIP value. We should extract CS/EIP/EFLAGS from different - * position on the stack based on the exception number. - */ - switch (regs->irq_id) { - case EXC_DF: - case EXC_TS: - case EXC_NP: - case EXC_SS: - case EXC_GP: - case EXC_PF: - case EXC_AC: - cs = regs->context.ctx2.xcs; - eip = regs->context.ctx2.eip; - eflags = regs->context.ctx2.eflags; - /* We should fix up the ESP due to error code */ - regs->esp += 4; - break; - default: - cs = regs->context.ctx1.xcs; - eip = regs->context.ctx1.eip; - eflags = regs->context.ctx1.eflags; - break; - } - - printf("EIP: %04x:[<%08lx>] EFLAGS: %08lx\n", - (u16)cs, eip, eflags); - if (gd->flags & GD_FLG_RELOC) - printf("Original EIP :[<%08lx>]\n", eip - gd->reloc_off); - - printf("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n", - regs->eax, regs->ebx, regs->ecx, regs->edx); - printf("ESI: %08lx EDI: %08lx EBP: %08lx ESP: %08lx\n", - regs->esi, regs->edi, regs->ebp, regs->esp); - printf(" DS: %04x ES: %04x FS: %04x GS: %04x SS: %04x\n", - (u16)regs->xds, (u16)regs->xes, (u16)regs->xfs, - (u16)regs->xgs, (u16)regs->xss); - - cr0 = read_cr0(); - cr2 = read_cr2(); - cr3 = read_cr3(); - cr4 = read_cr4(); - - printf("CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n", - cr0, cr2, cr3, cr4); - - d0 = get_debugreg(0); - d1 = get_debugreg(1); - d2 = get_debugreg(2); - d3 = get_debugreg(3); - - printf("DR0: %08lx DR1: %08lx DR2: %08lx DR3: %08lx\n", - d0, d1, d2, d3); - - d6 = get_debugreg(6); - d7 = get_debugreg(7); - printf("DR6: %08lx DR7: %08lx\n", - d6, d7); - - printf("Stack:\n"); - sp = regs->esp; - - sp += 64; - - while (sp > (regs->esp - 16)) { - if (sp == regs->esp) - printf("--->"); - else - printf(" "); - printf("0x%8.8lx : 0x%8.8lx\n", sp, (ulong)readl(sp)); - sp -= 4; - } -} - -static void do_exception(struct irq_regs *regs) -{ - printf("%s\n", exceptions[regs->irq_id]); - dump_regs(regs); - hang(); -} - -struct idt_entry { - u16 base_low; - u16 selector; - u8 res; - u8 access; - u16 base_high; -} __packed; - -struct desc_ptr { - unsigned short size; - unsigned long address; -} __packed; - -struct idt_entry idt[256] __aligned(16); - -struct desc_ptr idt_ptr; - -static inline void load_idt(const struct desc_ptr *dtr) -{ - asm volatile("cs lidt %0" : : "m" (*dtr)); -} - -void set_vector(u8 intnum, void *routine) -{ - idt[intnum].base_high = (u16)((ulong)(routine) >> 16); - idt[intnum].base_low = (u16)((ulong)(routine) & 0xffff); -} - -/* - * Ideally these would be defined static to avoid a checkpatch warning, but - * the compiler cannot see them in the inline asm and complains that they - * aren't defined - */ -void irq_0(void); -void irq_1(void); - -int cpu_init_interrupts(void) -{ - int i; - - int irq_entry_size = irq_1 - irq_0; - void *irq_entry = (void *)irq_0; - - /* Setup the IDT */ - for (i = 0; i < 256; i++) { - idt[i].access = 0x8e; - idt[i].res = 0; - idt[i].selector = X86_GDT_ENTRY_32BIT_CS * X86_GDT_ENTRY_SIZE; - set_vector(i, irq_entry); - irq_entry += irq_entry_size; - } - - idt_ptr.size = 256 * 8 - 1; - idt_ptr.address = (unsigned long) idt; - - load_idt(&idt_ptr); - - return 0; -} - -void *x86_get_idt(void) -{ - return &idt_ptr; -} - -void __do_irq(int irq) -{ - printf("Unhandled IRQ : %d\n", irq); -} -void do_irq(int irq) __attribute__((weak, alias("__do_irq"))); - -void enable_interrupts(void) -{ - asm("sti\n"); -} - -int disable_interrupts(void) -{ - long flags; - -#ifdef CONFIG_X86_64 - asm volatile ("pushfq ; popq %0 ; cli\n" : "=g" (flags) : ); -#else - asm volatile ("pushfl ; popl %0 ; cli\n" : "=g" (flags) : ); -#endif - return flags & X86_EFLAGS_IF; -} - -int interrupt_init(void) -{ - struct udevice *dev; - int ret; - - /* Try to set up the interrupt router, but don't require one */ - ret = uclass_first_device_err(UCLASS_IRQ, &dev); - if (ret && ret != -ENODEV) - return ret; - - /* - * When running as an EFI application we are not in control of - * interrupts and should leave them alone. - */ -#ifndef CONFIG_EFI_APP - /* Just in case... */ - disable_interrupts(); - -#ifdef CONFIG_I8259_PIC - /* Initialize the master/slave i8259 pic */ - i8259_init(); -#endif - - lapic_setup(); - - /* Initialize core interrupt and exception functionality of CPU */ - cpu_init_interrupts(); - - /* - * It is now safe to enable interrupts. - * - * TODO(sjg@chromium.org): But we don't handle these correctly when - * booted from EFI. - */ - if (ll_boot_init()) - enable_interrupts(); -#endif - - return 0; -} - -/* IRQ Low-Level Service Routine */ -void irq_llsr(struct irq_regs *regs) -{ - /* - * For detailed description of each exception, refer to: - * Intel® 64 and IA-32 Architectures Software Developer's Manual - * Volume 1: Basic Architecture - * Order Number: 253665-029US, November 2008 - * Table 6-1. Exceptions and Interrupts - */ - if (regs->irq_id < 32) { - /* Architecture defined exception */ - do_exception(regs); - } else { - /* Hardware or User IRQ */ - do_irq(regs->irq_id); - } -} - -/* - * OK - This looks really horrible, but it serves a purpose - It helps create - * fully relocatable code. - * - The call to irq_llsr will be a relative jump - * - The IRQ entries will be guaranteed to be in order - * Interrupt entries are now very small (a push and a jump) but they are - * now slower (all registers pushed on stack which provides complete - * crash dumps in the low level handlers - * - * Interrupt Entry Point: - * - Interrupt has caused eflags, CS and EIP to be pushed - * - Interrupt Vector Handler has pushed orig_eax - * - pt_regs.esp needs to be adjusted by 40 bytes: - * 12 bytes pushed by CPU (EFLAGSF, CS, EIP) - * 4 bytes pushed by vector handler (irq_id) - * 24 bytes pushed before SP (SS, GS, FS, ES, DS, EAX) - * NOTE: Only longs are pushed on/popped off the stack! - */ -asm(".globl irq_common_entry\n" \ - ".hidden irq_common_entry\n" \ - ".type irq_common_entry, @function\n" \ - "irq_common_entry:\n" \ - "cld\n" \ - "pushl %ss\n" \ - "pushl %gs\n" \ - "pushl %fs\n" \ - "pushl %es\n" \ - "pushl %ds\n" \ - "pushl %eax\n" \ - "movl %esp, %eax\n" \ - "addl $40, %eax\n" \ - "pushl %eax\n" \ - "pushl %ebp\n" \ - "pushl %edi\n" \ - "pushl %esi\n" \ - "pushl %edx\n" \ - "pushl %ecx\n" \ - "pushl %ebx\n" \ - "mov %esp, %eax\n" \ - "call irq_llsr\n" \ - "popl %ebx\n" \ - "popl %ecx\n" \ - "popl %edx\n" \ - "popl %esi\n" \ - "popl %edi\n" \ - "popl %ebp\n" \ - "popl %eax\n" \ - "popl %eax\n" \ - "popl %ds\n" \ - "popl %es\n" \ - "popl %fs\n" \ - "popl %gs\n" \ - "popl %ss\n" \ - "add $4, %esp\n" \ - "iret\n" \ - DECLARE_INTERRUPT(0) \ - DECLARE_INTERRUPT(1) \ - DECLARE_INTERRUPT(2) \ - DECLARE_INTERRUPT(3) \ - DECLARE_INTERRUPT(4) \ - DECLARE_INTERRUPT(5) \ - DECLARE_INTERRUPT(6) \ - DECLARE_INTERRUPT(7) \ - DECLARE_INTERRUPT(8) \ - DECLARE_INTERRUPT(9) \ - DECLARE_INTERRUPT(10) \ - DECLARE_INTERRUPT(11) \ - DECLARE_INTERRUPT(12) \ - DECLARE_INTERRUPT(13) \ - DECLARE_INTERRUPT(14) \ - DECLARE_INTERRUPT(15) \ - DECLARE_INTERRUPT(16) \ - DECLARE_INTERRUPT(17) \ - DECLARE_INTERRUPT(18) \ - DECLARE_INTERRUPT(19) \ - DECLARE_INTERRUPT(20) \ - DECLARE_INTERRUPT(21) \ - DECLARE_INTERRUPT(22) \ - DECLARE_INTERRUPT(23) \ - DECLARE_INTERRUPT(24) \ - DECLARE_INTERRUPT(25) \ - DECLARE_INTERRUPT(26) \ - DECLARE_INTERRUPT(27) \ - DECLARE_INTERRUPT(28) \ - DECLARE_INTERRUPT(29) \ - DECLARE_INTERRUPT(30) \ - DECLARE_INTERRUPT(31) \ - DECLARE_INTERRUPT(32) \ - DECLARE_INTERRUPT(33) \ - DECLARE_INTERRUPT(34) \ - DECLARE_INTERRUPT(35) \ - DECLARE_INTERRUPT(36) \ - DECLARE_INTERRUPT(37) \ - DECLARE_INTERRUPT(38) \ - DECLARE_INTERRUPT(39) \ - DECLARE_INTERRUPT(40) \ - DECLARE_INTERRUPT(41) \ - DECLARE_INTERRUPT(42) \ - DECLARE_INTERRUPT(43) \ - DECLARE_INTERRUPT(44) \ - DECLARE_INTERRUPT(45) \ - DECLARE_INTERRUPT(46) \ - DECLARE_INTERRUPT(47) \ - DECLARE_INTERRUPT(48) \ - DECLARE_INTERRUPT(49) \ - DECLARE_INTERRUPT(50) \ - DECLARE_INTERRUPT(51) \ - DECLARE_INTERRUPT(52) \ - DECLARE_INTERRUPT(53) \ - DECLARE_INTERRUPT(54) \ - DECLARE_INTERRUPT(55) \ - DECLARE_INTERRUPT(56) \ - DECLARE_INTERRUPT(57) \ - DECLARE_INTERRUPT(58) \ - DECLARE_INTERRUPT(59) \ - DECLARE_INTERRUPT(60) \ - DECLARE_INTERRUPT(61) \ - DECLARE_INTERRUPT(62) \ - DECLARE_INTERRUPT(63) \ - DECLARE_INTERRUPT(64) \ - DECLARE_INTERRUPT(65) \ - DECLARE_INTERRUPT(66) \ - DECLARE_INTERRUPT(67) \ - DECLARE_INTERRUPT(68) \ - DECLARE_INTERRUPT(69) \ - DECLARE_INTERRUPT(70) \ - DECLARE_INTERRUPT(71) \ - DECLARE_INTERRUPT(72) \ - DECLARE_INTERRUPT(73) \ - DECLARE_INTERRUPT(74) \ - DECLARE_INTERRUPT(75) \ - DECLARE_INTERRUPT(76) \ - DECLARE_INTERRUPT(77) \ - DECLARE_INTERRUPT(78) \ - DECLARE_INTERRUPT(79) \ - DECLARE_INTERRUPT(80) \ - DECLARE_INTERRUPT(81) \ - DECLARE_INTERRUPT(82) \ - DECLARE_INTERRUPT(83) \ - DECLARE_INTERRUPT(84) \ - DECLARE_INTERRUPT(85) \ - DECLARE_INTERRUPT(86) \ - DECLARE_INTERRUPT(87) \ - DECLARE_INTERRUPT(88) \ - DECLARE_INTERRUPT(89) \ - DECLARE_INTERRUPT(90) \ - DECLARE_INTERRUPT(91) \ - DECLARE_INTERRUPT(92) \ - DECLARE_INTERRUPT(93) \ - DECLARE_INTERRUPT(94) \ - DECLARE_INTERRUPT(95) \ - DECLARE_INTERRUPT(97) \ - DECLARE_INTERRUPT(96) \ - DECLARE_INTERRUPT(98) \ - DECLARE_INTERRUPT(99) \ - DECLARE_INTERRUPT(100) \ - DECLARE_INTERRUPT(101) \ - DECLARE_INTERRUPT(102) \ - DECLARE_INTERRUPT(103) \ - DECLARE_INTERRUPT(104) \ - DECLARE_INTERRUPT(105) \ - DECLARE_INTERRUPT(106) \ - DECLARE_INTERRUPT(107) \ - DECLARE_INTERRUPT(108) \ - DECLARE_INTERRUPT(109) \ - DECLARE_INTERRUPT(110) \ - DECLARE_INTERRUPT(111) \ - DECLARE_INTERRUPT(112) \ - DECLARE_INTERRUPT(113) \ - DECLARE_INTERRUPT(114) \ - DECLARE_INTERRUPT(115) \ - DECLARE_INTERRUPT(116) \ - DECLARE_INTERRUPT(117) \ - DECLARE_INTERRUPT(118) \ - DECLARE_INTERRUPT(119) \ - DECLARE_INTERRUPT(120) \ - DECLARE_INTERRUPT(121) \ - DECLARE_INTERRUPT(122) \ - DECLARE_INTERRUPT(123) \ - DECLARE_INTERRUPT(124) \ - DECLARE_INTERRUPT(125) \ - DECLARE_INTERRUPT(126) \ - DECLARE_INTERRUPT(127) \ - DECLARE_INTERRUPT(128) \ - DECLARE_INTERRUPT(129) \ - DECLARE_INTERRUPT(130) \ - DECLARE_INTERRUPT(131) \ - DECLARE_INTERRUPT(132) \ - DECLARE_INTERRUPT(133) \ - DECLARE_INTERRUPT(134) \ - DECLARE_INTERRUPT(135) \ - DECLARE_INTERRUPT(136) \ - DECLARE_INTERRUPT(137) \ - DECLARE_INTERRUPT(138) \ - DECLARE_INTERRUPT(139) \ - DECLARE_INTERRUPT(140) \ - DECLARE_INTERRUPT(141) \ - DECLARE_INTERRUPT(142) \ - DECLARE_INTERRUPT(143) \ - DECLARE_INTERRUPT(144) \ - DECLARE_INTERRUPT(145) \ - DECLARE_INTERRUPT(146) \ - DECLARE_INTERRUPT(147) \ - DECLARE_INTERRUPT(148) \ - DECLARE_INTERRUPT(149) \ - DECLARE_INTERRUPT(150) \ - DECLARE_INTERRUPT(151) \ - DECLARE_INTERRUPT(152) \ - DECLARE_INTERRUPT(153) \ - DECLARE_INTERRUPT(154) \ - DECLARE_INTERRUPT(155) \ - DECLARE_INTERRUPT(156) \ - DECLARE_INTERRUPT(157) \ - DECLARE_INTERRUPT(158) \ - DECLARE_INTERRUPT(159) \ - DECLARE_INTERRUPT(160) \ - DECLARE_INTERRUPT(161) \ - DECLARE_INTERRUPT(162) \ - DECLARE_INTERRUPT(163) \ - DECLARE_INTERRUPT(164) \ - DECLARE_INTERRUPT(165) \ - DECLARE_INTERRUPT(166) \ - DECLARE_INTERRUPT(167) \ - DECLARE_INTERRUPT(168) \ - DECLARE_INTERRUPT(169) \ - DECLARE_INTERRUPT(170) \ - DECLARE_INTERRUPT(171) \ - DECLARE_INTERRUPT(172) \ - DECLARE_INTERRUPT(173) \ - DECLARE_INTERRUPT(174) \ - DECLARE_INTERRUPT(175) \ - DECLARE_INTERRUPT(176) \ - DECLARE_INTERRUPT(177) \ - DECLARE_INTERRUPT(178) \ - DECLARE_INTERRUPT(179) \ - DECLARE_INTERRUPT(180) \ - DECLARE_INTERRUPT(181) \ - DECLARE_INTERRUPT(182) \ - DECLARE_INTERRUPT(183) \ - DECLARE_INTERRUPT(184) \ - DECLARE_INTERRUPT(185) \ - DECLARE_INTERRUPT(186) \ - DECLARE_INTERRUPT(187) \ - DECLARE_INTERRUPT(188) \ - DECLARE_INTERRUPT(189) \ - DECLARE_INTERRUPT(190) \ - DECLARE_INTERRUPT(191) \ - DECLARE_INTERRUPT(192) \ - DECLARE_INTERRUPT(193) \ - DECLARE_INTERRUPT(194) \ - DECLARE_INTERRUPT(195) \ - DECLARE_INTERRUPT(196) \ - DECLARE_INTERRUPT(197) \ - DECLARE_INTERRUPT(198) \ - DECLARE_INTERRUPT(199) \ - DECLARE_INTERRUPT(200) \ - DECLARE_INTERRUPT(201) \ - DECLARE_INTERRUPT(202) \ - DECLARE_INTERRUPT(203) \ - DECLARE_INTERRUPT(204) \ - DECLARE_INTERRUPT(205) \ - DECLARE_INTERRUPT(206) \ - DECLARE_INTERRUPT(207) \ - DECLARE_INTERRUPT(208) \ - DECLARE_INTERRUPT(209) \ - DECLARE_INTERRUPT(210) \ - DECLARE_INTERRUPT(211) \ - DECLARE_INTERRUPT(212) \ - DECLARE_INTERRUPT(213) \ - DECLARE_INTERRUPT(214) \ - DECLARE_INTERRUPT(215) \ - DECLARE_INTERRUPT(216) \ - DECLARE_INTERRUPT(217) \ - DECLARE_INTERRUPT(218) \ - DECLARE_INTERRUPT(219) \ - DECLARE_INTERRUPT(220) \ - DECLARE_INTERRUPT(221) \ - DECLARE_INTERRUPT(222) \ - DECLARE_INTERRUPT(223) \ - DECLARE_INTERRUPT(224) \ - DECLARE_INTERRUPT(225) \ - DECLARE_INTERRUPT(226) \ - DECLARE_INTERRUPT(227) \ - DECLARE_INTERRUPT(228) \ - DECLARE_INTERRUPT(229) \ - DECLARE_INTERRUPT(230) \ - DECLARE_INTERRUPT(231) \ - DECLARE_INTERRUPT(232) \ - DECLARE_INTERRUPT(233) \ - DECLARE_INTERRUPT(234) \ - DECLARE_INTERRUPT(235) \ - DECLARE_INTERRUPT(236) \ - DECLARE_INTERRUPT(237) \ - DECLARE_INTERRUPT(238) \ - DECLARE_INTERRUPT(239) \ - DECLARE_INTERRUPT(240) \ - DECLARE_INTERRUPT(241) \ - DECLARE_INTERRUPT(242) \ - DECLARE_INTERRUPT(243) \ - DECLARE_INTERRUPT(244) \ - DECLARE_INTERRUPT(245) \ - DECLARE_INTERRUPT(246) \ - DECLARE_INTERRUPT(247) \ - DECLARE_INTERRUPT(248) \ - DECLARE_INTERRUPT(249) \ - DECLARE_INTERRUPT(250) \ - DECLARE_INTERRUPT(251) \ - DECLARE_INTERRUPT(252) \ - DECLARE_INTERRUPT(253) \ - DECLARE_INTERRUPT(254) \ - DECLARE_INTERRUPT(255)); diff --git a/arch/x86/include/asm/mp.h b/arch/x86/include/asm/mp.h index 2e6c3120c7..83b99dcd19 100644 --- a/arch/x86/include/asm/mp.h +++ b/arch/x86/include/asm/mp.h @@ -90,4 +90,7 @@ int mp_init(struct mp_params *params); /* Probes the CPU device */ int mp_init_cpu(struct udevice *cpu, void *unused); +/* Set up additional CPUs */ +int x86_mp_init(void); + #endif /* _X86_MP_H_ */