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