17d36db35SAvi Kivity #include "libcflat.h" 27d36db35SAvi Kivity #include "apic.h" 3b5aa0cebSJan Kiszka #include "msr.h" 4a222b5e2SRadim Krčmář #include "processor.h" 52d18ccd3SSean Christopherson #include "smp.h" 6129ef680SNadav Amit #include "asm/barrier.h" 77d36db35SAvi Kivity 8df563aefSSean Christopherson /* xAPIC and I/O APIC are identify mapped, and never relocated. */ 9df563aefSSean Christopherson static void *g_apic = (void *)APIC_DEFAULT_PHYS_BASE; 10df563aefSSean Christopherson static void *g_ioapic = (void *)IO_APIC_DEFAULT_PHYS_BASE; 11df563aefSSean Christopherson 1218a34cceSNadav Amit u8 id_map[MAX_TEST_CPUS]; 137d36db35SAvi Kivity 147d36db35SAvi Kivity struct apic_ops { 157d36db35SAvi Kivity u32 (*reg_read)(unsigned reg); 167d36db35SAvi Kivity void (*reg_write)(unsigned reg, u32 val); 177d36db35SAvi Kivity void (*icr_write)(u32 val, u32 dest); 187d36db35SAvi Kivity u32 (*id)(void); 197d36db35SAvi Kivity }; 207d36db35SAvi Kivity 212d18ccd3SSean Christopherson static struct apic_ops *get_apic_ops(void) 222d18ccd3SSean Christopherson { 232d18ccd3SSean Christopherson return this_cpu_read_apic_ops(); 242d18ccd3SSean Christopherson } 252d18ccd3SSean Christopherson 267d36db35SAvi Kivity static void outb(unsigned char data, unsigned short port) 277d36db35SAvi Kivity { 287d36db35SAvi Kivity asm volatile ("out %0, %1" : : "a"(data), "d"(port)); 297d36db35SAvi Kivity } 307d36db35SAvi Kivity 310f187a08SSteve Rutherford void eoi(void) 320f187a08SSteve Rutherford { 330f187a08SSteve Rutherford apic_write(APIC_EOI, 0); 340f187a08SSteve Rutherford } 350f187a08SSteve Rutherford 367d36db35SAvi Kivity static u32 xapic_read(unsigned reg) 377d36db35SAvi Kivity { 387d36db35SAvi Kivity return *(volatile u32 *)(g_apic + reg); 397d36db35SAvi Kivity } 407d36db35SAvi Kivity 417d36db35SAvi Kivity static void xapic_write(unsigned reg, u32 val) 427d36db35SAvi Kivity { 437d36db35SAvi Kivity *(volatile u32 *)(g_apic + reg) = val; 447d36db35SAvi Kivity } 457d36db35SAvi Kivity 467d36db35SAvi Kivity static void xapic_icr_write(u32 val, u32 dest) 477d36db35SAvi Kivity { 487d36db35SAvi Kivity while (xapic_read(APIC_ICR) & APIC_ICR_BUSY) 497d36db35SAvi Kivity ; 507d36db35SAvi Kivity xapic_write(APIC_ICR2, dest << 24); 517d36db35SAvi Kivity xapic_write(APIC_ICR, val); 527d36db35SAvi Kivity } 537d36db35SAvi Kivity 547d36db35SAvi Kivity static uint32_t xapic_id(void) 557d36db35SAvi Kivity { 567d36db35SAvi Kivity return xapic_read(APIC_ID) >> 24; 577d36db35SAvi Kivity } 587d36db35SAvi Kivity 597d36db35SAvi Kivity static const struct apic_ops xapic_ops = { 607d36db35SAvi Kivity .reg_read = xapic_read, 617d36db35SAvi Kivity .reg_write = xapic_write, 627d36db35SAvi Kivity .icr_write = xapic_icr_write, 637d36db35SAvi Kivity .id = xapic_id, 647d36db35SAvi Kivity }; 657d36db35SAvi Kivity 667d36db35SAvi Kivity static u32 x2apic_read(unsigned reg) 677d36db35SAvi Kivity { 687d36db35SAvi Kivity unsigned a, d; 697d36db35SAvi Kivity 707d36db35SAvi Kivity asm volatile ("rdmsr" : "=a"(a), "=d"(d) : "c"(APIC_BASE_MSR + reg/16)); 717d36db35SAvi Kivity return a | (u64)d << 32; 727d36db35SAvi Kivity } 737d36db35SAvi Kivity 747d36db35SAvi Kivity static void x2apic_write(unsigned reg, u32 val) 757d36db35SAvi Kivity { 767d36db35SAvi Kivity asm volatile ("wrmsr" : : "a"(val), "d"(0), "c"(APIC_BASE_MSR + reg/16)); 777d36db35SAvi Kivity } 787d36db35SAvi Kivity 797d36db35SAvi Kivity static void x2apic_icr_write(u32 val, u32 dest) 807d36db35SAvi Kivity { 81129ef680SNadav Amit mb(); 827d36db35SAvi Kivity asm volatile ("wrmsr" : : "a"(val), "d"(dest), 837d36db35SAvi Kivity "c"(APIC_BASE_MSR + APIC_ICR/16)); 847d36db35SAvi Kivity } 857d36db35SAvi Kivity 867d36db35SAvi Kivity static uint32_t x2apic_id(void) 877d36db35SAvi Kivity { 88a0837ab6SRadim Krčmář return x2apic_read(APIC_ID); 897d36db35SAvi Kivity } 907d36db35SAvi Kivity 917d36db35SAvi Kivity static const struct apic_ops x2apic_ops = { 927d36db35SAvi Kivity .reg_read = x2apic_read, 937d36db35SAvi Kivity .reg_write = x2apic_write, 947d36db35SAvi Kivity .icr_write = x2apic_icr_write, 957d36db35SAvi Kivity .id = x2apic_id, 967d36db35SAvi Kivity }; 977d36db35SAvi Kivity 987d36db35SAvi Kivity u32 apic_read(unsigned reg) 997d36db35SAvi Kivity { 1002d18ccd3SSean Christopherson return get_apic_ops()->reg_read(reg); 1017d36db35SAvi Kivity } 1027d36db35SAvi Kivity 1037d36db35SAvi Kivity void apic_write(unsigned reg, u32 val) 1047d36db35SAvi Kivity { 1052d18ccd3SSean Christopherson get_apic_ops()->reg_write(reg, val); 1067d36db35SAvi Kivity } 1077d36db35SAvi Kivity 1087c5f3ee9SPaolo Bonzini bool apic_read_bit(unsigned reg, int n) 1097c5f3ee9SPaolo Bonzini { 1107c5f3ee9SPaolo Bonzini reg += (n >> 5) << 4; 1117c5f3ee9SPaolo Bonzini n &= 31; 1127c5f3ee9SPaolo Bonzini return (apic_read(reg) & (1 << n)) != 0; 1137c5f3ee9SPaolo Bonzini } 1147c5f3ee9SPaolo Bonzini 1157d36db35SAvi Kivity void apic_icr_write(u32 val, u32 dest) 1167d36db35SAvi Kivity { 1172d18ccd3SSean Christopherson get_apic_ops()->icr_write(val, dest); 1187d36db35SAvi Kivity } 1197d36db35SAvi Kivity 1207d36db35SAvi Kivity uint32_t apic_id(void) 1217d36db35SAvi Kivity { 1222d18ccd3SSean Christopherson return get_apic_ops()->id(); 1237d36db35SAvi Kivity } 1247d36db35SAvi Kivity 125e0a5cfcaSPaolo Bonzini uint8_t apic_get_tpr(void) 126e0a5cfcaSPaolo Bonzini { 127e0a5cfcaSPaolo Bonzini unsigned long tpr; 128e0a5cfcaSPaolo Bonzini 129e0a5cfcaSPaolo Bonzini #ifdef __x86_64__ 130e0a5cfcaSPaolo Bonzini asm volatile ("mov %%cr8, %0" : "=r"(tpr)); 131e0a5cfcaSPaolo Bonzini #else 132533a738fSAndrew Jones tpr = apic_read(APIC_TASKPRI) >> 4; 133e0a5cfcaSPaolo Bonzini #endif 134e0a5cfcaSPaolo Bonzini return tpr; 135e0a5cfcaSPaolo Bonzini } 136e0a5cfcaSPaolo Bonzini 137e0a5cfcaSPaolo Bonzini void apic_set_tpr(uint8_t tpr) 138e0a5cfcaSPaolo Bonzini { 139e0a5cfcaSPaolo Bonzini #ifdef __x86_64__ 140e0a5cfcaSPaolo Bonzini asm volatile ("mov %0, %%cr8" : : "r"((unsigned long) tpr)); 141e0a5cfcaSPaolo Bonzini #else 142533a738fSAndrew Jones apic_write(APIC_TASKPRI, tpr << 4); 143e0a5cfcaSPaolo Bonzini #endif 144e0a5cfcaSPaolo Bonzini } 145e0a5cfcaSPaolo Bonzini 1467d36db35SAvi Kivity int enable_x2apic(void) 1477d36db35SAvi Kivity { 1487d36db35SAvi Kivity unsigned a, b, c, d; 1497d36db35SAvi Kivity 1507d36db35SAvi Kivity asm ("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(1)); 1517d36db35SAvi Kivity 1527d36db35SAvi Kivity if (c & (1 << 21)) { 153b5aa0cebSJan Kiszka asm ("rdmsr" : "=a"(a), "=d"(d) : "c"(MSR_IA32_APICBASE)); 1547d36db35SAvi Kivity a |= 1 << 10; 155b5aa0cebSJan Kiszka asm ("wrmsr" : : "a"(a), "d"(d), "c"(MSR_IA32_APICBASE)); 1562d18ccd3SSean Christopherson this_cpu_write_apic_ops((void *)&x2apic_ops); 1577d36db35SAvi Kivity return 1; 1587d36db35SAvi Kivity } else { 1597d36db35SAvi Kivity return 0; 1607d36db35SAvi Kivity } 1617d36db35SAvi Kivity } 1627d36db35SAvi Kivity 163*8854f47aSSean Christopherson uint32_t pre_boot_apic_id(void) 164*8854f47aSSean Christopherson { 165*8854f47aSSean Christopherson u32 msr_lo, msr_hi; 166*8854f47aSSean Christopherson 167*8854f47aSSean Christopherson asm ("rdmsr" : "=a"(msr_lo), "=d"(msr_hi) : "c"(MSR_IA32_APICBASE)); 168*8854f47aSSean Christopherson 169*8854f47aSSean Christopherson return (msr_lo & APIC_EXTD) ? x2apic_id() : xapic_id(); 170*8854f47aSSean Christopherson } 171*8854f47aSSean Christopherson 172e38858bcSJim Mattson void disable_apic(void) 173e38858bcSJim Mattson { 174e38858bcSJim Mattson wrmsr(MSR_IA32_APICBASE, rdmsr(MSR_IA32_APICBASE) & ~(APIC_EN | APIC_EXTD)); 1752d18ccd3SSean Christopherson this_cpu_write_apic_ops((void *)&xapic_ops); 176e38858bcSJim Mattson } 177e38858bcSJim Mattson 178a222b5e2SRadim Krčmář void reset_apic(void) 179a222b5e2SRadim Krčmář { 180e38858bcSJim Mattson disable_apic(); 181e38858bcSJim Mattson wrmsr(MSR_IA32_APICBASE, rdmsr(MSR_IA32_APICBASE) | APIC_EN); 182d6e8f863SNadav Amit xapic_write(APIC_SPIV, 0x1ff); 183a222b5e2SRadim Krčmář } 184a222b5e2SRadim Krčmář 1850f187a08SSteve Rutherford u32 ioapic_read_reg(unsigned reg) 1860f187a08SSteve Rutherford { 1870f187a08SSteve Rutherford *(volatile u32 *)g_ioapic = reg; 1880f187a08SSteve Rutherford return *(volatile u32 *)(g_ioapic + 0x10); 1890f187a08SSteve Rutherford } 1900f187a08SSteve Rutherford 1917d36db35SAvi Kivity void ioapic_write_reg(unsigned reg, u32 value) 1927d36db35SAvi Kivity { 1937d36db35SAvi Kivity *(volatile u32 *)g_ioapic = reg; 1947d36db35SAvi Kivity *(volatile u32 *)(g_ioapic + 0x10) = value; 1957d36db35SAvi Kivity } 1967d36db35SAvi Kivity 1977d36db35SAvi Kivity void ioapic_write_redir(unsigned line, ioapic_redir_entry_t e) 1987d36db35SAvi Kivity { 1997d36db35SAvi Kivity ioapic_write_reg(0x10 + line * 2 + 0, ((u32 *)&e)[0]); 2007d36db35SAvi Kivity ioapic_write_reg(0x10 + line * 2 + 1, ((u32 *)&e)[1]); 2017d36db35SAvi Kivity } 2027d36db35SAvi Kivity 2030f187a08SSteve Rutherford ioapic_redir_entry_t ioapic_read_redir(unsigned line) 2040f187a08SSteve Rutherford { 2050f187a08SSteve Rutherford ioapic_redir_entry_t e; 2060f187a08SSteve Rutherford 2070f187a08SSteve Rutherford ((u32 *)&e)[0] = ioapic_read_reg(0x10 + line * 2 + 0); 2080f187a08SSteve Rutherford ((u32 *)&e)[1] = ioapic_read_reg(0x10 + line * 2 + 1); 2090f187a08SSteve Rutherford return e; 2100f187a08SSteve Rutherford 2110f187a08SSteve Rutherford } 2120f187a08SSteve Rutherford 21322207960SLiran Alon void ioapic_set_redir(unsigned line, unsigned vec, 214f66d11caSArbel Moshe trigger_mode_t trig_mode) 215f66d11caSArbel Moshe { 216f66d11caSArbel Moshe ioapic_redir_entry_t e = { 217f66d11caSArbel Moshe .vector = vec, 218f66d11caSArbel Moshe .delivery_mode = 0, 219f66d11caSArbel Moshe .trig_mode = trig_mode, 220f66d11caSArbel Moshe }; 221f66d11caSArbel Moshe 222f66d11caSArbel Moshe ioapic_write_redir(line, e); 223f66d11caSArbel Moshe } 224f66d11caSArbel Moshe 2250f187a08SSteve Rutherford void set_mask(unsigned line, int mask) 2260f187a08SSteve Rutherford { 2270f187a08SSteve Rutherford ioapic_redir_entry_t e = ioapic_read_redir(line); 2280f187a08SSteve Rutherford 2290f187a08SSteve Rutherford e.mask = mask; 2300f187a08SSteve Rutherford ioapic_write_redir(line, e); 2310f187a08SSteve Rutherford } 2320f187a08SSteve Rutherford 233f66d11caSArbel Moshe void set_irq_line(unsigned line, int val) 234f66d11caSArbel Moshe { 235f66d11caSArbel Moshe asm volatile("out %0, %1" : : "a"((u8)val), "d"((u16)(0x2000 + line))); 236f66d11caSArbel Moshe } 237f66d11caSArbel Moshe 2387d36db35SAvi Kivity void enable_apic(void) 2397d36db35SAvi Kivity { 2407d36db35SAvi Kivity printf("enabling apic\n"); 241add65e76SNadav Amit xapic_write(APIC_SPIV, 0x1ff); 2427d36db35SAvi Kivity } 2437d36db35SAvi Kivity 2447d36db35SAvi Kivity void mask_pic_interrupts(void) 2457d36db35SAvi Kivity { 2467d36db35SAvi Kivity outb(0xff, 0x21); 2477d36db35SAvi Kivity outb(0xff, 0xa1); 2487d36db35SAvi Kivity } 24918a34cceSNadav Amit 250760a2ddeSXinpeng Liu extern unsigned char online_cpus[(MAX_TEST_CPUS + 7) / 8]; 25118a34cceSNadav Amit 25218a34cceSNadav Amit void init_apic_map(void) 25318a34cceSNadav Amit { 25418a34cceSNadav Amit unsigned int i, j = 0; 25518a34cceSNadav Amit 256b00e75b3SSean Christopherson for (i = 0; i < MAX_TEST_CPUS; i++) { 25718a34cceSNadav Amit if ((1ul << (i % 8)) & (online_cpus[i / 8])) 25818a34cceSNadav Amit id_map[j++] = i; 25918a34cceSNadav Amit } 26018a34cceSNadav Amit } 261