refactor: add interrupt_bitmap struct

Since bitmaps for tracking interrupt IDs are used in both
manifest parsing as well as interrupt handling make a common
struct that can be used. Also introduce helper functions for
accessing and modifying the bitmap.

Signed-off-by: Daniel Boulby <daniel.boulby@arm.com>
Change-Id: Icbbc931d732bf7075f854adbe517c6ea341dc5d0
diff --git a/inc/hf/interrupt_desc.h b/inc/hf/interrupt_desc.h
index 1f78e48..e95e47b 100644
--- a/inc/hf/interrupt_desc.h
+++ b/inc/hf/interrupt_desc.h
@@ -20,9 +20,36 @@
 /* The number of bits in each element of the interrupt bitfields. */
 #define INTERRUPT_REGISTER_BITS 32
 
-#define INTID_INDEX(intid) (intid / INTERRUPT_REGISTER_BITS)
-#define INTID_MASK(v, intid) (v << (intid % INTERRUPT_REGISTER_BITS))
+struct interrupt_bitmap {
+	uint32_t bitmap[HF_NUM_INTIDS / INTERRUPT_REGISTER_BITS];
+};
 
+static inline uint32_t interrupt_bitmap_get_value(
+	struct interrupt_bitmap *bitmap, uint32_t intid)
+{
+	uint32_t index = intid / INTERRUPT_REGISTER_BITS;
+	uint32_t shift = intid % INTERRUPT_REGISTER_BITS;
+
+	return (bitmap->bitmap[index] >> shift) & 1U;
+}
+
+static inline void interrupt_bitmap_set_value(struct interrupt_bitmap *bitmap,
+					      uint32_t intid)
+{
+	uint32_t index = intid / INTERRUPT_REGISTER_BITS;
+	uint32_t shift = intid % INTERRUPT_REGISTER_BITS;
+
+	bitmap->bitmap[index] |= 1U << shift;
+}
+
+static inline void interrupt_bitmap_clear_value(struct interrupt_bitmap *bitmap,
+						uint32_t intid)
+{
+	uint32_t index = intid / INTERRUPT_REGISTER_BITS;
+	uint32_t shift = intid % INTERRUPT_REGISTER_BITS;
+
+	bitmap->bitmap[index] &= ~(1U << shift);
+}
 /**
  * Attributes encoding in the manifest:
 
diff --git a/inc/hf/vcpu.h b/inc/hf/vcpu.h
index 47f9ed6..c960793 100644
--- a/inc/hf/vcpu.h
+++ b/inc/hf/vcpu.h
@@ -42,11 +42,11 @@
 
 struct interrupts {
 	/** Bitfield keeping track of which interrupts are enabled. */
-	uint32_t interrupt_enabled[HF_NUM_INTIDS / INTERRUPT_REGISTER_BITS];
+	struct interrupt_bitmap interrupt_enabled;
 	/** Bitfield keeping track of which interrupts are pending. */
-	uint32_t interrupt_pending[HF_NUM_INTIDS / INTERRUPT_REGISTER_BITS];
+	struct interrupt_bitmap interrupt_pending;
 	/** Bitfield recording the interrupt pin configuration. */
