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