From: Sebastián Alba Vives <[email protected]>
When the atomic compare-and-swap for updating A/D bits in the page
table entry fails due to a concurrent PTE modification by another
vCPU, get_physical_address() jumps to the 'restart' label to re-walk
the page table from the root.
However, neither 'ptshift' nor 'base' are re-initialized before the
restart. After the walk completes, ptshift has been decremented to
its final value and base has been overwritten with an inner PTE PPN.
On goto restart, the for loop resets i=0 but ptshift and base remain
stale, causing the restarted walk to compute incorrect PTE addresses.
In an SMP guest with MTTCG and Svadu active, this can result in
incorrect physical address mappings or guest crashes.
Fix by saving the root base address and re-initializing both ptshift
and base on each restart.
Fixes: 0c3e702aca ("RISC-V CPU Helpers")
Signed-off-by: Sebastián Alba Vives <[email protected]>
Reviewed-by: Alistair Francis <[email protected]>
Message-ID: <[email protected]>
Signed-off-by: Alistair Francis <[email protected]>
(cherry picked from commit b2e874bfec59f6150b49a70df0529458efa0726b)
Signed-off-by: Michael Tokarev <[email protected]>
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 25619c556c..59f6d00774 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -1410,12 +1410,15 @@ static int get_physical_address(CPURISCVState *env,
hwaddr *physical,
adue = adue && (env->henvcfg & HENVCFG_ADUE);
}
- int ptshift = (levels - 1) * ptidxbits;
+ int ptshift;
target_ulong pte;
hwaddr pte_addr;
+ const hwaddr base_root = base;
int i;
restart:
+ ptshift = (levels - 1) * ptidxbits;
+ base = base_root;
for (i = 0; i < levels; i++, ptshift -= ptidxbits) {
target_ulong idx;
if (i == 0) {
--
2.47.3