smp.c 2.3 KB

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