Helpers for memory mapped IO.

This logic can be shared between architecture and drivers. The addresses
for memory mapped IO have an opaque type to avoid accidental misuse and
arrays have an associated size so overflows can be detected. Accessor
functions make the use if IO clear and optionally add memory barriers.

Change-Id: I59d82bd2ee7d41e0ab61438ca0ccf10b46f23c54
diff --git a/inc/hf/io.h b/inc/hf/io.h
new file mode 100644
index 0000000..12bc440
--- /dev/null
+++ b/inc/hf/io.h
@@ -0,0 +1,294 @@
+/*
+ * Copyright 2019 The Hafnium Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "hf/arch/barriers.h"
+
+#include "hf/assert.h"
+
+/* Opaque types for different sized fields of memory mapped IO. */
+
+typedef struct {
+	volatile uint8_t *ptr;
+} io8_t;
+
+typedef struct {
+	volatile uint16_t *ptr;
+} io16_t;
+
+typedef struct {
+	volatile uint32_t *ptr;
+} io32_t;
+
+typedef struct {
+	volatile uint64_t *ptr;
+} io64_t;
+
+typedef struct {
+	volatile uint8_t *base;
+	size_t count;
+} io8_array_t;
+
+typedef struct {
+	volatile uint16_t *base;
+	size_t count;
+} io16_array_t;
+
+typedef struct {
+	volatile uint32_t *base;
+	size_t count;
+} io32_array_t;
+
+typedef struct {
+	volatile uint64_t *base;
+	size_t count;
+} io64_array_t;
+
+/* Contructors for literals. */
+
+#define IO8_C(addr) ((io8_t){.ptr = (volatile uint8_t *)(addr)})
+#define IO16_C(addr) ((io16_t){.ptr = (volatile uint16_t *)(addr)})
+#define IO32_C(addr) ((io32_t){.ptr = (volatile uint32_t *)(addr)})
+#define IO64_C(addr) ((io64_t){.ptr = (volatile uint64_t *)(addr)})
+
+#define IO8_ARRAY_C(addr, cnt) \
+	((io8_array_t){.base = (volatile uint8_t *)(addr), .count = (cnt)})
+#define IO16_ARRAY_C(addr, cnt) \
+	((io16_array_t){.base = (volatile uint16_t *)(addr), .count = (cnt)})
+#define IO32_ARRAY_C(addr, cnt) \
+	((io32_array_t){.base = (volatile uint32_t *)(addr), .count = (cnt)})
+#define IO64_ARRAY_C(addr, cnt) \
+	((io64_array_t){.base = (volatile uint64_t *)(addr), .count = (cnt)})
+
+/** Read from memory-mapped IO. */
+
+static inline uint8_t io_read8(io8_t io)
+{
+	return *io.ptr;
+}
+
+static inline uint16_t io_read16(io16_t io)
+{
+	return *io.ptr;
+}
+
+static inline uint32_t io_read32(io32_t io)
+{
+	return *io.ptr;
+}
+
+static inline uint64_t io_read64(io64_t io)
+{
+	return *io.ptr;
+}
+
+static inline uint8_t io_read8_array(io8_array_t io, size_t n)
+{
+	assert(n < io.count);
+	return io.base[n];
+}
+
+static inline uint16_t io_read16_array(io16_array_t io, size_t n)
+{
+	assert(n < io.count);
+	return io.base[n];
+}
+
+static inline uint32_t io_read32_array(io32_array_t io, size_t n)
+{
+	assert(n < io.count);
+	return io.base[n];
+}
+
+static inline uint64_t io_read64_array(io64_array_t io, size_t n)
+{
+	assert(n < io.count);
+	return io.base[n];
+}
+
+/**
+ * Read from memory-mapped IO with memory barrier.
+ *
+ * The read is ordered before subsequent memory accesses.
+ */
+
+static inline uint8_t io_read8_mb(io8_t io)
+{
+	uint8_t v = io_read8(io);
+
+	dsb();
+	return v;
+}
+
+static inline uint16_t io_read16_mb(io16_t io)
+{
+	uint16_t v = io_read16(io);
+
+	dsb();
+	return v;
+}
+
+static inline uint32_t io_read32_mb(io32_t io)
+{
+	uint32_t v = io_read32(io);
+
+	dsb();
+	return v;
+}
+
+static inline uint64_t io_read64_mb(io64_t io)
+{
+	uint64_t v = io_read64(io);
+
+	dsb();
+	return v;
+}
+
+static inline uint8_t io_read8_array_mb(io8_array_t io, size_t n)
+{
+	uint8_t v = io_read8_array(io, n);
+
+	dsb();
+	return v;
+}
+
+static inline uint16_t io_read16_array_mb(io16_array_t io, size_t n)
+{
+	uint16_t v = io_read16_array(io, n);
+
+	dsb();
+	return v;
+}
+
+static inline uint32_t io_read32_array_mb(io32_array_t io, size_t n)
+{
+	uint32_t v = io_read32_array(io, n);
+
+	dsb();
+	return v;
+}
+
+static inline uint64_t io_read64_array_mb(io64_array_t io, size_t n)
+{
+	uint64_t v = io_read64_array(io, n);
+
+	dsb();
+	return v;
+}
+
+/* Write to memory-mapped IO. */
+
+static inline void io_write8(io8_t io, uint8_t v)
+{
+	*io.ptr = v;
+}
+
+static inline void io_write16(io16_t io, uint16_t v)
+{
+	*io.ptr = v;
+}
+
+static inline void io_write32(io32_t io, uint32_t v)
+{
+	*io.ptr = v;
+}
+
+static inline void io_write64(io64_t io, uint64_t v)
+{
+	*io.ptr = v;
+}
+
+static inline void io_write8_array(io8_array_t io, size_t n, uint8_t v)
+{
+	assert(n < io.count);
+	io.base[n] = v;
+}
+
+static inline void io_write16_array(io16_array_t io, size_t n, uint16_t v)
+{
+	assert(n < io.count);
+	io.base[n] = v;
+}
+
+static inline void io_write32_array(io32_array_t io, size_t n, uint32_t v)
+{
+	assert(n < io.count);
+	io.base[n] = v;
+}
+
+static inline void io_write64_array(io64_array_t io, size_t n, uint64_t v)
+{
+	assert(n < io.count);
+	io.base[n] = v;
+}
+
+/*
+ * Write to memory-mapped IO with memory barrier.
+ *
+ * The write is ordered after previous memory accesses.
+ */
+
+static inline void io_write8_mb(io8_t io, uint8_t v)
+{
+	dsb();
+	io_write8(io, v);
+}
+
+static inline void io_write16_mb(io16_t io, uint16_t v)
+{
+	dsb();
+	io_write16(io, v);
+}
+
+static inline void io_write32_mb(io32_t io, uint32_t v)
+{
+	dsb();
+	io_write32(io, v);
+}
+
+static inline void io_write64_mb(io64_t io, uint64_t v)
+{
+	dsb();
+	io_write64(io, v);
+}
+
+static inline void io_write8_array_mb(io8_array_t io, size_t n, uint8_t v)
+{
+	dsb();
+	io_write8_array(io, n, v);
+}
+
+static inline void io_write16_array_mb(io16_array_t io, size_t n, uint16_t v)
+{
+	dsb();
+	io_write16_array(io, n, v);
+}
+
+static inline void io_write32_array_mb(io32_array_t io, size_t n, uint32_t v)
+{
+	dsb();
+	io_write32_array(io, n, v);
+}
+
+static inline void io_write64_array_mb(io64_array_t io, size_t n, uint64_t v)
+{
+	dsb();
+	io_write64_array(io, n, v);
+}
diff --git a/src/arch/aarch64/hftest/interrupts_gicv3.c b/src/arch/aarch64/hftest/interrupts_gicv3.c
index a3fd489..80b67e2 100644
--- a/src/arch/aarch64/hftest/interrupts_gicv3.c
+++ b/src/arch/aarch64/hftest/interrupts_gicv3.c
@@ -45,22 +45,24 @@
 
 void interrupt_gic_setup(void)
 {
+	uint32_t ctlr = 1u << 4    /* Enable affinity routing. */
+			| 1u << 1; /* Enable group 1 non-secure interrupts. */
+
 	write_msr(ICC_CTLR_EL1, 0);
 
-	GICD_CTLR = 1u << 4    /* Enable affinity routing. */
-		    | 1u << 1; /* Enable group 1 non-secure interrupts. */
+	io_write32(GICD_CTLR, ctlr);
 
 	/* Mark CPU as awake. */
-	GICR_WAKER &= ~(1u << 1);
-	while ((GICR_WAKER & (1u << 2)) != 0) {
+	io_write32(GICR_WAKER, io_read32(GICR_WAKER) & ~(1u << 1));
+	while ((io_read32(GICR_WAKER) & (1u << 2)) != 0) {
 		dlog("Waiting for ChildrenAsleep==0\n");
 	}
 
 	/* Put interrupts into non-secure group 1. */
-	dlog("GICR_IGROUPR0 was %x\n", 0xffffffff, GICR_IGROUPR0);
-	GICR_IGROUPR0 = 0xffffffff;
+	dlog("GICR_IGROUPR0 was %x\n", 0xffffffff, io_read32(GICR_IGROUPR0));
+	io_write32(GICR_IGROUPR0, 0xffffffff);
 	dlog("wrote %x to GICR_IGROUPR0, got back %x\n", 0xffffffff,
-	     GICR_IGROUPR0);
+	     io_read32(GICR_IGROUPR0));
 	/* Enable non-secure group 1. */
 	write_msr(ICC_IGRPEN1_EL1, 0x00000001);
 	dlog("wrote %x to ICC_IGRPEN1_EL1, got back %x\n", 0x00000001,
@@ -69,15 +71,18 @@
 
 void interrupt_enable(uint32_t intid, bool enable)
 {
+	uint32_t index = intid / 32;
+	uint32_t bit = 1u << (intid % 32);
+
 	if (enable) {
-		GICD_ISENABLER(intid / 32) |= 1 << (intid % 32);
+		io_write32_array(GICD_ISENABLER, index, bit);
 		if (intid < 32) {
-			GICR_ISENABLER0 |= 1 << intid;
+			io_write32(GICR_ISENABLER0, bit);
 		}
 	} else {
-		GICD_ICENABLER(intid / 32) |= 1 << (intid % 32);
+		io_write32_array(GICD_ICENABLER, index, bit);
 		if (intid < 32) {
-			GICR_ICENABLER0 |= 1 << intid;
+			io_write32(GICR_ICENABLER0, bit);
 		}
 	}
 }
@@ -87,14 +92,14 @@
 	uint32_t i;
 
 	if (enable) {
-		GICR_ISENABLER0 = 0xffffffff;
+		io_write32(GICR_ISENABLER0, 0xffffffff);
 		for (i = 0; i < 32; ++i) {
-			GICD_ISENABLER(i) = 0xffffffff;
+			io_write32_array(GICD_ISENABLER, i, 0xffffffff);
 		}
 	} else {
-		GICR_ICENABLER0 = 0x00000000;
+		io_write32(GICR_ISENABLER0, 0);
 		for (i = 0; i < 32; ++i) {
-			GICD_ICENABLER(i) = 0x00000000;
+			io_write32_array(GICD_ISENABLER, i, 0);
 		}
 	}
 }
@@ -106,24 +111,29 @@
 
 void interrupt_set_priority(uint32_t intid, uint8_t priority)
 {
-	GICD_IPRIORITYR(intid) = priority;
+	io_write8_array(GICD_IPRIORITYR, intid, priority);
 }
 
 void interrupt_set_edge_triggered(uint32_t intid, bool edge_triggered)
 {
-	uint32_t bit = 1u << (intid % 16 * 2 + 1);
+	uint32_t index = intid / 16;
+	uint32_t bit = 1u << (((intid % 16) * 2) + 1);
 
 	if (intid < 32) {
+		uint32_t v = io_read32_array(GICR_ICFGR, index);
+
 		if (edge_triggered) {
-			GICR_ICFGR(intid / 16) |= bit;
+			io_write32_array(GICR_ICFGR, index, v | bit);
 		} else {
-			GICR_ICFGR(intid / 16) &= ~bit;
+			io_write32_array(GICR_ICFGR, index, v & ~bit);
 		}
 	} else {
+		uint32_t v = io_read32_array(GICD_ICFGR, index);
+
 		if (edge_triggered) {
-			GICD_ICFGR(intid / 16) |= bit;
+			io_write32_array(GICD_ICFGR, index, v | bit);
 		} else {
-			GICD_ICFGR(intid / 16) &= ~bit;
+			io_write32_array(GICD_ICFGR, index, v & ~bit);
 		}
 	}
 }
diff --git a/src/arch/aarch64/inc/hf/arch/vm/interrupts_gicv3.h b/src/arch/aarch64/inc/hf/arch/vm/interrupts_gicv3.h
index a07a5e7..5ebf6ac 100644
--- a/src/arch/aarch64/inc/hf/arch/vm/interrupts_gicv3.h
+++ b/src/arch/aarch64/inc/hf/arch/vm/interrupts_gicv3.h
@@ -19,30 +19,37 @@
 #include <stdbool.h>
 #include <stdint.h>
 
+#include "hf/io.h"
+
 #if GIC_VERSION != 3 && GIC_VERSION != 4
 #error This header should only be included for GICv3 or v4.
 #endif
 
+/* Keep macro alignment */
+/* clang-format off */
+
 #define SGI_BASE (GICR_BASE + 0x10000)
 
-#define GICD_CTLR (*(volatile uint32_t *)(GICD_BASE + 0x0000))
-#define GICD_ISENABLER(n) (((volatile uint32_t *)(GICD_BASE + 0x0100))[n])
-#define GICD_ICENABLER(n) (((volatile uint32_t *)(GICD_BASE + 0x0180))[n])
-#define GICD_ISPENDR(n) (((volatile uint32_t *)(GICD_BASE + 0x0200))[n])
-#define GICD_ICPENDR(n) (((volatile uint32_t *)(GICD_BASE + 0x0280))[n])
-#define GICD_ISACTIVER(n) (((volatile uint32_t *)(GICD_BASE + 0x0300))[n])
-#define GICD_ICACTIVER(n) (((volatile uint32_t *)(GICD_BASE + 0x0380))[n])
-#define GICD_IPRIORITYR(n) (((volatile uint8_t *)(GICD_BASE + 0x0400))[n])
-#define GICD_ITARGETSR(n) (((volatile uint32_t *)(GICD_BASE + 0x0800))[n])
-#define GICD_ICFGR(n) (((volatile uint32_t *)(GICD_BASE + 0x0c00))[n])
-#define GICR_WAKER (*(volatile uint32_t *)(GICR_BASE + 0x0014))
-#define GICR_IGROUPR0 (*(volatile uint32_t *)(SGI_BASE + 0x0080))
-#define GICR_ISENABLER0 (*(volatile uint32_t *)(SGI_BASE + 0x0100))
-#define GICR_ICENABLER0 (*(volatile uint32_t *)(SGI_BASE + 0x0180))
-#define GICR_ISPENDR0 (*(volatile uint32_t *)(SGI_BASE + 0x0200))
-#define GICR_ICPENDR0 (*(volatile uint32_t *)(SGI_BASE + 0x0280))
-#define GICR_ISACTIVER0 (*(volatile uint32_t *)(SGI_BASE + 0x0300))
-#define GICR_ICFGR(n) (((volatile uint32_t *)(SGI_BASE + 0x0c00))[n])
+#define GICD_CTLR       IO32_C(GICD_BASE + 0x0000)
+#define GICD_ISENABLER  IO32_ARRAY_C(GICD_BASE + 0x0100, 32)
+#define GICD_ICENABLER  IO32_ARRAY_C(GICD_BASE + 0x0180, 32)
+#define GICD_ISPENDR    IO32_ARRAY_C(GICD_BASE + 0x0200, 32)
+#define GICD_ICPENDR    IO32_ARRAY_C(GICD_BASE + 0x0280, 32)
+#define GICD_ISACTIVER  IO32_ARRAY_C(GICD_BASE + 0x0300, 32)
+#define GICD_ICACTIVER  IO32_ARRAY_C(GICD_BASE + 0x0380, 32)
+#define GICD_IPRIORITYR IO8_ARRAY_C(GICD_BASE + 0x0400, 1020)
+#define GICD_ITARGETSR  IO8_ARRAY_C(GICD_BASE + 0x0800, 1020)
+#define GICD_ICFGR      IO32_ARRAY_C(GICD_BASE + 0x0c00, 64)
+#define GICR_WAKER      IO32_C(GICR_BASE + 0x0014)
+#define GICR_IGROUPR0   IO32_C(SGI_BASE + 0x0080)
+#define GICR_ISENABLER0 IO32_C(SGI_BASE + 0x0100)
+#define GICR_ICENABLER0 IO32_C(SGI_BASE + 0x0180)
+#define GICR_ISPENDR0   IO32_C(SGI_BASE + 0x0200)
+#define GICR_ICPENDR0   IO32_C(SGI_BASE + 0x0280)
+#define GICR_ISACTIVER0 IO32_C(SGI_BASE + 0x0300)
+#define GICR_ICFGR      IO32_ARRAY_C(SGI_BASE + 0x0c00, 32)
+
+/* clang-format on */
 
 void exception_setup(void (*irq)(void));
 void interrupt_gic_setup(void);
diff --git a/src/arch/aarch64/pl011/io.h b/src/arch/aarch64/pl011/io.h
deleted file mode 100644
index 259fae2..0000000
--- a/src/arch/aarch64/pl011/io.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2018 The Hafnium Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "hf/arch/barriers.h"
-
-static inline uint32_t io_read(uintptr_t addr)
-{
-	return *(volatile uint32_t *)addr;
-}
-
-static inline uint32_t io_read_mb(uintptr_t addr)
-{
-	uint32_t v = io_read(addr);
-
-	dsb();
-	isb();
-
-	return v;
-}
-
-static inline void io_write(uintptr_t addr, uint32_t v)
-{
-	*(volatile uint32_t *)addr = v;
-}
-
-static inline void io_write_mb(uintptr_t addr, uint32_t v)
-{
-	dsb();
-	isb();
-	io_write(addr, v);
-}
diff --git a/src/arch/aarch64/pl011/pl011.c b/src/arch/aarch64/pl011/pl011.c
index 02b6123..fdf5a7d 100644
--- a/src/arch/aarch64/pl011/pl011.c
+++ b/src/arch/aarch64/pl011/pl011.c
@@ -14,18 +14,17 @@
  * limitations under the License.
  */
 
+#include "hf/io.h"
 #include "hf/mm.h"
 #include "hf/mpool.h"
 #include "hf/plat/console.h"
 #include "hf/vm.h"
 
-#include "io.h"
-
 /* UART Data Register. */
-#define UARTDR 0
+#define UARTDR IO32_C(PL011_BASE + 0x0)
 
 /* UART Flag Register. */
-#define UARTFR 0x018
+#define UARTFR IO32_C(PL011_BASE + 0x018)
 
 /* UART Flag Register bit: transmit fifo is full. */
 #define UARTFR_TXFF (1 << 5)
@@ -63,19 +62,19 @@
 	}
 
 	/* Wait until there is room in the tx buffer. */
