aboutsummaryrefslogtreecommitdiff
path: root/src/arch/i386
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch/i386')
-rw-r--r--src/arch/i386/boot/linuxbios_table.c65
-rw-r--r--src/arch/i386/boot/linuxbios_table.h4
-rw-r--r--src/arch/i386/boot/tables.c33
-rw-r--r--src/arch/i386/include/arch/hlt.h2
-rw-r--r--src/arch/i386/include/arch/romcc_io.h5
-rw-r--r--src/arch/i386/include/arch/smp/lapic.h55
-rw-r--r--src/arch/i386/include/arch/smp/mpspec.h10
-rw-r--r--src/arch/i386/include/arch/smp/spinlock.h6
-rw-r--r--src/arch/i386/include/stddef.h2
-rw-r--r--src/arch/i386/include/stdint.h2
-rw-r--r--src/arch/i386/lib/c_start.S30
-rw-r--r--src/arch/i386/lib/console.c11
-rw-r--r--src/arch/i386/lib/console.inc12
-rw-r--r--src/arch/i386/lib/cpu.c355
-rw-r--r--src/arch/i386/lib/id.inc11
-rw-r--r--src/arch/i386/smp/Config.lb6
-rw-r--r--src/arch/i386/smp/mpspec.c44
-rw-r--r--src/arch/i386/smp/secondary.S76
-rw-r--r--src/arch/i386/smp/start_stop.c240
19 files changed, 352 insertions, 617 deletions
diff --git a/src/arch/i386/boot/linuxbios_table.c b/src/arch/i386/boot/linuxbios_table.c
index 3b14488de8..5b7431479b 100644
--- a/src/arch/i386/boot/linuxbios_table.c
+++ b/src/arch/i386/boot/linuxbios_table.c
@@ -5,6 +5,8 @@
#include "linuxbios_table.h"
#include <string.h>
#include <version.h>
+#include <device/device.h>
+#include <stdlib.h>
struct lb_header *lb_table_init(unsigned long addr)
@@ -217,18 +219,75 @@ struct lb_memory *get_lb_mem(void)
return mem_ranges;
}
+struct mem_range *sizeram(void)
+{
+ struct mem_range *mem, *rmem;
+ struct device *dev;
+ unsigned int count;
+ count = 0;
+ for(dev = all_devices; dev; dev = dev->next) {
+ struct resource *res, *last;
+ last = &dev->resource[dev->resources];
+ for(res = &dev->resource[0]; res < last; res++) {
+ if ((res->flags & IORESOURCE_MEM) &&
+ (res->flags & IORESOURCE_CACHEABLE))
+ {
+ count++;
+ }
+ }
+ }
+ rmem = mem = malloc(sizeof(*mem) * (count + 1));
+ for(dev = all_devices; dev; dev = dev->next) {
+ struct resource *res, *last;
+ last = &dev->resource[dev->resources];
+ for(res = &dev->resource[0]; res < last; res++) {
+ if ((res->flags & IORESOURCE_MEM) &&
+ (res->flags & IORESOURCE_CACHEABLE))
+ {
+ mem->basek = res->base >> 10;
+ mem->sizek = res->size >> 10;
+ mem++;
+ }
+ }
+ }
+ mem->basek = 0;
+ mem->sizek = 0;
+#if 0
+ for(mem = rmem; mem->sizek; mem++) {
+ printk_debug("basek: %lu sizek: %lu\n",
+ mem->basek, mem->sizek);
+ }
+#endif
+ return rmem;
+}
+
+static struct mem_range *get_ramsize(void)
+{
+ struct mem_range *mem = 0;
+ if (!mem) {
+ mem = sizeram();
+ }
+ if (!mem) {
+ printk_emerg("No memory size information!\n");
+ for(;;) {
+ /* Ensure this loop is not optimized away */
+ asm volatile("":/* outputs */:/*inputs */ :"memory");
+ }
+ }
+ return mem;
+}
+
unsigned long write_linuxbios_table(
- unsigned long *processor_map,
- struct mem_range *ram,
unsigned long low_table_start, unsigned long low_table_end,
unsigned long rom_table_startk, unsigned long rom_table_endk)
{
unsigned long table_size;
- struct mem_range *ramp;
+ struct mem_range *ram, *ramp;
struct lb_header *head;
struct lb_memory *mem;
struct lb_record *rec_dest, *rec_src;
+ ram = get_ramsize();
head = lb_table_init(low_table_end);
low_table_end = (unsigned long)head;
#if HAVE_OPTION_TABLE == 1
diff --git a/src/arch/i386/boot/linuxbios_table.h b/src/arch/i386/boot/linuxbios_table.h
index 42c0a07dac..d15e1c722a 100644
--- a/src/arch/i386/boot/linuxbios_table.h
+++ b/src/arch/i386/boot/linuxbios_table.h
@@ -3,12 +3,8 @@
#include <boot/linuxbios_tables.h>
-struct mem_range;
-
/* This file holds function prototypes for building the linuxbios table. */
unsigned long write_linuxbios_table(
- unsigned long *processor_map,
- struct mem_range *ram,
unsigned long low_table_start, unsigned long low_table_end,
unsigned long rom_table_start, unsigned long rom_table_end);
diff --git a/src/arch/i386/boot/tables.c b/src/arch/i386/boot/tables.c
index 18e271db8c..b148abd1c2 100644
--- a/src/arch/i386/boot/tables.c
+++ b/src/arch/i386/boot/tables.c
@@ -1,39 +1,13 @@
#include <console/console.h>
-#include <mem.h>
#include <cpu/cpu.h>
#include <boot/tables.h>
#include <boot/linuxbios_tables.h>
#include <arch/pirq_routing.h>
#include <arch/smp/mpspec.h>
#include <arch/acpi.h>
-#include <pc80/mc146818rtc.h>
#include "linuxbios_table.h"
-#if CONFIG_SMP && CONFIG_MAX_PHYSICAL_CPUS && (CONFIG_MAX_PHYSICAL_CPUS < CONFIG_MAX_CPUS)
-static void remove_logical_cpus(unsigned long *processor_map)
-{
- /* To turn off hyperthreading just remove the logical
- * cpus from the processor map.
- */
- int disable_logical_cpus = !CONFIG_LOGICAL_CPUS;
- if (get_option(&disable_logical_cpus,"hyper_threading")) {
- disable_logical_cpus = !CONFIG_LOGICAL_CPUS;
- }
- if (disable_logical_cpus) {
- /* disable logical cpus */
- int cnt;
- for(cnt=CONFIG_MAX_PHYSICAL_CPUS;cnt<CONFIG_MAX_CPUS;cnt++)
- processor_map[cnt]=0;
- printk_debug("logical cpus disabled\n");
- }
-}
-#else
-
-#define remove_logical_cpus(processor_map) do {} while(0)
-
-#endif /* CONFIG_SMP && CONFIG_MAX_PHYSICAL_CPUS */
-
-struct lb_memory *write_tables(struct mem_range *mem, unsigned long *processor_map)
+struct lb_memory *write_tables(void)
{
unsigned long low_table_start, low_table_end;
unsigned long rom_table_start, rom_table_end;
@@ -56,8 +30,7 @@ struct lb_memory *write_tables(struct mem_range *mem, unsigned long *processor_m
post_code(0x96);
/* The smp table must be in 0-1K, 639K-640K, or 960K-1M */
- remove_logical_cpus(processor_map);
- low_table_end = write_smp_table(low_table_end, processor_map);
+ low_table_end = write_smp_table(low_table_end);
/* Write ACPI tables */
/* write them in the rom area because DSDT can be large (8K on epia-m) which
@@ -73,7 +46,7 @@ struct lb_memory *write_tables(struct mem_range *mem, unsigned long *processor_m
}
/* The linuxbios table must be in 0-4K or 960K-1M */
- write_linuxbios_table(processor_map, mem,
+ write_linuxbios_table(
low_table_start, low_table_end,
rom_table_start >> 10, rom_table_end >> 10);
diff --git a/src/arch/i386/include/arch/hlt.h b/src/arch/i386/include/arch/hlt.h
index 86ed7c8f41..7d3a563734 100644
--- a/src/arch/i386/include/arch/hlt.h
+++ b/src/arch/i386/include/arch/hlt.h
@@ -9,7 +9,7 @@ static void hlt(void)
#endif
-#ifdef __GNUC__
+#if defined(__GNUC__) && !defined(__ROMCC__)
static inline void hlt(void)
{
asm("hlt");
diff --git a/src/arch/i386/include/arch/romcc_io.h b/src/arch/i386/include/arch/romcc_io.h
index 0d5f071428..80037bd7ad 100644
--- a/src/arch/i386/include/arch/romcc_io.h
+++ b/src/arch/i386/include/arch/romcc_io.h
@@ -191,6 +191,11 @@ static inline void pnp_set_iobase(device_t dev, unsigned index, unsigned iobase)
pnp_write_config(dev, index + 1, iobase & 0xff);
}
+static inline uint16_t pnp_read_iobase(device_t dev, unsigned index)
+{
+ return (uint16_t)((pnp_read_config(dev, index) << 8) | pnp_read_config(dev, index + 1));
+}
+
static inline void pnp_set_irq(device_t dev, unsigned index, unsigned irq)
{
pnp_write_config(dev, index, irq);
diff --git a/src/arch/i386/include/arch/smp/lapic.h b/src/arch/i386/include/arch/smp/lapic.h
deleted file mode 100644
index 0ac87aa2d3..0000000000
--- a/src/arch/i386/include/arch/smp/lapic.h
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef ARCH_SMP_LAPIC_H
-#define ARCH_SMP_LAPIC_H
-
-#include <cpu/p6/msr.h>
-#include <cpu/p6/apic.h>
-#include <arch/hlt.h>
-
-static void enable_lapic(void)
-{
-
- msr_t msr;
- msr = rdmsr(0x1b);
- msr.hi &= 0xffffff00;
- msr.lo &= 0x000007ff;
- msr.lo |= APIC_DEFAULT_BASE | (1 << 11);
- wrmsr(0x1b, msr);
-}
-
-static void disable_lapic(void)
-{
- msr_t msr;
- msr = rdmsr(0x1b);
- msr.lo &= ~ (1 << 11);
- wrmsr(0x1b, msr);
-}
-
-static inline unsigned long lapicid(void)
-{
- return apic_read(APIC_ID) >> 24;
-}
-
-static void stop_this_cpu(void)
-{
- unsigned apicid;
- apicid = lapicid();
-
- /* Send an APIC INIT to myself */
- apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
- apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT | APIC_DM_INIT);
- /* Wait for the ipi send to finish */
- apic_wait_icr_idle();
-
- /* Deassert the APIC INIT */
- apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
- apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT);
- /* Wait for the ipi send to finish */
- apic_wait_icr_idle();
-
- /* If I haven't halted spin forever */
- for(;;) {
- hlt();
- }
-}
-
-#endif /* ARCH_SMP_LAPIC_H */
diff --git a/src/arch/i386/include/arch/smp/mpspec.h b/src/arch/i386/include/arch/smp/mpspec.h
index 66232c921d..9f22b7f4af 100644
--- a/src/arch/i386/include/arch/smp/mpspec.h
+++ b/src/arch/i386/include/arch/smp/mpspec.h
@@ -238,8 +238,7 @@ void smp_write_processor(struct mp_config_table *mc,
unsigned char apicid, unsigned char apicver,
unsigned char cpuflag, unsigned int cpufeature,
unsigned int featureflag);
-void smp_write_processors(struct mp_config_table *mc,
- unsigned long *processor_map);
+void smp_write_processors(struct mp_config_table *mc);
void smp_write_bus(struct mp_config_table *mc,
unsigned char id, unsigned char *bustype);
void smp_write_ioapic(struct mp_config_table *mc,
@@ -265,18 +264,15 @@ void smp_write_compatibility_address_space(struct mp_config_table *mc,
unsigned int range_list);
unsigned char smp_compute_checksum(void *v, int len);
void *smp_write_floating_table(unsigned long addr);
-unsigned long write_smp_table(unsigned long addr, unsigned long *processor_map);
+unsigned long write_smp_table(unsigned long addr);
#else /* HAVE_MP_TABLE */
static inline
-unsigned long write_smp_table(unsigned long addr, unsigned long *processor_map)
+unsigned long write_smp_table(unsigned long addr);
{
return addr;
}
#endif /* HAVE_MP_TABLE */
-/* A table (per mainboard) listing the initial apicid of each cpu. */
-extern unsigned long initial_apicid[CONFIG_MAX_CPUS];
-
#endif
diff --git a/src/arch/i386/include/arch/smp/spinlock.h b/src/arch/i386/include/arch/smp/spinlock.h
index d0cc11c6a7..65ad8d0673 100644
--- a/src/arch/i386/include/arch/smp/spinlock.h
+++ b/src/arch/i386/include/arch/smp/spinlock.h
@@ -54,4 +54,10 @@ static inline void spin_unlock(spinlock_t *lock)
:"=m" (lock->lock) : : "memory");
}
+/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
+static inline void cpu_relax(void)
+{
+ __asm__ __volatile__("rep;nop": : :"memory");
+}
+
#endif /* ARCH_SMP_SPINLOCK_H */
diff --git a/src/arch/i386/include/stddef.h b/src/arch/i386/include/stddef.h
index 4bf6b0a867..e4fc019c87 100644
--- a/src/arch/i386/include/stddef.h
+++ b/src/arch/i386/include/stddef.h
@@ -8,7 +8,7 @@ typedef long ssize_t;
typedef int wchar_t;
typedef unsigned int wint_t;
-#define NULL 0
+#define NULL ((void *)0)
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
diff --git a/src/arch/i386/include/stdint.h b/src/arch/i386/include/stdint.h
index 0fc4346317..76bd89a354 100644
--- a/src/arch/i386/include/stdint.h
+++ b/src/arch/i386/include/stdint.h
@@ -1,7 +1,7 @@
#ifndef I386_STDINT_H
#define I386_STDINT_H
-#if defined(__GNUC__)
+#if defined(__GNUC__) && !defined(__ROMCC__)
#define __HAVE_LONG_LONG__ 1
#else
#define __HAVE_LONG_LONG__ 0
diff --git a/src/arch/i386/lib/c_start.S b/src/arch/i386/lib/c_start.S
index 47fb64588c..c82da2f76e 100644
--- a/src/arch/i386/lib/c_start.S
+++ b/src/arch/i386/lib/c_start.S
@@ -1,8 +1,5 @@
#include <arch/asm.h>
#include <arch/intel.h>
-#if CONFIG_SMP==1
-#include <cpu/p6/apic.h>
-#endif
.section ".text"
.code32
.globl _start
@@ -39,27 +36,10 @@ _start:
/* set new stack */
movl $_estack, %esp
-#if CONFIG_SMP==1
- /* Get the cpu id */
- movl $APIC_DEFAULT_BASE, %edi
- movl APIC_ID(%edi), %eax
- shrl $24, %eax
-
- /* Get the cpu index (CONFIG_MAX_CPUS on error) */
- movl $-4, %ebx
-1: addl $4, %ebx
- cmpl $(CONFIG_MAX_CPUS << 2), %ebx
- je 2
- cmpl %eax, initial_apicid(%ebx)
- jne 1b
-2: shrl $2, %ebx
-
- /* Now compute the appropriate stack */
- movl %ebx, %eax
- movl $STACK_SIZE, %ebx
- mull %ebx
- subl %eax, %esp
-#endif
+
+ /* Push the cpu index and struct cpu */
+ pushl $0
+ pushl $0
/* push the boot_complete flag */
pushl %ebp
@@ -74,7 +54,7 @@ _start:
*/
intel_chip_post_macro(0xfe) /* post fe */
- /* Resort the stack location */
+ /* Restore the stack location */
movl %ebp, %esp
/* The boot_complete flag has already been pushed */
diff --git a/src/arch/i386/lib/console.c b/src/arch/i386/lib/console.c
index f3594e9786..76f4f16e01 100644
--- a/src/arch/i386/lib/console.c
+++ b/src/arch/i386/lib/console.c
@@ -118,21 +118,18 @@ static void print_spew_hex16(unsigned short value){ __console_tx_hex16(BIOS_SPEW
static void print_spew_hex32(unsigned int value) { __console_tx_hex32(BIOS_SPEW, value); }
static void print_spew(const char *str) { __console_tx_string(BIOS_SPEW, str); }
-#define __STR(X) #X
-#define STR(X) __STR(X)
-
#ifndef LINUXBIOS_EXTRA_VERSION
-#define LINUXBIOS_EXTRA_VERSION
+#define LINUXBIOS_EXTRA_VERSION ""
#endif
static void console_init(void)
{
static const char console_test[] =
"\r\n\r\nLinuxBIOS-"
- STR(LINUXBIOS_VERSION)
- STR(LINUXBIOS_EXTRA_VERSION)
+ LINUXBIOS_VERSION
+ LINUXBIOS_EXTRA_VERSION
" "
- STR(LINUXBIOS_BUILD)
+ LINUXBIOS_BUILD
" starting...\r\n";
print_info(console_test);
}
diff --git a/src/arch/i386/lib/console.inc b/src/arch/i386/lib/console.inc
index b617b8c1d0..be7df6af16 100644
--- a/src/arch/i386/lib/console.inc
+++ b/src/arch/i386/lib/console.inc
@@ -2,11 +2,8 @@
jmp console0
-#define __STR(X) #X
-#define STR(X) __STR(X)
-
#ifndef LINUXBIOS_EXTRA_VERSION
-#define LINUXBIOS_EXTRA_VERSION
+#define LINUXBIOS_EXTRA_VERSION ""
#endif
#ifndef ASM_CONSOLE_LOGLEVEL
@@ -14,13 +11,12 @@ jmp console0
#endif
console_test:
.ascii "\r\n\r\nLinuxBIOS-"
- .ascii STR(LINUXBIOS_VERSION)
- .ascii STR(LINUXBIOS_EXTRA_VERSION)
+ .ascii LINUXBIOS_VERSION
+ .ascii LINUXBIOS_EXTRA_VERSION
.ascii " "
- .ascii STR(LINUXBIOS_BUILD)
+ .ascii LINUXBIOS_BUILD
.asciz " starting...\r\n"
-#undef STR
/* uses: ax, dx */
#if CONFIG_CONSOLE_SERIAL8250
#define __CONSOLE_INLINE_TX_AL TTYS0_TX_AL
diff --git a/src/arch/i386/lib/cpu.c b/src/arch/i386/lib/cpu.c
index 23c35bc816..74db2e81f8 100644
--- a/src/arch/i386/lib/cpu.c
+++ b/src/arch/i386/lib/cpu.c
@@ -1,147 +1,252 @@
#include <console/console.h>
#include <cpu/cpu.h>
-#include <mem.h>
#include <arch/io.h>
#include <string.h>
-#include <cpu/cpufixup.h>
-#include <smp/start_stop.h>
-#include <cpu/cpufixup.h>
-#include <cpu/p6/mtrr.h>
-#include <cpu/p6/msr.h>
-#include <cpu/p6/apic.h>
-#include <cpu/p5/cpuid.h>
-#include <arch/smp/lapic.h>
-#if 0
-#include <cpu/l2_cache.h>
-#endif
-
-#if CONFIG_SMP || CONFIG_IOAPIC
-#define APIC 1
-#endif
-
-
-static void cache_on(struct mem_range *mem)
+#include <cpu/x86/mtrr.h>
+#include <cpu/x86/msr.h>
+#include <cpu/x86/lapic.h>
+#include <arch/cpu.h>
+#include <device/path.h>
+#include <device/device.h>
+#include <smp/spinlock.h>
+
+/* Standard macro to see if a specific flag is changeable */
+static inline int flag_is_changeable_p(uint32_t flag)
{
- post_code(0x60);
- printk_info("Enabling cache...");
-
-
- /* we need an #ifdef i586 here at some point ... */
- __asm__ __volatile__("mov %cr0, %eax\n\t"
- "and $0x9fffffff,%eax\n\t"
- "mov %eax, %cr0\n\t");
- /* turns out cache isn't really on until you set MTRR registers on
- * 686 and later.
- * NOTHING FANCY. Linux does a much better job anyway.
- * so absolute minimum needed to get it going.
- */
- /* OK, linux it turns out does nothing. We have to do it ... */
-#if i686==1
- // totalram here is in linux sizing, i.e. units of KB.
- // set_mtrr is responsible for getting it into the right units!
- setup_mtrrs(mem);
-#endif
-
- post_code(0x6A);
- printk_info("done.\n");
+ uint32_t f1, f2;
+
+ asm(
+ "pushfl\n\t"
+ "pushfl\n\t"
+ "popl %0\n\t"
+ "movl %0,%1\n\t"
+ "xorl %2,%0\n\t"
+ "pushl %0\n\t"
+ "popfl\n\t"
+ "pushfl\n\t"
+ "popl %0\n\t"
+ "popfl\n\t"
+ : "=&r" (f1), "=&r" (f2)
+ : "ir" (flag));
+ return ((f1^f2) & flag) != 0;
}
-static void interrupts_on()
+
+/* Probe for the CPUID instruction */
+static int have_cpuid_p(void)
{
- /* this is so interrupts work. This is very limited scope --
- * linux will do better later, we hope ...
- */
- /* this is the first way we learned to do it. It fails on real SMP
- * stuff. So we have to do things differently ...
- * see the Intel mp1.4 spec, page A-3
- */
+ return flag_is_changeable_p(X86_EFLAGS_ID);
+}
+
+/*
+ * 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;
+}
-#if defined(APIC)
- /* Only Pentium Pro and later have those MSR stuff */
- msr_t msr;
+/*
+ * 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;
+}
- printk_info("Setting up local apic...");
+/* List of cpu vendor strings along with their normalized
+ * id values.
+ */
+static 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 *x86_vendor_name[] = {
+ [X86_VENDOR_INTEL] = "Intel",
+ [X86_VENDOR_CYRIX] = "Cyrix",
+ [X86_VENDOR_AMD] = "AMD",
+ [X86_VENDOR_UMC] = "UMC",
+ [X86_VENDOR_NEXGEN] = "NexGen",
+ [X86_VENDOR_CENTAUR] = "Centaur",
+ [X86_VENDOR_RISE] = "Rise",
+ [X86_VENDOR_TRANSMETA] = "Transmeta",
+ [X86_VENDOR_NSC] = "NSC",
+ [X86_VENDOR_SIS] = "SiS",
+};
+
+static const char *cpu_vendor_name(int vendor)
+{
+ const char *name;
+ name = "<invalid cpu vendor>";
+ if ((vendor < (sizeof(x86_vendor_name)/sizeof(x86_vendor_name[0]))) &&
+ (x86_vendor_name[vendor] != 0))
+ {
+ name = x86_vendor_name[vendor];
+ }
+ return name;
+}
- /* Enable the local apic */
- msr = rdmsr(APIC_BASE_MSR);
- msr.lo |= APIC_BASE_MSR_ENABLE;
- msr.lo &= ~APIC_BASE_MSR_ADDR_MASK;
- msr.lo |= APIC_DEFAULT_BASE;
- wrmsr(APIC_BASE_MSR, msr);
+static void identify_cpu(struct device *cpu)
+{
+ char vendor_name[16];
+ int cpuid_level;
+ int i;
+
+ vendor_name[0] = '\0'; /* Unset */
+ cpuid_level = -1; /* Maximum supported CPUID level, -1=no CPUID */
+
+ /* Find the id and vendor_name */
+ if (!have_cpuid_p()) {
+ /* 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 (have_cpuid_p()) {
+ struct cpuid_result result;
+ result = cpuid(0x00000000);
+ cpuid_level = result.eax;
+ vendor_name[ 0] = (result.ebx >> 0) & 0xff;
+ vendor_name[ 1] = (result.ebx >> 8) & 0xff;
+ vendor_name[ 2] = (result.ebx >> 16) & 0xff;
+ vendor_name[ 3] = (result.ebx >> 24) & 0xff;
+ vendor_name[ 4] = (result.edx >> 0) & 0xff;
+ vendor_name[ 5] = (result.edx >> 8) & 0xff;
+ vendor_name[ 6] = (result.edx >> 16) & 0xff;
+ vendor_name[ 7] = (result.edx >> 24) & 0xff;
+ vendor_name[ 8] = (result.ecx >> 0) & 0xff;
+ vendor_name[ 9] = (result.ecx >> 8) & 0xff;
+ vendor_name[10] = (result.ecx >> 16) & 0xff;
+ vendor_name[11] = (result.ecx >> 24) & 0xff;
+ 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 < sizeof(x86_vendors)/sizeof(x86_vendors[0]); i++) {
+ if (memcmp(vendor_name, x86_vendors[i].name, 12) == 0) {
+ cpu->vendor = x86_vendors[i].vendor;
+ break;
+ }
+ }
+}
- /*
- * Set Task Priority to 'accept all'.
- */
- apic_write_around(APIC_TASKPRI,
- apic_read_around(APIC_TASKPRI) & ~APIC_TPRI_MASK);
-
- /* Put the local apic in virtual wire mode */
- apic_write_around(APIC_SPIV,
- (apic_read_around(APIC_SPIV) & ~(APIC_VECTOR_MASK))
- | APIC_SPIV_ENABLE);
- apic_write_around(APIC_LVT0,
- (apic_read_around(APIC_LVT0) &
- ~(APIC_LVT_MASKED | APIC_LVT_LEVEL_TRIGGER |
- APIC_LVT_REMOTE_IRR | APIC_INPUT_POLARITY |
- APIC_SEND_PENDING |APIC_LVT_RESERVED_1 |
- APIC_DELIVERY_MODE_MASK))
- | (APIC_LVT_REMOTE_IRR |APIC_SEND_PENDING |
- APIC_DELIVERY_MODE_EXTINT)
- );
- apic_write_around(APIC_LVT1,
- (apic_read_around(APIC_LVT1) &
- ~(APIC_LVT_MASKED | APIC_LVT_LEVEL_TRIGGER |
- APIC_LVT_REMOTE_IRR | APIC_INPUT_POLARITY |
- APIC_SEND_PENDING |APIC_LVT_RESERVED_1 |
- APIC_DELIVERY_MODE_MASK))
- | (APIC_LVT_REMOTE_IRR |APIC_SEND_PENDING |
- APIC_DELIVERY_MODE_NMI)
- );
-
- printk_debug(" apic_id: %d ", lapicid());
-
-#else /* APIC */
-#if i686==1
- /* Only Pentium Pro and later have those MSR stuff */
- msr_t msr;
-
- printk_info("Disabling local apic...");
-
- msr = rdmsr(APIC_BASE_MSR);
- msr.lo &= ~APIC_BASE_MSR_ENABLE;
- wrmsr(APIC_BASE_MSR, msr);
-#endif /* i686 */
-#endif /* APIC */
- printk_info("done.\n");
- post_code(0x9b);
+static void set_cpu_ops(struct device *cpu)
+{
+ struct cpu_driver *driver;
+ cpu->ops = 0;
+ for (driver = cpu_drivers; driver < ecpu_drivers; driver++) {
+ struct cpu_device_id *id;
+ for(id = driver->id_table; id->vendor != X86_VENDOR_INVALID; id++) {
+ if ((cpu->vendor == id->vendor) &&
+ (cpu->device == id->device))
+ {
+ goto found;
+ }
+ }
+ }
+ die("Unknown cpu");
+ return;
+ found:
+ cpu->ops = driver->ops;
}
-unsigned long cpu_initialize(struct mem_range *mem)
+void cpu_initialize(void)
{
/* Because we busy wait at the printk spinlock.
* It is important to keep the number of printed messages
* from secondary cpus to a minimum, when debugging is
* disabled.
*/
- unsigned long processor_id = this_processors_id();
- printk_notice("Initializing CPU #%d\n", processor_id);
-
- /* Turn on caching if we haven't already */
- cache_on(mem);
-#if i586==1
- display_cpuid();
-#endif
-#if i686==1
- mtrr_check();
-#endif
-
- /* some cpus need a fixup done. This is the hook for doing that. */
- cpufixup(mem);
-
- interrupts_on();
-
- processor_id = this_processors_id();
- printk_info("CPU #%d Initialized\n", processor_id);
- return processor_id;
+ struct device *cpu;
+ struct cpu_info *info;
+ info = cpu_info();
+
+ printk_notice("Initializing CPU #%d\n", info->index);
+
+ cpu = info->cpu;
+ if (!cpu) {
+ die("CPU: missing cpu device structure");
+ }
+
+ /* Find what type of cpu we are dealing with */
+ identify_cpu(cpu);
+ printk_debug("CPU: vendor %s device %x\n",
+ cpu_vendor_name(cpu->vendor), cpu->device);
+
+ /* Lookup the cpu's operations */
+ set_cpu_ops(cpu);
+
+ /* Initialize the cpu */
+ if (cpu->ops && cpu->ops->init) {
+ cpu->enabled = 1;
+ cpu->initialized = 1;
+ cpu->ops->init(cpu);
+ }
+
+ printk_info("CPU #%d Initialized\n", info->index);
+ return;
}
diff --git a/src/arch/i386/lib/id.inc b/src/arch/i386/lib/id.inc
index f28e23a2e8..44c452b03a 100644
--- a/src/arch/i386/lib/id.inc
+++ b/src/arch/i386/lib/id.inc
@@ -1,21 +1,16 @@
- .section ".id", "a", @progbits
-#define __STR(X) #X
-#define STR(X) __STR(X)
+ .section ".id", "a", @progbits
.globl __id_start
__id_start:
vendor:
- .asciz STR(MAINBOARD_VENDOR)
+ .asciz MAINBOARD_VENDOR
part:
- .asciz STR(MAINBOARD_PART_NUMBER)
+ .asciz MAINBOARD_PART_NUMBER
.long __id_end + 0x10 - vendor /* Reverse offset to the vendor id */
.long __id_end + 0x10 - part /* Reverse offset to the part number */
.long PAYLOAD_SIZE + ROM_IMAGE_SIZE /* Size of this romimage */
.globl __id_end
-#undef __STR
-#undef STR
-
__id_end:
.previous
diff --git a/src/arch/i386/smp/Config.lb b/src/arch/i386/smp/Config.lb
index d1e365c073..b41f5c295e 100644
--- a/src/arch/i386/smp/Config.lb
+++ b/src/arch/i386/smp/Config.lb
@@ -1,12 +1,8 @@
uses HAVE_MP_TABLE
-uses CONFIG_SMP
if HAVE_MP_TABLE
object mpspec.o
end
#object ioapic.o CONFIG_IOAPIC
-if CONFIG_SMP
- object start_stop.o
- object secondary.S
-end
+
diff --git a/src/arch/i386/smp/mpspec.c b/src/arch/i386/smp/mpspec.c
index 4a1e233be9..babfcbdca2 100644
--- a/src/arch/i386/smp/mpspec.c
+++ b/src/arch/i386/smp/mpspec.c
@@ -1,10 +1,9 @@
#include <console/console.h>
#include <cpu/cpu.h>
-#include <smp/start_stop.h>
#include <arch/smp/mpspec.h>
#include <string.h>
-#include <cpu/p5/cpuid.h>
-#include <cpu/p6/apic.h>
+#include <arch/cpu.h>
+#include <cpu/x86/lapic.h>
unsigned char smp_compute_checksum(void *v, int len)
{
@@ -94,30 +93,33 @@ void smp_write_processor(struct mp_config_table *mc,
* Having the proper apicid's in the table so the non-bootstrap
* processors can be woken up should be enough.
*/
-void smp_write_processors(struct mp_config_table *mc,
- unsigned long *processor_map)
+void smp_write_processors(struct mp_config_table *mc)
{
- int i;
- int processor_id;
+ int boot_apic_id;
unsigned apic_version;
unsigned cpu_features;
unsigned cpu_feature_flags;
- int eax, ebx, ecx, edx;
- processor_id = this_processors_id();
- apic_version = apic_read(APIC_LVR) & 0xff;
- cpuid(1, &eax, &ebx, &ecx, &edx);
- cpu_features = eax;
- cpu_feature_flags = edx;
- for(i = 0; i < CONFIG_MAX_CPUS; i++) {
- unsigned long cpu_apicid = initial_apicid[i];
+ struct cpuid_result result;
+ device_t cpu;
+ boot_apic_id = lapicid();
+ apic_version = lapic_read(LAPIC_LVR) & 0xff;
+ result = cpuid(1);
+ cpu_features = result.eax;
+ cpu_feature_flags = result.edx;
+ for(cpu = dev_root.link[1].children; cpu; cpu = cpu->sibling) {
unsigned long cpu_flag;
- if(initial_apicid[i]==-1)
+ if (cpu->path.type != DEVICE_PATH_APIC) {
+ continue;
+ }
+ if (!cpu->enabled) {
continue;
+ }
cpu_flag = MPC_CPU_ENABLED;
- if (processor_map[i] & CPU_BOOTPROCESSOR) {
- cpu_flag |= MPC_CPU_BOOTPROCESSOR;
+ if (boot_apic_id == cpu->path.u.apic.apic_id) {
+ cpu_flag = MPC_CPU_ENABLED;
}
- smp_write_processor(mc, cpu_apicid, apic_version,
+ smp_write_processor(mc,
+ cpu->path.u.apic.apic_id, apic_version,
cpu_flag, cpu_features, cpu_feature_flags
);
}
@@ -136,8 +138,8 @@ void smp_write_bus(struct mp_config_table *mc,
}
void smp_write_ioapic(struct mp_config_table *mc,
- unsigned char id, unsigned char ver,
- unsigned long apicaddr)
+ unsigned char id, unsigned char ver,
+ unsigned long apicaddr)
{
struct mpc_config_ioapic *mpc;
mpc = smp_next_mpc_entry(mc);
diff --git a/src/arch/i386/smp/secondary.S b/src/arch/i386/smp/secondary.S
deleted file mode 100644
index c27d6282b0..0000000000
--- a/src/arch/i386/smp/secondary.S
+++ /dev/null
@@ -1,76 +0,0 @@
-#include <arch/asm.h>
-#include <arch/intel.h>
-#include <cpu/p6/mtrr.h>
-#include <cpu/p6/apic.h>
- .text
- .globl _secondary_start
- .balign 4096
-_secondary_start:
- .code16
- cli
- xorl %eax, %eax
- movl %eax, %cr3 /* Invalidate TLB*/
-
- /* On hyper threaded cpus invalidating the cache here is
- * very very bad. Don't.
- */
-
- /* setup the data segment */
- movw %cs, %ax
- movw %ax, %ds
-
- data32 lgdt gdtaddr - _secondary_start
-
- movl %cr0, %eax
- andl $0x7FFAFFD1, %eax /* PG,AM,WP,NE,TS,EM,MP = 0 */
- orl $0x60000001, %eax /* CD, NW, PE = 1 */
- movl %eax, %cr0
-
- ljmpl $0x10, $1f
-1:
- .code32
- movw $0x18, %ax
- movw %ax, %ds
- movw %ax, %es
- movw %ax, %ss
- movw %ax, %fs
- movw %ax, %gs
-
- /* Enable the local apic, and map it where we expext it */
- movl $APIC_BASE_MSR, %ecx
- rdmsr
- orl $APIC_BASE_MSR_ENABLE, %eax
- andl $(~APIC_BASE_MSR_ADDR_MASK), %eax
- orl $APIC_DEFAULT_BASE, %eax
- wrmsr
-
- /* Get the apic_id */
- movl (APIC_ID + APIC_DEFAULT_BASE), %edi
- shrl $24, %edi
-
- /* Get the cpu index (CONFIG_MAX_CPUS on error) */
- movl $-4, %ebx
-1: addl $4, %ebx
- cmpl $(CONFIG_MAX_CPUS << 2), %ebx
- je 2
- cmpl %edi, initial_apicid(%ebx)
- jne 1b
-2: shrl $2, %ebx
-
- /* set the stack pointer */
- movl $_estack, %esp
- movl %ebx, %eax
- movl $STACK_SIZE, %ebx
- mull %ebx
- subl %eax, %esp
-
- call secondary_cpu_init
-1: hlt
- jmp 1b
-
-gdtaddr:
- .word gdt_limit /* the table limit */
- .long gdt /* we know the offset */
-
-
-.code32
diff --git a/src/arch/i386/smp/start_stop.c b/src/arch/i386/smp/start_stop.c
deleted file mode 100644
index bf26437984..0000000000
--- a/src/arch/i386/smp/start_stop.c
+++ /dev/null
@@ -1,240 +0,0 @@
-#include <smp/start_stop.h>
-#include <arch/smp/mpspec.h>
-#include <cpu/p6/apic.h>
-#include <delay.h>
-#include <string.h>
-#include <console/console.h>
-#include <arch/smp/lapic.h>
-#include <arch/hlt.h>
-
-
-unsigned long this_processors_id(void)
-{
- return lapicid();
-}
-
-int processor_index(unsigned long apicid)
-{
- int i;
- for(i = 0; i < CONFIG_MAX_CPUS; i++) {
- if (initial_apicid[i] == apicid) {
- return i;
- }
- }
- return -1;
-}
-
-void stop_cpu(unsigned long apicid)
-{
- int timeout;
- unsigned long send_status;
-
- /* send an APIC INIT to myself */
- apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
- apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT | APIC_DM_INIT);
-
- /* wait for the ipi send to finish */
- printk_spew("Waiting for send to finish...\n");
- timeout = 0;
- do {
- printk_spew("+");
- udelay(100);
- send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
- } while (send_status && (timeout++ < 1000));
- if (timeout >= 1000) {
- printk_err("timed out\n");
- }
- mdelay(10);
-
- printk_spew("Deasserting INIT.\n");
- /* Deassert the APIC INIT */
- apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
- apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT);
-
- printk_spew("Waiting for send to finish...\n");
- timeout = 0;
- do {
- printk_spew("+");
- udelay(100);
- send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
- } while (send_status && (timeout++ < 1000));
- if (timeout >= 1000) {
- printk_err("timed out\n");
- }
-
- while(1) {
- hlt();
- }
-}
-
-/* This is a lot more paranoid now, since Linux can NOT handle
- * being told there is a CPU when none exists. So any errors
- * will return 0, meaning no CPU.
- *
- * We actually handling that case by noting which cpus startup
- * and not telling anyone about the ones that dont.
- */
-int start_cpu(unsigned long apicid)
-{
- int timeout;
- unsigned long send_status, accept_status, start_eip;
- int j, num_starts, maxlvt;
- extern char _secondary_start[];
-
- /*
- * Starting actual IPI sequence...
- */
-
- printk_spew("Asserting INIT.\n");
-
- /*
- * Turn INIT on target chip
- */
- apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
-
- /*
- * Send IPI
- */
-
- apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT
- | APIC_DM_INIT);
-
- printk_spew("Waiting for send to finish...\n");
- timeout = 0;
- do {
- printk_spew("+");
- udelay(100);
- send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
- } while (send_status && (timeout++ < 1000));
- if (timeout >= 1000) {
- printk_err("CPU %d: First apic write timed out. Disabling\n",
- apicid);
- // too bad.
- printk_err("ESR is 0x%x\n", apic_read(APIC_ESR));
- if (apic_read(APIC_ESR)) {
- printk_err("Try to reset ESR\n");
- apic_write_around(APIC_ESR, 0);
- printk_err("ESR is 0x%x\n", apic_read(APIC_ESR));
- }
- return 0;
- }
- mdelay(10);
-
- printk_spew("Deasserting INIT.\n");
-
- /* Target chip */
- apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
-
- /* Send IPI */
- apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT);
-
- printk_spew("Waiting for send to finish...\n");
- timeout = 0;
- do {
- printk_spew("+");
- udelay(100);
- send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
- } while (send_status && (timeout++ < 1000));
- if (timeout >= 1000) {
- printk_err("CPU %d: Second apic write timed out. Disabling\n",
- apicid);
- // too bad.
- return 0;
- }
-
- start_eip = (unsigned long)_secondary_start;
- printk_spew("start_eip=0x%08lx\n", start_eip);
-
- num_starts = 2;
-
- /*
- * Run STARTUP IPI loop.
- */
- printk_spew("#startup loops: %d.\n", num_starts);
-
- maxlvt = 4;
-
- for (j = 1; j <= num_starts; j++) {
- printk_spew("Sending STARTUP #%d to %u.\n", j, apicid);
- apic_read_around(APIC_SPIV);
- apic_write(APIC_ESR, 0);
- apic_read(APIC_ESR);
- printk_spew("After apic_write.\n");
-
- /*
- * STARTUP IPI
- */
-
- /* Target chip */
- apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
-
- /* Boot on the stack */
- /* Kick the second */
- apic_write_around(APIC_ICR, APIC_DM_STARTUP
- | (start_eip >> 12));
-
- /*
- * Give the other CPU some time to accept the IPI.
- */
- udelay(300);
-
- printk_spew("Startup point 1.\n");
-
- printk_spew("Waiting for send to finish...\n");
- timeout = 0;
- do {
- printk_spew("+");
- udelay(100);
- send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
- } while (send_status && (timeout++ < 1000));
-
- /*
- * Give the other CPU some time to accept the IPI.
- */
- udelay(200);
- /*
- * Due to the Pentium erratum 3AP.
- */
- if (maxlvt > 3) {
- apic_read_around(APIC_SPIV);
- apic_write(APIC_ESR, 0);
- }
- accept_status = (apic_read(APIC_ESR) & 0xEF);
- if (send_status || accept_status)
- break;
- }
- printk_spew("After Startup.\n");
- if (send_status)
- printk_warning("APIC never delivered???\n");
- if (accept_status)
- printk_warning("APIC delivery error (%lx).\n", accept_status);
- if (send_status || accept_status)
- return 0;
- return 1;
-}
-
-
-void startup_other_cpus(unsigned long *processor_map)
-{
- unsigned long apicid = this_processors_id();
- int i;
-
- /* Assume the cpus are densly packed by apicid */
- for(i = 0; i < CONFIG_MAX_CPUS; i++) {
- unsigned long cpu_apicid = initial_apicid[i];
- if (cpu_apicid == -1) {
- printk_err("CPU %d not found\n",i);
- processor_map[i] = 0;
- continue;
- }
- if (cpu_apicid == apicid ) {
- continue;
- }
- if (!start_cpu(cpu_apicid)) {
- /* Put an error in processor_map[i]? */
- printk_err("CPU %d/%u would not start!\n",
- i, cpu_apicid);
- processor_map[i] = 0;
- }
- }
-}