xref: /kvm-unit-tests/lib/x86/smp.c (revision d31f6adb16fc88c51fa43a70a82eae79946f394d)
1 
2 #include <libcflat.h>
3 #include "smp.h"
4 #include "apic.h"
5 #include "fwcfg.h"
6 #include "desc.h"
7 
8 #define IPI_VECTOR 0x20
9 
10 typedef void (*ipi_function_type)(void *data);
11 
12 static struct spinlock ipi_lock;
13 static volatile ipi_function_type ipi_function;
14 static void *volatile ipi_data;
15 static volatile int ipi_done;
16 static volatile bool ipi_wait;
17 static int _cpu_count;
18 
19 static __attribute__((used)) void ipi()
20 {
21     void (*function)(void *data) = ipi_function;
22     void *data = ipi_data;
23     bool wait = ipi_wait;
24 
25     if (!wait) {
26 	ipi_done = 1;
27 	apic_write(APIC_EOI, 0);
28     }
29     function(data);
30     if (wait) {
31 	ipi_done = 1;
32 	apic_write(APIC_EOI, 0);
33     }
34 }
35 
36 asm (
37      "ipi_entry: \n"
38      "   call ipi \n"
39 #ifndef __x86_64__
40      "   iret"
41 #else
42      "   iretq"
43 #endif
44      );
45 
46 int cpu_count(void)
47 {
48     return _cpu_count;
49 }
50 
51 int smp_id(void)
52 {
53     unsigned id;
54 
55     asm ("mov %%gs:0, %0" : "=r"(id));
56     return id;
57 }
58 
59 static void setup_smp_id(void *data)
60 {
61     asm ("mov %0, %%gs:0" : : "r"(apic_id()) : "memory");
62 }
63 
64 static void __on_cpu(int cpu, void (*function)(void *data), void *data,
65                      int wait)
66 {
67     spin_lock(&ipi_lock);
68     if (cpu == smp_id())
69 	function(data);
70     else {
71 	ipi_done = 0;
72 	ipi_function = function;
73 	ipi_data = data;
74 	ipi_wait = wait;
75 	apic_icr_write(APIC_INT_ASSERT | APIC_DEST_PHYSICAL | APIC_DM_FIXED
76                        | IPI_VECTOR,
77                        cpu);
78 	while (!ipi_done)
79 	    ;
80     }
81     spin_unlock(&ipi_lock);
82 }
83 
84 void on_cpu(int cpu, void (*function)(void *data), void *data)
85 {
86     __on_cpu(cpu, function, data, 1);
87 }
88 
89 void on_cpu_async(int cpu, void (*function)(void *data), void *data)
90 {
91     __on_cpu(cpu, function, data, 0);
92 }
93 
94 
95 void smp_init(void)
96 {
97     int i;
98     void ipi_entry(void);
99 
100     _cpu_count = fwcfg_get_nb_cpus();
101 
102     setup_idt();
103     set_idt_entry(IPI_VECTOR, ipi_entry, 0);
104 
105     setup_smp_id(0);
106     for (i = 1; i < cpu_count(); ++i)
107         on_cpu(i, setup_smp_id, 0);
108 
109 }
110