-	uint32_t interrupt_type[HF_NUM_INTIDS / INTERRUPT_REGISTER_BITS];
+	struct interrupt_bitmap interrupt_type;
 	/**
 	 * The number of interrupts which are currently both enabled and
 	 * pending. Count independently virtual IRQ and FIQ interrupt types
@@ -167,6 +167,63 @@
 
 void vcpu_set_phys_core_idx(struct vcpu *vcpu);
 
+static inline bool vcpu_is_virt_interrupt_enabled(struct interrupts *interrupts,
+						  uint32_t intid)
+{
+	return interrupt_bitmap_get_value(&interrupts->interrupt_enabled,
+					  intid) == 1U;
+}
+
+static inline void vcpu_virt_interrupt_set_enabled(
+	struct interrupts *interrupts, uint32_t intid)
+{
+	interrupt_bitmap_set_value(&interrupts->interrupt_enabled, intid);
+}
+
+static inline void vcpu_virt_interrupt_clear_enabled(
+	struct interrupts *interrupts, uint32_t intid)
+{
+	interrupt_bitmap_clear_value(&interrupts->interrupt_enabled, intid);
+}
+
+static inline bool vcpu_is_virt_interrupt_pending(struct interrupts *interrupts,
+						  uint32_t intid)
+{
+	return interrupt_bitmap_get_value(&interrupts->interrupt_pending,
+					  intid) == 1U;
+}
+
+static inline void vcpu_virt_interrupt_set_pending(
+	struct interrupts *interrupts, uint32_t intid)
+{
+	interrupt_bitmap_set_value(&interrupts->interrupt_pending, intid);
+}
+
+static inline void vcpu_virt_interrupt_clear_pending(
+	struct interrupts *interrupts, uint32_t intid)
+{
+	interrupt_bitmap_clear_value(&interrupts->interrupt_pending, intid);
+}
+
+static inline enum interrupt_type vcpu_virt_interrupt_get_type(
+	struct interrupts *interrupts, uint32_t intid)
+{
+	return (enum interrupt_type)interrupt_bitmap_get_value(
+		&interrupts->interrupt_type, intid);
+}
+
+static inline void vcpu_virt_interrupt_set_type(struct interrupts *interrupts,
+						uint32_t intid,
+						enum interrupt_type type)
+{
+	if (type == INTERRUPT_TYPE_IRQ) {
+		interrupt_bitmap_clear_value(&interrupts->interrupt_type,
+					     intid);
+	} else {
+		interrupt_bitmap_set_value(&interrupts->interrupt_type, intid);
+	}
+}
+
 static inline void vcpu_irq_count_increment(struct vcpu_locked vcpu_locked)
 {
 	vcpu_locked.vcpu->interrupts.enabled_and_pending_irq_count++;
@@ -187,6 +244,30 @@
 	vcpu_locked.vcpu->interrupts.enabled_and_pending_fiq_count--;
 }
 
+static inline void vcpu_interrupt_count_increment(
+	struct vcpu_locked vcpu_locked, struct interrupts *interrupts,
+	uint32_t intid)
+{
+	if (vcpu_virt_interrupt_get_type(interrupts, intid) ==
+	    INTERRUPT_TYPE_IRQ) {
+		vcpu_irq_count_increment(vcpu_locked);
+	} else {
+		vcpu_fiq_count_increment(vcpu_locked);
+	}
+}
+
+static inline void vcpu_interrupt_count_decrement(
+	struct vcpu_locked vcpu_locked, struct interrupts *interrupts,
+	uint32_t intid)
+{
+	if (vcpu_virt_interrupt_get_type(interrupts, intid) ==
+	    INTERRUPT_TYPE_IRQ) {
+		vcpu_irq_count_decrement(vcpu_locked);
+	} else {
+		vcpu_fiq_count_decrement(vcpu_locked);
+	}
+}
+
 static inline uint32_t vcpu_interrupt_irq_count_get(
 	struct vcpu_locked vcpu_locked)
 {
diff --git a/src/api.c b/src/api.c
index 94af06d..39b6298 100644
--- a/src/api.c
+++ b/src/api.c
@@ -614,8 +614,7 @@
 				    struct vcpu **next)
 {
 	struct vcpu *target_vcpu = target_locked.vcpu;
-	uint32_t intid_index = INTID_INDEX(intid);
-	uint32_t intid_mask = INTID_MASK(1U, intid);
+	struct interrupts *interrupts = &target_vcpu->interrupts;
 	int64_t ret = 0;
 
 	/*
@@ -623,19 +622,13 @@
 	 * if it is enabled and was not previously pending. Otherwise we can
 	 * skip everything except setting the pending bit.
 	 */
