Now that things are in place, we switch to parallel init. The key to this change is that the INIT/STARTUP sequence is done in one step, and all cpus wake up at the same time. Synchronisation is done via waiting for individual flags stored in separate memory locations. --- i386/i386/apic.h | 4 ++- i386/i386/mp_desc.c | 65 ++++++++++++--------------------------------- i386/i386/mp_desc.h | 4 --- i386/i386/smp.c | 20 +++++++------- i386/i386/smp.h | 2 +- kern/processor.c | 4 --- 6 files changed, 31 insertions(+), 68 deletions(-)
diff --git a/i386/i386/apic.h b/i386/i386/apic.h index cb700c44..5b38bfba 100644 --- a/i386/i386/apic.h +++ b/i386/i386/apic.h @@ -314,7 +314,9 @@ extern uint32_t *hpet_addr; /* Since Logical Destination Register only has 8 bits of mask, * we can only address 8 unique groups of cpus for IPIs. */ -#define APIC_LOGICAL_ID(cpu) (1u << ((cpu) % 8)) +#define APIC_LOGICAL_CPU_GROUPS 8 +#define APIC_LOGICAL_ID(cpu) (1u << ((cpu) % APIC_LOGICAL_CPU_GROUPS)) + /* Set or clear a bit in a 255-bit APIC mask register. These registers are spread through eight 32-bit registers. */ diff --git a/i386/i386/mp_desc.c b/i386/i386/mp_desc.c index 3802cdc6..c90600f2 100644 --- a/i386/i386/mp_desc.c +++ b/i386/i386/mp_desc.c @@ -95,11 +95,6 @@ interrupt_stack_alloc(void) } #if NCPUS > 1 -/* - * Flag to mark SMP init by BSP complete - */ -int bspdone; - phys_addr_t apboot_addr; extern void *apboot, *apbootend; extern volatile ApicLocalUnit* lapic; @@ -233,9 +228,8 @@ paging_enable(void) void cpu_setup(int cpu) { - pmap_make_temporary_mapping(); pmap_set_page_dir(); - printf("AP=(%u) tempmap done\n", cpu); + printf("AP=(%u) pagedir done\n", cpu); paging_enable(); flush_instr_queue(); @@ -260,13 +254,6 @@ cpu_setup(int cpu) ap_ktss_init(cpu); printf("AP=(%u) ktss done\n", cpu); - pmap_remove_temporary_mapping(); - printf("AP=(%u) remove tempmap done\n", cpu); - - pmap_set_page_dir(); - flush_tlb(); - printf("AP=(%u) reset page dir done\n", cpu); - /* Initialize machine_slot fields with the cpu data */ machine_slot[cpu].cpu_subtype = CPU_SUBTYPE_AT386; machine_slot[cpu].cpu_type = machine_slot[0].cpu_type; @@ -284,36 +271,9 @@ cpu_ap_main() assert(cpu > 0); - do { - cpu_pause(); - } while (bspdone != cpu); - - __sync_synchronize(); - cpu_setup(cpu); } -kern_return_t -cpu_start(int cpu) -{ - int err; - - assert(machine_slot[cpu].running != TRUE); - - uint16_t apic_id = apic_get_cpu_apic_id(cpu); - - printf("Trying to enable: %d at 0x%lx\n", apic_id, apboot_addr); - - err = smp_startup_cpu(apic_id, apboot_addr); - - if (!err) { - printf("Started cpu %d (lapic id %04x)\n", cpu, apic_id); - return KERN_SUCCESS; - } - printf("FATAL: Cannot init AP %d\n", cpu); - for (;;); -} - void start_other_cpus(void) { @@ -340,23 +300,32 @@ start_other_cpus(void) */ lapic_disable(); - bspdone = 0; + /* This is set once for all APs to use */ + pmap_make_temporary_mapping(); + for (cpu = 1; cpu < ncpus; cpu++) { machine_slot[cpu].running = FALSE; + } - //Start cpu - printf("Starting AP %d\n", cpu); - cpu_start(cpu); + smp_startup_cpus(apic_get_current_cpu(), apboot_addr); + + for (cpu = 1; cpu < ncpus; cpu++) { + printf("Waiting for AP %d\n", cpu); - bspdone++; do { cpu_pause(); } while (machine_slot[cpu].running == FALSE); - - __sync_synchronize(); } printf("BSP: Completed SMP init\n"); + pmap_remove_temporary_mapping(); + + /* Flush TLB on all cpu groups */ + ncpus = (ncpus < APIC_LOGICAL_CPU_GROUPS) ? ncpus : APIC_LOGICAL_CPU_GROUPS; + for (cpu = 1; cpu < ncpus; cpu++) { + interrupt_processor(cpu); + } + /* Re-enable IOAPIC interrupts as per setup */ lapic_enable(); } diff --git a/i386/i386/mp_desc.h b/i386/i386/mp_desc.h index dc3a7dc8..92790171 100644 --- a/i386/i386/mp_desc.h +++ b/i386/i386/mp_desc.h @@ -74,8 +74,6 @@ extern struct real_descriptor *mp_gdt[NCPUS]; extern uint8_t solid_intstack[]; -extern int bspdone; - /* * Each CPU calls this routine to set up its descriptor tables. */ @@ -89,8 +87,6 @@ extern void interrupt_processor(int cpu); extern void start_other_cpus(void); -extern kern_return_t cpu_start(int cpu); - extern kern_return_t cpu_control(int cpu, const int *info, unsigned int count); extern void interrupt_stack_alloc(void); diff --git a/i386/i386/smp.c b/i386/i386/smp.c index 5861796a..befa0510 100644 --- a/i386/i386/smp.c +++ b/i386/i386/smp.c @@ -90,7 +90,7 @@ wait_for_ipi(void) } static int -smp_send_ipi_init(int apic_id) +smp_send_ipi_init(int bsp_apic_id) { int err; @@ -100,7 +100,7 @@ smp_send_ipi_init(int apic_id) * * This is EDGE triggered to match the deassert */ - apic_send_ipi(NO_SHORTHAND, INIT, PHYSICAL, ASSERT, EDGE, 0, apic_id); + apic_send_ipi(ALL_EXCLUDING_SELF, INIT, PHYSICAL, ASSERT, EDGE, 0, bsp_apic_id); /* Wait for delivery */ wait_for_ipi(); @@ -113,7 +113,7 @@ smp_send_ipi_init(int apic_id) * that does not support STARTUP IPIs at all, and instead jump * via a warm reset vector. */ - apic_send_ipi(NO_SHORTHAND, INIT, PHYSICAL, DE_ASSERT, EDGE, 0, apic_id); + apic_send_ipi(ALL_EXCLUDING_SELF, INIT, PHYSICAL, DE_ASSERT, EDGE, 0, bsp_apic_id); /* Wait for delivery */ wait_for_ipi(); @@ -126,7 +126,7 @@ smp_send_ipi_init(int apic_id) } static int -smp_send_ipi_startup(int apic_id, int vector) +smp_send_ipi_startup(int bsp_apic_id, int vector) { int err; @@ -137,7 +137,7 @@ smp_send_ipi_startup(int apic_id, int vector) * Have not seen any documentation for trigger mode for this IPI * but it seems to work with EDGE. (AMD BKDG FAM16h document specifies dont care) */ - apic_send_ipi(NO_SHORTHAND, STARTUP, PHYSICAL, ASSERT, EDGE, vector, apic_id); + apic_send_ipi(ALL_EXCLUDING_SELF, STARTUP, PHYSICAL, ASSERT, EDGE, vector, bsp_apic_id); /* Wait for delivery */ wait_for_ipi(); @@ -150,7 +150,7 @@ smp_send_ipi_startup(int apic_id, int vector) } /* See Intel IA32/64 Software Developer's Manual 3A Section 8.4.4.1 */ -int smp_startup_cpu(unsigned apic_id, phys_addr_t start_eip) +int smp_startup_cpus(unsigned bsp_apic_id, phys_addr_t start_eip) { #if 0 /* This block goes with a legacy method of INIT that only works with @@ -174,13 +174,13 @@ int smp_startup_cpu(unsigned apic_id, phys_addr_t start_eip) /* Local cache flush */ asm("wbinvd":::"memory"); - printf("Sending IPIs to APIC ID %u...\n", apic_id); + printf("Sending IPIs from BSP APIC ID %u...\n", bsp_apic_id); - smp_send_ipi_init(apic_id); + smp_send_ipi_init(bsp_apic_id); hpet_mdelay(10); - smp_send_ipi_startup(apic_id, start_eip >> STARTUP_VECTOR_SHIFT); + smp_send_ipi_startup(bsp_apic_id, start_eip >> STARTUP_VECTOR_SHIFT); hpet_udelay(200); - smp_send_ipi_startup(apic_id, start_eip >> STARTUP_VECTOR_SHIFT); + smp_send_ipi_startup(bsp_apic_id, start_eip >> STARTUP_VECTOR_SHIFT); hpet_udelay(200); printf("done\n"); diff --git a/i386/i386/smp.h b/i386/i386/smp.h index a34f79da..13b01787 100644 --- a/i386/i386/smp.h +++ b/i386/i386/smp.h @@ -26,7 +26,7 @@ int smp_init(void); void smp_remote_ast(unsigned logical_id); void smp_pmap_update(unsigned logical_id); -int smp_startup_cpu(unsigned apic_id, phys_addr_t start_eip); +int smp_startup_cpus(unsigned bsp_apic_id, phys_addr_t start_eip); #define cpu_pause() asm volatile ("pause" : : : "memory") #define STARTUP_VECTOR_SHIFT (20 - 8) diff --git a/kern/processor.c b/kern/processor.c index 0e42fa37..ba82ca2a 100644 --- a/kern/processor.c +++ b/kern/processor.c @@ -452,11 +452,7 @@ kern_return_t processor_start( { if (processor == PROCESSOR_NULL) return KERN_INVALID_ARGUMENT; -#if NCPUS > 1 - return cpu_start(processor->slot_num); -#else /* NCPUS > 1 */ return KERN_FAILURE; -#endif /* NCPUS > 1 */ } kern_return_t processor_exit( -- 2.45.2