Index: kernel/arch/mips32/include/arch/exception.h
===================================================================
--- kernel/arch/mips32/include/arch/exception.h	(revision e064102b80157d447412b71a989a3c26c6447a20)
+++ kernel/arch/mips32/include/arch/exception.h	(revision 124bc22f2e33238e1d61bb6d9361a50fd47613e7)
@@ -57,4 +57,19 @@
 #define EXC_VCED   31
 
+#define INT_SW0    0
+#define INT_SW1    1
+#define INT_HW0    2
+#define INT_HW1    3
+#define INT_HW2    4
+#define INT_HW3    5
+#define INT_HW4    6
+#define INT_TIMER  7
+
+#define INTERRUPTS    8
+#define HW_INTERRUPTS (INTERRUPTS - 3)
+
+typedef void (* int_handler_t)(unsigned int);
+extern int_handler_t int_handler[];
+
 extern void exception(istate_t *istate);
 extern void tlb_refill_entry(void);
Index: kernel/arch/mips32/include/arch/mach/malta/malta.h
===================================================================
--- kernel/arch/mips32/include/arch/mach/malta/malta.h	(revision e064102b80157d447412b71a989a3c26c6447a20)
+++ kernel/arch/mips32/include/arch/mach/malta/malta.h	(revision 124bc22f2e33238e1d61bb6d9361a50fd47613e7)
@@ -39,4 +39,5 @@
 #include <arch/machine_func.h>
 #include <arch/mm/page.h>
+#include <typedefs.h>
 
 #define MALTA_PCI_BASE		PA2KSEG1(0x18000000UL)
@@ -47,8 +48,7 @@
 
 #define TTY_BASE		(MALTA_PCI_BASE + 0x3f8)
-#define TTY_CPU_INT		2
 #define TTY_ISA_IRQ		4
 
-#define GT64120_PCI0_INTACK	(MALTA_GT64120_BASE + 0xc34)
+#define GT64120_PCI0_INTACK	((ioport32_t *) (MALTA_GT64120_BASE + 0xc34))
 
 extern struct mips32_machine_ops malta_machine_ops;
Index: kernel/arch/mips32/include/arch/machine_func.h
===================================================================
--- kernel/arch/mips32/include/arch/machine_func.h	(revision e064102b80157d447412b71a989a3c26c6447a20)
+++ kernel/arch/mips32/include/arch/machine_func.h	(revision 124bc22f2e33238e1d61bb6d9361a50fd47613e7)
@@ -43,4 +43,5 @@
 
 #include <typedefs.h>