-	while (io_read(PL011_BASE + UARTFR) & UARTFR_TXFF) {
+	while (io_read32(UARTFR) & UARTFR_TXFF) {
 		/* do nothing */
 	}
 
 	dmb();
 
 	/* Write the character out. */
-	io_write(PL011_BASE + UARTDR, c);
+	io_write32(UARTDR, c);
 
 	dmb();
 
 	/* Wait until the UART is no longer busy. */
-	while (io_read_mb(PL011_BASE + UARTFR) & UARTFR_BUSY) {
+	while (io_read32_mb(UARTFR) & UARTFR_BUSY) {
 		/* do nothing */
 	}
 }
diff --git a/test/vmapi/gicv3/busy_secondary.c b/test/vmapi/gicv3/busy_secondary.c
index 61da8e1..4631312 100644
--- a/test/vmapi/gicv3/busy_secondary.c
+++ b/test/vmapi/gicv3/busy_secondary.c
@@ -67,10 +67,10 @@
 	EXPECT_EQ(run_res.sleep.ns, HF_SLEEP_INDEFINITE);
 
 	/* Check that no interrupts are active or pending to start with. */
-	EXPECT_EQ(GICD_ISPENDR(0), 0);
-	EXPECT_EQ(GICR_ISPENDR0, 0);
-	EXPECT_EQ(GICD_ISACTIVER(0), 0);
-	EXPECT_EQ(GICR_ISACTIVER0, 0);
+	EXPECT_EQ(io_read32_array(GICD_ISPENDR, 0), 0);
+	EXPECT_EQ(io_read32(GICR_ISPENDR0), 0);
+	EXPECT_EQ(io_read32_array(GICD_ISACTIVER, 0), 0);
+	EXPECT_EQ(io_read32(GICR_ISACTIVER0), 0);
 
 	dlog("Starting timer\n");
 	/* Set virtual timer for 1 mS and enable. */
@@ -89,10 +89,10 @@
 
 	dlog("Waiting for interrupt\n");
 	while (last_interrupt_id == 0) {
-		EXPECT_EQ(GICD_ISPENDR(0), 0);
-		EXPECT_EQ(GICR_ISPENDR0, 0);
-		EXPECT_EQ(GICD_ISACTIVER(0), 0);
-		EXPECT_EQ(GICR_ISACTIVER0, 0);
+		EXPECT_EQ(io_read32_array(GICD_ISPENDR, 0), 0);
+		EXPECT_EQ(io_read32(GICR_ISPENDR0), 0);
+		EXPECT_EQ(io_read32_array(GICD_ISACTIVER, 0), 0);
+		EXPECT_EQ(io_read32(GICR_ISACTIVER0), 0);
 	}
 
 	/* Check that we got the interrupt. */
@@ -102,10 +102,10 @@
 	EXPECT_EQ(read_msr(CNTV_CTL_EL0), 0x00000005);
 
 	/* There should again be no pending or active interrupts. */
-	EXPECT_EQ(GICD_ISPENDR(0), 0);
-	EXPECT_EQ(GICR_ISPENDR0, 0);
-	EXPECT_EQ(GICD_ISACTIVER(0), 0);
-	EXPECT_EQ(GICR_ISACTIVER0, 0);
+	EXPECT_EQ(io_read32_array(GICD_ISPENDR, 0), 0);
+	EXPECT_EQ(io_read32(GICR_ISPENDR0), 0);
+	EXPECT_EQ(io_read32_array(GICD_ISACTIVER, 0), 0);
+	EXPECT_EQ(io_read32(GICR_ISACTIVER0), 0);
 }
 
 TEST(busy_secondary, physical_timer)
