From: Richard Henderson <[email protected]> Notice writes to pages which are being monitored. Mark the page dirty, re-enable writes, and retry the instruction without emulation.
Assert the fault is not from a stage1 page table walk. Signed-off-by: Richard Henderson <[email protected]> Tested-by: Philippe Mathieu-Daudé <[email protected]> Reviewed-by: Philippe Mathieu-Daudé <[email protected]> Signed-off-by: Philippe Mathieu-Daudé <[email protected]> --- target/arm/hvf/hvf.c | 52 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 9 deletions(-) diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index de1e8fb8a05..0f584b8137a 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -1869,9 +1869,10 @@ static int hvf_handle_exception(CPUState *cpu, hv_vcpu_exit_exception_t *excp) uint32_t srt = (syndrome >> 16) & 0x1f; uint32_t cm = (syndrome >> 8) & 0x1; uint64_t val = 0; + uint64_t ipa = excp->physical_address; + AddressSpace *as = cpu_get_address_space(cpu, ARMASIdx_NS); - trace_hvf_data_abort(excp->virtual_address, - excp->physical_address, isv, + trace_hvf_data_abort(excp->virtual_address, ipa, isv, iswrite, s1ptw, len, srt); if (cm) { @@ -1880,23 +1881,56 @@ static int hvf_handle_exception(CPUState *cpu, hv_vcpu_exit_exception_t *excp) break; } + /* Handle dirty page logging for ram. */ + if (iswrite) { + hwaddr xlat; + MemoryRegion *mr = address_space_translate(as, ipa, &xlat, + NULL, true, + MEMTXATTRS_UNSPECIFIED); + if (memory_region_is_ram(mr)) { + uintptr_t page_size = qemu_real_host_page_size(); + intptr_t page_mask = -(intptr_t)page_size; + uint64_t ipa_page = ipa & page_mask; + + /* TODO: Inject exception to the guest. */ + assert(!mr->readonly); + + if (memory_region_get_dirty_log_mask(mr)) { + memory_region_set_dirty(mr, ipa_page + xlat, page_size); + hvf_unprotect_dirty_range(ipa_page, page_size); + } + + /* Retry with page writes enabled. */ + break; + } + } + + /* + * TODO: If s1ptw, this is an error in the guest os page tables. + * Inject the exception into the guest. + */ + assert(!s1ptw); + + /* + * TODO: ISV will be 0 for SIMD or SVE accesses. + * Inject the exception into the guest. + */ assert(isv); + /* + * Emulate MMIO. + * TODO: Inject faults for errors. + */ if (iswrite) { val = hvf_get_reg(cpu, srt); - address_space_write(&address_space_memory, - excp->physical_address, - MEMTXATTRS_UNSPECIFIED, &val, len); + address_space_write(as, ipa, MEMTXATTRS_UNSPECIFIED, &val, len); } else { - address_space_read(&address_space_memory, - excp->physical_address, - MEMTXATTRS_UNSPECIFIED, &val, len); + address_space_read(as, ipa, MEMTXATTRS_UNSPECIFIED, &val, len); if (sse) { val = sextract64(val, 0, len * 8); } hvf_set_reg(cpu, srt, val); } - advance_pc = true; break; } -- 2.51.0
