Inject data/instruction abort exception instead of unknown reason

When the exception is caused by an instruction or data abort, inject it into
the EL1 instead of the (default) unknown reason. This gives the EL1 more
information and could help in handling or debugging these exceptions.

Bug: 147474217

Change-Id: I4db0c35322e2239ecde8b8144921c364d77bcc86
diff --git a/src/arch/aarch64/hypervisor/exceptions.S b/src/arch/aarch64/hypervisor/exceptions.S
index 17a5b63..c3c8d20 100644
--- a/src/arch/aarch64/hypervisor/exceptions.S
+++ b/src/arch/aarch64/hypervisor/exceptions.S
@@ -191,9 +191,8 @@
 	/* Read syndrome register and call C handler. */
 	mrs x0, esr_el2
 	bl handle_system_register_access
-	cbnz x0, vcpu_switch
 
-	/* vCPU is not changing. */
+	/* Continue running the same vCPU. */
 	mrs x0, tpidr_el2
 	b vcpu_restore_nonvolatile_and_run
 
diff --git a/src/arch/aarch64/hypervisor/handler.c b/src/arch/aarch64/hypervisor/handler.c
index 44fa3ae..fe32c5a 100644
--- a/src/arch/aarch64/hypervisor/handler.c
+++ b/src/arch/aarch64/hypervisor/handler.c
@@ -41,16 +41,6 @@
 #include "sysregs.h"
 
 /**
- * Gets the Exception Class from the ESR.
- */
-#define GET_ESR_EC(esr) ((esr) >> 26)
-
-/**
- * Gets the Instruction Length bit for the synchronous exception
- */
-#define GET_ESR_IL(esr) ((esr) & (1 << 25))
-
-/**
  * Gets the value to increment for the next PC.
  * The ESR encodes whether the instruction is 2 bytes or 4 bytes long.
  */
