diff options
author | Richard Henderson <richard.henderson@linaro.org> | 2024-04-16 17:39:25 -0700 |
---|---|---|
committer | Richard Henderson <richard.henderson@linaro.org> | 2024-05-15 10:03:44 +0200 |
commit | d8bc1381250b39079d5ed33d2be7eee801ca41c9 (patch) | |
tree | 91f5361b4cfa8d59f7ac53fa1f4709a4fd888b51 | |
parent | 5ae8adbb01cdb0bd2f3c1c444b3e543b38737102 (diff) | |
download | qemu-d8bc1381250b39079d5ed33d2be7eee801ca41c9.zip qemu-d8bc1381250b39079d5ed33d2be7eee801ca41c9.tar.gz qemu-d8bc1381250b39079d5ed33d2be7eee801ca41c9.tar.bz2 |
target/hppa: Implement PSW_X
Use PAGE_WRITE_INV to temporarily enable write permission
on for a given page, driven by PSW_X being set.
Reviewed-by: Helge Deller <deller@gmx.de>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
-rw-r--r-- | target/hppa/mem_helper.c | 42 |
1 files changed, 25 insertions, 17 deletions
diff --git a/target/hppa/mem_helper.c b/target/hppa/mem_helper.c index d09877a..ca7bbe0 100644 --- a/target/hppa/mem_helper.c +++ b/target/hppa/mem_helper.c @@ -296,30 +296,38 @@ int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx, goto egress; } - /* In reverse priority order, check for conditions which raise faults. - As we go, remove PROT bits that cover the condition we want to check. - In this way, the resulting PROT will force a re-check of the - architectural TLB entry for the next access. */ - if (unlikely(!ent->d)) { + /* + * In priority order, check for conditions which raise faults. + * Remove PROT bits that cover the condition we want to check, + * so that the resulting PROT will force a re-check of the + * architectural TLB entry for the next access. + */ + if (unlikely(ent->t)) { + prot &= PAGE_EXEC; + if (!(type & PAGE_EXEC)) { + /* The T bit is set -- Page Reference Fault. */ + ret = EXCP_PAGE_REF; + } + } else if (!ent->d) { + prot &= PAGE_READ | PAGE_EXEC; if (type & PAGE_WRITE) { /* The D bit is not set -- TLB Dirty Bit Fault. */ ret = EXCP_TLB_DIRTY; } + } else if (unlikely(ent->b)) { prot &= PAGE_READ | PAGE_EXEC; - } - if (unlikely(ent->b)) { if (type & PAGE_WRITE) { - /* The B bit is set -- Data Memory Break Fault. */ - ret = EXCP_DMB; - } - prot &= PAGE_READ | PAGE_EXEC; - } - if (unlikely(ent->t)) { - if (!(type & PAGE_EXEC)) { - /* The T bit is set -- Page Reference Fault. */ - ret = EXCP_PAGE_REF; + /* + * The B bit is set -- Data Memory Break Fault. + * Except when PSW_X is set, allow this single access to succeed. + * The write bit will be invalidated for subsequent accesses. + */ + if (env->psw_xb & PSW_X) { + prot |= PAGE_WRITE_INV; + } else { + ret = EXCP_DMB; + } } - prot &= PAGE_EXEC; } egress: |