xref: /kvm-unit-tests/lib/x86/apic.c (revision c604fa931a1cb70c3649ac1b7223178fc79eab6a)
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 
21 static struct apic_ops *get_apic_ops(void)
22 {
23 	return this_cpu_read_apic_ops();
24 }
25 
26 static void outb(unsigned char data, unsigned short port)
27 {
28 	asm volatile ("out %0, %1" : : "a"(data), "d"(port));
29 }
30 
31 void eoi(void)
32 {
33 	apic_write(APIC_EOI, 0);
34 }
35 
36 static u32 xapic_read(unsigned reg)
37 {
38 	return *(volatile u32 *)(g_apic + reg);
39 }
40 
41 static void xapic_write(unsigned reg, u32 val)
42 {
43 	*(volatile u32 *)(g_apic + reg) = val;
44 }
45 
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 
54 static uint32_t xapic_id(void)
55 {
56 	return xapic_read(APIC_ID) >> 24;
57 }
58 
59 uint32_t pre_boot_apic_id(void)
60 {
61 	return xapic_id();
62 }
63 
64 static const struct apic_ops xapic_ops = {
65 	.reg_read = xapic_read,
66 	.reg_write = xapic_write,
67 	.icr_write = xapic_icr_write,
68 	.id = xapic_id,
69 };
70 
71 static u32 x2apic_read(unsigned reg)
72 {
73 	unsigned a, d;
74 
75 	asm volatile ("rdmsr" : "=a"(a), "=d"(d) : "c"(APIC_BASE_MSR + reg/16));
76 	return a | (u64)d << 32;
77 }
78 
79 static void x2apic_write(unsigned reg, u32 val)
80 {
81 	asm volatile ("wrmsr" : : "a"(val), "d"(0), "c"(APIC_BASE_MSR + reg/16));
82 }
83 
84 static void x2apic_icr_write(u32 val, u32 dest)
85 {
86 	mb();
87 	asm volatile ("wrmsr" : : "a"(val), "d"(dest),
88 		      "c"(APIC_BASE_MSR + APIC_ICR/16));
89 }
90 
91 static uint32_t x2apic_id(void)
92 {
93 	return x2apic_read(APIC_ID);
94 }
95 
96 static const struct apic_ops x2apic_ops = {
97 	.reg_read = x2apic_read,
98 	.reg_write = x2apic_write,
99 	.icr_write = x2apic_icr_write,
100 	.id = x2apic_id,
101 };
102 
103 u32 apic_read(unsigned reg)
104 {
105 	return get_apic_ops()->reg_read(reg);
106 }
107 
108 void apic_write(unsigned reg, u32 val)
109 {
110 	get_apic_ops()->reg_write(reg, val);
111 }
112 
113 bool apic_read_bit(unsigned reg, int n)
114 {
115 	reg += (n >> 5) << 4;
116 	n &= 31;
117 	return (apic_read(reg) & (1 << n)) != 0;
118 }
119 
120 void apic_icr_write(u32 val, u32 dest)
121 {
122 	get_apic_ops()->icr_write(val, dest);
123 }
124 
125 uint32_t apic_id(void)
126 {
127 	return get_apic_ops()->id();
128 }
129 
130 uint8_t apic_get_tpr(void)
131 {
132 	unsigned long tpr;
133 
134 #ifdef __x86_64__
135 	asm volatile ("mov %%cr8, %0" : "=r"(tpr));
136 #else
137 	tpr = apic_read(APIC_TASKPRI) >> 4;
138 #endif
139 	return tpr;
140 }
141 
142 void apic_set_tpr(uint8_t tpr)
143 {
144 #ifdef __x86_64__
145 	asm volatile ("mov %0, %%cr8" : : "r"((unsigned long) tpr));
146 #else
147 	apic_write(APIC_TASKPRI, tpr << 4);
148 #endif
149 }
150 
151 int enable_x2apic(void)
152 {
153 	unsigned a, b, c, d;
154 
155 	asm ("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(1));
156 
157 	if (c & (1 << 21)) {
158 		asm ("rdmsr" : "=a"(a), "=d"(d) : "c"(MSR_IA32_APICBASE));
159 		a |= 1 << 10;
160 		asm ("wrmsr" : : "a"(a), "d"(d), "c"(MSR_IA32_APICBASE));
161 		this_cpu_write_apic_ops((void *)&x2apic_ops);
162 		return 1;
163 	} else {
164 		return 0;
165 	}
166 }
167 
168 void disable_apic(void)
169 {
170 	wrmsr(MSR_IA32_APICBASE, rdmsr(MSR_IA32_APICBASE) & ~(APIC_EN | APIC_EXTD));
171 	this_cpu_write_apic_ops((void *)&xapic_ops);
172 }
173 
174 void reset_apic(void)
175 {
176 	disable_apic();
177 	wrmsr(MSR_IA32_APICBASE, rdmsr(MSR_IA32_APICBASE) | APIC_EN);
178 	xapic_write(APIC_SPIV, 0x1ff);
179 }
180 
181 u32 ioapic_read_reg(unsigned reg)
182 {
183 	*(volatile u32 *)g_ioapic = reg;
184 	return *(volatile u32 *)(g_ioapic + 0x10);
185 }
186 
187 void ioapic_write_reg(unsigned reg, u32 value)
188 {
189 	*(volatile u32 *)g_ioapic = reg;
190 	*(volatile u32 *)(g_ioapic + 0x10) = value;
191 }
192 
193 void ioapic_write_redir(unsigned line, ioapic_redir_entry_t e)
194 {
195 	ioapic_write_reg(0x10 + line * 2 + 0, ((u32 *)&e)[0]);
196 	ioapic_write_reg(0x10 + line * 2 + 1, ((u32 *)&e)[1]);
197 }
198 
199 ioapic_redir_entry_t ioapic_read_redir(unsigned line)
200 {
201 	ioapic_redir_entry_t e;
202 
203 	((u32 *)&e)[0] = ioapic_read_reg(0x10 + line * 2 + 0);
204 	((u32 *)&e)[1] = ioapic_read_reg(0x10 + line * 2 + 1);
205 	return e;
206 
207 }
208 
209 void ioapic_set_redir(unsigned line, unsigned vec,
210 			     trigger_mode_t trig_mode)
211 {
212 	ioapic_redir_entry_t e = {
213 		.vector = vec,
214 		.delivery_mode = 0,
215 		.trig_mode = trig_mode,
216 	};
217 
218 	ioapic_write_redir(line, e);
219 }
220 
221 void set_mask(unsigned line, int mask)
222 {
223 	ioapic_redir_entry_t e = ioapic_read_redir(line);
224 
225 	e.mask = mask;
226 	ioapic_write_redir(line, e);
227 }
228 
229 void set_irq_line(unsigned line, int val)
230 {
231 	asm volatile("out %0, %1" : : "a"((u8)val), "d"((u16)(0x2000 + line)));
232 }
233 
234 void enable_apic(void)
235 {
236 	printf("enabling apic\n");
237 	xapic_write(APIC_SPIV, 0x1ff);
238 }
239 
240 void mask_pic_interrupts(void)
241 {
242 	outb(0xff, 0x21);
243 	outb(0xff, 0xa1);
244 }
245 
246 extern unsigned char online_cpus[(MAX_TEST_CPUS + 7) / 8];
247 
248 void init_apic_map(void)
249 {
250 	unsigned int i, j = 0;
251 
252 	for (i = 0; i < MAX_TEST_CPUS; i++) {
253 		if ((1ul << (i % 8)) & (online_cpus[i / 8]))
254 			id_map[j++] = i;
255 	}
256 }
257