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