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