xref: /kvm-unit-tests/lib/x86/smp.c (revision 0a2f06f7e195b851943da3c708b8e3eb1d58914c)
17d36db35SAvi Kivity 
27d36db35SAvi Kivity #include <libcflat.h>
3b73c7c6eSAndrew Jones #include "processor.h"
4b73c7c6eSAndrew Jones #include "atomic.h"
57d36db35SAvi Kivity #include "smp.h"
67d36db35SAvi Kivity #include "apic.h"
77d36db35SAvi Kivity #include "fwcfg.h"
8a4f9d79dSJan Kiszka #include "desc.h"
97d36db35SAvi Kivity 
107d36db35SAvi Kivity #define IPI_VECTOR 0x20
117d36db35SAvi Kivity 
12fa816346SAvi Kivity typedef void (*ipi_function_type)(void *data);
13fa816346SAvi Kivity 
147d36db35SAvi Kivity static struct spinlock ipi_lock;
15fa816346SAvi Kivity static volatile ipi_function_type ipi_function;
16a4f9d79dSJan Kiszka static void *volatile ipi_data;
177d36db35SAvi Kivity static volatile int ipi_done;
18e7bc5602SAvi Kivity static volatile bool ipi_wait;
19e7bc5602SAvi Kivity static int _cpu_count;
20b73c7c6eSAndrew Jones static atomic_t active_cpus;
217d36db35SAvi Kivity 
227db17e21SThomas Huth static __attribute__((used)) void ipi(void)
237d36db35SAvi Kivity {
24e7bc5602SAvi Kivity 	void (*function)(void *data) = ipi_function;
25e7bc5602SAvi Kivity 	void *data = ipi_data;
26e7bc5602SAvi Kivity 	bool wait = ipi_wait;
27e7bc5602SAvi Kivity 
28e7bc5602SAvi Kivity 	if (!wait) {
297d36db35SAvi Kivity 		ipi_done = 1;
30e7bc5602SAvi Kivity 		apic_write(APIC_EOI, 0);
31e7bc5602SAvi Kivity 	}
32e7bc5602SAvi Kivity 	function(data);
33b73c7c6eSAndrew Jones 	atomic_dec(&active_cpus);
34e7bc5602SAvi Kivity 	if (wait) {
35e7bc5602SAvi Kivity 		ipi_done = 1;
36e7bc5602SAvi Kivity 		apic_write(APIC_EOI, 0);
37e7bc5602SAvi Kivity 	}
387d36db35SAvi Kivity }
397d36db35SAvi Kivity 
407d36db35SAvi Kivity asm (
417d36db35SAvi Kivity 	 "ipi_entry: \n"
427d36db35SAvi Kivity 	 "   call ipi \n"
437d36db35SAvi Kivity #ifndef __x86_64__
447d36db35SAvi Kivity 	 "   iret"
457d36db35SAvi Kivity #else
467d36db35SAvi Kivity 	 "   iretq"
477d36db35SAvi Kivity #endif
487d36db35SAvi Kivity 	 );
497d36db35SAvi Kivity 
507d36db35SAvi Kivity int cpu_count(void)
517d36db35SAvi Kivity {
52a9f949c7SAvi Kivity 	return _cpu_count;
537d36db35SAvi Kivity }
547d36db35SAvi Kivity 
557d36db35SAvi Kivity int smp_id(void)
567d36db35SAvi Kivity {
577d36db35SAvi Kivity 	unsigned id;
587d36db35SAvi Kivity 
597d36db35SAvi Kivity 	asm ("mov %%gs:0, %0" : "=r"(id));
607d36db35SAvi Kivity 	return id;
617d36db35SAvi Kivity }
627d36db35SAvi Kivity 
637d36db35SAvi Kivity static void setup_smp_id(void *data)
647d36db35SAvi Kivity {
657d36db35SAvi Kivity 	asm ("mov %0, %%gs:0" : : "r"(apic_id()) : "memory");
667d36db35SAvi Kivity }
677d36db35SAvi Kivity 
68*0a2f06f7SSean Christopherson static void __on_cpu(int cpu, void (*function)(void *data), void *data, int wait)
697d36db35SAvi Kivity {
70*0a2f06f7SSean Christopherson 	const u32 ipi_icr = APIC_INT_ASSERT | APIC_DEST_PHYSICAL | APIC_DM_FIXED | IPI_VECTOR;
7118a34cceSNadav Amit 	unsigned int target = id_map[cpu];
7218a34cceSNadav Amit 
737d36db35SAvi Kivity 	spin_lock(&ipi_lock);
74*0a2f06f7SSean Christopherson 	if (target == smp_id()) {
757d36db35SAvi Kivity 		function(data);
76*0a2f06f7SSean Christopherson 	} else {
77b73c7c6eSAndrew Jones 		atomic_inc(&active_cpus);
787d36db35SAvi Kivity 		ipi_done = 0;
797d36db35SAvi Kivity 		ipi_function = function;
807d36db35SAvi Kivity 		ipi_data = data;
81e7bc5602SAvi Kivity 		ipi_wait = wait;
82*0a2f06f7SSean Christopherson 		apic_icr_write(ipi_icr, target);
837d36db35SAvi Kivity 		while (!ipi_done)
847d36db35SAvi Kivity 			;
857d36db35SAvi Kivity 	}
867d36db35SAvi Kivity 	spin_unlock(&ipi_lock);
877d36db35SAvi Kivity }
887d36db35SAvi Kivity 
897d36db35SAvi Kivity void on_cpu(int cpu, void (*function)(void *data), void *data)
907d36db35SAvi Kivity {
917d36db35SAvi Kivity 	__on_cpu(cpu, function, data, 1);
927d36db35SAvi Kivity }
937d36db35SAvi Kivity 
947d36db35SAvi Kivity void on_cpu_async(int cpu, void (*function)(void *data), void *data)
957d36db35SAvi Kivity {
967d36db35SAvi Kivity 	__on_cpu(cpu, function, data, 0);
977d36db35SAvi Kivity }
987d36db35SAvi Kivity 
99b73c7c6eSAndrew Jones void on_cpus(void (*function)(void *data), void *data)
100b73c7c6eSAndrew Jones {
101b73c7c6eSAndrew Jones 	int cpu;
102b73c7c6eSAndrew Jones 
103b73c7c6eSAndrew Jones 	for (cpu = cpu_count() - 1; cpu >= 0; --cpu)
104b73c7c6eSAndrew Jones 		on_cpu_async(cpu, function, data);
105b73c7c6eSAndrew Jones 
106b73c7c6eSAndrew Jones 	while (cpus_active() > 1)
107b73c7c6eSAndrew Jones 		pause();
108b73c7c6eSAndrew Jones }
109b73c7c6eSAndrew Jones 
110b73c7c6eSAndrew Jones int cpus_active(void)
111b73c7c6eSAndrew Jones {
112b73c7c6eSAndrew Jones 	return atomic_read(&active_cpus);
113b73c7c6eSAndrew Jones }
1147d36db35SAvi Kivity 
1157d36db35SAvi Kivity void smp_init(void)
1167d36db35SAvi Kivity {
1177d36db35SAvi Kivity 	int i;
1187d36db35SAvi Kivity 	void ipi_entry(void);
1197d36db35SAvi Kivity 
120a9f949c7SAvi Kivity 	_cpu_count = fwcfg_get_nb_cpus();
121a9f949c7SAvi Kivity 
1222bb987f3SAvi Kivity 	setup_idt();
12318a34cceSNadav Amit 	init_apic_map();
1242bb987f3SAvi Kivity 	set_idt_entry(IPI_VECTOR, ipi_entry, 0);
1257d36db35SAvi Kivity 
1267d36db35SAvi Kivity 	setup_smp_id(0);
1277d36db35SAvi Kivity 	for (i = 1; i < cpu_count(); ++i)
1287d36db35SAvi Kivity 		on_cpu(i, setup_smp_id, 0);
1297d36db35SAvi Kivity 
130b73c7c6eSAndrew Jones 	atomic_inc(&active_cpus);
1317d36db35SAvi Kivity }
13274e79380SPaolo Bonzini 
13374e79380SPaolo Bonzini static void do_reset_apic(void *data)
13474e79380SPaolo Bonzini {
13574e79380SPaolo Bonzini 	reset_apic();
13674e79380SPaolo Bonzini }
13774e79380SPaolo Bonzini 
13874e79380SPaolo Bonzini void smp_reset_apic(void)
13974e79380SPaolo Bonzini {
14074e79380SPaolo Bonzini 	int i;
14174e79380SPaolo Bonzini 
14274e79380SPaolo Bonzini 	reset_apic();
14374e79380SPaolo Bonzini 	for (i = 1; i < cpu_count(); ++i)
14474e79380SPaolo Bonzini 		on_cpu(i, do_reset_apic, 0);
14574e79380SPaolo Bonzini 
14674e79380SPaolo Bonzini 	atomic_inc(&active_cpus);
14774e79380SPaolo Bonzini }
148