-	if (!(target_vcpu->interrupts.interrupt_enabled[intid_index] &
-	      ~target_vcpu->interrupts.interrupt_pending[intid_index] &
-	      intid_mask)) {
+	if (!(vcpu_is_virt_interrupt_enabled(interrupts, intid) &&
+	      !vcpu_is_virt_interrupt_pending(interrupts, intid))) {
 		goto out;
 	}
 
 	/* Increment the count. */
-	if ((target_vcpu->interrupts.interrupt_type[intid_index] &
-	     intid_mask) == INTID_MASK(INTERRUPT_TYPE_IRQ, intid)) {
-		vcpu_irq_count_increment(target_locked);
-	} else {
-		vcpu_fiq_count_increment(target_locked);
-	}
+	vcpu_interrupt_count_increment(target_locked, interrupts, intid);
 
 	/*
 	 * Only need to update state if there was not already an
@@ -657,7 +650,7 @@
 
 out:
 	/* Either way, make it pending. */
-	target_vcpu->interrupts.interrupt_pending[intid_index] |= intid_mask;
+	vcpu_virt_interrupt_set_pending(interrupts, intid);
 
 	return ret;
 }
@@ -2061,8 +2054,7 @@
 			     enum interrupt_type type, struct vcpu *current)
 {
 	struct vcpu_locked current_locked;
-	uint32_t intid_index = INTID_INDEX(intid);
-	uint32_t intid_mask = INTID_MASK(1U, intid);
+	struct interrupts *interrupts = &current->interrupts;
 
 	if (intid >= HF_NUM_INTIDS) {
 		return -1;
@@ -2070,49 +2062,29 @@
 
 	current_locked = vcpu_lock(current);
 	if (enable) {
-		if (type == INTERRUPT_TYPE_IRQ) {
-			current->interrupts.interrupt_type[intid_index] &=
-				~intid_mask;
-		} else if (type == INTERRUPT_TYPE_FIQ) {
-			current->interrupts.interrupt_type[intid_index] |=
-				intid_mask;
-		}
-
 		/*
 		 * If it is pending and was not enabled before, increment the
 		 * count.
 		 */
-		if (current->interrupts.interrupt_pending[intid_index] &
-		    ~current->interrupts.interrupt_enabled[intid_index] &
-		    intid_mask) {
-			if ((current->interrupts.interrupt_type[intid_index] &
-			     intid_mask) ==
-			    INTID_MASK(INTERRUPT_TYPE_IRQ, intid)) {
-				vcpu_irq_count_increment(current_locked);
-			} else {
-				vcpu_fiq_count_increment(current_locked);
-			}
+		if (vcpu_is_virt_interrupt_pending(interrupts, intid) &&
+		    !vcpu_is_virt_interrupt_enabled(interrupts, intid)) {
+			vcpu_interrupt_count_increment(current_locked,
+						       interrupts, intid);
 		}
-		current->interrupts.interrupt_enabled[intid_index] |=
-			intid_mask;
+		vcpu_virt_interrupt_set_enabled(interrupts, intid);
+		vcpu_virt_interrupt_set_type(interrupts, intid, type);
 	} else {
 		/*
 		 * If it is pending and was enabled before, decrement the count.
 		 */
-		if (current->interrupts.interrupt_pending[intid_index] &
-		    current->interrupts.interrupt_enabled[intid_index] &
-		    intid_mask) {
-			if ((current->interrupts.interrupt_type[intid_index] &
-			     intid_mask) ==
-			    INTID_MASK(INTERRUPT_TYPE_IRQ, intid)) {
-				vcpu_irq_count_decrement(current_locked);
-			} else {
-				vcpu_fiq_count_decrement(current_locked);
-			}
+		if (vcpu_is_virt_interrupt_pending(interrupts, intid) &&
+		    vcpu_is_virt_interrupt_enabled(interrupts, intid)) {
+			vcpu_interrupt_count_decrement(current_locked,
+						       interrupts, intid);
 		}
-		current->interrupts.interrupt_enabled[intid_index] &=
-			~intid_mask;
-		current->interrupts.interrupt_type[intid_index] &= ~intid_mask;
+		vcpu_virt_interrupt_clear_enabled(interrupts, intid);
+		vcpu_virt_interrupt_set_type(interrupts, intid,
+					     INTERRUPT_TYPE_IRQ);
 	}
 
 	vcpu_unlock(&current_locked);
@@ -2129,6 +2101,7 @@
 	uint32_t i;
 	uint32_t first_interrupt = HF_INVALID_INTID;
 	struct vcpu_locked current_locked;
+	struct interrupts *interrupts = &current->interrupts;
 
 	/*
 	 * Find the first enabled and pending interrupt ID, return it, and
@@ -2137,27 +2110,23 @@
 	current_locked = vcpu_lock(current);
 	for (i = 0; i < HF_NUM_INTIDS / INTERRUPT_REGISTER_BITS; ++i) {
 		uint32_t enabled_and_pending =
-			current->interrupts.interrupt_enabled[i] &
-			current->interrupts.interrupt_pending[i];
+			interrupts->interrupt_enabled.bitmap[i] &
+			interrupts->interrupt_pending.bitmap[i];
 
 		if (enabled_and_pending != 0) {
 			uint8_t bit_index = ctz(enabled_and_pending);
-			uint32_t intid_mask = 1U << bit_index;
+
+			first_interrupt =
+				i * INTERRUPT_REGISTER_BITS + bit_index;
 
 			/*
 			 * Mark it as no longer pending and decrement the count.
 			 */
-			current->interrupts.interrupt_pending[i] &= ~intid_mask;
+			vcpu_virt_interrupt_clear_pending(interrupts,
+							  first_interrupt);
 
-			if ((current->interrupts.interrupt_type[i] &
-			     intid_mask) == (INTERRUPT_TYPE_IRQ << bit_index)) {
-				vcpu_irq_count_decrement(current_locked);
-			} else {
-				vcpu_fiq_count_decrement(current_locked);
-			}
-
-			first_interrupt =
-				i * INTERRUPT_REGISTER_BITS + bit_index;
+			vcpu_interrupt_count_decrement(
+				current_locked, interrupts, first_interrupt);
 			break;
 		}
 	}
diff --git a/src/manifest.c b/src/manifest.c
index 58a2ff2..1108c93 100644
--- a/src/manifest.c
+++ b/src/manifest.c
@@ -43,7 +43,7 @@
  * in the manifest.
  */
 struct allocated_fields {
-	uint32_t intids[HF_NUM_INTIDS / INTERRUPT_REGISTER_BITS];
+	struct interrupt_bitmap intids;
 	struct {
 		uintptr_t base;
 		uintptr_t limit;
@@ -543,7 +543,7 @@
 	struct uint32list_iter list;
 	uint16_t i = 0;
 	uint32_t j = 0;
-	uint32_t *allocated_intids = allocated_fields->intids;
+	struct interrupt_bitmap allocated_intids = allocated_fields->intids;
 
 	dlog_verbose("  Partition Device Regions\n");
 
@@ -604,23 +604,19 @@
 		while (uint32list_has_next(&list) &&
 		       j < PARTITION_MAX_INTERRUPTS_PER_DEVICE) {
 			uint32_t intid;
-			uint32_t intid_index;
-			uint32_t intid_mask;
 
 			TRY(uint32list_get_next(
 				&list, &dev_regions[i].interrupts[j].id));
 			intid = dev_regions[i].interrupts[j].id;
-			intid_index = INTID_INDEX(intid);
-			intid_mask = INTID_MASK(1U, intid);
 
 			dlog_verbose("        ID = %u\n", intid);
 
-			if ((allocated_intids[intid_index] & intid_mask) !=
-			    0U) {
+			if (interrupt_bitmap_get_value(&allocated_intids,
+						       intid) == 1U) {
 				return MANIFEST_ERROR_INTERRUPT_ID_REPEATED;
 			}
 
-			allocated_intids[intid_index] |= intid_mask;
+			interrupt_bitmap_set_value(&allocated_intids, intid);
 
 			if (uint32list_has_next(&list)) {
 				TRY(uint32list_get_next(&list,