17d36db35SAvi Kivity #include "libcflat.h" 27d36db35SAvi Kivity #include "apic.h" 3b5aa0cebSJan Kiszka #include "msr.h" 4a222b5e2SRadim Krčmář #include "processor.h" 57d36db35SAvi Kivity 6f66d11caSArbel Moshe void *g_apic = (void *)0xfee00000; 7f66d11caSArbel Moshe void *g_ioapic = (void *)0xfec00000; 87d36db35SAvi Kivity 97d36db35SAvi Kivity struct apic_ops { 107d36db35SAvi Kivity u32 (*reg_read)(unsigned reg); 117d36db35SAvi Kivity void (*reg_write)(unsigned reg, u32 val); 127d36db35SAvi Kivity void (*icr_write)(u32 val, u32 dest); 137d36db35SAvi Kivity u32 (*id)(void); 147d36db35SAvi Kivity }; 157d36db35SAvi Kivity 167d36db35SAvi Kivity static void outb(unsigned char data, unsigned short port) 177d36db35SAvi Kivity { 187d36db35SAvi Kivity asm volatile ("out %0, %1" : : "a"(data), "d"(port)); 197d36db35SAvi Kivity } 207d36db35SAvi Kivity 210f187a08SSteve Rutherford void eoi(void) 220f187a08SSteve Rutherford { 230f187a08SSteve Rutherford apic_write(APIC_EOI, 0); 240f187a08SSteve Rutherford } 250f187a08SSteve Rutherford 267d36db35SAvi Kivity static u32 xapic_read(unsigned reg) 277d36db35SAvi Kivity { 287d36db35SAvi Kivity return *(volatile u32 *)(g_apic + reg); 297d36db35SAvi Kivity } 307d36db35SAvi Kivity 317d36db35SAvi Kivity static void xapic_write(unsigned reg, u32 val) 327d36db35SAvi Kivity { 337d36db35SAvi Kivity *(volatile u32 *)(g_apic + reg) = val; 347d36db35SAvi Kivity } 357d36db35SAvi Kivity 367d36db35SAvi Kivity static void xapic_icr_write(u32 val, u32 dest) 377d36db35SAvi Kivity { 387d36db35SAvi Kivity while (xapic_read(APIC_ICR) & APIC_ICR_BUSY) 397d36db35SAvi Kivity ; 407d36db35SAvi Kivity xapic_write(APIC_ICR2, dest << 24); 417d36db35SAvi Kivity xapic_write(APIC_ICR, val); 427d36db35SAvi Kivity } 437d36db35SAvi Kivity 447d36db35SAvi Kivity static uint32_t xapic_id(void) 457d36db35SAvi Kivity { 467d36db35SAvi Kivity return xapic_read(APIC_ID) >> 24; 477d36db35SAvi Kivity } 487d36db35SAvi Kivity 497d36db35SAvi Kivity static const struct apic_ops xapic_ops = { 507d36db35SAvi Kivity .reg_read = xapic_read, 517d36db35SAvi Kivity .reg_write = xapic_write, 527d36db35SAvi Kivity .icr_write = xapic_icr_write, 537d36db35SAvi Kivity .id = xapic_id, 547d36db35SAvi Kivity }; 557d36db35SAvi Kivity 567d36db35SAvi Kivity static const struct apic_ops *apic_ops = &xapic_ops; 577d36db35SAvi Kivity 587d36db35SAvi Kivity static u32 x2apic_read(unsigned reg) 597d36db35SAvi Kivity { 607d36db35SAvi Kivity unsigned a, d; 617d36db35SAvi Kivity 627d36db35SAvi Kivity asm volatile ("rdmsr" : "=a"(a), "=d"(d) : "c"(APIC_BASE_MSR + reg/16)); 637d36db35SAvi Kivity return a | (u64)d << 32; 647d36db35SAvi Kivity } 657d36db35SAvi Kivity 667d36db35SAvi Kivity static void x2apic_write(unsigned reg, u32 val) 677d36db35SAvi Kivity { 687d36db35SAvi Kivity asm volatile ("wrmsr" : : "a"(val), "d"(0), "c"(APIC_BASE_MSR + reg/16)); 697d36db35SAvi Kivity } 707d36db35SAvi Kivity 717d36db35SAvi Kivity static void x2apic_icr_write(u32 val, u32 dest) 727d36db35SAvi Kivity { 737d36db35SAvi Kivity asm volatile ("wrmsr" : : "a"(val), "d"(dest), 747d36db35SAvi Kivity "c"(APIC_BASE_MSR + APIC_ICR/16)); 757d36db35SAvi Kivity } 767d36db35SAvi Kivity 777d36db35SAvi Kivity static uint32_t x2apic_id(void) 787d36db35SAvi Kivity { 79a0837ab6SRadim Krčmář return x2apic_read(APIC_ID); 807d36db35SAvi Kivity } 817d36db35SAvi Kivity 827d36db35SAvi Kivity static const struct apic_ops x2apic_ops = { 837d36db35SAvi Kivity .reg_read = x2apic_read, 847d36db35SAvi Kivity .reg_write = x2apic_write, 857d36db35SAvi Kivity .icr_write = x2apic_icr_write, 867d36db35SAvi Kivity .id = x2apic_id, 877d36db35SAvi Kivity }; 887d36db35SAvi Kivity 897d36db35SAvi Kivity u32 apic_read(unsigned reg) 907d36db35SAvi Kivity { 917d36db35SAvi Kivity return apic_ops->reg_read(reg); 927d36db35SAvi Kivity } 937d36db35SAvi Kivity 947d36db35SAvi Kivity void apic_write(unsigned reg, u32 val) 957d36db35SAvi Kivity { 967d36db35SAvi Kivity apic_ops->reg_write(reg, val); 977d36db35SAvi Kivity } 987d36db35SAvi Kivity 997c5f3ee9SPaolo Bonzini bool apic_read_bit(unsigned reg, int n) 1007c5f3ee9SPaolo Bonzini { 1017c5f3ee9SPaolo Bonzini reg += (n >> 5) << 4; 1027c5f3ee9SPaolo Bonzini n &= 31; 1037c5f3ee9SPaolo Bonzini return (apic_read(reg) & (1 << n)) != 0; 1047c5f3ee9SPaolo Bonzini } 1057c5f3ee9SPaolo Bonzini 1067d36db35SAvi Kivity void apic_icr_write(u32 val, u32 dest) 1077d36db35SAvi Kivity { 1087d36db35SAvi Kivity apic_ops->icr_write(val, dest); 1097d36db35SAvi Kivity } 1107d36db35SAvi Kivity 1117d36db35SAvi Kivity uint32_t apic_id(void) 1127d36db35SAvi Kivity { 1137d36db35SAvi Kivity return apic_ops->id(); 1147d36db35SAvi Kivity } 1157d36db35SAvi Kivity 116e0a5cfcaSPaolo Bonzini uint8_t apic_get_tpr(void) 117e0a5cfcaSPaolo Bonzini { 118e0a5cfcaSPaolo Bonzini unsigned long tpr; 119e0a5cfcaSPaolo Bonzini 120e0a5cfcaSPaolo Bonzini #ifdef __x86_64__ 121e0a5cfcaSPaolo Bonzini asm volatile ("mov %%cr8, %0" : "=r"(tpr)); 122e0a5cfcaSPaolo Bonzini #else 123533a738fSAndrew Jones tpr = apic_read(APIC_TASKPRI) >> 4; 124e0a5cfcaSPaolo Bonzini #endif 125e0a5cfcaSPaolo Bonzini return tpr; 126e0a5cfcaSPaolo Bonzini } 127e0a5cfcaSPaolo Bonzini 128e0a5cfcaSPaolo Bonzini void apic_set_tpr(uint8_t tpr) 129e0a5cfcaSPaolo Bonzini { 130e0a5cfcaSPaolo Bonzini #ifdef __x86_64__ 131e0a5cfcaSPaolo Bonzini asm volatile ("mov %0, %%cr8" : : "r"((unsigned long) tpr)); 132e0a5cfcaSPaolo Bonzini #else 133533a738fSAndrew Jones apic_write(APIC_TASKPRI, tpr << 4); 134e0a5cfcaSPaolo Bonzini #endif 135e0a5cfcaSPaolo Bonzini } 136e0a5cfcaSPaolo Bonzini 1377d36db35SAvi Kivity int enable_x2apic(void) 1387d36db35SAvi Kivity { 1397d36db35SAvi Kivity unsigned a, b, c, d; 1407d36db35SAvi Kivity 1417d36db35SAvi Kivity asm ("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(1)); 1427d36db35SAvi Kivity 1437d36db35SAvi Kivity if (c & (1 << 21)) { 144b5aa0cebSJan Kiszka asm ("rdmsr" : "=a"(a), "=d"(d) : "c"(MSR_IA32_APICBASE)); 1457d36db35SAvi Kivity a |= 1 << 10; 146b5aa0cebSJan Kiszka asm ("wrmsr" : : "a"(a), "d"(d), "c"(MSR_IA32_APICBASE)); 1477d36db35SAvi Kivity apic_ops = &x2apic_ops; 1487d36db35SAvi Kivity return 1; 1497d36db35SAvi Kivity } else { 1507d36db35SAvi Kivity return 0; 1517d36db35SAvi Kivity } 1527d36db35SAvi Kivity } 1537d36db35SAvi Kivity 154*e38858bcSJim Mattson void disable_apic(void) 155*e38858bcSJim Mattson { 156*e38858bcSJim Mattson wrmsr(MSR_IA32_APICBASE, rdmsr(MSR_IA32_APICBASE) & ~(APIC_EN | APIC_EXTD)); 157*e38858bcSJim Mattson apic_ops = &xapic_ops; 158*e38858bcSJim Mattson } 159*e38858bcSJim Mattson 160a222b5e2SRadim Krčmář void reset_apic(void) 161a222b5e2SRadim Krčmář { 162*e38858bcSJim Mattson disable_apic(); 163*e38858bcSJim Mattson wrmsr(MSR_IA32_APICBASE, rdmsr(MSR_IA32_APICBASE) | APIC_EN); 164a222b5e2SRadim Krčmář } 165a222b5e2SRadim Krčmář 1660f187a08SSteve Rutherford u32 ioapic_read_reg(unsigned reg) 1670f187a08SSteve Rutherford { 1680f187a08SSteve Rutherford *(volatile u32 *)g_ioapic = reg; 1690f187a08SSteve Rutherford return *(volatile u32 *)(g_ioapic + 0x10); 1700f187a08SSteve Rutherford } 1710f187a08SSteve Rutherford 1727d36db35SAvi Kivity void ioapic_write_reg(unsigned reg, u32 value) 1737d36db35SAvi Kivity { 1747d36db35SAvi Kivity *(volatile u32 *)g_ioapic = reg; 1757d36db35SAvi Kivity *(volatile u32 *)(g_ioapic + 0x10) = value; 1767d36db35SAvi Kivity } 1777d36db35SAvi Kivity 1787d36db35SAvi Kivity void ioapic_write_redir(unsigned line, ioapic_redir_entry_t e) 1797d36db35SAvi Kivity { 1807d36db35SAvi Kivity ioapic_write_reg(0x10 + line * 2 + 0, ((u32 *)&e)[0]); 1817d36db35SAvi Kivity ioapic_write_reg(0x10 + line * 2 + 1, ((u32 *)&e)[1]); 1827d36db35SAvi Kivity } 1837d36db35SAvi Kivity 1840f187a08SSteve Rutherford ioapic_redir_entry_t ioapic_read_redir(unsigned line) 1850f187a08SSteve Rutherford { 1860f187a08SSteve Rutherford ioapic_redir_entry_t e; 1870f187a08SSteve Rutherford 1880f187a08SSteve Rutherford ((u32 *)&e)[0] = ioapic_read_reg(0x10 + line * 2 + 0); 1890f187a08SSteve Rutherford ((u32 *)&e)[1] = ioapic_read_reg(0x10 + line * 2 + 1); 1900f187a08SSteve Rutherford return e; 1910f187a08SSteve Rutherford 1920f187a08SSteve Rutherford } 1930f187a08SSteve Rutherford 19422207960SLiran Alon void ioapic_set_redir(unsigned line, unsigned vec, 195f66d11caSArbel Moshe trigger_mode_t trig_mode) 196f66d11caSArbel Moshe { 197f66d11caSArbel Moshe ioapic_redir_entry_t e = { 198f66d11caSArbel Moshe .vector = vec, 199f66d11caSArbel Moshe .delivery_mode = 0, 200f66d11caSArbel Moshe .trig_mode = trig_mode, 201f66d11caSArbel Moshe }; 202f66d11caSArbel Moshe 203f66d11caSArbel Moshe ioapic_write_redir(line, e); 204f66d11caSArbel Moshe } 205f66d11caSArbel Moshe 2060f187a08SSteve Rutherford void set_mask(unsigned line, int mask) 2070f187a08SSteve Rutherford { 2080f187a08SSteve Rutherford ioapic_redir_entry_t e = ioapic_read_redir(line); 2090f187a08SSteve Rutherford 2100f187a08SSteve Rutherford e.mask = mask; 2110f187a08SSteve Rutherford ioapic_write_redir(line, e); 2120f187a08SSteve Rutherford } 2130f187a08SSteve Rutherford 214f66d11caSArbel Moshe void set_irq_line(unsigned line, int val) 215f66d11caSArbel Moshe { 216f66d11caSArbel Moshe asm volatile("out %0, %1" : : "a"((u8)val), "d"((u16)(0x2000 + line))); 217f66d11caSArbel Moshe } 218f66d11caSArbel Moshe 2197d36db35SAvi Kivity void enable_apic(void) 2207d36db35SAvi Kivity { 2217d36db35SAvi Kivity printf("enabling apic\n"); 2227d36db35SAvi Kivity xapic_write(0xf0, 0x1ff); /* spurious vector register */ 2237d36db35SAvi Kivity } 2247d36db35SAvi Kivity 2257d36db35SAvi Kivity void mask_pic_interrupts(void) 2267d36db35SAvi Kivity { 2277d36db35SAvi Kivity outb(0xff, 0x21); 2287d36db35SAvi Kivity outb(0xff, 0xa1); 2297d36db35SAvi Kivity } 230