@@ -125,10 +125,10 @@
 	EXPECT_EQ(run_res.sleep.ns, HF_SLEEP_INDEFINITE);
 
 	/* Check that no interrupts are active or pending to start with. */
-	EXPECT_EQ(GICD_ISPENDR(0), 0);
-	EXPECT_EQ(GICR_ISPENDR0, 0);
-	EXPECT_EQ(GICD_ISACTIVER(0), 0);
-	EXPECT_EQ(GICR_ISACTIVER0, 0);
+	EXPECT_EQ(io_read32_array(GICD_ISPENDR, 0), 0);
+	EXPECT_EQ(io_read32(GICR_ISPENDR0), 0);
+	EXPECT_EQ(io_read32_array(GICD_ISACTIVER, 0), 0);
+	EXPECT_EQ(io_read32(GICR_ISACTIVER0), 0);
 
 	dlog("Starting timer\n");
 	/* Set physical timer for 1 ms and enable. */
@@ -147,10 +147,10 @@
 
 	dlog("Waiting for interrupt\n");
 	while (last_interrupt_id == 0) {
-		EXPECT_EQ(GICD_ISPENDR(0), 0);
-		EXPECT_EQ(GICR_ISPENDR0, 0);
-		EXPECT_EQ(GICD_ISACTIVER(0), 0);
-		EXPECT_EQ(GICR_ISACTIVER0, 0);
+		EXPECT_EQ(io_read32_array(GICD_ISPENDR, 0), 0);
+		EXPECT_EQ(io_read32(GICR_ISPENDR0), 0);
+		EXPECT_EQ(io_read32_array(GICD_ISACTIVER, 0), 0);
+		EXPECT_EQ(io_read32(GICR_ISACTIVER0), 0);
 	}
 
 	/* Check that we got the interrupt. */
