1
0

apic.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. #include "libcflat.h"
  2. #include "apic.h"
  3. #include "vm.h"
  4. #include "smp.h"
  5. #include "desc.h"
  6. #include "isr.h"
  7. #include "msr.h"
  8. #include "atomic.h"
  9. static void test_lapic_existence(void)
  10. {
  11. u32 lvr;
  12. lvr = apic_read(APIC_LVR);
  13. printf("apic version: %x\n", lvr);
  14. report("apic existence", (u16)lvr == 0x14);
  15. }
  16. #define TSC_DEADLINE_TIMER_VECTOR 0xef
  17. #define BROADCAST_VECTOR 0xcf
  18. static int tdt_count;
  19. static void tsc_deadline_timer_isr(isr_regs_t *regs)
  20. {
  21. ++tdt_count;
  22. eoi();
  23. }
  24. static void __test_tsc_deadline_timer(void)
  25. {
  26. handle_irq(TSC_DEADLINE_TIMER_VECTOR, tsc_deadline_timer_isr);
  27. irq_enable();
  28. wrmsr(MSR_IA32_TSCDEADLINE, rdmsr(MSR_IA32_TSC));
  29. asm volatile ("nop");
  30. report("tsc deadline timer", tdt_count == 1);
  31. report("tsc deadline timer clearing", rdmsr(MSR_IA32_TSCDEADLINE) == 0);
  32. }
  33. static int enable_tsc_deadline_timer(void)
  34. {
  35. uint32_t lvtt;
  36. if (cpuid(1).c & (1 << 24)) {
  37. lvtt = APIC_LVT_TIMER_TSCDEADLINE | TSC_DEADLINE_TIMER_VECTOR;
  38. apic_write(APIC_LVTT, lvtt);
  39. return 1;
  40. } else {
  41. return 0;
  42. }
  43. }
  44. static void test_tsc_deadline_timer(void)
  45. {
  46. if(enable_tsc_deadline_timer()) {
  47. __test_tsc_deadline_timer();
  48. } else {
  49. report_skip("tsc deadline timer not detected");
  50. }
  51. }
  52. static void do_write_apicbase(void *data)
  53. {
  54. wrmsr(MSR_IA32_APICBASE, *(u64 *)data);
  55. }
  56. void test_enable_x2apic(void)
  57. {
  58. u64 invalid_state = APIC_DEFAULT_PHYS_BASE | APIC_BSP | APIC_EXTD;
  59. u64 apic_enabled = APIC_DEFAULT_PHYS_BASE | APIC_BSP | APIC_EN;
  60. u64 x2apic_enabled =
  61. APIC_DEFAULT_PHYS_BASE | APIC_BSP | APIC_EN | APIC_EXTD;
  62. if (enable_x2apic()) {
  63. printf("x2apic enabled\n");
  64. report("x2apic enabled to invalid state",
  65. test_for_exception(GP_VECTOR, do_write_apicbase,
  66. &invalid_state));
  67. report("x2apic enabled to apic enabled",
  68. test_for_exception(GP_VECTOR, do_write_apicbase,
  69. &apic_enabled));
  70. wrmsr(MSR_IA32_APICBASE, APIC_DEFAULT_PHYS_BASE | APIC_BSP);
  71. report("disabled to invalid state",
  72. test_for_exception(GP_VECTOR, do_write_apicbase,
  73. &invalid_state));
  74. report("disabled to x2apic enabled",
  75. test_for_exception(GP_VECTOR, do_write_apicbase,
  76. &x2apic_enabled));
  77. wrmsr(MSR_IA32_APICBASE, apic_enabled);
  78. report("apic enabled to invalid state",
  79. test_for_exception(GP_VECTOR, do_write_apicbase,
  80. &invalid_state));
  81. wrmsr(MSR_IA32_APICBASE, x2apic_enabled);
  82. apic_write(APIC_SPIV, 0x1ff);
  83. } else {
  84. printf("x2apic not detected\n");
  85. report("enable unsupported x2apic",
  86. test_for_exception(GP_VECTOR, do_write_apicbase,
  87. &x2apic_enabled));
  88. }
  89. }
  90. static void test_apic_disable(void)
  91. {
  92. u64 orig_apicbase = rdmsr(MSR_IA32_APICBASE);
  93. report_prefix_push("apic_disable");
  94. report("Local apic enabled", orig_apicbase & APIC_EN);
  95. report("CPUID.1H:EDX.APIC[bit 9] is set", cpuid(1).d & (1 << 9));
  96. wrmsr(MSR_IA32_APICBASE, orig_apicbase & ~(APIC_EN | APIC_EXTD));
  97. report("Local apic disabled", !(rdmsr(MSR_IA32_APICBASE) & APIC_EN));
  98. report("CPUID.1H:EDX.APIC[bit 9] is clear", !(cpuid(1).d & (1 << 9)));
  99. wrmsr(MSR_IA32_APICBASE, orig_apicbase & ~APIC_EXTD);
  100. wrmsr(MSR_IA32_APICBASE, orig_apicbase);
  101. apic_write(APIC_SPIV, 0x1ff);
  102. report("Local apic enabled", rdmsr(MSR_IA32_APICBASE) & APIC_EN);
  103. report("CPUID.1H:EDX.APIC[bit 9] is set", cpuid(1).d & (1 << 9));
  104. report_prefix_pop();
  105. }
  106. #define ALTERNATE_APIC_BASE 0x42000000
  107. static void test_apicbase(void)
  108. {
  109. u64 orig_apicbase = rdmsr(MSR_IA32_APICBASE);
  110. u32 lvr = apic_read(APIC_LVR);
  111. u64 value;
  112. wrmsr(MSR_IA32_APICBASE, orig_apicbase & ~(APIC_EN | APIC_EXTD));
  113. wrmsr(MSR_IA32_APICBASE, ALTERNATE_APIC_BASE | APIC_BSP | APIC_EN);
  114. report_prefix_push("apicbase");
  115. report("relocate apic",
  116. *(volatile u32 *)(ALTERNATE_APIC_BASE + APIC_LVR) == lvr);
  117. value = orig_apicbase | (1UL << cpuid_maxphyaddr());
  118. report("reserved physaddr bits",
  119. test_for_exception(GP_VECTOR, do_write_apicbase, &value));
  120. value = orig_apicbase | 1;
  121. report("reserved low bits",
  122. test_for_exception(GP_VECTOR, do_write_apicbase, &value));
  123. wrmsr(MSR_IA32_APICBASE, orig_apicbase);
  124. apic_write(APIC_SPIV, 0x1ff);
  125. report_prefix_pop();
  126. }
  127. static void do_write_apic_id(void *id)
  128. {
  129. apic_write(APIC_ID, *(u32 *)id);
  130. }
  131. static void __test_apic_id(void * unused)
  132. {
  133. u32 id, newid;
  134. u8 initial_xapic_id = cpuid(1).b >> 24;
  135. u32 initial_x2apic_id = cpuid(0xb).d;
  136. bool x2apic_mode = rdmsr(MSR_IA32_APICBASE) & APIC_EXTD;
  137. if (x2apic_mode)
  138. reset_apic();
  139. id = apic_id();
  140. report("xapic id matches cpuid", initial_xapic_id == id);
  141. newid = (id + 1) << 24;
  142. report("writeable xapic id",
  143. !test_for_exception(GP_VECTOR, do_write_apic_id, &newid) &&
  144. id + 1 == apic_id());
  145. if (!enable_x2apic())
  146. goto out;
  147. report("non-writeable x2apic id",
  148. test_for_exception(GP_VECTOR, do_write_apic_id, &newid));
  149. report("sane x2apic id", initial_xapic_id == (apic_id() & 0xff));
  150. /* old QEMUs do not set initial x2APIC ID */
  151. report("x2apic id matches cpuid",
  152. initial_xapic_id == (initial_x2apic_id & 0xff) &&
  153. initial_x2apic_id == apic_id());
  154. out:
  155. reset_apic();
  156. report("correct xapic id after reset", initial_xapic_id == apic_id());
  157. /* old KVMs do not reset xAPIC ID */
  158. if (id != apic_id())
  159. apic_write(APIC_ID, id << 24);
  160. if (x2apic_mode)
  161. enable_x2apic();
  162. }
  163. static void test_apic_id(void)
  164. {
  165. if (cpu_count() < 2)
  166. return;
  167. on_cpu(1, __test_apic_id, NULL);
  168. }
  169. static int ipi_count;
  170. static void self_ipi_isr(isr_regs_t *regs)
  171. {
  172. ++ipi_count;
  173. eoi();
  174. }
  175. static void test_self_ipi(void)
  176. {
  177. int vec = 0xf1;
  178. handle_irq(vec, self_ipi_isr);
  179. irq_enable();
  180. apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL | APIC_DM_FIXED | vec,
  181. 0);
  182. asm volatile ("nop");
  183. report("self ipi", ipi_count == 1);
  184. }
  185. volatile int nmi_counter_private, nmi_counter, nmi_hlt_counter, sti_loop_active;
  186. void sti_nop(char *p)
  187. {
  188. asm volatile (
  189. ".globl post_sti \n\t"
  190. "sti \n"
  191. /*
  192. * vmx won't exit on external interrupt if blocked-by-sti,
  193. * so give it a reason to exit by accessing an unmapped page.
  194. */
  195. "post_sti: testb $0, %0 \n\t"
  196. "nop \n\t"
  197. "cli"
  198. : : "m"(*p)
  199. );
  200. nmi_counter = nmi_counter_private;
  201. }
  202. static void sti_loop(void *ignore)
  203. {
  204. unsigned k = 0;
  205. while (sti_loop_active) {
  206. sti_nop((char *)(ulong)((k++ * 4096) % (128 * 1024 * 1024)));
  207. }
  208. }
  209. static void nmi_handler(isr_regs_t *regs)
  210. {
  211. extern void post_sti(void);
  212. ++nmi_counter_private;
  213. nmi_hlt_counter += regs->rip == (ulong)post_sti;
  214. }
  215. static void update_cr3(void *cr3)
  216. {
  217. write_cr3((ulong)cr3);
  218. }
  219. static void test_sti_nmi(void)
  220. {
  221. unsigned old_counter;
  222. if (cpu_count() < 2) {
  223. return;
  224. }
  225. handle_irq(2, nmi_handler);
  226. on_cpu(1, update_cr3, (void *)read_cr3());
  227. sti_loop_active = 1;
  228. on_cpu_async(1, sti_loop, 0);
  229. while (nmi_counter < 30000) {
  230. old_counter = nmi_counter;
  231. apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, 1);
  232. while (nmi_counter == old_counter) {
  233. ;
  234. }
  235. }
  236. sti_loop_active = 0;
  237. report("nmi-after-sti", nmi_hlt_counter == 0);
  238. }
  239. static volatile bool nmi_done, nmi_flushed;
  240. static volatile int nmi_received;
  241. static volatile int cpu0_nmi_ctr1, cpu1_nmi_ctr1;
  242. static volatile int cpu0_nmi_ctr2, cpu1_nmi_ctr2;
  243. static void multiple_nmi_handler(isr_regs_t *regs)
  244. {
  245. ++nmi_received;
  246. }
  247. static void kick_me_nmi(void *blah)
  248. {
  249. while (!nmi_done) {
  250. ++cpu1_nmi_ctr1;
  251. while (cpu1_nmi_ctr1 != cpu0_nmi_ctr1 && !nmi_done) {
  252. pause();
  253. }
  254. if (nmi_done) {
  255. return;
  256. }
  257. apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, 0);
  258. /* make sure the NMI has arrived by sending an IPI after it */
  259. apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_FIXED | APIC_INT_ASSERT
  260. | 0x44, 0);
  261. ++cpu1_nmi_ctr2;
  262. while (cpu1_nmi_ctr2 != cpu0_nmi_ctr2 && !nmi_done) {
  263. pause();
  264. }
  265. }
  266. }
  267. static void flush_nmi(isr_regs_t *regs)
  268. {
  269. nmi_flushed = true;
  270. apic_write(APIC_EOI, 0);
  271. }
  272. static void test_multiple_nmi(void)
  273. {
  274. int i;
  275. bool ok = true;
  276. if (cpu_count() < 2) {
  277. return;
  278. }
  279. sti();
  280. handle_irq(2, multiple_nmi_handler);
  281. handle_irq(0x44, flush_nmi);
  282. on_cpu_async(1, kick_me_nmi, 0);
  283. for (i = 0; i < 1000000; ++i) {
  284. nmi_flushed = false;
  285. nmi_received = 0;
  286. ++cpu0_nmi_ctr1;
  287. while (cpu1_nmi_ctr1 != cpu0_nmi_ctr1) {
  288. pause();
  289. }
  290. apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, 0);
  291. while (!nmi_flushed) {
  292. pause();
  293. }
  294. if (nmi_received != 2) {
  295. ok = false;
  296. break;
  297. }
  298. ++cpu0_nmi_ctr2;
  299. while (cpu1_nmi_ctr2 != cpu0_nmi_ctr2) {
  300. pause();
  301. }
  302. }
  303. nmi_done = true;
  304. report("multiple nmi", ok);
  305. }
  306. static volatile int lvtt_counter = 0;
  307. static void lvtt_handler(isr_regs_t *regs)
  308. {
  309. lvtt_counter++;
  310. eoi();
  311. }
  312. static void test_apic_timer_one_shot(void)
  313. {
  314. uint64_t tsc1, tsc2;
  315. static const uint32_t interval = 0x10000;
  316. #define APIC_LVT_TIMER_VECTOR (0xee)
  317. handle_irq(APIC_LVT_TIMER_VECTOR, lvtt_handler);
  318. irq_enable();
  319. /* One shot mode */
  320. apic_write(APIC_LVTT, APIC_LVT_TIMER_ONESHOT |
  321. APIC_LVT_TIMER_VECTOR);
  322. /* Divider == 1 */
  323. apic_write(APIC_TDCR, 0x0000000b);
  324. tsc1 = rdtsc();
  325. /* Set "Initial Counter Register", which starts the timer */
  326. apic_write(APIC_TMICT, interval);
  327. while (!lvtt_counter);
  328. tsc2 = rdtsc();
  329. /*
  330. * For LVT Timer clock, SDM vol 3 10.5.4 says it should be
  331. * derived from processor's bus clock (IIUC which is the same
  332. * as TSC), however QEMU seems to be using nanosecond. In all
  333. * cases, the following should satisfy on all modern
  334. * processors.
  335. */
  336. report("APIC LVT timer one shot", (lvtt_counter == 1) &&
  337. (tsc2 - tsc1 >= interval));
  338. }
  339. static atomic_t broadcast_counter;
  340. static void broadcast_handler(isr_regs_t *regs)
  341. {
  342. atomic_inc(&broadcast_counter);
  343. eoi();
  344. }
  345. static bool broadcast_received(unsigned ncpus)
  346. {
  347. unsigned counter;
  348. u64 start = rdtsc();
  349. do {
  350. counter = atomic_read(&broadcast_counter);
  351. if (counter >= ncpus)
  352. break;
  353. pause();
  354. } while (rdtsc() - start < 1000000000);
  355. atomic_set(&broadcast_counter, 0);
  356. return counter == ncpus;
  357. }
  358. static void test_physical_broadcast(void)
  359. {
  360. unsigned ncpus = cpu_count();
  361. unsigned long cr3 = read_cr3();
  362. u32 broadcast_address = enable_x2apic() ? 0xffffffff : 0xff;
  363. handle_irq(BROADCAST_VECTOR, broadcast_handler);
  364. for (int c = 1; c < ncpus; c++)
  365. on_cpu(c, update_cr3, (void *)cr3);
  366. printf("starting broadcast (%s)\n", enable_x2apic() ? "x2apic" : "xapic");
  367. apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_FIXED | APIC_INT_ASSERT |
  368. BROADCAST_VECTOR, broadcast_address);
  369. report("APIC physical broadcast address", broadcast_received(ncpus));
  370. apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_FIXED | APIC_INT_ASSERT |
  371. BROADCAST_VECTOR | APIC_DEST_ALLINC, 0);
  372. report("APIC physical broadcast shorthand", broadcast_received(ncpus));
  373. }
  374. int main()
  375. {
  376. setup_vm();
  377. smp_init();
  378. test_lapic_existence();
  379. mask_pic_interrupts();
  380. test_apic_id();
  381. test_apic_disable();
  382. // Disabled in v86: Not supported
  383. //test_enable_x2apic();
  384. if(false) test_apicbase();
  385. test_self_ipi();
  386. test_physical_broadcast();
  387. test_sti_nmi();
  388. test_multiple_nmi();
  389. test_apic_timer_one_shot();
  390. test_tsc_deadline_timer();
  391. return report_summary();
  392. }