* Delay initializing SMP stuff like APICs and kstacks of non-boot CPUs until after the boot menu

* When disabling SMP initialization of those parts is avoided so it works more cleanly
* Moved smp_find_mp_config() into smp_init() and moved MPS specific parts into smp_do_mp_config()
* Removed the global floating struct, if found it is now passed into smp_do_mp_config() like it is done for ACPI
* Made the file a bit more C++, applied coding style to some variable names and unified/improved some of the debug output

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23216 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz 2008-01-02 02:07:23 +00:00
parent 50a57aafa0
commit e812c77e4a
3 changed files with 112 additions and 135 deletions

View File

@ -60,8 +60,6 @@ extern "C" void smp_trampoline(void);
extern "C" void smp_trampoline_end(void);
static struct mp_floating_struct *sFloatingStruct = NULL;
static int smp_get_current_cpu(void);
@ -90,19 +88,17 @@ smp_get_current_cpu(void)
}
static uint32 *
static mp_floating_struct *
smp_mp_probe(uint32 base, uint32 limit)
{
uint32 *ptr;
TRACE(("smp_mp_probe: entry base 0x%lx, limit 0x%lx\n", base, limit));
for (ptr = (uint32 *) base; (uint32)ptr < limit; ptr++) {
if (*ptr == MP_FLOATING_SIGNATURE) {
TRACE(("smp_mp_probe: found floating pointer structure at %p\n", ptr));
return ptr;
for (uint32 *pointer = (uint32 *)base; (uint32)pointer < limit; pointer++) {
if (*pointer == MP_FLOATING_SIGNATURE) {
TRACE(("smp_mp_probe: found floating pointer structure at %p\n", pointer));
return (mp_floating_struct *)pointer;
}
}
return NULL;
}
@ -122,28 +118,43 @@ smp_acpi_probe(uint32 base, uint32 limit)
}
static void
smp_do_mp_config()
static status_t
smp_do_mp_config(mp_floating_struct *floatingStruct)
{
struct mp_config_table *config;
char *ptr;
int i;
#ifdef TRACE_SMP
const char *cpu_family[] = { "", "", "", "", "Intel 486",
"Intel Pentium", "Intel Pentium Pro", "Intel Pentium II" };
TRACE(("smp: intel mp version %s, %s",
(floatingStruct->spec_revision == 1) ? "1.1" : "1.4",
(floatingStruct->mp_feature_2 & 0x80)
? "imcr and pic compatibility mode.\n"
: "virtual wire compatibility mode.\n"));
if (floatingStruct->config_table == NULL) {
#if 1
// XXX need to implement
TRACE(("smp: standard configuration %d unimplemented\n", floatingStruct->mp_feature_1));
gKernelArgs.num_cpus = 1;
return B_OK;
#else
/* this system conforms to one of the default configurations */
TRACE(("smp: standard configuration %d\n", floatingStruct->mp_feature_1));
gKernelArgs.num_cpus = 2;
gKernelArgs.cpu_apic_id[0] = 0;
gKernelArgs.cpu_apic_id[1] = 1;
apic_phys = (unsigned int *) 0xfee00000;
ioapic_phys = (unsigned int *) 0xfec00000;
dprintf("smp: WARNING: standard configuration code is untested");
return B_OK;
#endif
}
/*
* we are not running in standard configuration, so we have to look through
* all of the mp configuration table crap to figure out how many processors
* we have, where our apics are, etc.
*/
mp_config_table *config = floatingStruct->config_table;
gKernelArgs.num_cpus = 0;
config = sFloatingStruct->config_table;
/* print out our new found configuration. */
TRACE(("smp: oem id: %.8s product id: %.12s\n", config->oem,
config->product));
TRACE(("smp: base table has %d entries, extended section %d bytes\n",
@ -151,58 +162,62 @@ smp_do_mp_config()
gKernelArgs.arch_args.apic_phys = (uint32)config->apic;
ptr = (char *)((uint32)config + sizeof(struct mp_config_table));
for (i = 0; i < config->num_base_entries; i++) {
switch (*ptr) {
char *pointer = (char *)((uint32)config + sizeof(struct mp_config_table));
for (int32 i = 0; i < config->num_base_entries; i++) {
switch (*pointer) {
case MP_BASE_PROCESSOR:
{
if (gKernelArgs.num_cpus == MAX_BOOT_CPUS) {
TRACE(("smp: already reached maximum boot CPUs (%d)\n", MAX_BOOT_CPUS));
ptr += sizeof(struct mp_base_processor);
pointer += sizeof(struct mp_base_processor);
break;
}
struct mp_base_processor *processor = (struct mp_base_processor *)ptr;
struct mp_base_processor *processor = (struct mp_base_processor *)pointer;
gKernelArgs.arch_args.cpu_apic_id[gKernelArgs.num_cpus] = processor->apic_id;
gKernelArgs.arch_args.cpu_os_id[processor->apic_id] = gKernelArgs.num_cpus;
gKernelArgs.arch_args.cpu_apic_version[gKernelArgs.num_cpus] = processor->apic_version;
#ifdef TRACE_SMP
const char *cpuFamily[] = { "", "", "", "", "Intel 486",
"Intel Pentium", "Intel Pentium Pro", "Intel Pentium II" };
#endif
TRACE(("smp: cpu#%ld: %s, apic id %d, version %d%s\n",
gKernelArgs.num_cpus, cpu_family[(processor->signature & 0xf00) >> 8],
gKernelArgs.num_cpus, cpuFamily[(processor->signature & 0xf00) >> 8],
processor->apic_id, processor->apic_version, (processor->cpu_flags & 0x2) ?
", BSP" : ""));
gKernelArgs.num_cpus++;
ptr += sizeof(struct mp_base_processor);
pointer += sizeof(struct mp_base_processor);
break;
}
case MP_BASE_BUS:
{
struct mp_base_bus *bus = (struct mp_base_bus *)ptr;
struct mp_base_bus *bus = (struct mp_base_bus *)pointer;
TRACE(("smp: bus %d: %c%c%c%c%c%c\n", bus->bus_id,
bus->name[0], bus->name[1], bus->name[2], bus->name[3],
bus->name[4], bus->name[5]));
ptr += sizeof(struct mp_base_bus);
pointer += sizeof(struct mp_base_bus);
break;
}
case MP_BASE_IO_APIC:
{
struct mp_base_ioapic *io = (struct mp_base_ioapic *) ptr;
struct mp_base_ioapic *io = (struct mp_base_ioapic *)pointer;
gKernelArgs.arch_args.ioapic_phys = (uint32)io->addr;
TRACE(("smp: found io apic with apic id %d, version %d\n",
io->ioapic_id, io->ioapic_version));
ptr += sizeof(struct mp_base_ioapic);
pointer += sizeof(struct mp_base_ioapic);
break;
}
case MP_BASE_IO_INTR:
case MP_BASE_LOCAL_INTR:
{
struct mp_base_interrupt *interrupt = (struct mp_base_interrupt *)ptr;
struct mp_base_interrupt *interrupt = (struct mp_base_interrupt *)pointer;
dprintf("smp: %s int: type %d, source bus %d, irq %3d, dest apic %d, int %3d, polarity %d, trigger mode %d\n",
interrupt->type == MP_BASE_IO_INTR ? "I/O" : "local",
@ -210,7 +225,7 @@ smp_do_mp_config()
interrupt->source_bus_irq, interrupt->dest_apic_id,
interrupt->dest_apic_int, interrupt->polarity,
interrupt->trigger_mode);
ptr += sizeof(struct mp_base_interrupt);
pointer += sizeof(struct mp_base_interrupt);
break;
}
}
@ -221,9 +236,7 @@ smp_do_mp_config()
(void *)gKernelArgs.arch_args.ioapic_phys,
gKernelArgs.num_cpus);
// this BIOS looks broken, because it didn't report any cpus (VMWare)
if (gKernelArgs.num_cpus == 0)
gKernelArgs.num_cpus = 1;
return gKernelArgs.num_cpus > 0 ? B_OK : B_ERROR;
}
@ -313,69 +326,6 @@ smp_do_acpi_config(acpi_rsdp *rsdp)
}
static int
smp_find_mp_config(void)
{
int i;
#if NO_SMP
if (1)
return gKernelArgs.num_cpus = 1;
#endif
// first try to find ACPI tables to get MP configuration as it handles
// physical as well as logical MP configurations as in multiple cpus,
// multiple cores or hyper threading.
for (i = 0; acpi_scan_spots[i].length > 0; i++) {
acpi_rsdp *rsdp = smp_acpi_probe(smp_scan_spots[i].start,
smp_scan_spots[i].stop);
if (rsdp != NULL && smp_do_acpi_config(rsdp) == B_OK)
return gKernelArgs.num_cpus;
}
for (i = 0; smp_scan_spots[i].length > 0; i++) {
sFloatingStruct = (struct mp_floating_struct *)smp_mp_probe(smp_scan_spots[i].start,
smp_scan_spots[i].stop);
if (sFloatingStruct != NULL)
break;
}
if (sFloatingStruct != NULL) {
TRACE(("smp_boot: intel mp version %s, %s",
(sFloatingStruct->spec_revision == 1) ? "1.1" : "1.4",
(sFloatingStruct->mp_feature_2 & 0x80)
? "imcr and pic compatibility mode.\n"
: "virtual wire compatibility mode.\n"));
if (sFloatingStruct->config_table == NULL) {
// XXX need to implement
#if 1
TRACE(("smp: standard configuration %d unimplemented\n", sFloatingStruct->mp_feature_1));
gKernelArgs.num_cpus = 1;
return 1;
#else
/* this system conforms to one of the default configurations */
// mp_num_def_config = sFloatingStruct->mp_feature_1;
TRACE(("smp: standard configuration %d\n", sFloatingStruct->mp_feature_1));
/* num_cpus = 2;
gKernelArgs.cpu_apic_id[0] = 0;
gKernelArgs.cpu_apic_id[1] = 1;
apic_phys = (unsigned int *) 0xfee00000;
ioapic_phys = (unsigned int *) 0xfec00000;
kprintf ("smp: WARNING: standard configuration code is untested");
*/
#endif
} else {
smp_do_mp_config();
}
return gKernelArgs.num_cpus;
}
return gKernelArgs.num_cpus = 1;
}
/** Target function of the trampoline code.
* The trampoline code should have the pgdir and a gdt set up for us,
* along with us being on the final stack for this processor. We need
@ -459,21 +409,48 @@ calculate_apic_timer_conversion_factor(void)
void
smp_boot_other_cpus(void)
smp_init_other_cpus(void)
{
uint32 trampolineCode;
uint32 trampolineStack;
uint32 i;
void *handle = load_driver_settings(B_SAFEMODE_DRIVER_SETTINGS);
if (handle != NULL) {
if (get_driver_boolean_parameter(handle, B_SAFEMODE_DISABLE_SMP, false, false)) {
// SMP has been disabled!
TRACE(("smp disabled per safemode setting\n"));
gKernelArgs.num_cpus = 1;
}
unload_driver_settings(handle);
}
if (gKernelArgs.num_cpus < 2)
return;
TRACE(("smp: found %ld cpus\n", gKernelArgs.num_cpus));
TRACE(("smp: apic_phys = %p\n", (void *)gKernelArgs.arch_args.apic_phys));
TRACE(("smp: ioapic_phys = %p\n", (void *)gKernelArgs.arch_args.ioapic_phys));
// map in the apic & ioapic
gKernelArgs.arch_args.apic = (uint32 *)mmu_map_physical_memory(
gKernelArgs.arch_args.apic_phys, B_PAGE_SIZE, kDefaultPageFlags);
gKernelArgs.arch_args.ioapic = (uint32 *)mmu_map_physical_memory(
gKernelArgs.arch_args.ioapic_phys, B_PAGE_SIZE, kDefaultPageFlags);
TRACE(("smp: apic = %p\n", gKernelArgs.arch_args.apic));
TRACE(("smp: ioapic = %p\n", gKernelArgs.arch_args.ioapic));
// calculate how fast the apic timer is
calculate_apic_timer_conversion_factor();
for (uint32 i = 1; i < gKernelArgs.num_cpus; i++) {
// create a final stack the trampoline code will put the ap processor on
gKernelArgs.cpu_kstack[i].start = (addr_t)mmu_allocate(NULL, KERNEL_STACK_SIZE);
gKernelArgs.cpu_kstack[i].size = KERNEL_STACK_SIZE;
}
}
void
smp_boot_other_cpus(void)
{
if (gKernelArgs.num_cpus < 2)
return;
@ -486,11 +463,11 @@ smp_boot_other_cpus(void)
// (these have to be < 1M physical, 0xa0000-0xfffff is reserved by the BIOS,
// and when PXE services are used, the 0x8d000-0x9ffff is also reserved)
#ifdef _PXE_ENV
trampolineCode = 0x8b000;
trampolineStack = 0x8c000;
uint32 trampolineCode = 0x8b000;
uint32 trampolineStack = 0x8c000;
#else
trampolineCode = 0x9f000;
trampolineStack = 0x9e000;
uint32 trampolineCode = 0x9f000;
uint32 trampolineStack = 0x9e000;
#endif
// copy the trampoline code over
@ -498,7 +475,7 @@ smp_boot_other_cpus(void)
(uint32)&smp_trampoline_end - (uint32)&smp_trampoline);
// boot the cpus
for (i = 1; i < gKernelArgs.num_cpus; i++) {
for (uint32 i = 1; i < gKernelArgs.num_cpus; i++) {
uint32 *finalStack;
uint32 *tempStack;
uint32 config;
@ -611,31 +588,29 @@ smp_add_safemode_menus(Menu *menu)
void
smp_init(void)
{
if (smp_find_mp_config() > 1) {
uint32 i;
#if NO_SMP
gKernelArgs.num_cpus = 1;
return;
#endif
TRACE(("smp_boot: had found > 1 cpus\n"));
TRACE(("post config:\n"));
TRACE(("num_cpus = %ld\n", gKernelArgs.num_cpus));
TRACE(("apic_phys = %p\n", (void *)gKernelArgs.arch_args.apic_phys));
TRACE(("ioapic_phys = %p\n", (void *)gKernelArgs.arch_args.ioapic_phys));
// map in the apic & ioapic
gKernelArgs.arch_args.apic = (uint32 *)mmu_map_physical_memory(
gKernelArgs.arch_args.apic_phys, B_PAGE_SIZE, kDefaultPageFlags);
gKernelArgs.arch_args.ioapic = (uint32 *)mmu_map_physical_memory(
gKernelArgs.arch_args.ioapic_phys, B_PAGE_SIZE, kDefaultPageFlags);
TRACE(("apic = %p\n", gKernelArgs.arch_args.apic));
TRACE(("ioapic = %p\n", gKernelArgs.arch_args.ioapic));
// calculate how fast the apic timer is
calculate_apic_timer_conversion_factor();
for (i = 1; i < gKernelArgs.num_cpus; i++) {
// create a final stack the trampoline code will put the ap processor on
gKernelArgs.cpu_kstack[i].start = (addr_t)mmu_allocate(NULL, KERNEL_STACK_SIZE);
gKernelArgs.cpu_kstack[i].size = KERNEL_STACK_SIZE;
}
// first try to find ACPI tables to get MP configuration as it handles
// physical as well as logical MP configurations as in multiple cpus,
// multiple cores or hyper threading.
for (int32 i = 0; acpi_scan_spots[i].length > 0; i++) {
acpi_rsdp *rsdp = smp_acpi_probe(smp_scan_spots[i].start,
smp_scan_spots[i].stop);
if (rsdp != NULL && smp_do_acpi_config(rsdp) == B_OK)
return;
}
// then try to find MPS tables and do configuration based on them
for (int32 i = 0; smp_scan_spots[i].length > 0; i++) {
mp_floating_struct *floatingStruct = smp_mp_probe(
smp_scan_spots[i].start, smp_scan_spots[i].stop);
if (floatingStruct != NULL && smp_do_mp_config(floatingStruct) == B_OK)
return;
}
// everything failed or we are not running an SMP system
gKernelArgs.num_cpus = 1;
}

View File

@ -18,6 +18,7 @@ extern "C" {
#endif
extern void smp_init(void);
extern void smp_init_other_cpus(void);
extern void smp_boot_other_cpus(void);
#ifdef __cplusplus

View File

@ -75,6 +75,7 @@ platform_start_kernel(void)
// or I don't see something important...
addr_t stackTop = gKernelArgs.cpu_kstack[0].start + gKernelArgs.cpu_kstack[0].size;
smp_init_other_cpus();
serial_cleanup();
mmu_init_for_kernel();
smp_boot_other_cpus();