@@ -160,8 +160,8 @@
 	EXPECT_EQ(read_msr(CNTP_CTL_EL0), 0x00000005);
 
 	/* There should again be no pending or active interrupts. */
-	EXPECT_EQ(GICD_ISPENDR(0), 0);
-	EXPECT_EQ(GICR_ISPENDR0, 0);
-	EXPECT_EQ(GICD_ISACTIVER(0), 0);
-	EXPECT_EQ(GICR_ISACTIVER0, 0);
+	EXPECT_EQ(io_read32_array(GICD_ISPENDR, 0), 0);
+	EXPECT_EQ(io_read32(GICR_ISPENDR0), 0);
+	EXPECT_EQ(io_read32_array(GICD_ISACTIVER, 0), 0);
+	EXPECT_EQ(io_read32(GICR_ISACTIVER0), 0);
 }
diff --git a/test/vmapi/gicv3/gicv3.c b/test/vmapi/gicv3/gicv3.c
index e1e1056..571f978 100644
--- a/test/vmapi/gicv3/gicv3.c
+++ b/test/vmapi/gicv3/gicv3.c
@@ -71,7 +71,7 @@
 
 	/* Should have affinity routing enabled, group 1 interrupts enabled,
 	 * group 0 disabled. */
-	EXPECT_EQ(GICD_CTLR & 0x13, 0x12);
+	EXPECT_EQ(io_read32(GICD_CTLR) & 0x13, 0x12);
 	EXPECT_EQ(read_msr(ICC_CTLR_EL1) & 0xff, 0);
 }
 
