xref: /kvm-unit-tests/lib/x86/apic.c (revision 8854f47ae36665c7f5f3c8cdefbcaeed03df9120)
17d36db35SAvi Kivity #include "libcflat.h"
27d36db35SAvi Kivity #include "apic.h"
3b5aa0cebSJan Kiszka #include "msr.h"
4a222b5e2SRadim Krčmář #include "processor.h"
52d18ccd3SSean Christopherson #include "smp.h"
6129ef680SNadav Amit #include "asm/barrier.h"
77d36db35SAvi Kivity 
8df563aefSSean Christopherson /* xAPIC and I/O APIC are identify mapped, and never relocated. */
9df563aefSSean Christopherson static void *g_apic = (void *)APIC_DEFAULT_PHYS_BASE;
10df563aefSSean Christopherson static void *g_ioapic = (void *)IO_APIC_DEFAULT_PHYS_BASE;
11df563aefSSean Christopherson 
1218a34cceSNadav Amit u8 id_map[MAX_TEST_CPUS];
137d36db35SAvi Kivity 
147d36db35SAvi Kivity struct apic_ops {
157d36db35SAvi Kivity 	u32 (*reg_read)(unsigned reg);
167d36db35SAvi Kivity 	void (*reg_write)(unsigned reg, u32 val);
177d36db35SAvi Kivity 	void (*icr_write)(u32 val, u32 dest);
187d36db35SAvi Kivity 	u32 (*id)(void);
197d36db35SAvi Kivity };
207d36db35SAvi Kivity 
212d18ccd3SSean Christopherson static struct apic_ops *get_apic_ops(void)
222d18ccd3SSean Christopherson {
232d18ccd3SSean Christopherson 	return this_cpu_read_apic_ops();
242d18ccd3SSean Christopherson }
252d18ccd3SSean Christopherson 
267d36db35SAvi Kivity static void outb(unsigned char data, unsigned short port)
277d36db35SAvi Kivity {
287d36db35SAvi Kivity 	asm volatile ("out %0, %1" : : "a"(data), "d"(port));
297d36db35SAvi Kivity }
307d36db35SAvi Kivity 
310f187a08SSteve Rutherford void eoi(void)
320f187a08SSteve Rutherford {
330f187a08SSteve Rutherford 	apic_write(APIC_EOI, 0);
340f187a08SSteve Rutherford }
350f187a08SSteve Rutherford 
367d36db35SAvi Kivity static u32 xapic_read(unsigned reg)
377d36db35SAvi Kivity {
387d36db35SAvi Kivity 	return *(volatile u32 *)(g_apic + reg);
397d36db35SAvi Kivity }
407d36db35SAvi Kivity 
417d36db35SAvi Kivity static void xapic_write(unsigned reg, u32 val)
427d36db35SAvi Kivity {
437d36db35SAvi Kivity 	*(volatile u32 *)(g_apic + reg) = val;
447d36db35SAvi Kivity }
457d36db35SAvi Kivity 
467d36db35SAvi Kivity static void xapic_icr_write(u32 val, u32 dest)
477d36db35SAvi Kivity {
487d36db35SAvi Kivity 	while (xapic_read(APIC_ICR) & APIC_ICR_BUSY)
497d36db35SAvi Kivity 		;
507d36db35SAvi Kivity 	xapic_write(APIC_ICR2, dest << 24);
517d36db35SAvi Kivity 	xapic_write(APIC_ICR, val);
527d36db35SAvi Kivity }
537d36db35SAvi Kivity 
547d36db35SAvi Kivity static uint32_t xapic_id(void)
557d36db35SAvi Kivity {
567d36db35SAvi Kivity 	return xapic_read(APIC_ID) >> 24;
577d36db35SAvi Kivity }
587d36db35SAvi Kivity 
597d36db35SAvi Kivity static const struct apic_ops xapic_ops = {
607d36db35SAvi Kivity 	.reg_read = xapic_read,
617d36db35SAvi Kivity 	.reg_write = xapic_write,
627d36db35SAvi Kivity 	.icr_write = xapic_icr_write,
637d36db35SAvi Kivity 	.id = xapic_id,
647d36db35SAvi Kivity };
657d36db35SAvi Kivity 
667d36db35SAvi Kivity static u32 x2apic_read(unsigned reg)
677d36db35SAvi Kivity {
687d36db35SAvi Kivity 	unsigned a, d;
697d36db35SAvi Kivity 
707d36db35SAvi Kivity 	asm volatile ("rdmsr" : "=a"(a), "=d"(d) : "c"(APIC_BASE_MSR + reg/16));
717d36db35SAvi Kivity 	return a | (u64)d << 32;
727d36db35SAvi Kivity }
737d36db35SAvi Kivity 
747d36db35SAvi Kivity static void x2apic_write(unsigned reg, u32 val)
757d36db35SAvi Kivity {
767d36db35SAvi Kivity 	asm volatile ("wrmsr" : : "a"(val), "d"(0), "c"(APIC_BASE_MSR + reg/16));
777d36db35SAvi Kivity }
787d36db35SAvi Kivity 
797d36db35SAvi Kivity static void x2apic_icr_write(u32 val, u32 dest)
807d36db35SAvi Kivity {
81129ef680SNadav Amit 	mb();
827d36db35SAvi Kivity 	asm volatile ("wrmsr" : : "a"(val), "d"(dest),
837d36db35SAvi Kivity 		      "c"(APIC_BASE_MSR + APIC_ICR/16));
847d36db35SAvi Kivity }
857d36db35SAvi Kivity 
867d36db35SAvi Kivity static uint32_t x2apic_id(void)
877d36db35SAvi Kivity {
88a0837ab6SRadim Krčmář 	return x2apic_read(APIC_ID);
897d36db35SAvi Kivity }
907d36db35SAvi Kivity 
917d36db35SAvi Kivity static const struct apic_ops x2apic_ops = {
927d36db35SAvi Kivity 	.reg_read = x2apic_read,
937d36db35SAvi Kivity 	.reg_write = x2apic_write,
947d36db35SAvi Kivity 	.icr_write = x2apic_icr_write,
957d36db35SAvi Kivity 	.id = x2apic_id,
967d36db35SAvi Kivity };
977d36db35SAvi Kivity 
987d36db35SAvi Kivity u32 apic_read(unsigned reg)
997d36db35SAvi Kivity {
1002d18ccd3SSean Christopherson 	return get_apic_ops()->reg_read(reg);
1017d36db35SAvi Kivity }
1027d36db35SAvi Kivity 
1037d36db35SAvi Kivity void apic_write(unsigned reg, u32 val)
1047d36db35SAvi Kivity {
1052d18ccd3SSean Christopherson 	get_apic_ops()->reg_write(reg, val);
1067d36db35SAvi Kivity }
1077d36db35SAvi Kivity 
1087c5f3ee9SPaolo Bonzini bool apic_read_bit(unsigned reg, int n)
1097c5f3ee9SPaolo Bonzini {
1107c5f3ee9SPaolo Bonzini 	reg += (n >> 5) << 4;
1117c5f3ee9SPaolo Bonzini 	n &= 31;
1127c5f3ee9SPaolo Bonzini 	return (apic_read(reg) & (1 << n)) != 0;
1137c5f3ee9SPaolo Bonzini }
1147c5f3ee9SPaolo Bonzini 
1157d36db35SAvi Kivity void apic_icr_write(u32 val, u32 dest)
1167d36db35SAvi Kivity {
1172d18ccd3SSean Christopherson 	get_apic_ops()->icr_write(val, dest);
1187d36db35SAvi Kivity }
1197d36db35SAvi Kivity 
1207d36db35SAvi Kivity uint32_t apic_id(void)
1217d36db35SAvi Kivity {
1222d18ccd3SSean Christopherson 	return get_apic_ops()->id();
1237d36db35SAvi Kivity }
1247d36db35SAvi Kivity 
125e0a5cfcaSPaolo Bonzini uint8_t apic_get_tpr(void)
126e0a5cfcaSPaolo Bonzini {
127e0a5cfcaSPaolo Bonzini 	unsigned long tpr;
128e0a5cfcaSPaolo Bonzini 
129e0a5cfcaSPaolo Bonzini #ifdef __x86_64__
130e0a5cfcaSPaolo Bonzini 	asm volatile ("mov %%cr8, %0" : "=r"(tpr));
131e0a5cfcaSPaolo Bonzini #else
132533a738fSAndrew Jones 	tpr = apic_read(APIC_TASKPRI) >> 4;
133e0a5cfcaSPaolo Bonzini #endif
134e0a5cfcaSPaolo Bonzini 	return tpr;
135e0a5cfcaSPaolo Bonzini }
136e0a5cfcaSPaolo Bonzini 
137e0a5cfcaSPaolo Bonzini void apic_set_tpr(uint8_t tpr)
138e0a5cfcaSPaolo Bonzini {
139e0a5cfcaSPaolo Bonzini #ifdef __x86_64__
140e0a5cfcaSPaolo Bonzini 	asm volatile ("mov %0, %%cr8" : : "r"((unsigned long) tpr));
141e0a5cfcaSPaolo Bonzini #else
142533a738fSAndrew Jones 	apic_write(APIC_TASKPRI, tpr << 4);
143e0a5cfcaSPaolo Bonzini #endif
144e0a5cfcaSPaolo Bonzini }
145e0a5cfcaSPaolo Bonzini 
1467d36db35SAvi Kivity int enable_x2apic(void)
1477d36db35SAvi Kivity {
1487d36db35SAvi Kivity 	unsigned a, b, c, d;
1497d36db35SAvi Kivity 
1507d36db35SAvi Kivity 	asm ("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(1));
1517d36db35SAvi Kivity 
1527d36db35SAvi Kivity 	if (c & (1 << 21)) {
153b5aa0cebSJan Kiszka 		asm ("rdmsr" : "=a"(a), "=d"(d) : "c"(MSR_IA32_APICBASE));
1547d36db35SAvi Kivity 		a |= 1 << 10;
155b5aa0cebSJan Kiszka 		asm ("wrmsr" : : "a"(a), "d"(d), "c"(MSR_IA32_APICBASE));
1562d18ccd3SSean Christopherson 		this_cpu_write_apic_ops((void *)&x2apic_ops);
1577d36db35SAvi Kivity 		return 1;
1587d36db35SAvi Kivity 	} else {
1597d36db35SAvi Kivity 		return 0;
1607d36db35SAvi Kivity 	}
1617d36db35SAvi Kivity }
1627d36db35SAvi Kivity 
163*8854f47aSSean Christopherson uint32_t pre_boot_apic_id(void)
164*8854f47aSSean Christopherson {
165*8854f47aSSean Christopherson 	u32 msr_lo, msr_hi;
166*8854f47aSSean Christopherson 
167*8854f47aSSean Christopherson 	asm ("rdmsr" : "=a"(msr_lo), "=d"(msr_hi) : "c"(MSR_IA32_APICBASE));
168*8854f47aSSean Christopherson 
169*8854f47aSSean Christopherson 	return (msr_lo & APIC_EXTD) ? x2apic_id() : xapic_id();
170*8854f47aSSean Christopherson }
171*8854f47aSSean Christopherson 
172e38858bcSJim Mattson void disable_apic(void)
173e38858bcSJim Mattson {
174e38858bcSJim Mattson 	wrmsr(MSR_IA32_APICBASE, rdmsr(MSR_IA32_APICBASE) & ~(APIC_EN | APIC_EXTD));
1752d18ccd3SSean Christopherson 	this_cpu_write_apic_ops((void *)&xapic_ops);
176e38858bcSJim Mattson }
177e38858bcSJim Mattson 
178a222b5e2SRadim Krčmář void reset_apic(void)
179a222b5e2SRadim Krčmář {
180e38858bcSJim Mattson 	disable_apic();
181e38858bcSJim Mattson 	wrmsr(MSR_IA32_APICBASE, rdmsr(MSR_IA32_APICBASE) | APIC_EN);
182d6e8f863SNadav Amit 	xapic_write(APIC_SPIV, 0x1ff);
183a222b5e2SRadim Krčmář }
184a222b5e2SRadim Krčmář 
1850f187a08SSteve Rutherford u32 ioapic_read_reg(unsigned reg)
1860f187a08SSteve Rutherford {
1870f187a08SSteve Rutherford 	*(volatile u32 *)g_ioapic = reg;
1880f187a08SSteve Rutherford 	return *(volatile u32 *)(g_ioapic + 0x10);
1890f187a08SSteve Rutherford }
1900f187a08SSteve Rutherford 
1917d36db35SAvi Kivity void ioapic_write_reg(unsigned reg, u32 value)
1927d36db35SAvi Kivity {
1937d36db35SAvi Kivity 	*(volatile u32 *)g_ioapic = reg;
1947d36db35SAvi Kivity 	*(volatile u32 *)(g_ioapic + 0x10) = value;
1957d36db35SAvi Kivity }
1967d36db35SAvi Kivity 
1977d36db35SAvi Kivity void ioapic_write_redir(unsigned line, ioapic_redir_entry_t e)
1987d36db35SAvi Kivity {
1997d36db35SAvi Kivity 	ioapic_write_reg(0x10 + line * 2 + 0, ((u32 *)&e)[0]);
2007d36db35SAvi Kivity 	ioapic_write_reg(0x10 + line * 2 + 1, ((u32 *)&e)[1]);
2017d36db35SAvi Kivity }
2027d36db35SAvi Kivity 
2030f187a08SSteve Rutherford ioapic_redir_entry_t ioapic_read_redir(unsigned line)
2040f187a08SSteve Rutherford {
2050f187a08SSteve Rutherford 	ioapic_redir_entry_t e;
2060f187a08SSteve Rutherford 
2070f187a08SSteve Rutherford 	((u32 *)&e)[0] = ioapic_read_reg(0x10 + line * 2 + 0);
2080f187a08SSteve Rutherford 	((u32 *)&e)[1] = ioapic_read_reg(0x10 + line * 2 + 1);
2090f187a08SSteve Rutherford 	return e;
2100f187a08SSteve Rutherford 
2110f187a08SSteve Rutherford }
2120f187a08SSteve Rutherford 
21322207960SLiran Alon void ioapic_set_redir(unsigned line, unsigned vec,
214f66d11caSArbel Moshe 			     trigger_mode_t trig_mode)
215f66d11caSArbel Moshe {
216f66d11caSArbel Moshe 	ioapic_redir_entry_t e = {
217f66d11caSArbel Moshe 		.vector = vec,
218f66d11caSArbel Moshe 		.delivery_mode = 0,
219f66d11caSArbel Moshe 		.trig_mode = trig_mode,
220f66d11caSArbel Moshe 	};
221f66d11caSArbel Moshe 
222f66d11caSArbel Moshe 	ioapic_write_redir(line, e);
223f66d11caSArbel Moshe }
224f66d11caSArbel Moshe 
2250f187a08SSteve Rutherford void set_mask(unsigned line, int mask)
2260f187a08SSteve Rutherford {
2270f187a08SSteve Rutherford 	ioapic_redir_entry_t e = ioapic_read_redir(line);
2280f187a08SSteve Rutherford 
2290f187a08SSteve Rutherford 	e.mask = mask;
2300f187a08SSteve Rutherford 	ioapic_write_redir(line, e);
2310f187a08SSteve Rutherford }
2320f187a08SSteve Rutherford 
233f66d11caSArbel Moshe void set_irq_line(unsigned line, int val)
234f66d11caSArbel Moshe {
235f66d11caSArbel Moshe 	asm volatile("out %0, %1" : : "a"((u8)val), "d"((u16)(0x2000 + line)));
236f66d11caSArbel Moshe }
237f66d11caSArbel Moshe 
2387d36db35SAvi Kivity void enable_apic(void)
2397d36db35SAvi Kivity {
2407d36db35SAvi Kivity 	printf("enabling apic\n");
241add65e76SNadav Amit 	xapic_write(APIC_SPIV, 0x1ff);
2427d36db35SAvi Kivity }
2437d36db35SAvi Kivity 
2447d36db35SAvi Kivity void mask_pic_interrupts(void)
2457d36db35SAvi Kivity {
2467d36db35SAvi Kivity 	outb(0xff, 0x21);
2477d36db35SAvi Kivity 	outb(0xff, 0xa1);
2487d36db35SAvi Kivity }
24918a34cceSNadav Amit 
250760a2ddeSXinpeng Liu extern unsigned char online_cpus[(MAX_TEST_CPUS + 7) / 8];
25118a34cceSNadav Amit 
25218a34cceSNadav Amit void init_apic_map(void)
25318a34cceSNadav Amit {
25418a34cceSNadav Amit 	unsigned int i, j = 0;
25518a34cceSNadav Amit 
256b00e75b3SSean Christopherson 	for (i = 0; i < MAX_TEST_CPUS; i++) {
25718a34cceSNadav Amit 		if ((1ul << (i % 8)) & (online_cpus[i / 8]))
25818a34cceSNadav Amit 			id_map[j++] = i;
25918a34cceSNadav Amit 	}
26018a34cceSNadav Amit }
261