mirror of https://github.com/l4ka/pistachio.git
Merged IA-32's and AMD64's init_cpu() as well as startup_system() function
This commit is contained in:
parent
43aab4b321
commit
08804e741f
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue