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 uint32_t pre_boot_apic_id(void) 60 { 61 return xapic_id(); 62 } 63 64 static const struct apic_ops xapic_ops = { 65 .reg_read = xapic_read, 66 .reg_write = xapic_write, 67 .icr_write = xapic_icr_write, 68 .id = xapic_id, 69 }; 70 71 static u32 x2apic_read(unsigned reg) 72 { 73 unsigned a, d; 74 75 asm volatile ("rdmsr" : "=a"(a), "=d"(d) : "c"(APIC_BASE_MSR + reg/16)); 76 return a | (u64)d << 32; 77 } 78 79 static void x2apic_write(unsigned reg, u32 val) 80 { 81 asm volatile ("wrmsr" : : "a"(val), "d"(0), "c"(APIC_BASE_MSR + reg/16)); 82 } 83 84 static void x2apic_icr_write(u32 val, u32 dest) 85 { 86 mb(); 87 asm volatile ("wrmsr" : : "a"(val), "d"(dest), 88 "c"(APIC_BASE_MSR + APIC_ICR/16)); 89 } 90 91 static uint32_t x2apic_id(void) 92 { 93 return x2apic_read(APIC_ID); 94 } 95 96 static const struct apic_ops x2apic_ops = { 97 .reg_read = x2apic_read, 98 .reg_write = x2apic_write, 99 .icr_write = x2apic_icr_write, 100 .id = x2apic_id, 101 }; 102 103 u32 apic_read(unsigned reg) 104 { 105 return get_apic_ops()->reg_read(reg); 106 } 107 108 void apic_write(unsigned reg, u32 val) 109 { 110 get_apic_ops()->reg_write(reg, val); 111 } 112 113 bool apic_read_bit(unsigned reg, int n) 114 { 115 reg += (n >> 5) << 4; 116 n &= 31; 117 return (apic_read(reg) & (1 << n)) != 0; 118 } 119 120 void apic_icr_write(u32 val, u32 dest) 121 { 122 get_apic_ops()->icr_write(val, dest); 123 } 124 125 uint32_t apic_id(void) 126 { 127 return get_apic_ops()->id(); 128 } 129 130 uint8_t apic_get_tpr(void) 131 { 132 unsigned long tpr; 133 134 #ifdef __x86_64__ 135 asm volatile ("mov %%cr8, %0" : "=r"(tpr)); 136 #else 137 tpr = apic_read(APIC_TASKPRI) >> 4; 138 #endif 139 return tpr; 140 } 141 142 void apic_set_tpr(uint8_t tpr) 143 { 144 #ifdef __x86_64__ 145 asm volatile ("mov %0, %%cr8" : : "r"((unsigned long) tpr)); 146 #else 147 apic_write(APIC_TASKPRI, tpr << 4); 148 #endif 149 } 150 151 int enable_x2apic(void) 152 { 153 unsigned a, b, c, d; 154 155 asm ("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(1)); 156 157 if (c & (1 << 21)) { 158 asm ("rdmsr" : "=a"(a), "=d"(d) : "c"(MSR_IA32_APICBASE)); 159 a |= 1 << 10; 160 asm ("wrmsr" : : "a"(a), "d"(d), "c"(MSR_IA32_APICBASE)); 161 this_cpu_write_apic_ops((void *)&x2apic_ops); 162 return 1; 163 } else { 164 return 0; 165 } 166 } 167 168 void disable_apic(void) 169 { 170 wrmsr(MSR_IA32_APICBASE, rdmsr(MSR_IA32_APICBASE) & ~(APIC_EN | APIC_EXTD)); 171 this_cpu_write_apic_ops((void *)&xapic_ops); 172 } 173 174 void reset_apic(void) 175 { 176 disable_apic(); 177 wrmsr(MSR_IA32_APICBASE, rdmsr(MSR_IA32_APICBASE) | APIC_EN); 178 xapic_write(APIC_SPIV, 0x1ff); 179 } 180 181 u32 ioapic_read_reg(unsigned reg) 182 { 183 *(volatile u32 *)g_ioapic = reg; 184 return *(volatile u32 *)(g_ioapic + 0x10); 185 } 186 187 void ioapic_write_reg(unsigned reg, u32 value) 188 { 189 *(volatile u32 *)g_ioapic = reg; 190 *(volatile u32 *)(g_ioapic + 0x10) = value; 191 } 192 193 void ioapic_write_redir(unsigned line, ioapic_redir_entry_t e) 194 { 195 ioapic_write_reg(0x10 + line * 2 + 0, ((u32 *)&e)[0]); 196 ioapic_write_reg(0x10 + line * 2 + 1, ((u32 *)&e)[1]); 197 } 198 199 ioapic_redir_entry_t ioapic_read_redir(unsigned line) 200 { 201 ioapic_redir_entry_t e; 202 203 ((u32 *)&e)[0] = ioapic_read_reg(0x10 + line * 2 + 0); 204 ((u32 *)&e)[1] = ioapic_read_reg(0x10 + line * 2 + 1); 205 return e; 206 207 } 208 209 void ioapic_set_redir(unsigned line, unsigned vec, 210 trigger_mode_t trig_mode) 211 { 212 ioapic_redir_entry_t e = { 213 .vector = vec, 214 .delivery_mode = 0, 215 .trig_mode = trig_mode, 216 }; 217 218 ioapic_write_redir(line, e); 219 } 220 221 void set_mask(unsigned line, int mask) 222 { 223 ioapic_redir_entry_t e = ioapic_read_redir(line); 224 225 e.mask = mask; 226 ioapic_write_redir(line, e); 227 } 228 229 void set_irq_line(unsigned line, int val) 230 { 231 asm volatile("out %0, %1" : : "a"((u8)val), "d"((u16)(0x2000 + line))); 232 } 233 234 void enable_apic(void) 235 { 236 printf("enabling apic\n"); 237 xapic_write(APIC_SPIV, 0x1ff); 238 } 239 240 void mask_pic_interrupts(void) 241 { 242 outb(0xff, 0x21); 243 outb(0xff, 0xa1); 244 } 245 246 extern unsigned char online_cpus[(MAX_TEST_CPUS + 7) / 8]; 247 248 void init_apic_map(void) 249 { 250 unsigned int i, j = 0; 251 252 for (i = 0; i < MAX_TEST_CPUS; i++) { 253 if ((1ul << (i % 8)) & (online_cpus[i / 8])) 254 id_map[j++] = i; 255 } 256 } 257