* [kvm-unit-tests PATCH] x86: APIC IDs might not be consecutive
@ 2019-05-18 16:07 Nadav Amit
2019-05-20 14:43 ` Paolo Bonzini
0 siblings, 1 reply; 2+ messages in thread
From: Nadav Amit @ 2019-05-18 16:07 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: kvm, rkrcmar, Nadav Amit
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(-)
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
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [kvm-unit-tests PATCH] x86: APIC IDs might not be consecutive
2019-05-18 16:07 [kvm-unit-tests PATCH] x86: APIC IDs might not be consecutive Nadav Amit
@ 2019-05-20 14:43 ` Paolo Bonzini
0 siblings, 0 replies; 2+ messages in thread
From: Paolo Bonzini @ 2019-05-20 14:43 UTC (permalink / raw)
To: Nadav Amit; +Cc: kvm, rkrcmar
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
>
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2019-05-20 14:43 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-05-18 16:07 [kvm-unit-tests PATCH] x86: APIC IDs might not be consecutive Nadav Amit
2019-05-20 14:43 ` Paolo Bonzini
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).