xref: /kvm-unit-tests/lib/x86/smp.c (revision e7bc5602bdfffee051a4eb2f06f7281db29b3c05)
17d36db35SAvi Kivity 
27d36db35SAvi Kivity #include <libcflat.h>
37d36db35SAvi Kivity #include "smp.h"
47d36db35SAvi Kivity #include "apic.h"
57d36db35SAvi Kivity #include "fwcfg.h"
67d36db35SAvi Kivity 
77d36db35SAvi Kivity #define IPI_VECTOR 0x20
87d36db35SAvi Kivity 
97d36db35SAvi Kivity static struct spinlock ipi_lock;
10*e7bc5602SAvi Kivity static volatile void (*ipi_function)(void *data);
11*e7bc5602SAvi Kivity static volatile void *ipi_data;
127d36db35SAvi Kivity static volatile int ipi_done;
13*e7bc5602SAvi Kivity static volatile bool ipi_wait;
14*e7bc5602SAvi Kivity static int _cpu_count;
157d36db35SAvi Kivity 
167d36db35SAvi Kivity static __attribute__((used)) void ipi()
177d36db35SAvi Kivity {
18*e7bc5602SAvi Kivity     void (*function)(void *data) = ipi_function;
19*e7bc5602SAvi Kivity     void *data = ipi_data;
20*e7bc5602SAvi Kivity     bool wait = ipi_wait;
21*e7bc5602SAvi Kivity 
22*e7bc5602SAvi Kivity     if (!wait) {
237d36db35SAvi Kivity 	ipi_done = 1;
24*e7bc5602SAvi Kivity 	apic_write(APIC_EOI, 0);
25*e7bc5602SAvi Kivity     }
26*e7bc5602SAvi Kivity     function(data);
27*e7bc5602SAvi Kivity     if (wait) {
28*e7bc5602SAvi Kivity 	ipi_done = 1;
29*e7bc5602SAvi Kivity 	apic_write(APIC_EOI, 0);
30*e7bc5602SAvi Kivity     }
317d36db35SAvi Kivity }
327d36db35SAvi Kivity 
337d36db35SAvi Kivity asm (
347d36db35SAvi Kivity      "ipi_entry: \n"
357d36db35SAvi Kivity      "   call ipi \n"
367d36db35SAvi Kivity #ifndef __x86_64__
377d36db35SAvi Kivity      "   iret"
387d36db35SAvi Kivity #else
397d36db35SAvi Kivity      "   iretq"
407d36db35SAvi Kivity #endif
417d36db35SAvi Kivity      );
427d36db35SAvi Kivity 
437d36db35SAvi Kivity 
447d36db35SAvi Kivity static void set_ipi_descriptor(void (*ipi_entry)(void))
457d36db35SAvi Kivity {
467d36db35SAvi Kivity     unsigned short *desc = (void *)(IPI_VECTOR * sizeof(long) * 2);
477d36db35SAvi Kivity     unsigned short cs;
487d36db35SAvi Kivity     unsigned long ipi = (unsigned long)ipi_entry;
497d36db35SAvi Kivity 
507d36db35SAvi Kivity     asm ("mov %%cs, %0" : "=r"(cs));
517d36db35SAvi Kivity     desc[0] = ipi;
527d36db35SAvi Kivity     desc[1] = cs;
537d36db35SAvi Kivity     desc[2] = 0x8e00;
547d36db35SAvi Kivity     desc[3] = ipi >> 16;
557d36db35SAvi Kivity #ifdef __x86_64__
567d36db35SAvi Kivity     desc[4] = ipi >> 32;
577d36db35SAvi Kivity     desc[5] = ipi >> 48;
587d36db35SAvi Kivity     desc[6] = 0;
597d36db35SAvi Kivity     desc[7] = 0;
607d36db35SAvi Kivity #endif
617d36db35SAvi Kivity }
627d36db35SAvi Kivity 
637d36db35SAvi Kivity void spin_lock(struct spinlock *lock)
647d36db35SAvi Kivity {
657d36db35SAvi Kivity     int v = 1;
667d36db35SAvi Kivity 
677d36db35SAvi Kivity     do {
687d36db35SAvi Kivity 	asm volatile ("xchg %1, %0" : "+m"(lock->v), "+r"(v));
697d36db35SAvi Kivity     } while (v);
707d36db35SAvi Kivity     asm volatile ("" : : : "memory");
717d36db35SAvi Kivity }
727d36db35SAvi Kivity 
737d36db35SAvi Kivity void spin_unlock(struct spinlock *lock)
747d36db35SAvi Kivity {
757d36db35SAvi Kivity     asm volatile ("" : : : "memory");
767d36db35SAvi Kivity     lock->v = 0;
777d36db35SAvi Kivity }
787d36db35SAvi Kivity 
797d36db35SAvi Kivity int cpu_count(void)
807d36db35SAvi Kivity {
817d36db35SAvi Kivity     return fwcfg_get_nb_cpus();
827d36db35SAvi Kivity }
837d36db35SAvi Kivity 
847d36db35SAvi Kivity int smp_id(void)
857d36db35SAvi Kivity {
867d36db35SAvi Kivity     unsigned id;
877d36db35SAvi Kivity 
887d36db35SAvi Kivity     asm ("mov %%gs:0, %0" : "=r"(id));
897d36db35SAvi Kivity     return id;
907d36db35SAvi Kivity }
917d36db35SAvi Kivity 
927d36db35SAvi Kivity static void setup_smp_id(void *data)
937d36db35SAvi Kivity {
947d36db35SAvi Kivity     asm ("mov %0, %%gs:0" : : "r"(apic_id()) : "memory");
957d36db35SAvi Kivity }
967d36db35SAvi Kivity 
977d36db35SAvi Kivity static void __on_cpu(int cpu, void (*function)(void *data), void *data,
987d36db35SAvi Kivity                      int wait)
997d36db35SAvi Kivity {
1007d36db35SAvi Kivity     spin_lock(&ipi_lock);
1017d36db35SAvi Kivity     if (cpu == smp_id())
1027d36db35SAvi Kivity 	function(data);
1037d36db35SAvi Kivity     else {
1047d36db35SAvi Kivity 	ipi_done = 0;
1057d36db35SAvi Kivity 	ipi_function = function;
1067d36db35SAvi Kivity 	ipi_data = data;
107*e7bc5602SAvi Kivity 	ipi_wait = wait;
1087d36db35SAvi Kivity 	apic_icr_write(APIC_INT_ASSERT | APIC_DEST_PHYSICAL | APIC_DM_FIXED
1097d36db35SAvi Kivity                        | IPI_VECTOR,
1107d36db35SAvi Kivity                        cpu);
1117d36db35SAvi Kivity 	while (!ipi_done)
1127d36db35SAvi Kivity 	    ;
1137d36db35SAvi Kivity     }
1147d36db35SAvi Kivity     spin_unlock(&ipi_lock);
1157d36db35SAvi Kivity }
1167d36db35SAvi Kivity 
1177d36db35SAvi Kivity void on_cpu(int cpu, void (*function)(void *data), void *data)
1187d36db35SAvi Kivity {
1197d36db35SAvi Kivity     __on_cpu(cpu, function, data, 1);
1207d36db35SAvi Kivity }
1217d36db35SAvi Kivity 
1227d36db35SAvi Kivity void on_cpu_async(int cpu, void (*function)(void *data), void *data)
1237d36db35SAvi Kivity {
1247d36db35SAvi Kivity     __on_cpu(cpu, function, data, 0);
1257d36db35SAvi Kivity }
1267d36db35SAvi Kivity 
1277d36db35SAvi Kivity 
1287d36db35SAvi Kivity void smp_init(void)
1297d36db35SAvi Kivity {
1307d36db35SAvi Kivity     int i;
1317d36db35SAvi Kivity     void ipi_entry(void);
1327d36db35SAvi Kivity 
1337d36db35SAvi Kivity     set_ipi_descriptor(ipi_entry);
1347d36db35SAvi Kivity 
1357d36db35SAvi Kivity     setup_smp_id(0);
1367d36db35SAvi Kivity     for (i = 1; i < cpu_count(); ++i)
1377d36db35SAvi Kivity         on_cpu(i, setup_smp_id, 0);
1387d36db35SAvi Kivity 
1397d36db35SAvi Kivity }
140