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