xref: /kvm-unit-tests/lib/x86/apic.c (revision cd5f2fb4ad641c51fe0f1a85264dc3f6ede6e131)
1 #include "libcflat.h"
2 #include "apic.h"
3 #include "msr.h"
4 #include "processor.h"
5 #include "smp.h"
6 #include "asm/barrier.h"
7 
8 /* xAPIC and I/O APIC are identify mapped, and never relocated. */
9 static void *g_apic = (void *)APIC_DEFAULT_PHYS_BASE;
10 static void *g_ioapic = (void *)IO_APIC_DEFAULT_PHYS_BASE;
11 
12 u8 id_map[MAX_TEST_CPUS];
13 
14 struct apic_ops {
15 	u32 (*reg_read)(unsigned reg);
16 	void (*reg_write)(unsigned reg, u32 val);
17 	void (*icr_write)(u32 val, u32 dest);
18 	u32 (*id)(void);
19 };
20 
get_apic_ops(void)21 static struct apic_ops *get_apic_ops(void)
22 {
23 	return this_cpu_read_apic_ops();
24 }
25 
outb(unsigned char data,unsigned short port)26 static void outb(unsigned char data, unsigned short port)
27 {
28 	asm volatile ("out %0, %1" : : "a"(data), "d"(port));
29 }
30 
eoi(void)31 void eoi(void)
32 {
33 	apic_write(APIC_EOI, 0);
34 }
35 
xapic_read(unsigned reg)36 static u32 xapic_read(unsigned reg)
37 {
38 	return *(volatile u32 *)(g_apic + reg);
39 }
40 
xapic_write(unsigned reg,u32 val)41 static void xapic_write(unsigned reg, u32 val)
42 {
43 	*(volatile u32 *)(g_apic + reg) = val;
44 }
45 
xapic_icr_write(u32 val,u32 dest)46 static void xapic_icr_write(u32 val, u32 dest)
47 {
48 	while (xapic_read(APIC_ICR) & APIC_ICR_BUSY)
49 		;
50 	xapic_write(APIC_ICR2, dest << 24);
51 	xapic_write(APIC_ICR, val);
52 }
53 
xapic_id(void)54 static uint32_t xapic_id(void)
55 {
56 	return xapic_read(APIC_ID) >> 24;
57 }
58 
59 static const struct apic_ops xapic_ops = {
60 	.reg_read = xapic_read,
61 	.reg_write = xapic_write,
62 	.icr_write = xapic_icr_write,
63 	.id = xapic_id,
64 };
65 
x2apic_read(unsigned reg)66 static u32 x2apic_read(unsigned reg)
67 {
68 	unsigned a, d;
69 
70 	asm volatile ("rdmsr" : "=a"(a), "=d"(d) : "c"(APIC_BASE_MSR + reg/16));
71 	return a | (u64)d << 32;
72 }
73 
x2apic_write(unsigned reg,u32 val)74 static void x2apic_write(unsigned reg, u32 val)
75 {
76 	asm volatile ("wrmsr" : : "a"(val), "d"(0), "c"(APIC_BASE_MSR + reg/16));
77 }
78 
x2apic_icr_write(u32 val,u32 dest)79 static void x2apic_icr_write(u32 val, u32 dest)
80 {
81 	mb();
82 	asm volatile ("wrmsr" : : "a"(val), "d"(dest),
83 		      "c"(APIC_BASE_MSR + APIC_ICR/16));
84 }
85 
x2apic_id(void)86 static uint32_t x2apic_id(void)
87 {
88 	return x2apic_read(APIC_ID);
89 }
90 
91 static const struct apic_ops x2apic_ops = {
92 	.reg_read = x2apic_read,
93 	.reg_write = x2apic_write,
94 	.icr_write = x2apic_icr_write,
95 	.id = x2apic_id,
96 };
97 
apic_read(unsigned reg)98 u32 apic_read(unsigned reg)
99 {
100 	return get_apic_ops()->reg_read(reg);
101 }
102 
apic_write(unsigned reg,u32 val)103 void apic_write(unsigned reg, u32 val)
104 {
105 	get_apic_ops()->reg_write(reg, val);
106 }
107 
apic_read_bit(unsigned reg,int n)108 bool apic_read_bit(unsigned reg, int n)
109 {
110 	reg += (n >> 5) << 4;
111 	n &= 31;
112 	return (apic_read(reg) & (1 << n)) != 0;
113 }
114 
apic_icr_write(u32 val,u32 dest)115 void apic_icr_write(u32 val, u32 dest)
116 {
117 	get_apic_ops()->icr_write(val, dest);
118 }
119 
apic_id(void)120 uint32_t apic_id(void)
121 {
122 	return get_apic_ops()->id();
123 }
124 
apic_get_tpr(void)125 uint8_t apic_get_tpr(void)
126 {
127 	unsigned long tpr;
128 
129 #ifdef __x86_64__
130 	asm volatile ("mov %%cr8, %0" : "=r"(tpr));
131 #else
132 	tpr = apic_read(APIC_TASKPRI) >> 4;
133 #endif
134 	return tpr;
135 }
136 
apic_set_tpr(uint8_t tpr)137 void apic_set_tpr(uint8_t tpr)
138 {
139 #ifdef __x86_64__
140 	asm volatile ("mov %0, %%cr8" : : "r"((unsigned long) tpr));
141 #else
142 	apic_write(APIC_TASKPRI, tpr << 4);
143 #endif
144 }
145 
enable_x2apic(void)146 int enable_x2apic(void)
147 {
148 	unsigned a, b, c, d;
149 
150 	asm ("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(1));
151 
152 	if (c & (1 << 21)) {
153 		asm ("rdmsr" : "=a"(a), "=d"(d) : "c"(MSR_IA32_APICBASE));
154 		a |= 1 << 10;
155 		asm ("wrmsr" : : "a"(a), "d"(d), "c"(MSR_IA32_APICBASE));
156 		this_cpu_write_apic_ops((void *)&x2apic_ops);
157 		return 1;
158 	} else {
159 		return 0;
160 	}
161 }
162 
pre_boot_apic_id(void)163 uint32_t pre_boot_apic_id(void)
164 {
165 	u32 msr_lo, msr_hi;
166 
167 	asm ("rdmsr" : "=a"(msr_lo), "=d"(msr_hi) : "c"(MSR_IA32_APICBASE));
168 
169 	return (msr_lo & APIC_EXTD) ? x2apic_id() : xapic_id();
170 }
171 
disable_apic(void)172 void disable_apic(void)
173 {
174 	wrmsr(MSR_IA32_APICBASE, rdmsr(MSR_IA32_APICBASE) & ~(APIC_EN | APIC_EXTD));
175 	this_cpu_write_apic_ops((void *)&xapic_ops);
176 }
177 
reset_apic(void)178 void reset_apic(void)
179 {
180 	disable_apic();
181 	wrmsr(MSR_IA32_APICBASE, rdmsr(MSR_IA32_APICBASE) | APIC_EN);
182 	xapic_write(APIC_SPIV, 0x1ff);
183 }
184 
ioapic_read_reg(unsigned reg)185 u32 ioapic_read_reg(unsigned reg)
186 {
187 	*(volatile u32 *)g_ioapic = reg;
188 	return *(volatile u32 *)(g_ioapic + 0x10);
189 }
190 
ioapic_write_reg(unsigned reg,u32 value)191 void ioapic_write_reg(unsigned reg, u32 value)
192 {
193 	*(volatile u32 *)g_ioapic = reg;
194 	*(volatile u32 *)(g_ioapic + 0x10) = value;
195 }
196 
ioapic_write_redir(unsigned line,ioapic_redir_entry_t e)197 void ioapic_write_redir(unsigned line, ioapic_redir_entry_t e)
198 {
199 	ioapic_write_reg(0x10 + line * 2 + 0, ((u32 *)&e)[0]);
200 	ioapic_write_reg(0x10 + line * 2 + 1, ((u32 *)&e)[1]);
201 }
202 
ioapic_read_redir(unsigned line)203 ioapic_redir_entry_t ioapic_read_redir(unsigned line)
204 {
205 	ioapic_redir_entry_t e;
206 
207 	((u32 *)&e)[0] = ioapic_read_reg(0x10 + line * 2 + 0);
208 	((u32 *)&e)[1] = ioapic_read_reg(0x10 + line * 2 + 1);
209 	return e;
210 
211 }
212 
ioapic_set_redir(unsigned line,unsigned vec,trigger_mode_t trig_mode)213 void ioapic_set_redir(unsigned line, unsigned vec,
214 			     trigger_mode_t trig_mode)
215 {
216 	ioapic_redir_entry_t e = {
217 		.vector = vec,
218 		.delivery_mode = 0,
219 		.trig_mode = trig_mode,
220 	};
221 
222 	ioapic_write_redir(line, e);
223 }
224 
set_mask(unsigned line,int mask)225 void set_mask(unsigned line, int mask)
226 {
227 	ioapic_redir_entry_t e = ioapic_read_redir(line);
228 
229 	e.mask = mask;
230 	ioapic_write_redir(line, e);
231 }
232 
set_irq_line(unsigned line,int val)233 void set_irq_line(unsigned line, int val)
234 {
235 	asm volatile("out %0, %1" : : "a"((u8)val), "d"((u16)(0x2000 + line)));
236 }
237 
enable_apic(void)238 void enable_apic(void)
239 {
240 	printf("enabling apic\n");
241 	xapic_write(APIC_SPIV, 0x1ff);
242 }
243 
mask_pic_interrupts(void)244 void mask_pic_interrupts(void)
245 {
246 	outb(0xff, 0x21);
247 	outb(0xff, 0xa1);
248 }
249 
init_apic_map(void)250 void init_apic_map(void)
251 {
252 	unsigned int i, j = 0;
253 
254 	for (i = 0; i < MAX_TEST_CPUS; i++) {
255 		if ((1ul << (i % 8)) & (online_cpus[i / 8]))
256 			id_map[j++] = i;
257 	}
258 }
259 
apic_setup_timer(int vector,u32 mode)260 void apic_setup_timer(int vector, u32 mode)
261 {
262 	apic_cleanup_timer();
263 
264 	assert((mode & APIC_LVT_TIMER_MASK) == mode);
265 
266 	apic_write(APIC_TDCR, APIC_TDR_DIV_1);
267 	apic_write(APIC_LVTT, vector | mode);
268 }
269 
apic_start_timer(u32 value)270 void apic_start_timer(u32 value)
271 {
272 	/*
273 	 * APIC timer runs at the 'core crystal clock', divided by the value in
274 	 * APIC_TDCR.
275 	 */
276 	apic_write(APIC_TMICT, value);
277 }
278 
apic_stop_timer(void)279 void apic_stop_timer(void)
280 {
281 	apic_write(APIC_TMICT, 0);
282 }
283 
apic_cleanup_timer(void)284 void apic_cleanup_timer(void)
285 {
286 	u32 lvtt = apic_read(APIC_LVTT);
287 
288 	/* Stop the timer/counter. */
289 	apic_stop_timer();
290 
291 	/* Mask the timer interrupt in the local vector table. */
292 	apic_write(APIC_LVTT, lvtt | APIC_LVT_MASKED);
293 
294 	/* Enable interrupts to ensure any pending timer IRQs are serviced. */
295 	sti_nop_cli();
296 }
297