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