Merged IA-32's and AMD64's init_cpu() as well as startup_system() function

This commit is contained in:
Sebastian Biemueller 2007-08-19 16:17:11 +02:00
parent 43aab4b321
commit 08804e741f
5 changed files with 298 additions and 510 deletions

View File

@ -58,4 +58,4 @@ unless ARCH_AMD64 suppress dependent AMD64_COMPATIBILITY_MODE
derive AMD64_FXSR from CPU_AMD64_P4 or CPU_AMD64_K8
derive AMD64_TSC from CPU_AMD64_P4 or CPU_AMD64_K8
derive AMD64_PAT from CPU_AMD64_P4 or CPU_AMD64_K8
derive AMD64_PGE from CPU_AMD64_P4 or CPU_AMD64_K8

View File

@ -409,6 +409,7 @@ derive MULTI_ARCHITECTURE from ARCH_AMD64 and AMD64_COMPATIBILITY_MODE
derive X86_TSC from IA32_TSC or AMD64_TSC
derive X86_PAT from IA32_PAT or AMD64_PAT
derive X86_FXSR from IA32_FXSR or AMD64_FXSR
derive X86_PGE from IA32_PGE or AMD64_PGE
source "powerpc.cml"
source "powerpc64.cml"

View File

@ -88,18 +88,8 @@ void clear_bss (void);
**********************************************************************/
#if defined(CONFIG_SMP)
extern "C" void _start_ap(void);
extern "C" void init_paging();
extern "C" void SECTION(SEC_INIT) startup_processor();
extern spinlock_t smp_boot_lock;
/* commence to sync TSC */
extern void smp_bp_commence();
extern spinlock_t smp_commence_lock;
amd64_segdesc_t smp_boot_gdt[3];
static void setup_smp_boot_gdt()
void setup_smp_boot_gdt (void)
{
/* segment descriptors in long mode and legacy mode are almost identical.
* However, in long mode, most of the fields are ignored, thus we can set
@ -111,9 +101,6 @@ static void setup_smp_boot_gdt()
smp_boot_gdt[gdt_idx(X86_KDS)].set_seg((u64_t)0, amd64_segdesc_t::data, 0, amd64_segdesc_t::m_comp);
# undef gdt_idx
}
u8_t get_apic_id();
#endif
@ -137,7 +124,7 @@ void SECTION(SEC_INIT) check_cpu_features()
*
*/
static void SECTION(SEC_INIT) init_bootmem()
void SECTION(SEC_INIT) init_bootmem (void)
{
extern u8_t _start_bootmem[];
@ -151,7 +138,9 @@ static void SECTION(SEC_INIT) init_bootmem()
kmem.init(start_bootmem, end_bootmem);
}
static void add_more_kmem()
void add_more_kmem (void)
{
/*
@ -195,7 +184,7 @@ static void add_more_kmem()
}
static void SECTION(SEC_INIT) init_meminfo()
void SECTION(SEC_INIT) init_meminfo (void)
{
extern word_t _memory_descriptors_size[];
@ -359,7 +348,7 @@ void SECTION(SEC_INIT) setup_gdt(x86_tss_t &tss, cpuid_t cpuid)
/**
* setup_msrs: initializes all model specific registers for CPU
*/
static void setup_msrs()
void setup_msrs (void)
{
/* sysret (63..48) / syscall (47..32) CS/SS MSR */
@ -393,264 +382,3 @@ static void setup_msrs()
}
cpuid_t SECTION(".init.cpu") init_cpu()
{
cpuid_t cpuid = 0;
#if defined(CONFIG_SMP)
cpuid = get_apic_id();
#endif
/* set up task state segment */
TRACE_INIT("Activating TSS (CPU %d)\n", cpuid);
tss.setup();
/* set up global descriptor table */
TRACE_INIT("Initializing GDT (CPU %d)\n", cpuid);
setup_gdt(tss, cpuid);
/* activate idt */
TRACE_INIT("Activating IDT (CPU %d)\n", cpuid);;
idt.activate();
/* configure IRQ hardware - local part */
get_interrupt_ctrl()->init_cpu();
#if defined(CONFIG_PERFMON)
#if defined(CONFIG_TBUF_PERFMON)
/* initialize tracebuffer */
TRACE_INIT("Initializing Tracebuffer PMCs (CPU %d)\n", cpuid);
setup_perfmon_cpu(cpuid);
#endif
/* Allow performance counters for users */
TRACE_INIT("Enabling performance monitoring at user level (CPU %d)\n", cpuid);
x86_cr4_set(X86_CR4_PCE);
#endif /* defined(CONFIG_PERFMON) */
TRACE_INIT("Enabling global pages (CPU %d)\n", cpuid);
x86_mmu_t::enable_global_pages();
#if defined(CONFIG_FLUSHFILTER)
TRACE_INIT("Enabling flush filter (CPU %d)\n", cpuid);
x86_amdhwcr_t::enable_flushfilter();
#endif
/* activate msrs */
TRACE_INIT("Activating MSRS (CPU %d)\n", cpuid);
setup_msrs();
/* initialize the kernel's timer source - per CPU part*/
TRACE_INIT("Initializing Timer (CPU %d)\n", cpuid);
get_timer()->init_cpu();
/* initialize V4 processor info */
TRACE_INIT("Initializing Processor (CPU %d)\n", cpuid);
init_processor (cpuid, get_timer()->get_bus_freq(),
get_timer()->get_proc_freq());
/* CPU specific mappings */
get_kernel_space()->init_cpu_mappings(cpuid);
return cpuid;
}
/**
* Entry Point into C Kernel
*
* Precondition: 64bit-mode enabled
* idempotent mapping and mapping at KERNEL_OFFSET
*
*/
extern "C" void SECTION(".init.init64") startup_system(u32_t is_ap)
{
#if defined(CONFIG_SMP)
/* check if we are running on the BSP or on an AP */
if ( is_ap )
startup_processor();
#endif
/* clear bss */
clear_bss();
/* init console */
init_console();
/* call global constructors */
call_global_ctors();
/* call node constructors */
call_node_ctors();
/* say hello ... */
init_hello();
/* Get CPU Features */
TRACE_INIT("Checking CPU features\n");
check_cpu_features();
/* feed the kernel memory allocator */
TRACE_INIT("Initializing boot memory (%p - %p)\n",
start_bootmem, end_bootmem);
init_bootmem();
/* initialize kernel space */
TRACE_INIT("Initializing kernel space\n");
init_kernel_space();
{
/* copied here to catch errors early */
TRACE_INIT("Activating TSS (Preliminary)\n");
tss.setup();
/* set up global descriptor table */
TRACE_INIT("Initializing GDT (Preliminary)\n");
setup_gdt(tss, 0);
/* activate idt */
TRACE_INIT("Activating IDT (Preliminary)\n");
idt.activate();
}
/* initialize kernel interface page */
TRACE_INIT("Initializing kernel interface page (%p)\n",
get_kip());
get_kip()->init();
/* add additional kernel memory */
TRACE_INIT("Adding more kernel memory\n");
add_more_kmem();
/* init memory info */
TRACE_INIT("Initializing memory info\n");
init_meminfo();
/* initialize mapping database */
TRACE_INIT("Initializing mapping database\n");
init_mdb ();
#if defined(CONFIG_IO_FLEXPAGES)
/* configure IRQ hardware - global part */
TRACE_INIT("Initializing IO port space\n");
init_io_space();
#endif
#if defined(CONFIG_TRACEBUFFER)
/* allocate and setup tracebuffer */
TRACE_INIT("Initializing Tracebuffer\n");
setup_tracebuffer();
#endif
/* initialize kernel debugger if any */
TRACE_INIT("Initializing kernel debugger\n");
if (get_kip()->kdebug_init)
get_kip()->kdebug_init();
/* configure IRQ hardware - global part */
TRACE_INIT("Initializing IRQ hardware\n");
get_interrupt_ctrl()->init_arch();
/* initialize the kernel's timer source */
TRACE_INIT("Initializing Timer\n");
get_timer()->init_global();
#if defined(CONFIG_SMP)
/* start APs on an SMP + rendezvous */
{
TRACE_INIT("Starting application processors (%p->%p)\n",
_start_ap, SMP_STARTUP_ADDRESS);
/* aqcuire commence lock before starting any processor */
smp_commence_lock.init (1);
/* boot gdt */
setup_smp_boot_gdt();
/* IPI trap gates */
init_xcpu_handling ();
// copy startup code to startup page
for (word_t i = 0; i < AMD64_4KPAGE_SIZE / sizeof(word_t); i++)
((word_t*)SMP_STARTUP_ADDRESS)[i] = ((word_t*)_start_ap)[i];
/* at this stage we still have our 1:1 mapping at 0 */
/* this is the location of the warm-reset vector
* (40:67h in real mode addressing) which points to the
* cpu startup code
*/
*((volatile unsigned short *) 0x469) = (SMP_STARTUP_ADDRESS >> 4); // real mode segment selector
*((volatile unsigned short *) 0x467) = (SMP_STARTUP_ADDRESS) & 0xf; // offset
local_apic_t<APIC_MAPPINGS> local_apic;
// make sure we don't try to kick out more CPUs we can handle
int smp_cpus = 1;
u8_t apic_id = get_apic_id();
for (word_t id = 0; id < sizeof(word_t) * 8; id++)
{
if (id == apic_id)
continue;
// note the typecast (word_t)1
// This is important if we want to check for a maximum of
// 64 cpus .If we would'nt cast, (1 << id) would be a 32bit
// integer and overflow if id == 0x20.
if ((get_interrupt_ctrl()->get_lapic_map() & ((word_t)1 << id)) != 0)
{
if (++smp_cpus > CONFIG_SMP_MAX_CPUS)
{
printf("found more CPUs than Pistachio supports\n");
spin_forever();
}
smp_boot_lock.lock(); // unlocked by AP
TRACE_INIT("Sending startup IPI to APIC %d\n", id);
local_apic.send_init_ipi(id, true);
for (int i = 0; i < 100000; i++);
local_apic.send_init_ipi(id, false);
for (int i = 0; i < 100000; i++);
local_apic.send_startup_ipi(id, (void(*)(void))SMP_STARTUP_ADDRESS);
#warning VU: time out on AP call in
}
}
}
smp_bp_commence ();
#endif /* CONFIG_SMP */
/* Initialize CPU */
TRACE_INIT("Initializing CPU 0\n");
cpuid_t cpuid = init_cpu();
#if defined(CONFIG_AMD64_COMPATIBILITY_MODE)
TRACE_INIT("Initializing 32-bit kernel interface page (%p)\n",
ia32::get_kip());
ia32::get_kip()->init();
init_kip_32();
#endif /* defined(CONFIG_AMD64_COMPATIBILITY_MODE) */
/* initialize the scheduler */
get_current_scheduler()->init(true);
/* get the thing going - we should never return */
get_current_scheduler()->start(cpuid);
/* make sure we don't fall off the edge */
spin_forever(1);
}

View File

@ -34,8 +34,7 @@
#include <kmemory.h>
#include <mapping.h>
#include <ctors.h>
#define SEC_INIT ".init"
#include <init.h>
/* cpu specific types */
#include INC_ARCH(cpu.h)
@ -91,9 +90,6 @@ static word_t init_ptable[MAX_KERNEL_MAPPINGS][1024] __attribute__((aligned(4096
#endif /* !CONFIG_IA32_PSE */
// from glue/v4-x86/
void clear_bss (void);
/**********************************************************************
*
@ -101,24 +97,14 @@ void clear_bss (void);
*
**********************************************************************/
#if defined(CONFIG_SMP)
extern "C" void _start_ap(void);
extern spinlock_t smp_boot_lock;
/* commence to sync TSC */
extern void smp_bp_commence();
extern spinlock_t smp_commence_lock;
ia32_segdesc_t smp_boot_gdt[3];
static void setup_smp_boot_gdt()
void setup_smp_boot_gdt (void)
{
# define gdt_idx(x) ((x) >> 3)
smp_boot_gdt[gdt_idx(X86_KCS)].set_seg(0, ~0UL, 0, ia32_segdesc_t::code);
smp_boot_gdt[gdt_idx(X86_KDS)].set_seg(0, ~0UL, 0, ia32_segdesc_t::data);
# undef gdt_idx
}
u8_t get_apic_id();
#endif
@ -241,7 +227,7 @@ void SECTION(SEC_INIT) setup_gdt(x86_tss_t &tss, cpuid_t cpuid)
/**
* setup_msrs: initializes all model specific registers for CPU
*/
static void setup_msrs()
void setup_msrs (void)
{
#ifdef CONFIG_IA32_SYSENTER
/* here we also setup the model specific registers for the syscalls */
@ -329,63 +315,6 @@ void SECTION(".init.cpu") check_cpu_features()
}
}
/**
* init_cpu: initializes the processor
*
* this function is called once for each processor to initialize
* the processor specific data and registers
*/
cpuid_t SECTION(".init.cpu") init_cpu()
{
cpuid_t cpuid = 0;
/* configure IRQ hardware - local part
* this has to be done before reading the cpuid since it may change
* when having one of those broken BIOSes like ServerWorks */
get_interrupt_ctrl()->init_cpu();
#if defined(CONFIG_SMP)
cpuid = get_apic_id();
#endif
/* Allow performance counters for users */
#if defined(CONFIG_PERFMON)
#if defined(CONFIG_TBUF_PERFMON)
/* initialize tracebuffer */
setup_perfmon_cpu(cpuid);
#endif
/* Allow performance counters for users */
x86_cr4_set(X86_CR4_PCE);
#endif /* defined(CONFIG_PERFMON) */
/* initialize the CPU specific mappings */
get_kernel_space()->init_cpu_mappings(cpuid);
// call cpu ctors
call_cpu_ctors();
tss.setup(X86_KDS);
setup_gdt(tss, cpuid);
/* can take exceptions from now on,
* idt is initialized via a constructor */
idt.activate();
/* activate msrs */
setup_msrs();
/* initialize timer - local part */
get_timer()->init_cpu();
/* initialize V4 processor info */
init_processor (cpuid, get_timer()->get_bus_freq(),
get_timer()->get_proc_freq());
return cpuid;
}
/***********************************************************************
@ -414,7 +343,7 @@ static void __attribute__((unused)) dump_pdir()
* At system startup, a fixed amount of kernel memory is allocated
* to allow basic initialization of the system before sigma0 is up.
*/
static void SECTION(SEC_INIT) init_bootmem()
void SECTION(SEC_INIT) init_bootmem (void)
{
TRACE_INIT("Initializing boot memory (%p - %p)\n",
start_bootmem, end_bootmem);
@ -450,7 +379,7 @@ static void SECTION(SEC_INIT) init_bootmem()
/**
* init_meminfo: registers memory section with KIP
*/
static void SECTION(SEC_INIT) init_meminfo()
void SECTION(SEC_INIT) init_meminfo(void)
{
/* register virtual memory */
get_kip()->memory_info.insert(memdesc_t::conventional,
@ -495,7 +424,7 @@ static void SECTION(SEC_INIT) __attribute__((unused)) init_arch()
{
}
static void SECTION(SEC_INIT) add_more_kmem()
void SECTION(SEC_INIT) add_more_kmem (void)
{
/* Scan memory descriptors for a block of reserved physical memory
* that is within the range of (to be) contiguously mapped
@ -568,151 +497,6 @@ static void SECTION(SEC_INIT) add_more_kmem()
}
/**
* startup_system: starts up the system
*
* precondition: paging is initialized with init_paging
*
* The startup happens in two steps
* 1) all global initializations are performed
* this includes initializing necessary devices and
* the kernel debugger. The kernel memory allocator
* is set up (see init_arch).
*
* 2) the boot processor itself is initialized
*/
extern "C" void SECTION(SEC_INIT) startup_system()
{
clear_bss();
// allow printing in ctors
init_console ();
call_global_ctors();
call_node_ctors();
/* system initialization - boot CPU's job */
{
/* mention ourself */
init_hello ();
/* first thing -- check CPU features */
check_cpu_features();
/* feed the kernel memory allocator */
init_bootmem();
/* initialize the kernel pagetable */
init_kernel_space();
{ /* copied here to catch errors early */
tss.setup(X86_KDS);
setup_gdt(tss, 0);
idt.activate();
}
/* initialize kernel interface page */
get_kip()->init();
add_more_kmem();
init_meminfo ();
/* configure IRQ hardware - global part */
get_interrupt_ctrl()->init_arch();
/* initialize timer - global part */
get_timer()->init_global();
/* initialize mapping database */
init_mdb ();
#if defined(CONFIG_IO_FLEXPAGES)
/* initialize IO address space */
TRACE_INIT("Initializing IO space\n");
init_io_space();
#endif
#if defined(CONFIG_TRACEBUFFER)
/* allocate tracebuffer */
setup_tracebuffer();
#endif
/* initialize kernel debugger if any */
if (get_kip()->kdebug_init)
get_kip()->kdebug_init();
}
#if defined(CONFIG_SMP)
/* start APs on an SMP + rendezvous */
{
TRACE_INIT("Starting application processors (%p->%p)\n",
_start_ap, SMP_STARTUP_ADDRESS);
// aqcuire commence lock before starting any processor
smp_commence_lock.init (1);
// boot gdt
setup_smp_boot_gdt();
// IPI trap gates
init_xcpu_handling ();
// copy startup code to startup page
for (word_t i = 0; i < IA32_PAGE_SIZE / sizeof(word_t); i++)
((word_t*)SMP_STARTUP_ADDRESS)[i] = ((word_t*)_start_ap)[i];
/* at this stage we still have our 1:1 mapping at 0 */
*((volatile unsigned short *) 0x469) = (SMP_STARTUP_ADDRESS >> 4);
*((volatile unsigned short *) 0x467) = (SMP_STARTUP_ADDRESS) & 0xf;
local_apic_t<APIC_MAPPINGS> local_apic;
// make sure we don't try to kick out more CPUs we can handle
int smp_cpus = 1;
u8_t apic_id = get_apic_id();
for (word_t id = 0; id < sizeof(word_t) * 8; id++)
{
if (id == apic_id)
continue;
if ((get_interrupt_ctrl()->get_lapic_map() & (1 << id)) != 0)
{
if (++smp_cpus > CONFIG_SMP_MAX_CPUS)
{
printf("found more CPUs than Pistachio supports\n");
spin_forever();
}
smp_boot_lock.lock(); // unlocked by AP
TRACE_INIT("Sending startup IPI to APIC %d\n", id);
local_apic.send_init_ipi(id, true);
for (int i = 0; i < 100000; i++);
local_apic.send_init_ipi(id, false);
local_apic.send_startup_ipi(id, (void(*)(void))SMP_STARTUP_ADDRESS);
#warning VU: time out on AP call in
}
}
}
#endif
/* local initialization - all are equal */
cpuid_t cpuid = init_cpu ();
TRACE_INIT("%s done\n", __FUNCTION__);
#ifdef CONFIG_SMP
smp_bp_commence ();
#endif
get_current_scheduler()->init (true);
get_current_scheduler()->start (cpuid);
/* does not return */
spin_forever(cpuid);
}
/**
* init_paging: initializes the startup pagetable

View File

@ -34,17 +34,37 @@
#include <ctors.h>
#include <init.h>
#include INC_ARCHX(x86,apic.h)
#include INC_GLUE(idt.h)
#include INC_GLUE(intctrl.h)
#include INC_GLUE(space.h)
#include INC_GLUEX(x86,timer.h)
#include INC_GLUEX(x86,memory.h)
#include INC_ARCHX(x86,apic.h)
#include INC_ARCHX(x86,amdhwcr.h)
#include INC_API(kernelinterface.h)
#include INC_API(processor.h)
#include INC_API(schedule.h)
#include INC_PLAT(perfmon.h)
#if defined(CONFIG_AMD64_COMPATIBILITY_MODE)
#include INC_GLUE(ia32/kernelinterface.h)
#include INC_GLUE(ia32/init.h)
#endif /* defined(CONFIG_AMD64_COMPATIBILITY_MODE) */
// from either glue/v4-ia32/ or glue/v4-x86/
void add_more_kmem();
void setup_msrs();
void SECTION(SEC_INIT) init_meminfo();
void SECTION(".init.cpu") check_cpu_features();
cpuid_t SECTION(".init.cpu") init_cpu();
void SECTION(SEC_INIT) init_bootmem();
void SECTION(SEC_INIT) setup_gdt(x86_tss_t &tss, cpuid_t cpuid);
void SECTION(SEC_INIT) setup_tracebuffer (void);
#if defined(CONFIG_SMP)
/**************************************************************************
@ -60,16 +80,14 @@ spinlock_t smp_boot_lock;
spinlock_t smp_commence_lock;
//INLINE
u8_t get_apic_id (void)
INLINE u8_t get_apic_id (void)
{
local_apic_t<APIC_MAPPINGS> apic;
return apic.id();
}
//static
void smp_ap_commence (void)
static void smp_ap_commence (void)
{
smp_boot_lock.unlock();
@ -80,8 +98,7 @@ void smp_ap_commence (void)
}
//static
void smp_bp_commence (void)
static void smp_bp_commence (void)
{
// wait for last processor to call in
smp_boot_lock.lock();
@ -126,3 +143,261 @@ void SECTION(SEC_INIT) clear_bss (void)
*p = 0;
}
/**
* init_cpu: initializes the processor
*
* this function is called once for each processor to initialize
* the processor specific data and registers
*/
cpuid_t SECTION(".init.cpu") init_cpu (void)
{
cpuid_t cpuid = 0;
/* configure IRQ hardware - local part
* this has to be done before reading the cpuid since it may change
* when having one of those broken BIOSes like ServerWorks */
get_interrupt_ctrl()->init_cpu();
#if defined(CONFIG_SMP)
cpuid = get_apic_id();
#endif
call_cpu_ctors();
TRACE_INIT("Activating TSS (CPU %d)\n", cpuid);
tss.setup(X86_KDS);
TRACE_INIT("Initializing GDT (CPU %d)\n", cpuid);
setup_gdt(tss, cpuid);
/* can take exceptions from now on,
* idt is initialized via a constructor */
TRACE_INIT("Activating IDT (CPU %d)\n", cpuid);;
idt.activate();
#if defined(CONFIG_PERFMON)
#if defined(CONFIG_TBUF_PERFMON)
/* initialize tracebuffer */
TRACE_INIT("Initializing Tracebuffer PMCs (CPU %d)\n", cpuid);
setup_perfmon_cpu(cpuid);
#endif
/* Allow performance counters for users */
TRACE_INIT("Enabling performance monitoring at user level (CPU %d)\n", cpuid);
x86_cr4_set(X86_CR4_PCE);
#endif /* defined(CONFIG_PERFMON) */
#if defined(CONFIG_X86_PGE)
TRACE_INIT("Enabling global pages (CPU %d)\n", cpuid);
x86_mmu_t::enable_global_pages();
#endif
#if defined(CONFIG_FLUSHFILTER)
TRACE_INIT("Enabling flush filter (CPU %d)\n", cpuid);
x86_amdhwcr_t::enable_flushfilter();
#endif
TRACE_INIT("Activating MSRS (CPU %d)\n", cpuid);
setup_msrs();
TRACE_INIT("Initializing Timer (CPU %d)\n", cpuid);
get_timer()->init_cpu();
/* initialize V4 processor info */
TRACE_INIT("Initializing Processor (CPU %d)\n", cpuid);
init_processor (cpuid, get_timer()->get_bus_freq(),
get_timer()->get_proc_freq());
/* CPU specific mappings */
get_kernel_space()->init_cpu_mappings(cpuid);
return cpuid;
}
/**
* Entry Point into C Kernel
*
* Precondition:
* - paging is initialized via init_paging
* - idempotent mapping at KERNEL_OFFSET
*
* The startup happens in two steps
* 1) all global initializations are performed
* this includes initializing necessary devices and
* the kernel debugger. The kernel memory allocator
* is set up (see init_arch).
*
* 2) the boot processor itself is initialized
*/
#if defined(CONFIG_IS_64BIT)
extern "C" void SECTION(".init.init64") startup_system(u32_t is_ap)
#else
extern "C" void SECTION(SEC_INIT) startup_system (void)
#endif
{
#if defined(CONFIG_IS_64BIT) && defined(CONFIG_SMP)
/* check if we are running on the BSP or on an AP */
if ( is_ap )
startup_processor();
#endif
clear_bss();
init_console();
call_global_ctors();
call_node_ctors();
init_hello();
TRACE_INIT("Checking CPU features\n");
check_cpu_features();
/* feed the kernel memory allocator */
TRACE_INIT("Initializing boot memory (%p - %p)\n",
start_bootmem, end_bootmem);
init_bootmem();
TRACE_INIT("Initializing kernel space\n");
init_kernel_space();
TRACE_INIT("Activating TSS (Preliminary)\n");
tss.setup(X86_KDS);
TRACE_INIT("Initializing GDT (Preliminary)\n");
setup_gdt(tss, 0);
TRACE_INIT("Activating IDT (Preliminary)\n");
idt.activate();
TRACE_INIT("Initializing kernel interface page (%p)\n", get_kip());
get_kip()->init();
TRACE_INIT("Adding more kernel memory\n");
add_more_kmem();
TRACE_INIT("Initializing memory info\n");
init_meminfo();
TRACE_INIT("Initializing mapping database\n");
init_mdb();
#if defined(CONFIG_IO_FLEXPAGES)
TRACE_INIT("Initializing IO port space\n");
init_io_space();
#endif
#if defined(CONFIG_TRACEBUFFER)
/* allocate and setup tracebuffer */
TRACE_INIT("Initializing Tracebuffer\n");
setup_tracebuffer();
#endif
TRACE_INIT("Initializing kernel debugger\n");
if (get_kip()->kdebug_init)
get_kip()->kdebug_init();
/* configure IRQ hardware - global part */
TRACE_INIT("Initializing IRQ hardware\n");
get_interrupt_ctrl()->init_arch();
/* initialize the kernel's timer source */
TRACE_INIT("Initializing Timer\n");
get_timer()->init_global();
#if defined(CONFIG_SMP)
/* start APs on an SMP + rendezvous */
TRACE_INIT("Starting application processors (%p->%p)\n",
_start_ap, SMP_STARTUP_ADDRESS);
/* aqcuire commence lock before starting any processor */
smp_commence_lock.init (1);
/* boot gdt */
setup_smp_boot_gdt();
/* IPI trap gates */
init_xcpu_handling ();
// copy startup code to startup page
for (word_t i = 0; i < X86_4KPAGE_SIZE / sizeof(word_t); i++)
((word_t*)SMP_STARTUP_ADDRESS)[i] = ((word_t*)_start_ap)[i];
/* at this stage we still have our 1:1 mapping at 0 */
/* this is the location of the warm-reset vector
* (40:67h in real mode addressing) which points to the
* cpu startup code
*/
*((volatile unsigned short *) 0x469) = (SMP_STARTUP_ADDRESS >> 4); // real mode segment selector
*((volatile unsigned short *) 0x467) = (SMP_STARTUP_ADDRESS) & 0xf; // offset
local_apic_t<APIC_MAPPINGS> local_apic;
// make sure we don't try to kick out more CPUs we can handle
int smp_cpus = 1;
u8_t apic_id = get_apic_id();
for (word_t id = 0; id < sizeof(word_t) * 8; id++)
{
if (id == apic_id)
continue;
// note the typecast (word_t)1
// This is important if we want to check for a maximum of
// 64 cpus .If we would'nt cast, (1 << id) would be a 32bit
// integer and overflow if id == 0x20.
if ((get_interrupt_ctrl()->get_lapic_map() & ((word_t)1 << id)) != 0)
{
if (++smp_cpus > CONFIG_SMP_MAX_CPUS)
{
printf("found more CPUs than Pistachio supports\n");
spin_forever();
}
smp_boot_lock.lock(); // unlocked by AP
TRACE_INIT("Sending startup IPI to APIC %d\n", id);
local_apic.send_init_ipi(id, true);
for (int i = 0; i < 100000; i++);
local_apic.send_init_ipi(id, false);
for (int i = 0; i < 100000; i++);
local_apic.send_startup_ipi(id, (void(*)(void))SMP_STARTUP_ADDRESS);
#warning VU: time out on AP call in
}
}
smp_bp_commence ();
#endif /* CONFIG_SMP */
/* Initialize CPU */
TRACE_INIT("Initializing CPU 0\n");
cpuid_t cpuid = init_cpu();
#if defined(CONFIG_AMD64_COMPATIBILITY_MODE)
TRACE_INIT("Initializing 32-bit kernel interface page (%p)\n",
ia32::get_kip());
ia32::get_kip()->init();
init_kip_32();
#endif /* defined(CONFIG_AMD64_COMPATIBILITY_MODE) */
/* initialize the scheduler */
get_current_scheduler()->init(true);
/* get the thing going - we should never return */
get_current_scheduler()->start(cpuid);
/* make sure we don't fall off the edge */
spin_forever(1);
}