diff --git a/test/vmapi/gicv3/interrupts.c b/test/vmapi/gicv3/interrupts.c
index 3945bb0..c6c07f9 100644
--- a/test/vmapi/gicv3/interrupts.c
+++ b/test/vmapi/gicv3/interrupts.c
@@ -39,10 +39,10 @@
 	interrupt_set_priority(intid, 0x80);
 	arch_irq_enable();
 	interrupt_enable_all(true);
-	EXPECT_EQ(GICD_ISPENDR(0), 0);
-	EXPECT_EQ(GICR_ISPENDR0, 0);
-	EXPECT_EQ(GICD_ISACTIVER(0), 0);
-	EXPECT_EQ(GICR_ISACTIVER0, 0);
+	EXPECT_EQ(io_read32_array(GICD_ISPENDR, 0), 0);
+	EXPECT_EQ(io_read32(GICR_ISPENDR0), 0);
+	EXPECT_EQ(io_read32_array(GICD_ISACTIVER, 0), 0);
+	EXPECT_EQ(io_read32(GICR_ISACTIVER0), 0);
 
 	/* Send ourselves the SGI. */
 	last_interrupt_id = 0xffffffff;
@@ -52,9 +52,9 @@
 
 	/* Check that we got it, and we are back to not active or pending. */
 	EXPECT_EQ(last_interrupt_id, intid);
