xref: /kvm-unit-tests/lib/x86/apic.c (revision d8de5a333fde550f6bd93c41ee0539de3cabd4ab)
17d36db35SAvi Kivity #include "libcflat.h"
27d36db35SAvi Kivity #include "apic.h"
3b5aa0cebSJan Kiszka #include "msr.h"
4a222b5e2SRadim Krčmář #include "processor.h"
5129ef680SNadav Amit #include "asm/barrier.h"
67d36db35SAvi Kivity 
7f66d11caSArbel Moshe void *g_apic = (void *)0xfee00000;
8f66d11caSArbel Moshe void *g_ioapic = (void *)0xfec00000;
918a34cceSNadav Amit u8 id_map[MAX_TEST_CPUS];
107d36db35SAvi Kivity 
117d36db35SAvi Kivity struct apic_ops {
127d36db35SAvi Kivity     u32 (*reg_read)(unsigned reg);
137d36db35SAvi Kivity     void (*reg_write)(unsigned reg, u32 val);
147d36db35SAvi Kivity     void (*icr_write)(u32 val, u32 dest);
157d36db35SAvi Kivity     u32 (*id)(void);
167d36db35SAvi Kivity };
177d36db35SAvi Kivity 
187d36db35SAvi Kivity static void outb(unsigned char data, unsigned short port)
197d36db35SAvi Kivity {
207d36db35SAvi Kivity     asm volatile ("out %0, %1" : : "a"(data), "d"(port));
217d36db35SAvi Kivity }
227d36db35SAvi Kivity 
230f187a08SSteve Rutherford void eoi(void)
240f187a08SSteve Rutherford {
250f187a08SSteve Rutherford     apic_write(APIC_EOI, 0);
260f187a08SSteve Rutherford }
270f187a08SSteve Rutherford 
287d36db35SAvi Kivity static u32 xapic_read(unsigned reg)
297d36db35SAvi Kivity {
307d36db35SAvi Kivity     return *(volatile u32 *)(g_apic + reg);
317d36db35SAvi Kivity }
327d36db35SAvi Kivity 
337d36db35SAvi Kivity static void xapic_write(unsigned reg, u32 val)
347d36db35SAvi Kivity {
357d36db35SAvi Kivity     *(volatile u32 *)(g_apic + reg) = val;
367d36db35SAvi Kivity }
377d36db35SAvi Kivity 
387d36db35SAvi Kivity static void xapic_icr_write(u32 val, u32 dest)
397d36db35SAvi Kivity {
407d36db35SAvi Kivity     while (xapic_read(APIC_ICR) & APIC_ICR_BUSY)
417d36db35SAvi Kivity         ;
427d36db35SAvi Kivity     xapic_write(APIC_ICR2, dest << 24);
437d36db35SAvi Kivity     xapic_write(APIC_ICR, val);
447d36db35SAvi Kivity }
457d36db35SAvi Kivity 
467d36db35SAvi Kivity static uint32_t xapic_id(void)
477d36db35SAvi Kivity {
487d36db35SAvi Kivity     return xapic_read(APIC_ID) >> 24;
497d36db35SAvi Kivity }
507d36db35SAvi Kivity 
51*d8de5a33SSean Christopherson uint32_t pre_boot_apic_id(void)
52*d8de5a33SSean Christopherson {
53*d8de5a33SSean Christopherson 	return xapic_id();
54*d8de5a33SSean Christopherson }
55*d8de5a33SSean Christopherson 
567d36db35SAvi Kivity static const struct apic_ops xapic_ops = {
577d36db35SAvi Kivity     .reg_read = xapic_read,
587d36db35SAvi Kivity     .reg_write = xapic_write,
597d36db35SAvi Kivity     .icr_write = xapic_icr_write,
607d36db35SAvi Kivity     .id = xapic_id,
617d36db35SAvi Kivity };
627d36db35SAvi Kivity 
637d36db35SAvi Kivity static const struct apic_ops *apic_ops = &xapic_ops;
647d36db35SAvi Kivity 
657d36db35SAvi Kivity static u32 x2apic_read(unsigned reg)
667d36db35SAvi Kivity {
677d36db35SAvi Kivity     unsigned a, d;
687d36db35SAvi Kivity 
697d36db35SAvi Kivity     asm volatile ("rdmsr" : "=a"(a), "=d"(d) : "c"(APIC_BASE_MSR + reg/16));
707d36db35SAvi Kivity     return a | (u64)d << 32;
717d36db35SAvi Kivity }
727d36db35SAvi Kivity 
737d36db35SAvi Kivity static void x2apic_write(unsigned reg, u32 val)
747d36db35SAvi Kivity {
757d36db35SAvi Kivity     asm volatile ("wrmsr" : : "a"(val), "d"(0), "c"(APIC_BASE_MSR + reg/16));
767d36db35SAvi Kivity }
777d36db35SAvi Kivity 
787d36db35SAvi Kivity static void x2apic_icr_write(u32 val, u32 dest)
797d36db35SAvi Kivity {
80129ef680SNadav Amit     mb();
817d36db35SAvi Kivity     asm volatile ("wrmsr" : : "a"(val), "d"(dest),
827d36db35SAvi Kivity                   "c"(APIC_BASE_MSR + APIC_ICR/16));
837d36db35SAvi Kivity }
847d36db35SAvi Kivity 
857d36db35SAvi Kivity static uint32_t x2apic_id(void)
867d36db35SAvi Kivity {
87a0837ab6SRadim Krčmář     return x2apic_read(APIC_ID);
887d36db35SAvi Kivity }
897d36db35SAvi Kivity 
907d36db35SAvi Kivity static const struct apic_ops x2apic_ops = {
917d36db35SAvi Kivity     .reg_read = x2apic_read,
927d36db35SAvi Kivity     .reg_write = x2apic_write,
937d36db35SAvi Kivity     .icr_write = x2apic_icr_write,
947d36db35SAvi Kivity     .id = x2apic_id,
957d36db35SAvi Kivity };
967d36db35SAvi Kivity 
977d36db35SAvi Kivity u32 apic_read(unsigned reg)
987d36db35SAvi Kivity {
997d36db35SAvi Kivity     return apic_ops->reg_read(reg);
1007d36db35SAvi Kivity }
1017d36db35SAvi Kivity 
1027d36db35SAvi Kivity void apic_write(unsigned reg, u32 val)
1037d36db35SAvi Kivity {
1047d36db35SAvi Kivity     apic_ops->reg_write(reg, val);
1057d36db35SAvi Kivity }
1067d36db35SAvi Kivity 
1077c5f3ee9SPaolo Bonzini bool apic_read_bit(unsigned reg, int n)
1087c5f3ee9SPaolo Bonzini {
1097c5f3ee9SPaolo Bonzini     reg += (n >> 5) << 4;
1107c5f3ee9SPaolo Bonzini     n &= 31;
1117c5f3ee9SPaolo Bonzini     return (apic_read(reg) & (1 << n)) != 0;
1127c5f3ee9SPaolo Bonzini }
1137c5f3ee9SPaolo Bonzini 
1147d36db35SAvi Kivity void apic_icr_write(u32 val, u32 dest)
1157d36db35SAvi Kivity {
1167d36db35SAvi Kivity     apic_ops->icr_write(val, dest);
1177d36db35SAvi Kivity }
1187d36db35SAvi Kivity 
1197d36db35SAvi Kivity uint32_t apic_id(void)
1207d36db35SAvi Kivity {
1217d36db35SAvi Kivity     return apic_ops->id();
1227d36db35SAvi Kivity }
1237d36db35SAvi Kivity 
124e0a5cfcaSPaolo Bonzini uint8_t apic_get_tpr(void)
125e0a5cfcaSPaolo Bonzini {
126e0a5cfcaSPaolo Bonzini 	unsigned long tpr;
127e0a5cfcaSPaolo Bonzini 
128e0a5cfcaSPaolo Bonzini #ifdef __x86_64__
129e0a5cfcaSPaolo Bonzini 	asm volatile ("mov %%cr8, %0" : "=r"(tpr));
130e0a5cfcaSPaolo Bonzini #else
131533a738fSAndrew Jones 	tpr = apic_read(APIC_TASKPRI) >> 4;
132e0a5cfcaSPaolo Bonzini #endif
133e0a5cfcaSPaolo Bonzini 	return tpr;
134e0a5cfcaSPaolo Bonzini }
135e0a5cfcaSPaolo Bonzini 
136e0a5cfcaSPaolo Bonzini void apic_set_tpr(uint8_t tpr)
137e0a5cfcaSPaolo Bonzini {
138e0a5cfcaSPaolo Bonzini #ifdef __x86_64__
139e0a5cfcaSPaolo Bonzini 	asm volatile ("mov %0, %%cr8" : : "r"((unsigned long) tpr));
140e0a5cfcaSPaolo Bonzini #else
141533a738fSAndrew Jones 	apic_write(APIC_TASKPRI, tpr << 4);
142e0a5cfcaSPaolo Bonzini #endif
143e0a5cfcaSPaolo Bonzini }
144e0a5cfcaSPaolo Bonzini 
1457d36db35SAvi Kivity int enable_x2apic(void)
1467d36db35SAvi Kivity {
1477d36db35SAvi Kivity     unsigned a, b, c, d;
1487d36db35SAvi Kivity 
1497d36db35SAvi Kivity     asm ("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(1));
1507d36db35SAvi Kivity 
1517d36db35SAvi Kivity     if (c & (1 << 21)) {
152b5aa0cebSJan Kiszka         asm ("rdmsr" : "=a"(a), "=d"(d) : "c"(MSR_IA32_APICBASE));
1537d36db35SAvi Kivity         a |= 1 << 10;
154b5aa0cebSJan Kiszka         asm ("wrmsr" : : "a"(a), "d"(d), "c"(MSR_IA32_APICBASE));
1557d36db35SAvi Kivity         apic_ops = &x2apic_ops;
1567d36db35SAvi Kivity         return 1;
1577d36db35SAvi Kivity     } else {
1587d36db35SAvi Kivity         return 0;
1597d36db35SAvi Kivity     }
1607d36db35SAvi Kivity }
1617d36db35SAvi Kivity 
162e38858bcSJim Mattson void disable_apic(void)
163e38858bcSJim Mattson {
164e38858bcSJim Mattson     wrmsr(MSR_IA32_APICBASE, rdmsr(MSR_IA32_APICBASE) & ~(APIC_EN | APIC_EXTD));
165e38858bcSJim Mattson     apic_ops = &xapic_ops;
166e38858bcSJim Mattson }
167e38858bcSJim Mattson 
168a222b5e2SRadim Krčmář void reset_apic(void)
169a222b5e2SRadim Krčmář {
170e38858bcSJim Mattson     disable_apic();
171e38858bcSJim Mattson     wrmsr(MSR_IA32_APICBASE, rdmsr(MSR_IA32_APICBASE) | APIC_EN);
172d6e8f863SNadav Amit     xapic_write(APIC_SPIV, 0x1ff);
173a222b5e2SRadim Krčmář }
174a222b5e2SRadim Krčmář 
1750f187a08SSteve Rutherford u32 ioapic_read_reg(unsigned reg)
1760f187a08SSteve Rutherford {
1770f187a08SSteve Rutherford     *(volatile u32 *)g_ioapic = reg;
1780f187a08SSteve Rutherford     return *(volatile u32 *)(g_ioapic + 0x10);
1790f187a08SSteve Rutherford }
1800f187a08SSteve Rutherford 
1817d36db35SAvi Kivity void ioapic_write_reg(unsigned reg, u32 value)
1827d36db35SAvi Kivity {
1837d36db35SAvi Kivity     *(volatile u32 *)g_ioapic = reg;
1847d36db35SAvi Kivity     *(volatile u32 *)(g_ioapic + 0x10) = value;
1857d36db35SAvi Kivity }
1867d36db35SAvi Kivity 
1877d36db35SAvi Kivity void ioapic_write_redir(unsigned line, ioapic_redir_entry_t e)
1887d36db35SAvi Kivity {
1897d36db35SAvi Kivity     ioapic_write_reg(0x10 + line * 2 + 0, ((u32 *)&e)[0]);
1907d36db35SAvi Kivity     ioapic_write_reg(0x10 + line * 2 + 1, ((u32 *)&e)[1]);
1917d36db35SAvi Kivity }
1927d36db35SAvi Kivity 
1930f187a08SSteve Rutherford ioapic_redir_entry_t ioapic_read_redir(unsigned line)
1940f187a08SSteve Rutherford {
1950f187a08SSteve Rutherford     ioapic_redir_entry_t e;
1960f187a08SSteve Rutherford 
1970f187a08SSteve Rutherford     ((u32 *)&e)[0] = ioapic_read_reg(0x10 + line * 2 + 0);
1980f187a08SSteve Rutherford     ((u32 *)&e)[1] = ioapic_read_reg(0x10 + line * 2 + 1);
1990f187a08SSteve Rutherford     return e;
2000f187a08SSteve Rutherford 
2010f187a08SSteve Rutherford }
2020f187a08SSteve Rutherford 
20322207960SLiran Alon void ioapic_set_redir(unsigned line, unsigned vec,
204f66d11caSArbel Moshe 			     trigger_mode_t trig_mode)
205f66d11caSArbel Moshe {
206f66d11caSArbel Moshe 	ioapic_redir_entry_t e = {
207f66d11caSArbel Moshe 		.vector = vec,
208f66d11caSArbel Moshe 		.delivery_mode = 0,
209f66d11caSArbel Moshe 		.trig_mode = trig_mode,
210f66d11caSArbel Moshe 	};
211f66d11caSArbel Moshe 
212f66d11caSArbel Moshe 	ioapic_write_redir(line, e);
213f66d11caSArbel Moshe }
214f66d11caSArbel Moshe 
2150f187a08SSteve Rutherford void set_mask(unsigned line, int mask)
2160f187a08SSteve Rutherford {
2170f187a08SSteve Rutherford     ioapic_redir_entry_t e = ioapic_read_redir(line);
2180f187a08SSteve Rutherford 
2190f187a08SSteve Rutherford     e.mask = mask;
2200f187a08SSteve Rutherford     ioapic_write_redir(line, e);
2210f187a08SSteve Rutherford }
2220f187a08SSteve Rutherford 
223f66d11caSArbel Moshe void set_irq_line(unsigned line, int val)
224f66d11caSArbel Moshe {
225f66d11caSArbel Moshe 	asm volatile("out %0, %1" : : "a"((u8)val), "d"((u16)(0x2000 + line)));
226f66d11caSArbel Moshe }
227f66d11caSArbel Moshe 
2287d36db35SAvi Kivity void enable_apic(void)
2297d36db35SAvi Kivity {
2307d36db35SAvi Kivity     printf("enabling apic\n");
231add65e76SNadav Amit     xapic_write(APIC_SPIV, 0x1ff);
2327d36db35SAvi Kivity }
2337d36db35SAvi Kivity 
2347d36db35SAvi Kivity void mask_pic_interrupts(void)
2357d36db35SAvi Kivity {
2367d36db35SAvi Kivity     outb(0xff, 0x21);
2377d36db35SAvi Kivity     outb(0xff, 0xa1);
2387d36db35SAvi Kivity }
23918a34cceSNadav Amit 
240760a2ddeSXinpeng Liu extern unsigned char online_cpus[(MAX_TEST_CPUS + 7) / 8];
24118a34cceSNadav Amit 
24218a34cceSNadav Amit void init_apic_map(void)
24318a34cceSNadav Amit {
24418a34cceSNadav Amit 	unsigned int i, j = 0;
24518a34cceSNadav Amit 
246b00e75b3SSean Christopherson 	for (i = 0; i < MAX_TEST_CPUS; i++) {
24718a34cceSNadav Amit 		if ((1ul << (i % 8)) & (online_cpus[i / 8]))
24818a34cceSNadav Amit 			id_map[j++] = i;
24918a34cceSNadav Amit 	}
25018a34cceSNadav Amit }
251