aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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;
}