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