-	EXPECT_EQ(GICD_ISPENDR(0), 0);
-	EXPECT_EQ(GICD_ISACTIVER(0), 0);
-	EXPECT_EQ(GICR_ISACTIVER0, 0);
+	EXPECT_EQ(io_read32_array(GICD_ISPENDR, 0), 0);
+	EXPECT_EQ(io_read32_array(GICD_ISACTIVER, 0), 0);
+	EXPECT_EQ(io_read32(GICR_ISACTIVER0), 0);
 }
 
 TEST(interrupts, disable_sgi)
@@ -66,10 +66,10 @@
 	interrupt_set_priority_mask(0xff);
 	interrupt_set_priority(intid, 0x80);
 	arch_irq_enable();
-	EXPECT_EQ(GICD_ISPENDR(0), 0);
-	EXPECT_EQ(GICR_ISPENDR0, 0);
-	EXPECT_EQ(GICD_ISACTIVER(0), 0);
-	EXPECT_EQ(GICR_ISACTIVER0, 0);
+	EXPECT_EQ(io_read32_array(GICD_ISPENDR, 0), 0);
+	EXPECT_EQ(io_read32(GICR_ISPENDR0), 0);
+	EXPECT_EQ(io_read32_array(GICD_ISACTIVER, 0), 0);
+	EXPECT_EQ(io_read32(GICR_ISACTIVER0), 0);
 
 	/* Send ourselves the SGI. */
 	last_interrupt_id = 0xffffffff;