+#include <stdbool.h>
 
 struct mips32_machine_ops {
Index: kernel/arch/mips32/src/exception.c
===================================================================
--- kernel/arch/mips32/src/exception.c	(revision e064102b80157d447412b71a989a3c26c6447a20)
+++ kernel/arch/mips32/src/exception.c	(revision 124bc22f2e33238e1d61bb6d9361a50fd47613e7)
@@ -47,4 +47,5 @@
 #include <symtab.h>
 #include <log.h>
+#include <arch/machine_func.h>
 
 static const char *exctable[] = {
@@ -174,5 +175,5 @@
 
 	unsigned int i;
-	for (i = 0; i < 8; i++) {
+	for (i = 0; i < INTERRUPTS; i++) {
 
 		/*
@@ -183,14 +184,7 @@
 		 */
 		if (im & ip & (1 << i)) {
-			irq_t *irq = irq_dispatch_and_lock(i);
-			if (irq) {
-				/*
-				 * The IRQ handler was found.
-				 */
-				irq->handler(irq);
-				if (irq->cir)
-					irq->cir(irq->cir_arg, i);
-				irq_spinlock_unlock(&irq->lock, false);
-			} else {
+			if (int_handler[i])
+				int_handler[i](i);
+			else {
 				/*
 				 * Spurious interrupt.
Index: kernel/arch/mips32/src/interrupt.c
===================================================================
--- kernel/arch/mips32/src/interrupt.c	(revision e064102b80157d447412b71a989a3c26c6447a20)
+++ kernel/arch/mips32/src/interrupt.c	(revision 124bc22f2e33238e1d61bb6d9361a50fd47613e7)
@@ -41,10 +41,4 @@
 #include <ipc/sysipc.h>
 
-#define IRQ_COUNT   8
-#define TIMER_IRQ   7
-
-function virtual_timer_fnc = NULL;
-static irq_t timer_irq;
-
 // TODO: This is SMP unsafe!!!
 
@@ -52,4 +46,7 @@
 static unsigned long nextcount;
 static unsigned long lastcount;
+
+/** Table of interrupt handlers. */
+int_handler_t int_handler[INTERRUPTS] = {};
 
 /** Disable interrupts.
@@ -113,10 +110,5 @@
 }
 
-static irq_ownership_t timer_claim(irq_t *irq)
-{
-	return IRQ_ACCEPT;
-}
-
-static void timer_irq_handler(irq_t *irq)
+static void timer_interrupt_handler(unsigned int intr)
 {
 	if (cp0_count_read() < lastcount)
@@ -135,14 +127,5 @@
 	cp0_compare_write(nextcount);
 
-	/*
-	 * We are holding a lock which prevents preemption.
-	 * Release the lock, call clock() and reacquire the lock again.
-	 */
-	irq_spinlock_unlock(&irq->lock, false);
 	clock();
-	irq_spinlock_lock(&irq->lock, false);
-
-	if (virtual_timer_fnc != NULL)
-		virtual_timer_fnc();
 }
 
@@ -150,14 +133,8 @@
 void interrupt_init(void)
 {
-	irq_init(IRQ_COUNT, IRQ_COUNT);
-
-	irq_initialize(&timer_irq);
-	timer_irq.inr = TIMER_IRQ;
-	timer_irq.claim = timer_claim;
-	timer_irq.handler = timer_irq_handler;
-	irq_register(&timer_irq);
+	int_handler[INT_TIMER] = timer_interrupt_handler;
 
 	timer_start();
-	cp0_unmask_int(TIMER_IRQ);
+	cp0_unmask_int(INT_TIMER);
 }
 
Index: kernel/arch/mips32/src/mach/malta/malta.c
===================================================================
--- kernel/arch/mips32/src/mach/malta/malta.c	(revision e064102b80157d447412b71a989a3c26c6447a20)
+++ kernel/arch/mips32/src/mach/malta/malta.c	(revision 124bc22f2e33238e1d61bb6d9361a50fd47613e7)
@@ -42,4 +42,7 @@
 #include <genarch/srln/srln.h>
 #include <arch/interrupt.h>
+#include <stdbool.h>
+#include <byteorder.h>
+#include <log.h>
 
 static void malta_init(void);
@@ -68,15 +71,28 @@
 #endif
 
-#ifdef CONFIG_NS16550
-static void tty_clear_interrupt(void *arg, inr_t inr)
+static void malta_isa_irq_handler(unsigned int i)
 {
-	(void) pio_read_8((ioport8_t *) GT64120_PCI0_INTACK);
+	uint8_t isa_irq = host2uint32_t_le(pio_read_32(GT64120_PCI0_INTACK));
+	irq_t *irq = irq_dispatch_and_lock(isa_irq);
+	if (irq) {
+		irq->handler(irq);
+		irq_spinlock_unlock(&irq->lock, false);
+	} else {
+#ifdef CONFIG_DEBUG
+		log(LF_ARCH, LVL_DEBUG, "cpu%u: spurious IRQ (irq=%u)",
+		    CPU->id, isa_irq);
+#endif
+	}
 	pic_eoi();
 }
-#endif
 
 void malta_init(void)
 {
+	irq_init(16, 16);
+
 	i8259_init((i8259_t *) PIC0_BASE, (i8259_t *) PIC1_BASE, 2, 0, 8);
+
+	int_handler[INT_HW0] = malta_isa_irq_handler;
+	cp0_unmask_int(INT_HW0);
 
 #if (defined(CONFIG_NS16550) || defined(CONFIG_NS16550_OUT))
@@ -86,6 +102,6 @@
 	outdev_t **tty_out_ptr = NULL;
 #endif
-	tty_instance = ns16550_init((ioport8_t *) TTY_BASE, 0, TTY_CPU_INT,
-	    tty_clear_interrupt, NULL, tty_out_ptr);
+	tty_instance = ns16550_init((ioport8_t *) TTY_BASE, 0, TTY_ISA_IRQ,
+	    NULL, NULL, tty_out_ptr);
 #endif
 }
@@ -121,5 +137,4 @@
 			ns16550_wire(tty_instance, srln);
 			pic_enable_irqs(1 << TTY_ISA_IRQ);
-			cp0_unmask_int(TTY_CPU_INT);
 		}
 	}
Index: kernel/arch/mips32/src/mach/msim/msim.c
===================================================================
--- kernel/arch/mips32/src/mach/msim/msim.c	(revision e064102b80157d447412b71a989a3c26c6447a20)
+++ kernel/arch/mips32/src/mach/msim/msim.c	(revision 124bc22f2e33238e1d61bb6d9361a50fd47613e7)
@@ -41,4 +41,5 @@
 #include <genarch/drivers/dsrln/dsrlnout.h>
 #include <genarch/srln/srln.h>
+#include <stdbool.h>
 
 static void msim_init(void);
@@ -60,6 +61,28 @@
 };
 
+static void msim_irq_handler(unsigned int i)
+{
+	irq_t *irq = irq_dispatch_and_lock(i);
+	if (irq) {
+		irq->handler(irq);
+		irq_spinlock_unlock(&irq->lock, false);
+	} else {
+#ifdef CONFIG_DEBUG
+		log(LF_ARCH, LVL_DEBUG, "cpu%u: spurious IRQ (irq=%u)",
+		    CPU->id, i);
+#endif
+	}
+}
+
 void msim_init(void)
 {
+	irq_init(HW_INTERRUPTS, HW_INTERRUPTS);
+
+	int_handler[INT_HW0] = msim_irq_handler;
+	int_handler[INT_HW1] = msim_irq_handler;
+	int_handler[INT_HW2] = msim_irq_handler;
+	int_handler[INT_HW3] = msim_irq_handler;
+	int_handler[INT_HW4] = msim_irq_handler;
+
 	dorder_init();
 	cp0_unmask_int(MSIM_DDISK_IRQ);
