void ioapic_route_irq(uint8_t irq, uint8_t dest) { if (((irq + KERNEL_IRQ_OFFSET) >= NUM_IRQS) || (ioapic_redirects[irq].ioapic_address == NULL)) { panic("TRYING TO REROUTE AN INVALID IRQ!"); } // THIS IS A TEMP CHECK. IF WE USE LOGICAL PARTITIONS THIS MUST BE REMOVED extern volatile uint32_t num_cpus; if (dest >= num_cpus) panic("TRYING TO REROUTE TO AN INVALID DESTINATION!"); if (irq == 0 && dest != 0) cprintf("WARNING: Rerouting IRQ to core != 0 may cause undefined behavior!\n"); // Bit pack our redirection entry. This is black magic based on the spec. See the x58 spec. uint32_t redirect_low = KERNEL_IRQ_OFFSET + irq; redirect_low = redirect_low | (ioapic_redirects[irq].ioapic_flags << 8); uint32_t redirect_high = dest << 24; // YOU MUST MUST MUST MUST MUST MUST MUST write the high bits first. If you don't, you get interrupts going to crazy places // Ask Paul about that afternoon of his life. write_mmreg32((uint32_t)ioapic_redirects[irq].ioapic_address , IOAPIC_REDIRECT_OFFSET + 2*ioapic_redirects[irq].ioapic_int + 1); write_mmreg32((uint32_t)ioapic_redirects[irq].ioapic_address + IOAPIC_WRITE_WINDOW_OFFSET, redirect_high); write_mmreg32((uint32_t)ioapic_redirects[irq].ioapic_address , IOAPIC_REDIRECT_OFFSET + 2*ioapic_redirects[irq].ioapic_int); write_mmreg32((uint32_t)ioapic_redirects[irq].ioapic_address + IOAPIC_WRITE_WINDOW_OFFSET, redirect_low); }
static void rtblput(struct apic *apic, int sel, uint32_t hi, uint32_t lo) { sel = Ioredtbl + 2 * sel; write_mmreg32(apic->addr + Ioregsel, sel + 1); write_mmreg32(apic->addr + Iowin, hi); write_mmreg32(apic->addr + Ioregsel, sel); write_mmreg32(apic->addr + Iowin, lo); }
static void rtblget(struct apic *apic, int sel, uint32_t * hi, uint32_t * lo) { sel = Ioredtbl + 2 * sel; write_mmreg32(apic->addr + Ioregsel, sel + 1); *hi = read_mmreg32(apic->addr + Iowin); write_mmreg32(apic->addr + Ioregsel, sel); *lo = read_mmreg32(apic->addr + Iowin); }
/* * Sets the LAPIC timer to go off after a certain number of ticks. The primary * clock freq is actually the bus clock, which we figure out during timer_init * Unmasking is implied. Ref SDM, 3A, 9.6.4 */ void __lapic_set_timer(uint32_t ticks, uint8_t vec, bool periodic, uint8_t div) { // clears bottom bit and then set divider write_mmreg32(LAPIC_TIMER_DIVIDE, (read_mmreg32(LAPIC_TIMER_DIVIDE) &~0xf) | (div & 0xf)); // set LVT with interrupt handling information write_mmreg32(LAPIC_LVT_TIMER, vec | (periodic << 17)); write_mmreg32(LAPIC_TIMER_INIT, ticks); // For debugging when we expand this //cprintf("LAPIC LVT Timer: 0x%08x\n", read_mmreg32(LAPIC_LVT_TIMER)); //cprintf("LAPIC Init Count: 0x%08x\n", read_mmreg32(LAPIC_TIMER_INIT)); //cprintf("LAPIC Current Count: 0x%08x\n", read_mmreg32(LAPIC_TIMER_CURRENT)); }
/** @brief Reconfigure the correct IOAPIC to no longer route a given irq to any core * * This function will take an irq given by 'irq' and using the interal IOAPIC * strucures will adjust the IOAPIC to no longer route that irq to any destination * * This function must be called after ioapic_init() is called, but need not be called after a matching ioapic_route_irq() * * There is no notion of success besides invalid data, which casues a panic. * * @todo Decide on a synchronization mechinism * * @param[in] irq The IRQ we are trying to unroute. This is non-kernal-offseted. EX: Pit is IRQ 0, not 32. */ void ioapic_unroute_irq(uint8_t irq) { if (((irq + KERNEL_IRQ_OFFSET) >= NUM_IRQS) || (ioapic_redirects[irq].ioapic_address == NULL)) { panic("TRYING TO REROUTE AN INVALID IRQ!"); } // Must write low first, else we will reroute to a wrong core for a split before turning off write_mmreg32((uint32_t)ioapic_redirects[irq].ioapic_address , IOAPIC_REDIRECT_OFFSET + 2*ioapic_redirects[irq].ioapic_int); write_mmreg32((uint32_t)ioapic_redirects[irq].ioapic_address + IOAPIC_WRITE_WINDOW_OFFSET, IOAPIC_UNROUTE_LOW); write_mmreg32((uint32_t)ioapic_redirects[irq].ioapic_address , IOAPIC_REDIRECT_OFFSET + 2*ioapic_redirects[irq].ioapic_int + 1); write_mmreg32((uint32_t)ioapic_redirects[irq].ioapic_address + IOAPIC_WRITE_WINDOW_OFFSET, IOAPIC_UNROUTE_HIGH); }
static void perfmon_arm_irq(void) { write_mmreg32(LAPIC_LVT_PERFMON, IdtLAPIC_PCINT); }