Index: kernel/generic/src/ipc/irq.c
===================================================================
--- kernel/generic/src/ipc/irq.c	(revision 9d58539899ea3bf36d74e87b391c0a986e338e26)
+++ kernel/generic/src/ipc/irq.c	(revision cfaa35a2627b7c78cd80ef394dfcb862cb582f7b)
@@ -39,14 +39,14 @@
  * when interrupt is detected. The application may provide a simple 'top-half'
  * handler as part of its registration, which can perform simple operations
- * (read/write port/memory, add information to notification ipc message).
+ * (read/write port/memory, add information to notification IPC message).
  *
  * The structure of a notification message is as follows:
  * - IMETHOD: interface and method as registered by
  *            the SYS_IRQ_REGISTER syscall
- * - ARG1: payload modified by a 'top-half' handler
- * - ARG2: payload modified by a 'top-half' handler
- * - ARG3: payload modified by a 'top-half' handler
- * - ARG4: payload modified by a 'top-half' handler
- * - ARG5: payload modified by a 'top-half' handler
+ * - ARG1: payload modified by a 'top-half' handler (scratch[1])
+ * - ARG2: payload modified by a 'top-half' handler (scratch[2])
+ * - ARG3: payload modified by a 'top-half' handler (scratch[3])
+ * - ARG4: payload modified by a 'top-half' handler (scratch[4])
+ * - ARG5: payload modified by a 'top-half' handler (scratch[5])
  * - in_phone_hash: interrupt counter (may be needed to assure correct order
  *                  in multithreaded drivers)
