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);