x86: use a proper allocator for IRQ vectors Yet another arena allocator! Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
diff --git a/kern/arch/riscv/trap.c b/kern/arch/riscv/trap.c index 78150be..32d1f95 100644 --- a/kern/arch/riscv/trap.c +++ b/kern/arch/riscv/trap.c
@@ -362,6 +362,17 @@ return -1; } +int get_irq_vector(void) +{ + printk("%s not implemented\n", __FUNCTION); + return -1; +} + +void put_irq_vector(int vec) +{ + printk("%s not implemented\n", __FUNCTION); +} + void __arch_reflect_trap_hwtf(struct hw_trapframe *hw_tf, unsigned int trap_nr, unsigned int err, unsigned long aux) {
diff --git a/kern/arch/x86/ioapic.c b/kern/arch/x86/ioapic.c index 8d2d197..70a71d2 100644 --- a/kern/arch/x86/ioapic.c +++ b/kern/arch/x86/ioapic.c
@@ -59,9 +59,6 @@ /* reverse mapping of IDT vector to the RDT/IOAPIC entry triggering vector */ static struct Rdt *rdtvecno[IdtMAX + 1]; -static spinlock_t idtnolock; -static int idtno = IdtIOAPIC; - struct apic xioapic[Napic]; static bool ioapic_exists(void) @@ -372,21 +369,6 @@ } } -int nextvec(void) -{ - unsigned int vecno; - - /* TODO: half-way decent integer service (vmem) */ - spin_lock(&idtnolock); - vecno = idtno; - idtno = (idtno + 1) % IdtMAX; - if (idtno < IdtIOAPIC) - idtno += IdtIOAPIC; - spin_unlock(&idtnolock); - - return vecno; -} - static void msi_mask_irq(struct irq_handler *irq_h, int apic_vector) { pci_msi_mask(irq_h->dev_private); @@ -423,7 +405,11 @@ uint64_t msivec; struct msix_irq_vector *linkage; - vno = nextvec(); + vno = get_irq_vector(); + if (!vno) { + printk("[kernel] Unable to get a vector for MSI(X)!\n"); + return -1; + } /* routing the IRQ to core 0 (hi = 0) in physical mode (Pm) */ lo = IPlow | TMedge | Pm | vno; @@ -432,7 +418,7 @@ irq_h->dev_private = pci_msix_enable(p, msivec); if (!irq_h->dev_private) { if (pci_msi_enable(p, msivec) == -1) { - /* TODO: should free vno here */ + put_irq_vector(vno); return -1; } irq_h->dev_private = p; @@ -657,7 +643,12 @@ * this stays around regardless of enabled/disabled, since we don't reap * vectors yet. nor do we really mess with enabled... */ if ((rdt->lo & 0xff) == 0) { - vecno = nextvec(); + vecno = get_irq_vector(); + if (!vecno) { + printk("[kernel] unable to get an IOAPIC vector\n"); + spin_unlock(&rdt->apic->lock); + return -1; + } rdt->lo |= vecno; rdtvecno[vecno] = rdt; } else {
diff --git a/kern/arch/x86/trap.c b/kern/arch/x86/trap.c index 799d6e3..daa7588 100644 --- a/kern/arch/x86/trap.c +++ b/kern/arch/x86/trap.c
@@ -38,6 +38,8 @@ struct irq_handler *irq_handlers[NUM_IRQS]; spinlock_t irq_handler_wlock = SPINLOCK_INITIALIZER_IRQSAVE; +static struct arena *irq_vectors; + static bool try_handle_exception_fixup(struct hw_trapframe *hw_tf) { if (in_kernel(hw_tf)) { @@ -181,6 +183,11 @@ asm volatile("lidt %0" : : "m"(idt_pd)); + irq_vectors = arena_create("irq_vectors", (void*)IdtIOAPIC, + MaxIdtIOAPIC - IdtIOAPIC, 1, + NULL, NULL, NULL, 0, MEM_ATOMIC); + assert(irq_vectors); + pic_remap(); pic_mask_all(); @@ -838,6 +845,18 @@ return 0; } +/* 0 is an error. It's not a valid IRQ vector for Akaros, even if + * divide-by-zero has trap/irq vector 0 (T_DIVIDE). */ +int get_irq_vector(void) +{ + return (int)(long)arena_alloc(irq_vectors, 1, MEM_ATOMIC); +} + +void put_irq_vector(int vec) +{ + arena_free(irq_vectors, (void*)(long)vec, 1); +} + /* These routing functions only allow the routing of an irq to a single core. * If we want to route to multiple cores, we'll probably need to set up logical * groups or something and take some additional parameters. */
diff --git a/kern/include/trap.h b/kern/include/trap.h index c3ae8d1..6056b2c 100644 --- a/kern/include/trap.h +++ b/kern/include/trap.h
@@ -18,6 +18,9 @@ uint32_t tbdf); int deregister_irq(int vector, uint32_t tbdf); int route_irqs(int cpu_vec, int coreid); +int get_irq_vector(void); +void put_irq_vector(int vec); + void print_trapframe(struct hw_trapframe *hw_tf); void print_swtrapframe(struct sw_trapframe *sw_tf); void print_vmtrapframe(struct vm_trapframe *vm_tf);