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