17d36db35SAvi Kivity #include "libcflat.h" 27d36db35SAvi Kivity #include "apic.h" 3b5aa0cebSJan Kiszka #include "msr.h" 47d36db35SAvi Kivity 57d36db35SAvi Kivity static void *g_apic = (void *)0xfee00000; 67d36db35SAvi Kivity static void *g_ioapic = (void *)0xfec00000; 77d36db35SAvi Kivity 87d36db35SAvi Kivity struct apic_ops { 97d36db35SAvi Kivity u32 (*reg_read)(unsigned reg); 107d36db35SAvi Kivity void (*reg_write)(unsigned reg, u32 val); 117d36db35SAvi Kivity void (*icr_write)(u32 val, u32 dest); 127d36db35SAvi Kivity u32 (*id)(void); 137d36db35SAvi Kivity }; 147d36db35SAvi Kivity 157d36db35SAvi Kivity static void outb(unsigned char data, unsigned short port) 167d36db35SAvi Kivity { 177d36db35SAvi Kivity asm volatile ("out %0, %1" : : "a"(data), "d"(port)); 187d36db35SAvi Kivity } 197d36db35SAvi Kivity 200f187a08SSteve Rutherford void eoi(void) 210f187a08SSteve Rutherford { 220f187a08SSteve Rutherford apic_write(APIC_EOI, 0); 230f187a08SSteve Rutherford } 240f187a08SSteve Rutherford 257d36db35SAvi Kivity static u32 xapic_read(unsigned reg) 267d36db35SAvi Kivity { 277d36db35SAvi Kivity return *(volatile u32 *)(g_apic + reg); 287d36db35SAvi Kivity } 297d36db35SAvi Kivity 307d36db35SAvi Kivity static void xapic_write(unsigned reg, u32 val) 317d36db35SAvi Kivity { 327d36db35SAvi Kivity *(volatile u32 *)(g_apic + reg) = val; 337d36db35SAvi Kivity } 347d36db35SAvi Kivity 357d36db35SAvi Kivity static void xapic_icr_write(u32 val, u32 dest) 367d36db35SAvi Kivity { 377d36db35SAvi Kivity while (xapic_read(APIC_ICR) & APIC_ICR_BUSY) 387d36db35SAvi Kivity ; 397d36db35SAvi Kivity xapic_write(APIC_ICR2, dest << 24); 407d36db35SAvi Kivity xapic_write(APIC_ICR, val); 417d36db35SAvi Kivity } 427d36db35SAvi Kivity 437d36db35SAvi Kivity static uint32_t xapic_id(void) 447d36db35SAvi Kivity { 457d36db35SAvi Kivity return xapic_read(APIC_ID) >> 24; 467d36db35SAvi Kivity } 477d36db35SAvi Kivity 487d36db35SAvi Kivity static const struct apic_ops xapic_ops = { 497d36db35SAvi Kivity .reg_read = xapic_read, 507d36db35SAvi Kivity .reg_write = xapic_write, 517d36db35SAvi Kivity .icr_write = xapic_icr_write, 527d36db35SAvi Kivity .id = xapic_id, 537d36db35SAvi Kivity }; 547d36db35SAvi Kivity 557d36db35SAvi Kivity static const struct apic_ops *apic_ops = &xapic_ops; 567d36db35SAvi Kivity 577d36db35SAvi Kivity static u32 x2apic_read(unsigned reg) 587d36db35SAvi Kivity { 597d36db35SAvi Kivity unsigned a, d; 607d36db35SAvi Kivity 617d36db35SAvi Kivity asm volatile ("rdmsr" : "=a"(a), "=d"(d) : "c"(APIC_BASE_MSR + reg/16)); 627d36db35SAvi Kivity return a | (u64)d << 32; 637d36db35SAvi Kivity } 647d36db35SAvi Kivity 657d36db35SAvi Kivity static void x2apic_write(unsigned reg, u32 val) 667d36db35SAvi Kivity { 677d36db35SAvi Kivity asm volatile ("wrmsr" : : "a"(val), "d"(0), "c"(APIC_BASE_MSR + reg/16)); 687d36db35SAvi Kivity } 697d36db35SAvi Kivity 707d36db35SAvi Kivity static void x2apic_icr_write(u32 val, u32 dest) 717d36db35SAvi Kivity { 727d36db35SAvi Kivity asm volatile ("wrmsr" : : "a"(val), "d"(dest), 737d36db35SAvi Kivity "c"(APIC_BASE_MSR + APIC_ICR/16)); 747d36db35SAvi Kivity } 757d36db35SAvi Kivity 767d36db35SAvi Kivity static uint32_t x2apic_id(void) 777d36db35SAvi Kivity { 78a0837ab6SRadim Krčmář return x2apic_read(APIC_ID); 797d36db35SAvi Kivity } 807d36db35SAvi Kivity 817d36db35SAvi Kivity static const struct apic_ops x2apic_ops = { 827d36db35SAvi Kivity .reg_read = x2apic_read, 837d36db35SAvi Kivity .reg_write = x2apic_write, 847d36db35SAvi Kivity .icr_write = x2apic_icr_write, 857d36db35SAvi Kivity .id = x2apic_id, 867d36db35SAvi Kivity }; 877d36db35SAvi Kivity 887d36db35SAvi Kivity u32 apic_read(unsigned reg) 897d36db35SAvi Kivity { 907d36db35SAvi Kivity return apic_ops->reg_read(reg); 917d36db35SAvi Kivity } 927d36db35SAvi Kivity 937d36db35SAvi Kivity void apic_write(unsigned reg, u32 val) 947d36db35SAvi Kivity { 957d36db35SAvi Kivity apic_ops->reg_write(reg, val); 967d36db35SAvi Kivity } 977d36db35SAvi Kivity 98*7c5f3ee9SPaolo Bonzini bool apic_read_bit(unsigned reg, int n) 99*7c5f3ee9SPaolo Bonzini { 100*7c5f3ee9SPaolo Bonzini reg += (n >> 5) << 4; 101*7c5f3ee9SPaolo Bonzini n &= 31; 102*7c5f3ee9SPaolo Bonzini return (apic_read(reg) & (1 << n)) != 0; 103*7c5f3ee9SPaolo Bonzini } 104*7c5f3ee9SPaolo Bonzini 1057d36db35SAvi Kivity void apic_icr_write(u32 val, u32 dest) 1067d36db35SAvi Kivity { 1077d36db35SAvi Kivity apic_ops->icr_write(val, dest); 1087d36db35SAvi Kivity } 1097d36db35SAvi Kivity 1107d36db35SAvi Kivity uint32_t apic_id(void) 1117d36db35SAvi Kivity { 1127d36db35SAvi Kivity return apic_ops->id(); 1137d36db35SAvi Kivity } 1147d36db35SAvi Kivity 1157d36db35SAvi Kivity int enable_x2apic(void) 1167d36db35SAvi Kivity { 1177d36db35SAvi Kivity unsigned a, b, c, d; 1187d36db35SAvi Kivity 1197d36db35SAvi Kivity asm ("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(1)); 1207d36db35SAvi Kivity 1217d36db35SAvi Kivity if (c & (1 << 21)) { 122b5aa0cebSJan Kiszka asm ("rdmsr" : "=a"(a), "=d"(d) : "c"(MSR_IA32_APICBASE)); 1237d36db35SAvi Kivity a |= 1 << 10; 124b5aa0cebSJan Kiszka asm ("wrmsr" : : "a"(a), "d"(d), "c"(MSR_IA32_APICBASE)); 1257d36db35SAvi Kivity apic_ops = &x2apic_ops; 1267d36db35SAvi Kivity return 1; 1277d36db35SAvi Kivity } else { 1287d36db35SAvi Kivity return 0; 1297d36db35SAvi Kivity } 1307d36db35SAvi Kivity } 1317d36db35SAvi Kivity 1320f187a08SSteve Rutherford u32 ioapic_read_reg(unsigned reg) 1330f187a08SSteve Rutherford { 1340f187a08SSteve Rutherford *(volatile u32 *)g_ioapic = reg; 1350f187a08SSteve Rutherford return *(volatile u32 *)(g_ioapic + 0x10); 1360f187a08SSteve Rutherford } 1370f187a08SSteve Rutherford 1387d36db35SAvi Kivity void ioapic_write_reg(unsigned reg, u32 value) 1397d36db35SAvi Kivity { 1407d36db35SAvi Kivity *(volatile u32 *)g_ioapic = reg; 1417d36db35SAvi Kivity *(volatile u32 *)(g_ioapic + 0x10) = value; 1427d36db35SAvi Kivity } 1437d36db35SAvi Kivity 1447d36db35SAvi Kivity void ioapic_write_redir(unsigned line, ioapic_redir_entry_t e) 1457d36db35SAvi Kivity { 1467d36db35SAvi Kivity ioapic_write_reg(0x10 + line * 2 + 0, ((u32 *)&e)[0]); 1477d36db35SAvi Kivity ioapic_write_reg(0x10 + line * 2 + 1, ((u32 *)&e)[1]); 1487d36db35SAvi Kivity } 1497d36db35SAvi Kivity 1500f187a08SSteve Rutherford ioapic_redir_entry_t ioapic_read_redir(unsigned line) 1510f187a08SSteve Rutherford { 1520f187a08SSteve Rutherford ioapic_redir_entry_t e; 1530f187a08SSteve Rutherford 1540f187a08SSteve Rutherford ((u32 *)&e)[0] = ioapic_read_reg(0x10 + line * 2 + 0); 1550f187a08SSteve Rutherford ((u32 *)&e)[1] = ioapic_read_reg(0x10 + line * 2 + 1); 1560f187a08SSteve Rutherford return e; 1570f187a08SSteve Rutherford 1580f187a08SSteve Rutherford } 1590f187a08SSteve Rutherford 1600f187a08SSteve Rutherford void set_mask(unsigned line, int mask) 1610f187a08SSteve Rutherford { 1620f187a08SSteve Rutherford ioapic_redir_entry_t e = ioapic_read_redir(line); 1630f187a08SSteve Rutherford 1640f187a08SSteve Rutherford e.mask = mask; 1650f187a08SSteve Rutherford ioapic_write_redir(line, e); 1660f187a08SSteve Rutherford } 1670f187a08SSteve Rutherford 1687d36db35SAvi Kivity void enable_apic(void) 1697d36db35SAvi Kivity { 1707d36db35SAvi Kivity printf("enabling apic\n"); 1717d36db35SAvi Kivity xapic_write(0xf0, 0x1ff); /* spurious vector register */ 1727d36db35SAvi Kivity } 1737d36db35SAvi Kivity 1747d36db35SAvi Kivity void mask_pic_interrupts(void) 1757d36db35SAvi Kivity { 1767d36db35SAvi Kivity outb(0xff, 0x21); 1777d36db35SAvi Kivity outb(0xff, 0xa1); 1787d36db35SAvi Kivity } 179