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