diff mbox series

[kvm-unit-tests] x86: APIC IDs might not be consecutive

Message ID 20190518160741.4911-1-nadav.amit@gmail.com (mailing list archive)
State New, archived
Headers show
Series [kvm-unit-tests] x86: APIC IDs might not be consecutive | expand

Commit Message

Nadav Amit May 18, 2019, 4:07 p.m. UTC
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@gmail.com>
---
 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(-)

Comments

Paolo Bonzini May 20, 2019, 2:43 p.m. UTC | #1
On 18/05/19 18:07, Nadav Amit wrote:
> 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@gmail.com>

x86/cstart.S is missing:

diff --git a/x86/cstart.S b/x86/cstart.S
index 79c5024..2fa4c30 100644
--- a/x86/cstart.S
+++ b/x86/cstart.S
@@ -2,11 +2,13 @@
 #include "apic-defs.h"

 .globl boot_idt
+.global online_cpus
+
 boot_idt = 0

 ipi_vector = 0x20

-max_cpus = 64
+max_cpus = MAX_TEST_CPUS

 .bss

@@ -123,6 +125,13 @@ prepare_32:

 smp_stacktop:	.long 0xa0000

+save_id:
+	movl $(APIC_DEFAULT_PHYS_BASE + APIC_ID), %eax
+	movl (%eax), %eax
+	shrl $24, %eax
+	lock btsl %eax, online_cpus
+	retl
+
 ap_start32:
 	mov $0x10, %ax
 	mov %ax, %ds
@@ -134,6 +143,7 @@ ap_start32:
 	lock/xaddl %esp, smp_stacktop
 	setup_percpu_area
 	call prepare_32
+	call save_id
 	call load_tss
 	call enable_apic
 	call enable_x2apic
@@ -145,6 +155,7 @@ ap_start32:
 	jmp 1b

 start32:
+	call save_id
 	call load_tss
 	call mask_pic_interrupts
 	call enable_apic
@@ -194,6 +205,9 @@ smp_init:
 smp_init_done:
 	ret

+online_cpus:
+	.quad 0
+
 cpu_online_count:	.word 1

 .code16

(untested).  I'm afraid this might bitrot pretty easily, but I'll
queue it after some more testing.

Paolo

> ---
>  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
>
diff mbox series

Patch

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