1 #include "libcflat.h" 2 #include "apic.h" 3 #include "msr.h" 4 #include "processor.h" 5 #include "smp.h" 6 #include "asm/barrier.h" 7 8 /* xAPIC and I/O APIC are identify mapped, and never relocated. */ 9 static void *g_apic = (void *)APIC_DEFAULT_PHYS_BASE; 10 static void *g_ioapic = (void *)IO_APIC_DEFAULT_PHYS_BASE; 11 12 u8 id_map[MAX_TEST_CPUS]; 13 14 struct apic_ops { 15 u32 (*reg_read)(unsigned reg); 16 void (*reg_write)(unsigned reg, u32 val); 17 void (*icr_write)(u32 val, u32 dest); 18 u32 (*id)(void); 19 }; 20 21 static struct apic_ops *get_apic_ops(void) 22 { 23 return this_cpu_read_apic_ops(); 24 } 25 26 static void outb(unsigned char data, unsigned short port) 27 { 28 asm volatile ("out %0, %1" : : "a"(data), "d"(port)); 29 } 30 31 void eoi(void) 32 { 33 apic_write(APIC_EOI, 0); 34 } 35 36 static u32 xapic_read(unsigned reg) 37 { 38 return *(volatile u32 *)(g_apic + reg); 39 } 40 41 static void xapic_write(unsigned reg, u32 val) 42 { 43 *(volatile u32 *)(g_apic + reg) = val; 44 } 45 46 static void xapic_icr_write(u32 val, u32 dest) 47 { 48 while (xapic_read(APIC_ICR) & APIC_ICR_BUSY) 49 ; 50 xapic_write(APIC_ICR2, dest << 24); 51 xapic_write(APIC_ICR, val); 52 } 53 54 static uint32_t xapic_id(void) 55 { 56 return xapic_read(APIC_ID) >> 24; 57 } 58 59 static const struct apic_ops xapic_ops = { 60 .reg_read = xapic_read, 61 .reg_write = xapic_write, 62 .icr_write = xapic_icr_write, 63 .id = xapic_id, 64 }; 65 66 static u32 x2apic_read(unsigned reg) 67 { 68 unsigned a, d; 69 70 asm volatile ("rdmsr" : "=a"(a), "=d"(d) : "c"(APIC_BASE_MSR + reg/16)); 71 return a | (u64)d << 32; 72 } 73 74 static void x2apic_write(unsigned reg, u32 val) 75 { 76 asm volatile ("wrmsr" : : "a"(val), "d"(0), "c"(APIC_BASE_MSR + reg/16)); 77 } 78 79 static void x2apic_icr_write(u32 val, u32 dest) 80 { 81 mb(); 82 asm volatile ("wrmsr" : : "a"(val), "d"(dest), 83 "c"(APIC_BASE_MSR + APIC_ICR/16)); 84 } 85 86 static uint32_t x2apic_id(void) 87 { 88 return x2apic_read(APIC_ID); 89 } 90 91 static const struct apic_ops x2apic_ops = { 92 .reg_read = x2apic_read, 93 .reg_write = x2apic_write, 94 .icr_write = x2apic_icr_write, 95 .id = x2apic_id, 96 }; 97 98 u32 apic_read(unsigned reg) 99 { 100 return get_apic_ops()->reg_read(reg); 101 } 102 103 void apic_write(unsigned reg, u32 val) 104 { 105 get_apic_ops()->reg_write(reg, val); 106 } 107 108 bool apic_read_bit(unsigned reg, int n) 109 { 110 reg += (n >> 5) << 4; 111 n &= 31; 112 return (apic_read(reg) & (1 << n)) != 0; 113 } 114 115 void apic_icr_write(u32 val, u32 dest) 116 { 117 get_apic_ops()->icr_write(val, dest); 118 } 119 120 uint32_t apic_id(void) 121 { 122 return get_apic_ops()->id(); 123 } 124 125 uint8_t apic_get_tpr(void) 126 { 127 unsigned long tpr; 128 129 #ifdef __x86_64__ 130 asm volatile ("mov %%cr8, %0" : "=r"(tpr)); 131 #else 132 tpr = apic_read(APIC_TASKPRI) >> 4; 133 #endif 134 return tpr; 135 } 136 137 void apic_set_tpr(uint8_t tpr) 138 { 139 #ifdef __x86_64__ 140 asm volatile ("mov %0, %%cr8" : : "r"((unsigned long) tpr)); 141 #else 142 apic_write(APIC_TASKPRI, tpr << 4); 143 #endif 144 } 145 146 int enable_x2apic(void) 147 { 148 unsigned a, b, c, d; 149 150 asm ("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(1)); 151 152 if (c & (1 << 21)) { 153 asm ("rdmsr" : "=a"(a), "=d"(d) : "c"(MSR_IA32_APICBASE)); 154 a |= 1 << 10; 155 asm ("wrmsr" : : "a"(a), "d"(d), "c"(MSR_IA32_APICBASE)); 156 this_cpu_write_apic_ops((void *)&x2apic_ops); 157 return 1; 158 } else { 159 return 0; 160 } 161 } 162 163 uint32_t pre_boot_apic_id(void) 164 { 165 u32 msr_lo, msr_hi; 166 167 asm ("rdmsr" : "=a"(msr_lo), "=d"(msr_hi) : "c"(MSR_IA32_APICBASE)); 168 169 return (msr_lo & APIC_EXTD) ? x2apic_id() : xapic_id(); 170 } 171 172 void disable_apic(void) 173 { 174 wrmsr(MSR_IA32_APICBASE, rdmsr(MSR_IA32_APICBASE) & ~(APIC_EN | APIC_EXTD)); 175 this_cpu_write_apic_ops((void *)&xapic_ops); 176 } 177 178 void reset_apic(void) 179 { 180 disable_apic(); 181 wrmsr(MSR_IA32_APICBASE, rdmsr(MSR_IA32_APICBASE) | APIC_EN); 182 xapic_write(APIC_SPIV, 0x1ff); 183 } 184 185 u32 ioapic_read_reg(unsigned reg) 186 { 187 *(volatile u32 *)g_ioapic = reg; 188 return *(volatile u32 *)(g_ioapic + 0x10); 189 } 190 191 void ioapic_write_reg(unsigned reg, u32 value) 192 { 193 *(volatile u32 *)g_ioapic = reg; 194 *(volatile u32 *)(g_ioapic + 0x10) = value; 195 } 196 197 void ioapic_write_redir(unsigned line, ioapic_redir_entry_t e) 198 { 199 ioapic_write_reg(0x10 + line * 2 + 0, ((u32 *)&e)[0]); 200 ioapic_write_reg(0x10 + line * 2 + 1, ((u32 *)&e)[1]); 201 } 202 203 ioapic_redir_entry_t ioapic_read_redir(unsigned line) 204 { 205 ioapic_redir_entry_t e; 206 207 ((u32 *)&e)[0] = ioapic_read_reg(0x10 + line * 2 + 0); 208 ((u32 *)&e)[1] = ioapic_read_reg(0x10 + line * 2 + 1); 209 return e; 210 211 } 212 213 void ioapic_set_redir(unsigned line, unsigned vec, 214 trigger_mode_t trig_mode) 215 { 216 ioapic_redir_entry_t e = { 217 .vector = vec, 218 .delivery_mode = 0, 219 .trig_mode = trig_mode, 220 }; 221 222 ioapic_write_redir(line, e); 223 } 224 225 void set_mask(unsigned line, int mask) 226 { 227 ioapic_redir_entry_t e = ioapic_read_redir(line); 228 229 e.mask = mask; 230 ioapic_write_redir(line, e); 231 } 232 233 void set_irq_line(unsigned line, int val) 234 { 235 asm volatile("out %0, %1" : : "a"((u8)val), "d"((u16)(0x2000 + line))); 236 } 237 238 void enable_apic(void) 239 { 240 printf("enabling apic\n"); 241 xapic_write(APIC_SPIV, 0x1ff); 242 } 243 244 void mask_pic_interrupts(void) 245 { 246 outb(0xff, 0x21); 247 outb(0xff, 0xa1); 248 } 249 250 void init_apic_map(void) 251 { 252 unsigned int i, j = 0; 253 254 for (i = 0; i < MAX_TEST_CPUS; i++) { 255 if ((1ul << (i % 8)) & (online_cpus[i / 8])) 256 id_map[j++] = i; 257 } 258 } 259 260 void apic_setup_timer(int vector, u32 mode) 261 { 262 apic_cleanup_timer(); 263 264 assert((mode & APIC_LVT_TIMER_MASK) == mode); 265 266 apic_write(APIC_TDCR, APIC_TDR_DIV_1); 267 apic_write(APIC_LVTT, vector | mode); 268 } 269 270 void apic_start_timer(u32 value) 271 { 272 /* 273 * APIC timer runs at the 'core crystal clock', divided by the value in 274 * APIC_TDCR. 275 */ 276 apic_write(APIC_TMICT, value); 277 } 278 279 void apic_stop_timer(void) 280 { 281 apic_write(APIC_TMICT, 0); 282 } 283 284 void apic_cleanup_timer(void) 285 { 286 u32 lvtt = apic_read(APIC_LVTT); 287 288 /* Stop the timer/counter. */ 289 apic_stop_timer(); 290 291 /* Mask the timer interrupt in the local vector table. */ 292 apic_write(APIC_LVTT, lvtt | APIC_LVT_MASKED); 293 294 /* Enable interrupts to ensure any pending timer IRQs are serviced. */ 295 sti_nop_cli(); 296 } 297