[RFC kvm-unit-tests 09/27] arm: realm: Add support for changing the state of memory

Joey Gouly
2023-01-27T11:57:27Z

For a Realm, the guest physical address (in reality the IPA/GPA of the VM)
has an associated state (Realm IPA State, RIPAS) which is either of :
RIPAS_RAM
RIPAS_EMPTY

The state of the physical address decides certain behaviors. e.g., any access
to a RIPAS_EMPTY PA will generate a Synchronous External Abort back to the Realm,
from the RMM.

All "PA" that represents RAM for the Realm, must be set to RIPAS_RAM before
an access is made. When the initial image (e.g., test, DTB) of a Realm is
loaded, the hypervisor/VMM can transition the state of the loaded "area" to
RIPAS_RAM. The rest of the "RAM" must be transitioned by the test payload
before any access is made.

Similarly, a Realm could set an "IPA" to RIPAS_EMPTY, when it is about to use
the "unprotected" alias of the IPA. This is a hint for the host to reclaim the
page from the protected "IPA.

This patchs adds supporting helpers for setting the IPA state from Realm. These
will be used later for the Realm.

Co-developed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Joey Gouly <joey.gouly@arm.com>
---
lib/arm/mmu.c | 1 +
lib/arm64/asm/rsi.h | 8 ++++++++
lib/arm64/rsi.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 53 insertions(+)

diff --git a/lib/arm/mmu.c b/lib/arm/mmu.c
index 6f1f42f5..2b5a7141 100644
--- a/lib/arm/mmu.c
+++ b/lib/arm/mmu.c
@@ -12,6 +12,7 @@
#include <asm/setup.h>
#include <asm/page.h>
#include <asm/io.h>
+#include <asm/rsi.h>

#include "alloc_page.h"
#include "vmalloc.h"
diff --git a/lib/arm64/asm/rsi.h b/lib/arm64/asm/rsi.h
index 8b9b91b2..c8179341 100644
--- a/lib/arm64/asm/rsi.h
+++ b/lib/arm64/asm/rsi.h
@@ -33,4 +33,12 @@ static inline bool is_realm(void)
return rsi_present;
}

+enum ripas_t {
+ RIPAS_EMPTY,
+ RIPAS_RAM,
+};
+
+void arm_set_memory_protected(unsigned long va, size_t size);
+void arm_set_memory_shared(unsigned long va, size_t size);
+
#endif /* __ASMARM64_RSI_H_ */
diff --git a/lib/arm64/rsi.c b/lib/arm64/rsi.c
index 23a4e963..08c77889 100644
--- a/lib/arm64/rsi.c
+++ b/lib/arm64/rsi.c
@@ -65,3 +65,47 @@ void arm_rsi_init(void)
/* Set the upper bit of the IPA as the NS_SHARED pte attribute */
prot_ns_shared = (1UL << phys_mask_shift);
}
+
+static unsigned rsi_set_addr_range_state(unsigned long start, unsigned long size,
+ enum ripas_t state, unsigned long *top)
+{
+ struct smccc_result res;
+
+ rsi_invoke(SMC_RSI_IPA_STATE_SET, start, size, state, 0, 0, 0, 0, 0, 0, 0, 0, &res);
+ *top = res.r1;
+ return res.r0;
+}
+
+static void arm_set_memory_state(unsigned long start,
+ unsigned long size,
+ unsigned int ripas)
+{
+ int ret;
+ unsigned long end, top;
+ unsigned long old_start = start;
+
+ if (!is_realm())
+ return;
+
+ start = ALIGN_DOWN(start, RSI_GRANULE_SIZE);
+ if (start != old_start)
+ size += old_start - start;
+ end = ALIGN(start + size, RSI_GRANULE_SIZE);
+ while (start != end) {
+ ret = rsi_set_addr_range_state(start, (end - start),
+ ripas, &top);
+ assert(!ret);
+ assert(top <= end);
+ start = top;
+ }
+}
+
+void arm_set_memory_protected(unsigned long start, unsigned long size)
+{
+ arm_set_memory_state(start, size, RIPAS_RAM);
+}
+
+void arm_set_memory_shared(unsigned long start, unsigned long size)
+{
+ arm_set_memory_state(start, size, RIPAS_EMPTY);
+}
--
2.17.1