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