@@ -79,10 +79,10 @@
 
 	/* Check that we didn't get it, but it is pending (and not active). */
 	EXPECT_EQ(last_interrupt_id, 0xffffffff);
-	EXPECT_EQ(GICD_ISPENDR(0), 0);
-	EXPECT_EQ(GICR_ISPENDR0, 0x1 << intid);
-	EXPECT_EQ(GICD_ISACTIVER(0), 0);
-	EXPECT_EQ(GICR_ISACTIVER0, 0);
+	EXPECT_EQ(io_read32_array(GICD_ISPENDR, 0), 0);
+	EXPECT_EQ(io_read32(GICR_ISPENDR0), 0x1 << intid);
+	EXPECT_EQ(io_read32_array(GICD_ISACTIVER, 0), 0);
+	EXPECT_EQ(io_read32(GICR_ISACTIVER0), 0);
 }
 
 TEST(interrupts, physical_timer)
@@ -97,10 +97,10 @@
 	 * Check that no (SGI or PPI) interrupts are active or pending to start
 	 * with.
 	 */
-	EXPECT_EQ(GICD_ISPENDR(0), 0);
-	EXPECT_EQ(GICR_ISPENDR0, 0);
-	EXPECT_EQ(GICD_ISACTIVER(0), 0);
-	EXPECT_EQ(GICR_ISACTIVER0, 0);
+	EXPECT_EQ(io_read32_array(GICD_ISPENDR, 0), 0);
+	EXPECT_EQ(io_read32(GICR_ISPENDR0), 0);
+	EXPECT_EQ(io_read32_array(GICD_ISACTIVER, 0), 0);
+	EXPECT_EQ(io_read32(GICR_ISACTIVER0), 0);
 
 	dlog("Starting timer\n");
 	/* Set physical timer for 1 tick. */