@@ -212,7 +202,7 @@
 	(void)spsr;
 
 	switch (ec) {
-	case 0x25: /* EC = 100101, Data abort. */
+	case EC_DATA_ABORT_SAME_EL:
 		dlog("Data abort: pc=%#x, esr=%#x, ec=%#x", elr, esr, ec);
 		if (!(esr & (1U << 10))) { /* Check FnV bit. */
 			dlog(", far=%#x", read_msr(far_el2));
@@ -493,18 +483,16 @@
 }
 
 /**
- * Injects an exception with an unknown reason (EC=0x0) to the EL1.
+ * Injects an exception with the specified Exception Syndrom Register value into
+ * the EL1.
  * See Arm Architecture Reference Manual Armv8-A, page D13-2924.
  *
  * NOTE: This function assumes that the lazy registers haven't been saved, and
  * writes to the lazy registers of the CPU directly instead of the vCPU.
  */
-static struct vcpu *inject_el1_unknown_exception(struct vcpu *vcpu,
-						 uintreg_t esr_el2)
+static void inject_el1_exception(struct vcpu *vcpu, uintreg_t esr_el1_value)
 {
-	uintreg_t esr_el1_value = GET_ESR_IL(esr_el2);
 	uintreg_t handler_address = get_el1_exception_handler_addr(vcpu);
-	char *direction_str;
 
 	/* Update the CPU state to inject the exception. */
 	write_msr(esr_el1, esr_el1_value);
@@ -522,6 +510,56 @@
 
 	/* Transfer control to the exception hander. */
 	vcpu->regs.pc = handler_address;
+}
+
+/**
+ * Injects a Data Abort exception (same exception level).
+ */
+static void inject_el1_data_abort_exception(struct vcpu *vcpu,
+					    uintreg_t esr_el2)
+{
+	/*
+	 *  ISS encoding remains the same, but the EC is changed to reflect
+	 *  where the exception came from.
+	 *  See Arm Architecture Reference Manual Armv8-A, pages D13-2943/2982.
+	 */
+	uintreg_t esr_el1_value = GET_ESR_ISS(esr_el2) | GET_ESR_IL(esr_el2) |
+				  (EC_DATA_ABORT_SAME_EL << ESR_EC_OFFSET);
+
+	dlog("Injecting Data Abort exception into VM%d.\n", vcpu->vm->id);
+
+	inject_el1_exception(vcpu, esr_el1_value);
+}
+
+/**
+ * Injects a Data Abort exception (same exception level).
+ */
+static void inject_el1_instruction_abort_exception(struct vcpu *vcpu,
+						   uintreg_t esr_el2)
+{
+	/*
+	 *  ISS encoding remains the same, but the EC is changed to reflect
+	 *  where the exception came from.
+	 *  See Arm Architecture Reference Manual Armv8-A, pages D13-2941/2980.
+	 */
+	uintreg_t esr_el1_value =
+		GET_ESR_ISS(esr_el2) | GET_ESR_IL(esr_el2) |
+		(EC_INSTRUCTION_ABORT_SAME_EL << ESR_EC_OFFSET);
+
+	dlog("Injecting Instruction Abort exception into VM%d.\n",
+	     vcpu->vm->id);
+
+	inject_el1_exception(vcpu, esr_el1_value);
+}
+
+/**
+ * Injects an exception with an unknown reason into the EL1.
+ */
+static void inject_el1_unknown_exception(struct vcpu *vcpu, uintreg_t esr_el2)
+{
+	uintreg_t esr_el1_value =
+		GET_ESR_IL(esr_el2) | (EC_UNKNOWN << ESR_EC_OFFSET);
+	char *direction_str;
 
 	direction_str = ISS_IS_READ(esr_el2) ? "read" : "write";
 	dlog("Trapped access to system register %s: op0=%d, op1=%d, crn=%d, "
@@ -531,10 +569,8 @@
 	     GET_ISS_RT(esr_el2));
 
 	dlog("Injecting Unknown Reason exception into VM%d.\n", vcpu->vm->id);
-	dlog("Exception handler address 0x%x\n", handler_address);
 
-	/* Schedule the same VM to continue running. */
-	return NULL;
+	inject_el1_exception(vcpu, esr_el1_value);
 }
 
 struct vcpu *hvc_handler(struct vcpu *vcpu)
@@ -676,7 +712,7 @@
 	uintreg_t ec = GET_ESR_EC(esr);
 
 	switch (ec) {
-	case 0x01: /* EC = 000001, WFI or WFE. */
+	case EC_WFI_WFE:
 		/* Skip the instruction. */
 		vcpu->regs.pc += GET_NEXT_PC_INC(esr);
 		/* Check TI bit of ISS, 0 = WFI, 1 = WFE. */
@@ -692,25 +728,33 @@
 		/* WFI */
 		return api_wait_for_interrupt(vcpu);
 
-	case 0x24: /* EC = 100100, Data abort. */
+	case EC_DATA_ABORT_LOWER_EL:
 		info = fault_info_init(
 			esr, vcpu, (esr & (1U << 6)) ? MM_MODE_W : MM_MODE_R);
 		if (vcpu_handle_page_fault(vcpu, &info)) {
 			return NULL;
 		}
-		break;
+		/* Inform the EL1 of the data abort. */
+		inject_el1_data_abort_exception(vcpu, esr);
 
-	case 0x20: /* EC = 100000, Instruction abort. */
+		/* Schedule the same VM to continue running. */
+		return NULL;
+
+	case EC_INSTRUCTION_ABORT_LOWER_EL:
 		info = fault_info_init(esr, vcpu, MM_MODE_X);
 		if (vcpu_handle_page_fault(vcpu, &info)) {
 			return NULL;
 		}
-		break;
+		/* Inform the EL1 of the instruction abort. */
+		inject_el1_instruction_abort_exception(vcpu, esr);
 
-	case 0x16: /* EC = 010110, HVC instruction */
+		/* Schedule the same VM to continue running. */
+		return NULL;
+
+	case EC_HVC:
 		return hvc_handler(vcpu);
 
-	case 0x17: /* EC = 010111, SMC instruction. */ {
+	case EC_SMC: {
 		uintreg_t smc_pc = vcpu->regs.pc;
 		struct vcpu *next = smc_handler(vcpu);
 
@@ -720,11 +764,7 @@
 		return next;
 	}
 
-	/*
-	 * EC = 011000, MSR, MRS or System instruction execution that is not
-	 * reported using EC 000000, 000001 or 000111.
-	 */
-	case 0x18:
+	case EC_MSR:
 		/*
 		 * NOTE: This should never be reached because it goes through a
 		 * separate path handled by handle_system_register_access().
@@ -742,41 +782,47 @@
 	 * The exception wasn't handled. Inject to the VM to give it chance to
 	 * handle as an unknown exception.
 	 */
-	return inject_el1_unknown_exception(vcpu, esr);
+	inject_el1_unknown_exception(vcpu, esr);
+
+	/* Schedule the same VM to continue running. */
+	return NULL;
 }
 
 /**
  * Handles EC = 011000, MSR, MRS instruction traps.
  * Returns non-null ONLY if the access failed and the vCPU is changing.
  */
-struct vcpu *handle_system_register_access(uintreg_t esr_el2)
+void handle_system_register_access(uintreg_t esr_el2)
 {
 	struct vcpu *vcpu = current();
 	spci_vm_id_t vm_id = vcpu->vm->id;
 	uintreg_t ec = GET_ESR_EC(esr_el2);
 
-	CHECK(ec == 0x18);
+	CHECK(ec == EC_MSR);
 	/*
 	 * Handle accesses to debug and performance monitor registers.
 	 * Inject an exception for unhandled/unsupported registers.
 	 */
 	if (debug_el1_is_register_access(esr_el2)) {
 		if (!debug_el1_process_access(vcpu, vm_id, esr_el2)) {
-			return inject_el1_unknown_exception(vcpu, esr_el2);
+			inject_el1_unknown_exception(vcpu, esr_el2);
+			return;
 		}
 	} else if (perfmon_is_register_access(esr_el2)) {
 		if (!perfmon_process_access(vcpu, vm_id, esr_el2)) {
-			return inject_el1_unknown_exception(vcpu, esr_el2);
+			inject_el1_unknown_exception(vcpu, esr_el2);
+			return;
 		}
 	} else if (feature_id_is_register_access(esr_el2)) {
 		if (!feature_id_process_access(vcpu, esr_el2)) {
-			return inject_el1_unknown_exception(vcpu, esr_el2);
+			inject_el1_unknown_exception(vcpu, esr_el2);
+			return;
 		}
 	} else {
-		return inject_el1_unknown_exception(vcpu, esr_el2);
+		inject_el1_unknown_exception(vcpu, esr_el2);
+		return;
 	}
 
 	/* Instruction was fulfilled. Skip it and run the next one. */
 	vcpu->regs.pc += GET_NEXT_PC_INC(esr_el2);
-	return NULL;
 }
diff --git a/src/arch/aarch64/sysregs.h b/src/arch/aarch64/sysregs.h
index 8e4ca00..7198576 100644
--- a/src/arch/aarch64/sysregs.h
+++ b/src/arch/aarch64/sysregs.h
@@ -95,13 +95,85 @@
  */
 #define MDCR_EL2_HPMN (UINT64_C(0x1f) << 0)
 
+/*
+ * Definitions for interpreting the ESR_ELx registers.
+ * See Arm Architecture Reference Manual Armv8-A, D13.2.36 and D13.2.37.
+ */
+
+/**
+ * Offset for the Exception Class (EC) field in the ESR.
+ */
+#define ESR_EC_OFFSET UINT64_C(26)
+
+/**
+ * Gets the Exception Class from the ESR.
+ */
+#define GET_ESR_EC(esr) ((esr) >> ESR_EC_OFFSET)
+
+/**
+ * Gets the Instruction Length bit for the synchronous exception
+ */
+#define GET_ESR_IL(esr) ((esr) & (1 << 25))
+
+/**
+ * ESR code for an Unknown Reason exception.
+ */
+#define EC_UNKNOWN UINT64_C(0x0)
+
+/**
+ * ESR code for trapped WFI or WFE instruction execution.
+ */
+#define EC_WFI_WFE UINT64_C(0x1)
+
+/**
+ * ESR code for HVC instruction execution.
+ */
+#define EC_HVC UINT64_C(0x16)
+
+/**
+ * ESR code for SMC instruction execution.
+ */
+#define EC_SMC UINT64_C(0x17)
+
+/**
+ * ESR code for MSR, MRS, or System instruction execution.
+ */
+#define EC_MSR UINT64_C(0x18)
+
+/**
+ * ESR code for Instruction Abort from a lower Exception level.
+ */
+#define EC_INSTRUCTION_ABORT_LOWER_EL UINT64_C(0x20)
+
+/**
+ * ESR code for Instruction Abort without a change in Exception level.
+ */
+#define EC_INSTRUCTION_ABORT_SAME_EL UINT64_C(0x21)
+
+/**
+ * ESR code for Data Abort from a lower Exception level.
+ */
+#define EC_DATA_ABORT_LOWER_EL UINT64_C(0x24)
+
+/**
+ * ESR code for Data Abort without a change in Exception level.
+ */
+#define EC_DATA_ABORT_SAME_EL UINT64_C(0x25)
+
+/**
+ * Mask for ISS bits in ESR_ELx registers.
+ */
+#define ISS_MASK ((UINT64_C(0x1) << 22) - UINT64_C(0x1))
+
+#define GET_ESR_ISS(esr) (ISS_MASK & (esr))
+
 /**
  * System register are identified by op0, op2, op1, crn, crm. The ISS encoding
  * includes also rt and direction. Exclude them, @see D13.2.37 (D13-2977).
  */
-#define ISS_SYSREG_MASK                                                      \
-	(((UINT64_C(0x1) << 22) - UINT64_C(0x1)) & /* Select the ISS bits */ \
-	 ~(UINT64_C(0x1f) << 5) &		   /* exclude rt */          \
+#define ISS_SYSREG_MASK                                     \
+	(ISS_MASK &		  /* Select the ISS bits */ \
+	 ~(UINT64_C(0x1f) << 5) & /* exclude rt */          \
 	 ~UINT64_C(0x1) /* exclude direction */)
 
 #define GET_ISS_SYSREG(esr) (ISS_SYSREG_MASK & (esr))
diff --git a/test/arch/mm_test.c b/test/arch/mm_test.c
index bf0c186..6ea8726 100644
--- a/test/arch/mm_test.c
+++ b/test/arch/mm_test.c
@@ -20,7 +20,7 @@
 
 #include "test/hftest.h"
 
-/** There must be at least two levels in the page table.  */
+/** There must be at least two levels in the page table. */
 #define MAX_LEVEL_LOWER_BOUND 1
 
 /**
diff --git a/test/inc/test/vmapi/exception_handler.h b/test/inc/test/vmapi/exception_handler.h
index 07ef312..47de143 100644
--- a/test/inc/test/vmapi/exception_handler.h
+++ b/test/inc/test/vmapi/exception_handler.h
@@ -20,7 +20,11 @@
 
 bool exception_handler_skip_instruction(void);
 
-bool exception_handler_yield(void);
+bool exception_handler_yield_unknown(void);
+
+bool exception_handler_yield_data_abort(void);
+
+bool exception_handler_yield_instruction_abort(void);
 
 int exception_handler_get_num(void);
 
diff --git a/test/vmapi/common/BUILD.gn b/test/vmapi/common/BUILD.gn
index 48be642..081c90e 100644
--- a/test/vmapi/common/BUILD.gn
+++ b/test/vmapi/common/BUILD.gn
@@ -21,4 +21,5 @@
     "exception_handler.c",
     "spci.c",
   ]
+  include_dirs = [ "//src/arch/aarch64" ]
 }
diff --git a/test/vmapi/common/exception_handler.c b/test/vmapi/common/exception_handler.c
index c58a5b8..14fe1e1 100644
--- a/test/vmapi/common/exception_handler.c
+++ b/test/vmapi/common/exception_handler.c
@@ -19,6 +19,7 @@
 #include "vmapi/hf/call.h"
 
 #include "../msr.h"
+#include "sysregs.h"
 #include "test/hftest.h"
 
 /**
@@ -81,7 +82,7 @@
  * EL1 exception handler to use in unit test VMs.
  * Yields control back to the hypervisor and sends the number of exceptions.
  */
-bool exception_handler_yield(void)
+static bool exception_handler_yield(void)
 {
 	dlog("%s function is triggered!\n", __func__);
 	++exception_handler_exception_count;
@@ -93,6 +94,42 @@
 }
 
 /**
+ * EL1 exception handler to use in unit test VMs.
+ * Yields control back to the hypervisor and sends the number of exceptions.
+ * Asserts that the Exception Class is Unknown.
+ */
+bool exception_handler_yield_unknown(void)
+{
+	uintreg_t esr_el1 = read_msr(ESR_EL1);
+	EXPECT_EQ(GET_ESR_EC(esr_el1), EC_UNKNOWN);
+	return exception_handler_yield();
+}
+
+/**
+ * EL1 exception handler to use in unit test VMs.
+ * Yields control back to the hypervisor and sends the number of exceptions.
+ * Asserts that the Exception Class is Data Abort (same EL).
+ */
+bool exception_handler_yield_data_abort(void)
+{
+	uintreg_t esr_el1 = read_msr(ESR_EL1);
+	EXPECT_EQ(GET_ESR_EC(esr_el1), EC_DATA_ABORT_SAME_EL);
+	return exception_handler_yield();
+}
+
+/**
+ * EL1 exception handler to use in unit test VMs.
+ * Yields control back to the hypervisor and sends the number of exceptions.
+ * Asserts that the Exception Class is Instruction Abort (same EL).
+ */
+bool exception_handler_yield_instruction_abort(void)
+{
+	uintreg_t esr_el1 = read_msr(ESR_EL1);
+	EXPECT_EQ(GET_ESR_EC(esr_el1), EC_INSTRUCTION_ABORT_SAME_EL);
+	return exception_handler_yield();
+}
+
+/**
  * Returns the number of times the instruction handler was invoked.
  */
 int exception_handler_get_num(void)
diff --git a/test/vmapi/primary_with_secondaries/services/boot.c b/test/vmapi/primary_with_secondaries/services/boot.c
index a7b9b66..6314c1b 100644
--- a/test/vmapi/primary_with_secondaries/services/boot.c
+++ b/test/vmapi/primary_with_secondaries/services/boot.c
@@ -55,7 +55,7 @@
 
 TEST_SERVICE(boot_memory_underrun)
 {
-	exception_setup(NULL, exception_handler_yield);
+	exception_setup(NULL, exception_handler_yield_data_abort);
 	/*
 	 * Try to read memory below the start of the image. This should result
 	 * in the VM trapping and yielding.
@@ -66,7 +66,7 @@
 
 TEST_SERVICE(boot_memory_overrun)
 {
-	exception_setup(NULL, exception_handler_yield);
+	exception_setup(NULL, exception_handler_yield_data_abort);
 	/*
 	 * Try to read memory above the limit defined by memory_size. This
 	 * should result in the VM trapping and yielding.
diff --git a/test/vmapi/primary_with_secondaries/services/memory.c b/test/vmapi/primary_with_secondaries/services/memory.c
index 38b292d..05272b1 100644
--- a/test/vmapi/primary_with_secondaries/services/memory.c
+++ b/test/vmapi/primary_with_secondaries/services/memory.c
@@ -80,7 +80,7 @@
 		SPCI_MEMORY_CACHE_WRITE_BACK, SPCI_MEMORY_OUTER_SHAREABLE);
 	EXPECT_EQ(spci_mem_donate(msg_size, msg_size, 0).func, SPCI_SUCCESS_32);
 
-	exception_setup(NULL, exception_handler_yield);
+	exception_setup(NULL, exception_handler_yield_data_abort);
 
 	/* Try using the memory that isn't valid unless it's been returned. */
 	page[16] = 123;
@@ -103,7 +103,7 @@
 		SPCI_MEMORY_CACHE_WRITE_BACK, SPCI_MEMORY_OUTER_SHAREABLE);
 	EXPECT_EQ(spci_mem_lend(msg_size, msg_size, 0).func, SPCI_SUCCESS_32);
 
-	exception_setup(NULL, exception_handler_yield);
+	exception_setup(NULL, exception_handler_yield_data_abort);
 
 	/* Try using the memory that isn't valid unless it's been returned. */
 	page[633] = 180;
@@ -113,7 +113,7 @@
 
 TEST_SERVICE(spci_memory_return)
 {
-	exception_setup(NULL, exception_handler_yield);
+	exception_setup(NULL, exception_handler_yield_data_abort);
 
 	/* Loop, giving memory back to the sender. */
 	for (;;) {
@@ -167,7 +167,7 @@
 
 TEST_SERVICE(spci_donate_check_upper_bound)
 {
-	exception_setup(NULL, exception_handler_yield);
+	exception_setup(NULL, exception_handler_yield_data_abort);
 
 	for (;;) {
 		struct spci_value ret = spci_msg_wait();
@@ -200,7 +200,7 @@
 
 TEST_SERVICE(spci_donate_check_lower_bound)
 {
-	exception_setup(NULL, exception_handler_yield);
+	exception_setup(NULL, exception_handler_yield_data_abort);
 
 	for (;;) {
 		struct spci_value ret = spci_msg_wait();
@@ -248,7 +248,7 @@
 
 	EXPECT_EQ(ret.func, SPCI_MEM_DONATE_32);
 
-	exception_setup(NULL, exception_handler_yield);
+	exception_setup(NULL, exception_handler_yield_data_abort);
 
 	ptr = (uint8_t *)constituents[0].address;
 
@@ -371,7 +371,7 @@
 
 TEST_SERVICE(spci_memory_lend_relinquish)
 {
-	exception_setup(NULL, exception_handler_yield);
+	exception_setup(NULL, exception_handler_yield_data_abort);
 
 	/* Loop, giving memory back to the sender. */
 	for (;;) {
@@ -540,7 +540,7 @@
  */
 TEST_SERVICE(spci_memory_lend_relinquish_X)
 {
-	exception_setup(NULL, exception_handler_yield);
+	exception_setup(NULL, exception_handler_yield_instruction_abort);
 
 	for (;;) {
 		struct spci_value ret = spci_msg_wait();
@@ -583,7 +583,7 @@
  */
 TEST_SERVICE(spci_memory_lend_relinquish_RW)
 {
-	exception_setup(NULL, exception_handler_yield);
+	exception_setup(NULL, exception_handler_yield_data_abort);
 
 	for (;;) {
 		struct spci_value ret = spci_msg_wait();
@@ -652,7 +652,7 @@
 
 	EXPECT_EQ(ret.func, SPCI_MEM_LEND_32);
 
-	exception_setup(NULL, exception_handler_yield);
+	exception_setup(NULL, exception_handler_yield_data_abort);
 
 	/* Choose which constituent we want to test. */
 	index = *(uint8_t *)constituents[0].address;
@@ -680,7 +680,7 @@
 	struct spci_memory_region_constituent *constituents =
 		spci_memory_region_get_constituents(memory_region);
 
-	exception_setup(NULL, exception_handler_yield);
+	exception_setup(NULL, exception_handler_yield_data_abort);
 
 	EXPECT_EQ(ret.func, SPCI_MEM_LEND_32);
 
diff --git a/test/vmapi/primary_with_secondaries/services/unmapped.c b/test/vmapi/primary_with_secondaries/services/unmapped.c
index df00f6c..d4b323c 100644
--- a/test/vmapi/primary_with_secondaries/services/unmapped.c
+++ b/test/vmapi/primary_with_secondaries/services/unmapped.c
@@ -31,7 +31,7 @@
 {
 	/* Not using NULL so static analysis doesn't complain. */
 	int *p = (int *)1;
-	exception_setup(NULL, exception_handler_yield);
+	exception_setup(NULL, exception_handler_yield_data_abort);
 	*p = 12;
 	FAIL("Exception not generated by invalid access.");
 }
@@ -48,7 +48,7 @@
 		ARRAY_SIZE(constituents), 0, 0, SPCI_MEMORY_RW_X,
 		SPCI_MEMORY_NORMAL_MEM, SPCI_MEMORY_CACHE_WRITE_BACK,
 		SPCI_MEMORY_OUTER_SHAREABLE);
-	exception_setup(NULL, exception_handler_yield);
+	exception_setup(NULL, exception_handler_yield_data_abort);
 
 	EXPECT_EQ(spci_mem_donate(msg_size, msg_size, 0).func, SPCI_SUCCESS_32);
 
@@ -60,7 +60,7 @@
 {
 	/* Not using NULL so static analysis doesn't complain. */
 	int (*f)(void) = (int (*)(void))4;
-	exception_setup(NULL, exception_handler_yield);
+	exception_setup(NULL, exception_handler_yield_instruction_abort);
 	f();
 	FAIL("Exception not generated by invalid access.");
 }
@@ -85,7 +85,7 @@
 		SPCI_MEMORY_NORMAL_MEM, SPCI_MEMORY_CACHE_WRITE_BACK,
 		SPCI_MEMORY_OUTER_SHAREABLE);
 
-	exception_setup(NULL, exception_handler_yield);
+	exception_setup(NULL, exception_handler_yield_instruction_abort);
 
 	EXPECT_EQ(spci_mem_donate(msg_size, msg_size, 0).func, SPCI_SUCCESS_32);