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