apic.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. #include "libcflat.h"
  2. #include "apic.h"
  3. #include "msr.h"
  4. #include "processor.h"
  5. static void *g_apic = (void *)0xfee00000;
  6. static void *g_ioapic = (void *)0xfec00000;
  7. struct apic_ops {
  8. u32 (*reg_read)(unsigned reg);
  9. void (*reg_write)(unsigned reg, u32 val);
  10. void (*icr_write)(u32 val, u32 dest);
  11. u32 (*id)(void);
  12. };
  13. static void outb(unsigned char data, unsigned short port)
  14. {
  15. asm volatile ("out %0, %1" : : "a"(data), "d"(port));
  16. }
  17. void eoi(void)
  18. {
  19. apic_write(APIC_EOI, 0);
  20. }
  21. static u32 xapic_read(unsigned reg)
  22. {
  23. return *(volatile u32 *)(g_apic + reg);
  24. }
  25. static void xapic_write(unsigned reg, u32 val)
  26. {
  27. *(volatile u32 *)(g_apic + reg) = val;
  28. }
  29. static void xapic_icr_write(u32 val, u32 dest)
  30. {
  31. while (xapic_read(APIC_ICR) & APIC_ICR_BUSY)
  32. ;
  33. xapic_write(APIC_ICR2, dest << 24);
  34. xapic_write(APIC_ICR, val);
  35. }
  36. static uint32_t xapic_id(void)
  37. {
  38. return xapic_read(APIC_ID) >> 24;
  39. }
  40. static const struct apic_ops xapic_ops = {
  41. .reg_read = xapic_read,
  42. .reg_write = xapic_write,
  43. .icr_write = xapic_icr_write,
  44. .id = xapic_id,
  45. };
  46. static const struct apic_ops *apic_ops = &xapic_ops;
  47. static u32 x2apic_read(unsigned reg)
  48. {
  49. unsigned a, d;
  50. asm volatile ("rdmsr" : "=a"(a), "=d"(d) : "c"(APIC_BASE_MSR + reg/16));
  51. return a | (u64)d << 32;
  52. }
  53. static void x2apic_write(unsigned reg, u32 val)
  54. {
  55. asm volatile ("wrmsr" : : "a"(val), "d"(0), "c"(APIC_BASE_MSR + reg/16));
  56. }
  57. static void x2apic_icr_write(u32 val, u32 dest)
  58. {
  59. asm volatile ("wrmsr" : : "a"(val), "d"(dest),
  60. "c"(APIC_BASE_MSR + APIC_ICR/16));
  61. }
  62. static uint32_t x2apic_id(void)
  63. {
  64. return x2apic_read(APIC_ID);
  65. }
  66. static const struct apic_ops x2apic_ops = {
  67. .reg_read = x2apic_read,
  68. .reg_write = x2apic_write,
  69. .icr_write = x2apic_icr_write,
  70. .id = x2apic_id,
  71. };
  72. u32 apic_read(unsigned reg)
  73. {
  74. return apic_ops->reg_read(reg);
  75. }
  76. void apic_write(unsigned reg, u32 val)
  77. {
  78. apic_ops->reg_write(reg, val);
  79. }
  80. bool apic_read_bit(unsigned reg, int n)
  81. {
  82. reg += (n >> 5) << 4;
  83. n &= 31;
  84. return (apic_read(reg) & (1 << n)) != 0;
  85. }
  86. void apic_icr_write(u32 val, u32 dest)
  87. {
  88. apic_ops->icr_write(val, dest);
  89. }
  90. uint32_t apic_id(void)
  91. {
  92. return apic_ops->id();
  93. }
  94. uint8_t apic_get_tpr(void)
  95. {
  96. unsigned long tpr;
  97. #ifdef __x86_64__
  98. asm volatile ("mov %%cr8, %0" : "=r"(tpr));
  99. #else
  100. tpr = apic_read(APIC_TASKPRI) >> 4;
  101. #endif
  102. return tpr;
  103. }
  104. void apic_set_tpr(uint8_t tpr)
  105. {
  106. #ifdef __x86_64__
  107. asm volatile ("mov %0, %%cr8" : : "r"((unsigned long) tpr));
  108. #else
  109. apic_write(APIC_TASKPRI, tpr << 4);
  110. #endif
  111. }
  112. int enable_x2apic(void)
  113. {
  114. unsigned a, b, c, d;
  115. asm ("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(1));
  116. if (c & (1 << 21)) {
  117. asm ("rdmsr" : "=a"(a), "=d"(d) : "c"(MSR_IA32_APICBASE));
  118. a |= 1 << 10;
  119. asm ("wrmsr" : : "a"(a), "d"(d), "c"(MSR_IA32_APICBASE));
  120. apic_ops = &x2apic_ops;
  121. return 1;
  122. } else {
  123. return 0;
  124. }
  125. }
  126. void reset_apic(void)
  127. {
  128. u64 disabled = rdmsr(MSR_IA32_APICBASE) & ~(APIC_EN | APIC_EXTD);
  129. wrmsr(MSR_IA32_APICBASE, disabled);
  130. apic_ops = &xapic_ops;
  131. wrmsr(MSR_IA32_APICBASE, disabled | APIC_EN);
  132. }
  133. u32 ioapic_read_reg(unsigned reg)
  134. {
  135. *(volatile u32 *)g_ioapic = reg;
  136. return *(volatile u32 *)(g_ioapic + 0x10);
  137. }
  138. void ioapic_write_reg(unsigned reg, u32 value)
  139. {
  140. *(volatile u32 *)g_ioapic = reg;
  141. *(volatile u32 *)(g_ioapic + 0x10) = value;
  142. }
  143. void ioapic_write_redir(unsigned line, ioapic_redir_entry_t e)
  144. {
  145. ioapic_write_reg(0x10 + line * 2 + 0, ((u32 *)&e)[0]);
  146. ioapic_write_reg(0x10 + line * 2 + 1, ((u32 *)&e)[1]);
  147. }
  148. ioapic_redir_entry_t ioapic_read_redir(unsigned line)
  149. {
  150. ioapic_redir_entry_t e;
  151. ((u32 *)&e)[0] = ioapic_read_reg(0x10 + line * 2 + 0);
  152. ((u32 *)&e)[1] = ioapic_read_reg(0x10 + line * 2 + 1);
  153. return e;
  154. }
  155. void set_mask(unsigned line, int mask)
  156. {
  157. ioapic_redir_entry_t e = ioapic_read_redir(line);
  158. e.mask = mask;
  159. ioapic_write_redir(line, e);
  160. }
  161. void enable_apic(void)
  162. {
  163. printf("enabling apic\n");
  164. xapic_write(0xf0, 0x1ff); /* spurious vector register */
  165. }
  166. void mask_pic_interrupts(void)
  167. {
  168. outb(0xff, 0x21);
  169. outb(0xff, 0xa1);
  170. }