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