aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2023-08-22 17:24:22 +0100
committerPeter Maydell <peter.maydell@linaro.org>2023-08-22 17:24:22 +0100
commit7b5a266c1f889812ae849751a1442fb9d0038e53 (patch)
treea4e41b25e39d6bd71c3f1ad443b772e6e4f687ae
parent2b20e79757081bab53e97b729969b1812e491f9f (diff)
target/arm/ptw: Check for block descriptors at invalid levels
The architecture doesn't permit block descriptors at any arbitrary level of the page table walk; it depends on the granule size which levels are permitted. We implemented only a partial version of this check which assumes that block descriptors are valid at all levels except level 3, which meant that we wouldn't deliver the Translation fault for all cases of this sort of guest page table error. Implement the logic corresponding to the pseudocode AArch64.DecodeDescriptorType() and AArch64.BlockDescSupported(). Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20230807141514.19075-14-peter.maydell@linaro.org
-rw-r--r--target/arm/ptw.c25
1 files changed, 23 insertions, 2 deletions
diff --git a/target/arm/ptw.c b/target/arm/ptw.c
index 7f217a3189..fbb0f8a0bf 100644
--- a/target/arm/ptw.c
+++ b/target/arm/ptw.c
@@ -1551,6 +1551,25 @@ static int check_s2_mmu_setup(ARMCPU *cpu, bool is_aa64, uint64_t tcr,
return INT_MIN;
}
+static bool lpae_block_desc_valid(ARMCPU *cpu, bool ds,
+ ARMGranuleSize gran, int level)
+{
+ /*
+ * See pseudocode AArch46.BlockDescSupported(): block descriptors
+ * are not valid at all levels, depending on the page size.
+ */
+ switch (gran) {
+ case Gran4K:
+ return (level == 0 && ds) || level == 1 || level == 2;
+ case Gran16K:
+ return (level == 1 && ds) || level == 2;
+ case Gran64K:
+ return (level == 1 && arm_pamax(cpu) == 52) || level == 2;
+ default:
+ g_assert_not_reached();
+ }
+}
+
/**
* get_phys_addr_lpae: perform one stage of page table walk, LPAE format
*
@@ -1786,8 +1805,10 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw,
new_descriptor = descriptor;
restart_atomic_update:
- if (!(descriptor & 1) || (!(descriptor & 2) && (level == 3))) {
- /* Invalid, or the Reserved level 3 encoding */
+ if (!(descriptor & 1) ||
+ (!(descriptor & 2) &&
+ !lpae_block_desc_valid(cpu, param.ds, param.gran, level))) {
+ /* Invalid, or a block descriptor at an invalid level */
goto do_translation_fault;
}