xref: /kvm-unit-tests/lib/x86/apic.c (revision 533a738f363e83f810f5ab89a87d6abbbe944b26)
17d36db35SAvi Kivity #include "libcflat.h"
27d36db35SAvi Kivity #include "apic.h"
3b5aa0cebSJan Kiszka #include "msr.h"
4a222b5e2SRadim Krčmář #include "processor.h"
57d36db35SAvi Kivity 
67d36db35SAvi Kivity static void *g_apic = (void *)0xfee00000;
77d36db35SAvi Kivity static void *g_ioapic = (void *)0xfec00000;
87d36db35SAvi Kivity 
97d36db35SAvi Kivity struct apic_ops {
107d36db35SAvi Kivity     u32 (*reg_read)(unsigned reg);
117d36db35SAvi Kivity     void (*reg_write)(unsigned reg, u32 val);
127d36db35SAvi Kivity     void (*icr_write)(u32 val, u32 dest);
137d36db35SAvi Kivity     u32 (*id)(void);
147d36db35SAvi Kivity };
157d36db35SAvi Kivity 
167d36db35SAvi Kivity static void outb(unsigned char data, unsigned short port)
177d36db35SAvi Kivity {
187d36db35SAvi Kivity     asm volatile ("out %0, %1" : : "a"(data), "d"(port));
197d36db35SAvi Kivity }
207d36db35SAvi Kivity 
210f187a08SSteve Rutherford void eoi(void)
220f187a08SSteve Rutherford {
230f187a08SSteve Rutherford     apic_write(APIC_EOI, 0);
240f187a08SSteve Rutherford }
250f187a08SSteve Rutherford 
267d36db35SAvi Kivity static u32 xapic_read(unsigned reg)
277d36db35SAvi Kivity {
287d36db35SAvi Kivity     return *(volatile u32 *)(g_apic + reg);
297d36db35SAvi Kivity }
307d36db35SAvi Kivity 
317d36db35SAvi Kivity static void xapic_write(unsigned reg, u32 val)
327d36db35SAvi Kivity {
337d36db35SAvi Kivity     *(volatile u32 *)(g_apic + reg) = val;
347d36db35SAvi Kivity }
357d36db35SAvi Kivity 
367d36db35SAvi Kivity static void xapic_icr_write(u32 val, u32 dest)
377d36db35SAvi Kivity {
387d36db35SAvi Kivity     while (xapic_read(APIC_ICR) & APIC_ICR_BUSY)
397d36db35SAvi Kivity         ;
407d36db35SAvi Kivity     xapic_write(APIC_ICR2, dest << 24);
417d36db35SAvi Kivity     xapic_write(APIC_ICR, val);
427d36db35SAvi Kivity }
437d36db35SAvi Kivity 
447d36db35SAvi Kivity static uint32_t xapic_id(void)
457d36db35SAvi Kivity {
467d36db35SAvi Kivity     return xapic_read(APIC_ID) >> 24;
477d36db35SAvi Kivity }
487d36db35SAvi Kivity 
497d36db35SAvi Kivity static const struct apic_ops xapic_ops = {
507d36db35SAvi Kivity     .reg_read = xapic_read,
517d36db35SAvi Kivity     .reg_write = xapic_write,
527d36db35SAvi Kivity     .icr_write = xapic_icr_write,
537d36db35SAvi Kivity     .id = xapic_id,
547d36db35SAvi Kivity };
557d36db35SAvi Kivity 
567d36db35SAvi Kivity static const struct apic_ops *apic_ops = &xapic_ops;
577d36db35SAvi Kivity 
587d36db35SAvi Kivity static u32 x2apic_read(unsigned reg)
597d36db35SAvi Kivity {
607d36db35SAvi Kivity     unsigned a, d;
617d36db35SAvi Kivity 
627d36db35SAvi Kivity     asm volatile ("rdmsr" : "=a"(a), "=d"(d) : "c"(APIC_BASE_MSR + reg/16));
637d36db35SAvi Kivity     return a | (u64)d << 32;
647d36db35SAvi Kivity }
657d36db35SAvi Kivity 
667d36db35SAvi Kivity static void x2apic_write(unsigned reg, u32 val)
677d36db35SAvi Kivity {
687d36db35SAvi Kivity     asm volatile ("wrmsr" : : "a"(val), "d"(0), "c"(APIC_BASE_MSR + reg/16));
697d36db35SAvi Kivity }
707d36db35SAvi Kivity 
717d36db35SAvi Kivity static void x2apic_icr_write(u32 val, u32 dest)
727d36db35SAvi Kivity {
737d36db35SAvi Kivity     asm volatile ("wrmsr" : : "a"(val), "d"(dest),
747d36db35SAvi Kivity                   "c"(APIC_BASE_MSR + APIC_ICR/16));
757d36db35SAvi Kivity }
767d36db35SAvi Kivity 
777d36db35SAvi Kivity static uint32_t x2apic_id(void)
787d36db35SAvi Kivity {
79a0837ab6SRadim Krčmář     return x2apic_read(APIC_ID);
807d36db35SAvi Kivity }
817d36db35SAvi Kivity 
827d36db35SAvi Kivity static const struct apic_ops x2apic_ops = {
837d36db35SAvi Kivity     .reg_read = x2apic_read,
847d36db35SAvi Kivity     .reg_write = x2apic_write,
857d36db35SAvi Kivity     .icr_write = x2apic_icr_write,
867d36db35SAvi Kivity     .id = x2apic_id,
877d36db35SAvi Kivity };
887d36db35SAvi Kivity 
897d36db35SAvi Kivity u32 apic_read(unsigned reg)
907d36db35SAvi Kivity {
917d36db35SAvi Kivity     return apic_ops->reg_read(reg);
927d36db35SAvi Kivity }
937d36db35SAvi Kivity 
947d36db35SAvi Kivity void apic_write(unsigned reg, u32 val)
957d36db35SAvi Kivity {
967d36db35SAvi Kivity     apic_ops->reg_write(reg, val);
977d36db35SAvi Kivity }
987d36db35SAvi Kivity 
997c5f3ee9SPaolo Bonzini bool apic_read_bit(unsigned reg, int n)
1007c5f3ee9SPaolo Bonzini {
1017c5f3ee9SPaolo Bonzini     reg += (n >> 5) << 4;
1027c5f3ee9SPaolo Bonzini     n &= 31;
1037c5f3ee9SPaolo Bonzini     return (apic_read(reg) & (1 << n)) != 0;
1047c5f3ee9SPaolo Bonzini }
1057c5f3ee9SPaolo Bonzini 
1067d36db35SAvi Kivity void apic_icr_write(u32 val, u32 dest)
1077d36db35SAvi Kivity {
1087d36db35SAvi Kivity     apic_ops->icr_write(val, dest);
1097d36db35SAvi Kivity }
1107d36db35SAvi Kivity 
1117d36db35SAvi Kivity uint32_t apic_id(void)
1127d36db35SAvi Kivity {
1137d36db35SAvi Kivity     return apic_ops->id();
1147d36db35SAvi Kivity }
1157d36db35SAvi Kivity 
116e0a5cfcaSPaolo Bonzini uint8_t apic_get_tpr(void)
117e0a5cfcaSPaolo Bonzini {
118e0a5cfcaSPaolo Bonzini 	unsigned long tpr;
119e0a5cfcaSPaolo Bonzini 
120e0a5cfcaSPaolo Bonzini #ifdef __x86_64__
121e0a5cfcaSPaolo Bonzini 	asm volatile ("mov %%cr8, %0" : "=r"(tpr));
122e0a5cfcaSPaolo Bonzini #else
123*533a738fSAndrew Jones 	tpr = apic_read(APIC_TASKPRI) >> 4;
124e0a5cfcaSPaolo Bonzini #endif
125e0a5cfcaSPaolo Bonzini 	return tpr;
126e0a5cfcaSPaolo Bonzini }
127e0a5cfcaSPaolo Bonzini 
128e0a5cfcaSPaolo Bonzini void apic_set_tpr(uint8_t tpr)
129e0a5cfcaSPaolo Bonzini {
130e0a5cfcaSPaolo Bonzini #ifdef __x86_64__
131e0a5cfcaSPaolo Bonzini 	asm volatile ("mov %0, %%cr8" : : "r"((unsigned long) tpr));
132e0a5cfcaSPaolo Bonzini #else
133*533a738fSAndrew Jones 	apic_write(APIC_TASKPRI, tpr << 4);
134e0a5cfcaSPaolo Bonzini #endif
135e0a5cfcaSPaolo Bonzini }
136e0a5cfcaSPaolo Bonzini 
1377d36db35SAvi Kivity int enable_x2apic(void)
1387d36db35SAvi Kivity {
1397d36db35SAvi Kivity     unsigned a, b, c, d;
1407d36db35SAvi Kivity 
1417d36db35SAvi Kivity     asm ("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(1));
1427d36db35SAvi Kivity 
1437d36db35SAvi Kivity     if (c & (1 << 21)) {
144b5aa0cebSJan Kiszka         asm ("rdmsr" : "=a"(a), "=d"(d) : "c"(MSR_IA32_APICBASE));
1457d36db35SAvi Kivity         a |= 1 << 10;
146b5aa0cebSJan Kiszka         asm ("wrmsr" : : "a"(a), "d"(d), "c"(MSR_IA32_APICBASE));
1477d36db35SAvi Kivity         apic_ops = &x2apic_ops;
1487d36db35SAvi Kivity         return 1;
1497d36db35SAvi Kivity     } else {
1507d36db35SAvi Kivity         return 0;
1517d36db35SAvi Kivity     }
1527d36db35SAvi Kivity }
1537d36db35SAvi Kivity 
154a222b5e2SRadim Krčmář void reset_apic(void)
155a222b5e2SRadim Krčmář {
156a222b5e2SRadim Krčmář     u64 disabled = rdmsr(MSR_IA32_APICBASE) & ~(APIC_EN | APIC_EXTD);
157a222b5e2SRadim Krčmář     wrmsr(MSR_IA32_APICBASE, disabled);
158a222b5e2SRadim Krčmář     apic_ops = &xapic_ops;
159a222b5e2SRadim Krčmář     wrmsr(MSR_IA32_APICBASE, disabled | APIC_EN);
160a222b5e2SRadim Krčmář }
161a222b5e2SRadim Krčmář 
1620f187a08SSteve Rutherford u32 ioapic_read_reg(unsigned reg)
1630f187a08SSteve Rutherford {
1640f187a08SSteve Rutherford     *(volatile u32 *)g_ioapic = reg;
1650f187a08SSteve Rutherford     return *(volatile u32 *)(g_ioapic + 0x10);
1660f187a08SSteve Rutherford }
1670f187a08SSteve Rutherford 
1687d36db35SAvi Kivity void ioapic_write_reg(unsigned reg, u32 value)
1697d36db35SAvi Kivity {
1707d36db35SAvi Kivity     *(volatile u32 *)g_ioapic = reg;
1717d36db35SAvi Kivity     *(volatile u32 *)(g_ioapic + 0x10) = value;
1727d36db35SAvi Kivity }
1737d36db35SAvi Kivity 
1747d36db35SAvi Kivity void ioapic_write_redir(unsigned line, ioapic_redir_entry_t e)
1757d36db35SAvi Kivity {
1767d36db35SAvi Kivity     ioapic_write_reg(0x10 + line * 2 + 0, ((u32 *)&e)[0]);
1777d36db35SAvi Kivity     ioapic_write_reg(0x10 + line * 2 + 1, ((u32 *)&e)[1]);
1787d36db35SAvi Kivity }
1797d36db35SAvi Kivity 
1800f187a08SSteve Rutherford ioapic_redir_entry_t ioapic_read_redir(unsigned line)
1810f187a08SSteve Rutherford {
1820f187a08SSteve Rutherford     ioapic_redir_entry_t e;
1830f187a08SSteve Rutherford 
1840f187a08SSteve Rutherford     ((u32 *)&e)[0] = ioapic_read_reg(0x10 + line * 2 + 0);
1850f187a08SSteve Rutherford     ((u32 *)&e)[1] = ioapic_read_reg(0x10 + line * 2 + 1);
1860f187a08SSteve Rutherford     return e;
1870f187a08SSteve Rutherford 
1880f187a08SSteve Rutherford }
1890f187a08SSteve Rutherford 
1900f187a08SSteve Rutherford void set_mask(unsigned line, int mask)
1910f187a08SSteve Rutherford {
1920f187a08SSteve Rutherford     ioapic_redir_entry_t e = ioapic_read_redir(line);
1930f187a08SSteve Rutherford 
1940f187a08SSteve Rutherford     e.mask = mask;
1950f187a08SSteve Rutherford     ioapic_write_redir(line, e);
1960f187a08SSteve Rutherford }
1970f187a08SSteve Rutherford 
1987d36db35SAvi Kivity void enable_apic(void)
1997d36db35SAvi Kivity {
2007d36db35SAvi Kivity     printf("enabling apic\n");
2017d36db35SAvi Kivity     xapic_write(0xf0, 0x1ff); /* spurious vector register */
2027d36db35SAvi Kivity }
2037d36db35SAvi Kivity 
2047d36db35SAvi Kivity void mask_pic_interrupts(void)
2057d36db35SAvi Kivity {
2067d36db35SAvi Kivity     outb(0xff, 0x21);
2077d36db35SAvi Kivity     outb(0xff, 0xa1);
2087d36db35SAvi Kivity }
209