1 #include "libcflat.h" 2 #include "apic.h" 3 #include "msr.h" 4 5 static void *g_apic = (void *)0xfee00000; 6 static void *g_ioapic = (void *)0xfec00000; 7 8 struct apic_ops { 9 u32 (*reg_read)(unsigned reg); 10 void (*reg_write)(unsigned reg, u32 val); 11 void (*icr_write)(u32 val, u32 dest); 12 u32 (*id)(void); 13 }; 14 15 static void outb(unsigned char data, unsigned short port) 16 { 17 asm volatile ("out %0, %1" : : "a"(data), "d"(port)); 18 } 19 20 void eoi(void) 21 { 22 apic_write(APIC_EOI, 0); 23 } 24 25 static u32 xapic_read(unsigned reg) 26 { 27 return *(volatile u32 *)(g_apic + reg); 28 } 29 30 static void xapic_write(unsigned reg, u32 val) 31 { 32 *(volatile u32 *)(g_apic + reg) = val; 33 } 34 35 static void xapic_icr_write(u32 val, u32 dest) 36 { 37 while (xapic_read(APIC_ICR) & APIC_ICR_BUSY) 38 ; 39 xapic_write(APIC_ICR2, dest << 24); 40 xapic_write(APIC_ICR, val); 41 } 42 43 static uint32_t xapic_id(void) 44 { 45 return xapic_read(APIC_ID) >> 24; 46 } 47 48 static const struct apic_ops xapic_ops = { 49 .reg_read = xapic_read, 50 .reg_write = xapic_write, 51 .icr_write = xapic_icr_write, 52 .id = xapic_id, 53 }; 54 55 static const struct apic_ops *apic_ops = &xapic_ops; 56 57 static u32 x2apic_read(unsigned reg) 58 { 59 unsigned a, d; 60 61 asm volatile ("rdmsr" : "=a"(a), "=d"(d) : "c"(APIC_BASE_MSR + reg/16)); 62 return a | (u64)d << 32; 63 } 64 65 static void x2apic_write(unsigned reg, u32 val) 66 { 67 asm volatile ("wrmsr" : : "a"(val), "d"(0), "c"(APIC_BASE_MSR + reg/16)); 68 } 69 70 static void x2apic_icr_write(u32 val, u32 dest) 71 { 72 asm volatile ("wrmsr" : : "a"(val), "d"(dest), 73 "c"(APIC_BASE_MSR + APIC_ICR/16)); 74 } 75 76 static uint32_t x2apic_id(void) 77 { 78 return x2apic_read(APIC_ID); 79 } 80 81 static const struct apic_ops x2apic_ops = { 82 .reg_read = x2apic_read, 83 .reg_write = x2apic_write, 84 .icr_write = x2apic_icr_write, 85 .id = x2apic_id, 86 }; 87 88 u32 apic_read(unsigned reg) 89 { 90 return apic_ops->reg_read(reg); 91 } 92 93 void apic_write(unsigned reg, u32 val) 94 { 95 apic_ops->reg_write(reg, val); 96 } 97 98 bool apic_read_bit(unsigned reg, int n) 99 { 100 reg += (n >> 5) << 4; 101 n &= 31; 102 return (apic_read(reg) & (1 << n)) != 0; 103 } 104 105 void apic_icr_write(u32 val, u32 dest) 106 { 107 apic_ops->icr_write(val, dest); 108 } 109 110 uint32_t apic_id(void) 111 { 112 return apic_ops->id(); 113 } 114 115 int enable_x2apic(void) 116 { 117 unsigned a, b, c, d; 118 119 asm ("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(1)); 120 121 if (c & (1 << 21)) { 122 asm ("rdmsr" : "=a"(a), "=d"(d) : "c"(MSR_IA32_APICBASE)); 123 a |= 1 << 10; 124 asm ("wrmsr" : : "a"(a), "d"(d), "c"(MSR_IA32_APICBASE)); 125 apic_ops = &x2apic_ops; 126 return 1; 127 } else { 128 return 0; 129 } 130 } 131 132 u32 ioapic_read_reg(unsigned reg) 133 { 134 *(volatile u32 *)g_ioapic = reg; 135 return *(volatile u32 *)(g_ioapic + 0x10); 136 } 137 138 void ioapic_write_reg(unsigned reg, u32 value) 139 { 140 *(volatile u32 *)g_ioapic = reg; 141 *(volatile u32 *)(g_ioapic + 0x10) = value; 142 } 143 144 void ioapic_write_redir(unsigned line, ioapic_redir_entry_t e) 145 { 146 ioapic_write_reg(0x10 + line * 2 + 0, ((u32 *)&e)[0]); 147 ioapic_write_reg(0x10 + line * 2 + 1, ((u32 *)&e)[1]); 148 } 149 150 ioapic_redir_entry_t ioapic_read_redir(unsigned line) 151 { 152 ioapic_redir_entry_t e; 153 154 ((u32 *)&e)[0] = ioapic_read_reg(0x10 + line * 2 + 0); 155 ((u32 *)&e)[1] = ioapic_read_reg(0x10 + line * 2 + 1); 156 return e; 157 158 } 159 160 void set_mask(unsigned line, int mask) 161 { 162 ioapic_redir_entry_t e = ioapic_read_redir(line); 163 164 e.mask = mask; 165 ioapic_write_redir(line, e); 166 } 167 168 void enable_apic(void) 169 { 170 printf("enabling apic\n"); 171 xapic_write(0xf0, 0x1ff); /* spurious vector register */ 172 } 173 174 void mask_pic_interrupts(void) 175 { 176 outb(0xff, 0x21); 177 outb(0xff, 0xa1); 178 } 179