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