@@ -110,10 +110,10 @@
 
 	dlog("waiting for interrupt\n");
 	while (last_interrupt_id == 0) {
-		EXPECT_EQ(GICD_ISPENDR(0), 0);
-		EXPECT_EQ(GICR_ISPENDR0, 0);
-		EXPECT_EQ(GICD_ISACTIVER(0), 0);
-		EXPECT_EQ(GICR_ISACTIVER0, 0);
+		EXPECT_EQ(io_read32_array(GICD_ISPENDR, 0), 0);
+		EXPECT_EQ(io_read32(GICR_ISPENDR0), 0);
+		EXPECT_EQ(io_read32_array(GICD_ISACTIVER, 0), 0);
+		EXPECT_EQ(io_read32(GICR_ISACTIVER0), 0);
 	}
 
 	/* Check that we got the interrupt. */
@@ -123,10 +123,10 @@
 	EXPECT_EQ(read_msr(CNTP_CTL_EL0), 0x00000005);
 
 	/* There should again be no pending or active interrupts. */
-	EXPECT_EQ(GICD_ISPENDR(0), 0);
-	EXPECT_EQ(GICR_ISPENDR0, 0);
-	EXPECT_EQ(GICD_ISACTIVER(0), 0);
-	EXPECT_EQ(GICR_ISACTIVER0, 0);
+	EXPECT_EQ(io_read32_array(GICD_ISPENDR, 0), 0);
+	EXPECT_EQ(io_read32(GICR_ISPENDR0), 0);
+	EXPECT_EQ(io_read32_array(GICD_ISACTIVER, 0), 0);
+	EXPECT_EQ(io_read32(GICR_ISACTIVER0), 0);
 }
 
 TEST(interrupts, virtual_timer)
@@ -138,10 +138,10 @@
 	arch_irq_enable();
 
 	/* Check that no interrupts are active or pending to start with. */
-	EXPECT_EQ(GICD_ISPENDR(0), 0);
-	EXPECT_EQ(GICR_ISPENDR0, 0);
-	EXPECT_EQ(GICD_ISACTIVER(0), 0);
-	EXPECT_EQ(GICR_ISACTIVER0, 0);
+	EXPECT_EQ(io_read32_array(GICD_ISPENDR, 0), 0);
+	EXPECT_EQ(io_read32(GICR_ISPENDR0), 0);
+	EXPECT_EQ(io_read32_array(GICD_ISACTIVER, 0), 0);
+	EXPECT_EQ(io_read32(GICR_ISACTIVER0), 0);
 
 	dlog("Starting timer\n");
 	/* Set virtual timer for 1 tick. */
@@ -151,10 +151,10 @@
 
 	dlog("Waiting for interrupt\n");
 	while (last_interrupt_id == 0) {
-		EXPECT_EQ(GICD_ISPENDR(0), 0);
-		EXPECT_EQ(GICR_ISPENDR0, 0);
-		EXPECT_EQ(GICD_ISACTIVER(0), 0);
-		EXPECT_EQ(GICR_ISACTIVER0, 0);
+		EXPECT_EQ(io_read32_array(GICD_ISPENDR, 0), 0);
+		EXPECT_EQ(io_read32(GICR_ISPENDR0), 0);
+		EXPECT_EQ(io_read32_array(GICD_ISACTIVER, 0), 0);
+		EXPECT_EQ(io_read32(GICR_ISACTIVER0), 0);
 	}
 
 	/* Check that we got the interrupt. */
@@ -164,8 +164,8 @@
 	EXPECT_EQ(read_msr(CNTV_CTL_EL0), 0x00000005);
 
 	/* There should again be no pending or active interrupts. */
-	EXPECT_EQ(GICD_ISPENDR(0), 0);
-	EXPECT_EQ(GICR_ISPENDR0, 0);
-	EXPECT_EQ(GICD_ISACTIVER(0), 0);
-	EXPECT_EQ(GICR_ISACTIVER0, 0);
+	EXPECT_EQ(io_read32_array(GICD_ISPENDR, 0), 0);
+	EXPECT_EQ(io_read32(GICR_ISPENDR0), 0);
+	EXPECT_EQ(io_read32_array(GICD_ISACTIVER, 0), 0);
+	EXPECT_EQ(io_read32(GICR_ISACTIVER0), 0);
 }