Index: kernel/genarch/src/drivers/gicv2/gicv2.c
===================================================================
--- kernel/genarch/src/drivers/gicv2/gicv2.c	(revision 4099129ccf64362ab0419129df91da4d122df9cf)
+++ kernel/genarch/src/drivers/gicv2/gicv2.c	(revision 4099129ccf64362ab0419129df91da4d122df9cf)
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2016 Petr Pavlu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup genarch
+ * @{
+ */
+/** @file
+ * @brief ARM Generic Interrupt Controller, Architecture version 2.0.
+ *
+ * This IRQ controller is present on the QEMU virt platform for ARM.
+ */
+
+#include <arch/asm.h>
+#include <genarch/drivers/gicv2/gicv2.h>
+#include <assert.h>
+
+/** Initialize GICv2 interrupt controller.
+ *
+ * @param irqc Instance structure.
+ * @param distr Distributor registers.
+ * @param cpui CPU interface registers.
+ */
+void gicv2_init(gicv2_t *irqc, gicv2_distr_regs_t *distr,
+    gicv2_cpui_regs_t *cpui)
+{
+	irqc->distr = distr;
+	irqc->cpui = cpui;
+
+	/* Get maximum number of interrupts. */
+	uint32_t typer = pio_read_32(&distr->typer);
+	irqc->inum_total = (((typer & GICV2D_TYPER_IT_LINES_NUMBER_MASK) >>
+	    GICV2D_TYPER_IT_LINES_NUMBER_SHIFT) + 1) * 32;
+
+	/* Disable all interrupts. */
+	for (unsigned i = 0; i < irqc->inum_total / 32; i++)
+		pio_write_32(&distr->icenabler[i], 0xffffffff);
+
+	/* Enable interrupts for all priority levels. */
+	pio_write_32(&cpui->pmr, 0xff);
+
+	/* Enable signaling of interrupts. */
+	pio_write_32(&cpui->ctlr, GICV2C_CTLR_ENABLE_FLAG);
+	pio_write_32(&distr->ctlr, GICV2D_CTLR_ENABLE_FLAG);
+}
+
+/** Obtain total number of interrupts that the controller supports. */
+unsigned gicv2_inum_get_total(gicv2_t *irqc)
+{
+	return irqc->inum_total;
+}
+
+/** Obtain number of pending interrupt. */
+void gicv2_inum_get(gicv2_t *irqc, unsigned *inum, unsigned *cpuid)
+{
+	uint32_t iar = pio_read_32(&irqc->cpui->iar);
+
+	*inum = (iar & GICV2C_IAR_INTERRUPT_ID_MASK) >>
+	    GICV2C_IAR_INTERRUPT_ID_SHIFT;
+	*cpuid = (iar & GICV2C_IAR_CPUID_MASK) >> GICV2C_IAR_CPUID_SHIFT;
+}
+
+/** Signal end of interrupt to the controller. */
+void gicv2_end(gicv2_t *irqc, unsigned inum, unsigned cpuid)
+{
+	assert((inum & ~((unsigned) GICV2C_IAR_INTERRUPT_ID_MASK >>
+	    GICV2C_IAR_INTERRUPT_ID_SHIFT)) == 0);
+	assert((cpuid & ~((unsigned) GICV2C_IAR_CPUID_MASK >>
+	    GICV2C_IAR_CPUID_SHIFT)) == 0);
+
+	uint32_t eoir = (inum << GICV2C_IAR_INTERRUPT_ID_SHIFT) |
+	    (cpuid << GICV2C_IAR_CPUID_SHIFT);
+	pio_write_32(&irqc->cpui->eoir, eoir);
+}
+
+/** Enable specific interrupt. */
+void gicv2_enable(gicv2_t *irqc, unsigned inum)
+{
+	assert(inum < irqc->inum_total);
+
+	pio_write_32(&irqc->distr->isenabler[inum / 32], 1 << (inum % 32));
+}
+
+/** Disable specific interrupt. */
+void gicv2_disable(gicv2_t *irqc, unsigned inum)
+{
+	assert(inum < irqc->inum_total);
+
+	pio_write_32(&irqc->distr->icenabler[inum / 32], 1 << (inum % 32));
+}
+
+/** @}
+ */
Index: kernel/genarch/src/drivers/pl011/pl011.c
===================================================================
--- kernel/genarch/src/drivers/pl011/pl011.c	(revision 82dcd25c398bba039ee7b8cd99d314494d87fdad)
+++ kernel/genarch/src/drivers/pl011/pl011.c	(revision 4099129ccf64362ab0419129df91da4d122df9cf)
@@ -60,7 +60,11 @@
 	pl011_uart_t *uart = dev->data;
 
-	if (!ascii_check(ch)) {
+	/* If the userspace owns the console, do not output anything. */
+	if (uart->parea.mapped && !console_override)
+		return;
+
+	if (!ascii_check(ch))
 		pl011_uart_sendb(uart, U_SPECIAL);
-	} else {
+	else {
 		if (ch == '\n')
 			pl011_uart_sendb(uart, (uint8_t) '\r');
@@ -100,5 +104,5 @@
 	assert(uart);
 	uart->regs = (void *)km_map(addr, sizeof(pl011_uart_regs_t),
-	    KM_NATURAL_ALIGNMENT, PAGE_NOT_CACHEABLE);
+	    KM_NATURAL_ALIGNMENT, PAGE_WRITE | PAGE_NOT_CACHEABLE);
 	assert(uart->regs);
 
@@ -131,4 +135,11 @@
 	uart->irq.instance = uart;
 
+	ddi_parea_init(&uart->parea);
+	uart->parea.pbase = addr;
+	uart->parea.frames = 1;
+	uart->parea.unpriv = false;
+	uart->parea.mapped = false;
+	ddi_parea_register(&uart->parea);
+
 	return true;
 }