@@ -87,7 +87,5 @@
 static void ranges_unmap(irq_pio_range_t *ranges, size_t rangecount)
 {
-	size_t i;
-
-	for (i = 0; i < rangecount; i++) {
+	for (size_t i = 0; i < rangecount; i++) {
 #ifdef IO_SPACE_BOUNDARY
 		if ((void *) ranges[i].base >= IO_SPACE_BOUNDARY)
@@ -100,14 +98,11 @@
     irq_cmd_t *cmds, size_t cmdcount)
 {
-	uintptr_t *pbase;
-	size_t i, j;
-
 	/* Copy the physical base addresses aside. */
-	pbase = malloc(rangecount * sizeof(uintptr_t), 0);
-	for (i = 0; i < rangecount; i++)
+	uintptr_t *pbase = malloc(rangecount * sizeof(uintptr_t), 0);
+	for (size_t i = 0; i < rangecount; i++)
 		pbase[i] = ranges[i].base;
-
+	
 	/* Map the PIO ranges into the kernel virtual address space. */
-	for (i = 0; i < rangecount; i++) {
+	for (size_t i = 0; i < rangecount; i++) {
 #ifdef IO_SPACE_BOUNDARY
 		if ((void *) ranges[i].base < IO_SPACE_BOUNDARY)
@@ -122,25 +117,25 @@
 		}
 	}
-
+	
 	/* Rewrite the pseudocode addresses from physical to kernel virtual. */
-	for (i = 0; i < cmdcount; i++) {
+	for (size_t i = 0; i < cmdcount; i++) {
 		uintptr_t addr;
 		size_t size;
-
+		
 		/* Process only commands that use an address. */
 		switch (cmds[i].cmd) {
 		case CMD_PIO_READ_8:
-        	case CMD_PIO_WRITE_8:
-        	case CMD_PIO_WRITE_A_8:
+		case CMD_PIO_WRITE_8:
+		case CMD_PIO_WRITE_A_8:
 			size = 1;
 			break;
-        	case CMD_PIO_READ_16:
-        	case CMD_PIO_WRITE_16:
-        	case CMD_PIO_WRITE_A_16:
+		case CMD_PIO_READ_16:
+		case CMD_PIO_WRITE_16:
+		case CMD_PIO_WRITE_A_16:
 			size = 2;
 			break;
-        	case CMD_PIO_READ_32:
-        	case CMD_PIO_WRITE_32:
-        	case CMD_PIO_WRITE_A_32:
+		case CMD_PIO_READ_32:
+		case CMD_PIO_WRITE_32:
+		case CMD_PIO_WRITE_A_32:
 			size = 4;
 			break;
@@ -149,21 +144,21 @@
 			continue;
 		}
-
+		
 		addr = (uintptr_t) cmds[i].addr;
 		
+		size_t j;
 		for (j = 0; j < rangecount; j++) {
-
 			/* Find the matching range. */
 			if (!iswithin(pbase[j], ranges[j].size, addr, size))
 				continue;
-
+			
 			/* Switch the command to a kernel virtual address. */
 			addr -= pbase[j];
 			addr += ranges[j].base;
-
+			
 			cmds[i].addr = (void *) addr;
 			break;
 		}
-
+		
 		if (j == rangecount) {
 			/*
@@ -176,6 +171,46 @@
 		}
 	}
-
+	
 	free(pbase);
+	return EOK;
+}
+
+/** Statically check the top-half pseudocode
+ *
+ * Check the top-half pseudocode for invalid or unsafe
+ * constructs.
+ *
+ */
+static int code_check(irq_cmd_t *cmds, size_t cmdcount)
+{
+	for (size_t i = 0; i < cmdcount; i++) {
+		/*
+		 * Check for accepted ranges.
+		 */
+		if (cmds[i].cmd >= CMD_LAST)
+			return EINVAL;
+		
+		if (cmds[i].srcarg >= IPC_CALL_LEN)
+			return EINVAL;
+		
+		if (cmds[i].dstarg >= IPC_CALL_LEN)
+			return EINVAL;
+		
+		switch (cmds[i].cmd) {
+		case CMD_PREDICATE:
+			/*
+			 * Check for control flow overflow.
+			 * Note that jumping just beyond the last
+			 * command is a correct behaviour.
+			 */
+			if (i + cmds[i].value > cmdcount)
+				return EINVAL;
+			
+			break;
+		default:
+			break;
+		}
+	}
+	
 	return EOK;
 }
@@ -207,5 +242,5 @@
 	irq_pio_range_t *ranges = NULL;
 	irq_cmd_t *cmds = NULL;
-
+	
 	irq_code_t *code = malloc(sizeof(*code), 0);
 	int rc = copy_from_uspace(code, ucode, sizeof(*code));
@@ -222,5 +257,5 @@
 	if (rc != EOK)
 		goto error;
-
+	
 	cmds = malloc(sizeof(code->cmds[0]) * code->cmdcount, 0);
 	rc = copy_from_uspace(cmds, code->cmds,
@@ -228,20 +263,26 @@
 	if (rc != EOK)
 		goto error;
-
+	
+	rc = code_check(cmds, code->cmdcount);
+	if (rc != EOK)
+		goto error;
+	
 	rc = ranges_map_and_apply(ranges, code->rangecount, cmds,
 	    code->cmdcount);
 	if (rc != EOK)
 		goto error;
-
+	
 	code->ranges = ranges;
 	code->cmds = cmds;
-
+	
 	return code;
-
+	
 error:
 	if (cmds)
 		free(cmds);
+	
 	if (ranges)
 		free(ranges);
+	
 	free(code);
 	return NULL;
@@ -250,11 +291,12 @@
 /** Register an answerbox as a receiving end for IRQ notifications.
  *
- * @param box		Receiving answerbox.
- * @param inr		IRQ number.
- * @param devno		Device number.
- * @param imethod	Interface and method to be associated with the
- *			notification.
- * @param ucode		Uspace pointer to top-half pseudocode.
- * @return		EOK on success or a negative error code.
+ * @param box     Receiving answerbox.
+ * @param inr     IRQ number.
+ * @param devno   Device number.
+ * @param imethod Interface and method to be associated with the
+ *                notification.
+ * @param ucode   Uspace pointer to top-half pseudocode.
+ *
+ * @return EOK on success or a negative error code.
  *
  */
@@ -266,5 +308,5 @@
 		(sysarg_t) devno
 	};
-
+	
 	if ((inr < 0) || (inr > last_inr))
 		return ELIMIT;
@@ -329,8 +371,10 @@
 /** Unregister task from IRQ notification.
  *
- * @param box		Answerbox associated with the notification.
- * @param inr		IRQ number.
- * @param devno		Device number.
- * @return		EOK on success or a negative error code.
+ * @param box   Answerbox associated with the notification.
+ * @param inr   IRQ number.
+ * @param devno Device number.
+ *
+ * @return EOK on success or a negative error code.
+ *
  */
 int ipc_irq_unregister(answerbox_t *box, inr_t inr, devno_t devno)
@@ -340,5 +384,5 @@
 		(sysarg_t) devno
 	};
-
+	
 	if ((inr < 0) || (inr > last_inr))
 		return ELIMIT;
@@ -436,5 +480,5 @@
 		/* Remove from the hash table. */
 		hash_table_remove(&irq_uspace_hash_table, key, 2);
-
+		
 		/*
 		 * Release both locks so that we can free the pseudo code.
@@ -442,5 +486,5 @@
 		irq_spinlock_unlock(&box->irq_lock, false);
 		irq_spinlock_unlock(&irq_uspace_hash_table_lock, true);
-
+		
 		code_free(irq->notif_cfg.code);
 		free(irq);
@@ -466,5 +510,5 @@
 {
 	irq_spinlock_lock(&irq->notif_cfg.answerbox->irq_lock, false);
-	list_append(&call->link, &irq->notif_cfg.answerbox->irq_notifs);
+	list_append(&call->ab_link, &irq->notif_cfg.answerbox->irq_notifs);
 	irq_spinlock_unlock(&irq->notif_cfg.answerbox->irq_lock, false);
 	
@@ -492,30 +536,19 @@
 	
 	for (size_t i = 0; i < code->cmdcount; i++) {
-		uint32_t dstval;
-		
 		uintptr_t srcarg = code->cmds[i].srcarg;
 		uintptr_t dstarg = code->cmds[i].dstarg;
 		
-		if (srcarg >= IPC_CALL_LEN)
-			break;
-		
-		if (dstarg >= IPC_CALL_LEN)
-			break;
-	
 		switch (code->cmds[i].cmd) {
 		case CMD_PIO_READ_8:
-			dstval = pio_read_8((ioport8_t *) code->cmds[i].addr);
-			if (dstarg)
-				scratch[dstarg] = dstval;
+			scratch[dstarg] =
+			    pio_read_8((ioport8_t *) code->cmds[i].addr);
 			break;
 		case CMD_PIO_READ_16:
-			dstval = pio_read_16((ioport16_t *) code->cmds[i].addr);
-			if (dstarg)
-				scratch[dstarg] = dstval;
+			scratch[dstarg] =
+			    pio_read_16((ioport16_t *) code->cmds[i].addr);
 			break;
 		case CMD_PIO_READ_32:
-			dstval = pio_read_32((ioport32_t *) code->cmds[i].addr);
-			if (dstarg)
-				scratch[dstarg] = dstval;
+			scratch[dstarg] =
+			    pio_read_32((ioport32_t *) code->cmds[i].addr);
 			break;
 		case CMD_PIO_WRITE_8:
@@ -532,32 +565,26 @@
 			break;
 		case CMD_PIO_WRITE_A_8:
-			if (srcarg) {
-				pio_write_8((ioport8_t *) code->cmds[i].addr,
-				    (uint8_t) scratch[srcarg]);
-			}
+			pio_write_8((ioport8_t *) code->cmds[i].addr,
+			    (uint8_t) scratch[srcarg]);
 			break;
 		case CMD_PIO_WRITE_A_16:
-			if (srcarg) {
-				pio_write_16((ioport16_t *) code->cmds[i].addr,
-				    (uint16_t) scratch[srcarg]);
-			}
+			pio_write_16((ioport16_t *) code->cmds[i].addr,
+			    (uint16_t) scratch[srcarg]);
 			break;
 		case CMD_PIO_WRITE_A_32:
-			if (srcarg) {
-				pio_write_32((ioport32_t *) code->cmds[i].addr,
-				    (uint32_t) scratch[srcarg]);
-			}
-			break;
-		case CMD_BTEST:
-			if ((srcarg) && (dstarg)) {
-				dstval = scratch[srcarg] & code->cmds[i].value;
-				scratch[dstarg] = dstval;
-			}
+			pio_write_32((ioport32_t *) code->cmds[i].addr,
+			    (uint32_t) scratch[srcarg]);
+			break;
+		case CMD_LOAD:
+			scratch[dstarg] = code->cmds[i].value;
+			break;
+		case CMD_AND:
+			scratch[dstarg] = scratch[srcarg] &
+			    code->cmds[i].value;
 			break;
 		case CMD_PREDICATE:
-			if ((srcarg) && (!scratch[srcarg])) {
+			if (scratch[srcarg] == 0)
 				i += code->cmds[i].value;
-				continue;
-			}
+			
 			break;
 		case CMD_ACCEPT:
@@ -582,5 +609,5 @@
 {
 	ASSERT(irq);
-
+	
 	ASSERT(interrupts_disabled());
 	ASSERT(irq_spinlock_locked(&irq->lock));
