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