diff options
Diffstat (limited to 'src/arch/i386/lib/cpu.c')
-rw-r--r-- | src/arch/i386/lib/cpu.c | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/src/arch/i386/lib/cpu.c b/src/arch/i386/lib/cpu.c new file mode 100644 index 0000000000..3e27e7acdc --- /dev/null +++ b/src/arch/i386/lib/cpu.c @@ -0,0 +1,139 @@ +#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> +#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) +{ + 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 defined(i686) + // 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"); +} + +static void interrupts_on() +{ + /* 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 + */ + +#if defined(APIC) + /* Only Pentium Pro and later have those MSR stuff */ + unsigned long low, high; + + printk_info("Setting up local apic..."); + + /* Enable the local apic */ + rdmsr(APIC_BASE_MSR, low, high); + low |= APIC_BASE_MSR_ENABLE; + low &= ~APIC_BASE_MSR_ADDR_MASK; + low |= APIC_DEFAULT_BASE; + wrmsr(APIC_BASE_MSR, low, high); + + + /* 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) + ); +#else /* APIC */ +#ifdef i686 + /* Only Pentium Pro and later have those MSR stuff */ + unsigned long low, high; + + printk_info("Disabling local apic..."); + + rdmsr(APIC_BASE_MSR, low, high); + low &= ~APIC_BASE_MSR_ENABLE; + wrmsr(APIC_BASE_MSR, low, high); +#endif /* i686 */ +#endif /* APIC */ + printk_info("done.\n"); + post_code(0x9b); +} + +unsigned long cpu_initialize(struct mem_range *mem) +{ + /* 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); + + /* some cpus need a fixup done. This is the hook for doing that. */ + cpufixup(mem); + + /* Turn on caching if we haven't already */ + cache_on(mem); + + display_cpuid(); + mtrr_check(); + +#if 0 + /* now that everything is really up, enable the l2 cache if desired. + * The enable can wait until this point, because linuxbios and it's + * data areas are tiny, easily fitting into the L1 cache. + */ + configure_l2_cache(); +#endif + interrupts_on(); + printk_info("CPU #%d Initialized\n", processor_id); + return processor_id; +} + |