xref: /kvm-unit-tests/lib/x86/apic.c (revision 4b5caf0c5621cd74baca7faad994777a98793c34)
1 #include "libcflat.h"
2 #include "apic.h"
3 #include "msr.h"
4 
5 static void *g_apic = (void *)0xfee00000;
6 static void *g_ioapic = (void *)0xfec00000;
7 
8 struct apic_ops {
9     u32 (*reg_read)(unsigned reg);
10     void (*reg_write)(unsigned reg, u32 val);
11     void (*icr_write)(u32 val, u32 dest);
12     u32 (*id)(void);
13 };
14 
15 static void outb(unsigned char data, unsigned short port)
16 {
17     asm volatile ("out %0, %1" : : "a"(data), "d"(port));
18 }
19 
20 void eoi(void)
21 {
22     apic_write(APIC_EOI, 0);
23 }
24 
25 static u32 xapic_read(unsigned reg)
26 {
27     return *(volatile u32 *)(g_apic + reg);
28 }
29 
30 static void xapic_write(unsigned reg, u32 val)
31 {
32     *(volatile u32 *)(g_apic + reg) = val;
33 }
34 
35 static void xapic_icr_write(u32 val, u32 dest)
36 {
37     while (xapic_read(APIC_ICR) & APIC_ICR_BUSY)
38         ;
39     xapic_write(APIC_ICR2, dest << 24);
40     xapic_write(APIC_ICR, val);
41 }
42 
43 static uint32_t xapic_id(void)
44 {
45     return xapic_read(APIC_ID) >> 24;
46 }
47 
48 static const struct apic_ops xapic_ops = {
49     .reg_read = xapic_read,
50     .reg_write = xapic_write,
51     .icr_write = xapic_icr_write,
52     .id = xapic_id,
53 };
54 
55 static const struct apic_ops *apic_ops = &xapic_ops;
56 
57 static u32 x2apic_read(unsigned reg)
58 {
59     unsigned a, d;
60 
61     asm volatile ("rdmsr" : "=a"(a), "=d"(d) : "c"(APIC_BASE_MSR + reg/16));
62     return a | (u64)d << 32;
63 }
64 
65 static void x2apic_write(unsigned reg, u32 val)
66 {
67     asm volatile ("wrmsr" : : "a"(val), "d"(0), "c"(APIC_BASE_MSR + reg/16));
68 }
69 
70 static void x2apic_icr_write(u32 val, u32 dest)
71 {
72     asm volatile ("wrmsr" : : "a"(val), "d"(dest),
73                   "c"(APIC_BASE_MSR + APIC_ICR/16));
74 }
75 
76 static uint32_t x2apic_id(void)
77 {
78     return x2apic_read(APIC_ID);
79 }
80 
81 static const struct apic_ops x2apic_ops = {
82     .reg_read = x2apic_read,
83     .reg_write = x2apic_write,
84     .icr_write = x2apic_icr_write,
85     .id = x2apic_id,
86 };
87 
88 u32 apic_read(unsigned reg)
89 {
90     return apic_ops->reg_read(reg);
91 }
92 
93 void apic_write(unsigned reg, u32 val)
94 {
95     apic_ops->reg_write(reg, val);
96 }
97 
98 bool apic_read_bit(unsigned reg, int n)
99 {
100     reg += (n >> 5) << 4;
101     n &= 31;
102     return (apic_read(reg) & (1 << n)) != 0;
103 }
104 
105 void apic_icr_write(u32 val, u32 dest)
106 {
107     apic_ops->icr_write(val, dest);
108 }
109 
110 uint32_t apic_id(void)
111 {
112     return apic_ops->id();
113 }
114 
115 int enable_x2apic(void)
116 {
117     unsigned a, b, c, d;
118 
119     asm ("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(1));
120 
121     if (c & (1 << 21)) {
122         asm ("rdmsr" : "=a"(a), "=d"(d) : "c"(MSR_IA32_APICBASE));
123         a |= 1 << 10;
124         asm ("wrmsr" : : "a"(a), "d"(d), "c"(MSR_IA32_APICBASE));
125         apic_ops = &x2apic_ops;
126         return 1;
127     } else {
128         return 0;
129     }
130 }
131 
132 u32 ioapic_read_reg(unsigned reg)
133 {
134     *(volatile u32 *)g_ioapic = reg;
135     return *(volatile u32 *)(g_ioapic + 0x10);
136 }
137 
138 void ioapic_write_reg(unsigned reg, u32 value)
139 {
140     *(volatile u32 *)g_ioapic = reg;
141     *(volatile u32 *)(g_ioapic + 0x10) = value;
142 }
143 
144 void ioapic_write_redir(unsigned line, ioapic_redir_entry_t e)
145 {
146     ioapic_write_reg(0x10 + line * 2 + 0, ((u32 *)&e)[0]);
147     ioapic_write_reg(0x10 + line * 2 + 1, ((u32 *)&e)[1]);
148 }
149 
150 ioapic_redir_entry_t ioapic_read_redir(unsigned line)
151 {
152     ioapic_redir_entry_t e;
153 
154     ((u32 *)&e)[0] = ioapic_read_reg(0x10 + line * 2 + 0);
155     ((u32 *)&e)[1] = ioapic_read_reg(0x10 + line * 2 + 1);
156     return e;
157 
158 }
159 
160 void set_mask(unsigned line, int mask)
161 {
162     ioapic_redir_entry_t e = ioapic_read_redir(line);
163 
164     e.mask = mask;
165     ioapic_write_redir(line, e);
166 }
167 
168 void enable_apic(void)
169 {
170     printf("enabling apic\n");
171     xapic_write(0xf0, 0x1ff); /* spurious vector register */
172 }
173 
174 void mask_pic_interrupts(void)
175 {
176     outb(0xff, 0x21);
177     outb(0xff, 0xa1);
178 }
179