I'm far from confident this handling here is correct. Hence RFC. In particular not sure on what locks I should hold for this to be even moderately safe.
The function already appears to be inconsistent in what it returns as the CONFIG_ATOMIC64 block returns the endian converted 'eventual' value of the cmpxchg whereas the TCG_OVERSIZED_GUEST case returns the previous value. Signed-off-by: Jonathan Cameron <[email protected]> --- target/arm/ptw.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/target/arm/ptw.c b/target/arm/ptw.c index 5eb3577bcd..37ddb4a4db 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -711,8 +711,38 @@ static uint64_t arm_casq_ptw(CPUARMState *env, uint64_t old_val, void *host = ptw->out_host; if (unlikely(!host)) { - fi->type = ARMFault_UnsuppAtomicUpdate; - return 0; + /* Can I do a load and store via the physical address */ + + bool locked = bql_locked(); + if (!locked) { + bql_lock(); + } + /* Page table in MMIO Memory Region */ + if (ptw->out_be) { + old_val = cpu_to_be64(old_val); + new_val = cpu_to_be64(new_val); + cpu_physical_memory_read(ptw->out_phys, &cur_val, 8); + if (cur_val == old_val) { + cpu_physical_memory_write(ptw->out_phys, &new_val, 8); + cur_val = be64_to_cpu(new_val); + } else { + cur_val = be64_to_cpu(cur_val); + } + } else { + old_val = cpu_to_le64(old_val); + new_val = cpu_to_le64(new_val); + cpu_physical_memory_read(ptw->out_phys, &cur_val, 8); + if (cur_val == old_val) { + cpu_physical_memory_write(ptw->out_phys, &new_val, 8); + cur_val = le64_to_cpu(new_val); + } else { + cur_val = le64_to_cpu(cur_val); + } + } + if (!locked) { + bql_unlock(); + } + return cur_val; } /* -- 2.39.2
