APIC IDs do not have to be consecutive. Crease a map between logical CPU identifiers and the physical APIC IDs for this matter and add a level of indirection. During boot, save in a bitmap the APIC IDs of the enabled CPU and use it later when sending IPIs. Signed-off-by: Nadav Amit <nadav.amit@xxxxxxxxx> --- lib/x86/apic-defs.h | 7 +++++++ lib/x86/apic.c | 13 +++++++++++++ lib/x86/apic.h | 3 +++ lib/x86/smp.c | 10 +++++++--- x86/apic.c | 10 +++++----- x86/cstart64.S | 16 +++++++++++++++- 6 files changed, 50 insertions(+), 9 deletions(-) diff --git a/lib/x86/apic-defs.h b/lib/x86/apic-defs.h index e7c3e92..7107f0f 100644 --- a/lib/x86/apic-defs.h +++ b/lib/x86/apic-defs.h @@ -1,6 +1,13 @@ #ifndef _ASM_X86_APICDEF_H #define _ASM_X86_APICDEF_H +/* + * Abuse this header file to hold the number of max-cpus, making it available + * both in C and ASM + */ + +#define MAX_TEST_CPUS (64) + /* * Constants for various Intel APICs. (local APIC, IOAPIC, etc.) * diff --git a/lib/x86/apic.c b/lib/x86/apic.c index d4528bd..bc2706e 100644 --- a/lib/x86/apic.c +++ b/lib/x86/apic.c @@ -5,6 +5,7 @@ void *g_apic = (void *)0xfee00000; void *g_ioapic = (void *)0xfec00000; +u8 id_map[MAX_TEST_CPUS]; struct apic_ops { u32 (*reg_read)(unsigned reg); @@ -228,3 +229,15 @@ void mask_pic_interrupts(void) outb(0xff, 0x21); outb(0xff, 0xa1); } + +extern unsigned char online_cpus[256 / 8]; + +void init_apic_map(void) +{ + unsigned int i, j = 0; + + for (i = 0; i < sizeof(online_cpus) * 8; i++) { + if ((1ul << (i % 8)) & (online_cpus[i / 8])) + id_map[j++] = i; + } +} diff --git a/lib/x86/apic.h b/lib/x86/apic.h index 651124d..537fdfb 100644 --- a/lib/x86/apic.h +++ b/lib/x86/apic.h @@ -4,6 +4,8 @@ #include <stdint.h> #include "apic-defs.h" +extern u8 id_map[MAX_TEST_CPUS]; + extern void *g_apic; extern void *g_ioapic; @@ -55,6 +57,7 @@ uint32_t apic_id(void); int enable_x2apic(void); void disable_apic(void); void reset_apic(void); +void init_apic_map(void); /* Converts byte-addressable APIC register offset to 4-byte offset. */ static inline u32 apic_reg_index(u32 reg) diff --git a/lib/x86/smp.c b/lib/x86/smp.c index 2e98de8..30bd1a0 100644 --- a/lib/x86/smp.c +++ b/lib/x86/smp.c @@ -68,8 +68,10 @@ static void setup_smp_id(void *data) static void __on_cpu(int cpu, void (*function)(void *data), void *data, int wait) { + unsigned int target = id_map[cpu]; + spin_lock(&ipi_lock); - if (cpu == smp_id()) + if (target == smp_id()) function(data); else { atomic_inc(&active_cpus); @@ -78,8 +80,7 @@ static void __on_cpu(int cpu, void (*function)(void *data), void *data, ipi_data = data; ipi_wait = wait; apic_icr_write(APIC_INT_ASSERT | APIC_DEST_PHYSICAL | APIC_DM_FIXED - | IPI_VECTOR, - cpu); + | IPI_VECTOR, target); while (!ipi_done) ; } @@ -112,6 +113,8 @@ int cpus_active(void) return atomic_read(&active_cpus); } +extern unsigned long long online_cpus; + void smp_init(void) { int i; @@ -120,6 +123,7 @@ void smp_init(void) _cpu_count = fwcfg_get_nb_cpus(); setup_idt(); + init_apic_map(); set_idt_entry(IPI_VECTOR, ipi_entry, 0); setup_smp_id(0); diff --git a/x86/apic.c b/x86/apic.c index 7ef4a27..83cae0c 100644 --- a/x86/apic.c +++ b/x86/apic.c @@ -272,7 +272,7 @@ static void test_self_ipi(void) handle_irq(vec, self_ipi_isr); irq_enable(); apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL | APIC_DM_FIXED | vec, - 0); + id_map[0]); do { pause(); @@ -336,7 +336,7 @@ static void test_sti_nmi(void) on_cpu_async(1, sti_loop, 0); while (nmi_counter < 30000) { old_counter = nmi_counter; - apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, 1); + apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, id_map[1]); while (nmi_counter == old_counter) { ; } @@ -365,10 +365,10 @@ static void kick_me_nmi(void *blah) if (nmi_done) { return; } - apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, 0); + apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, id_map[0]); /* make sure the NMI has arrived by sending an IPI after it */ apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_FIXED | APIC_INT_ASSERT - | 0x44, 0); + | 0x44, id_map[0]); ++cpu1_nmi_ctr2; while (cpu1_nmi_ctr2 != cpu0_nmi_ctr2 && !nmi_done) { pause(); @@ -402,7 +402,7 @@ static void test_multiple_nmi(void) while (cpu1_nmi_ctr1 != cpu0_nmi_ctr1) { pause(); } - apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, 0); + apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, id_map[0]); while (!nmi_flushed) { pause(); } diff --git a/x86/cstart64.S b/x86/cstart64.S index 31e41cc..a4b55c5 100644 --- a/x86/cstart64.S +++ b/x86/cstart64.S @@ -7,10 +7,11 @@ boot_idt = 0 .globl idt_descr .globl tss_descr .globl gdt64_desc +.globl online_cpus ipi_vector = 0x20 -max_cpus = 64 +max_cpus = MAX_TEST_CPUS .bss @@ -208,9 +209,18 @@ ap_start32: ljmpl $8, $ap_start64 .code64 +save_id: + mov $(APIC_DEFAULT_PHYS_BASE + APIC_ID), %eax + mov (%rax), %eax + shr $24, %eax + movzx %ax, %rax + lock btsq %rax, online_cpus + retq + ap_start64: call load_tss call enable_apic + call save_id call enable_x2apic sti nop @@ -223,6 +233,7 @@ start64: call load_tss call mask_pic_interrupts call enable_apic + call save_id call smp_init call enable_x2apic mov mb_boot_info(%rip), %rbx @@ -256,6 +267,9 @@ idt_descr: .word 16 * 256 - 1 .quad boot_idt +online_cpus: + .quad 0 + load_tss: lidtq idt_descr mov $(APIC_DEFAULT_PHYS_BASE + APIC_ID), %eax -- 2.17.1