diff mbox series

[v3,27/32] s390x/tcg: Provide probe_write_access helper

Message ID 20190307121539.12842-28-david@redhat.com
State New
Headers show
Series s390x/tcg: Vector Instruction Support Part 1 | expand

Commit Message

David Hildenbrand March 7, 2019, 12:15 p.m. UTC
Instead of checking e.g. the first access on every touched page, we should
check the actual access, otherwise we might get false positives when Low
Address Protection (LAP) is active. As probe_write() can only deal with
accesses to one page, we have to loop.

Use i64 for the length, although not needed - easier to reuse
TCG temps we already have in the translation functions where this will
be used. Also allow it to be used from other helpers.

Signed-off-by: David Hildenbrand <david@redhat.com>
---
 target/s390x/helper.h     |  1 +
 target/s390x/internal.h   |  2 ++
 target/s390x/mem_helper.c | 25 +++++++++++++++++++++++++
 3 files changed, 28 insertions(+)

Comments

Richard Henderson March 7, 2019, 2:10 p.m. UTC | #1
On 3/7/19 4:15 AM, David Hildenbrand wrote:
> +void probe_write_access(CPUS390XState *env, uint64_t addr, uint64_t len,
> +                        uintptr_t ra)
> +{
> +#ifdef CONFIG_USER_ONLY
> +    if (!h2g_valid(addr) || !h2g_valid(addr + len - 1)) {
> +        s390_program_interrupt(env, PGM_ADDRESSING, ILEN_AUTO, ra);
> +    }

You need

  || page_check_range(addr, len, PAGE_WRITE) < 0

as well.


r~
David Hildenbrand March 7, 2019, 2:34 p.m. UTC | #2
On 07.03.19 15:10, Richard Henderson wrote:
> On 3/7/19 4:15 AM, David Hildenbrand wrote:
>> +void probe_write_access(CPUS390XState *env, uint64_t addr, uint64_t len,
>> +                        uintptr_t ra)
>> +{
>> +#ifdef CONFIG_USER_ONLY
>> +    if (!h2g_valid(addr) || !h2g_valid(addr + len - 1)) {
>> +        s390_program_interrupt(env, PGM_ADDRESSING, ILEN_AUTO, ra);
>> +    }
> 
> You need
> 
>   || page_check_range(addr, len, PAGE_WRITE) < 0
> 
> as well.

Indeed, thanks.

So it should be


+void probe_write_access(CPUS390XState *env, uint64_t addr, uint64_t len,
+                        uintptr_t ra)
+{
+#ifdef CONFIG_USER_ONLY
+    if (!h2g_valid(addr) || !h2g_valid(addr + len - 1) ||
+        page_check_range(addr, len, PAGE_WRITE) < 0) {
+        s390_program_interrupt(env, PGM_ADDRESSING, ILEN_AUTO, ra);
+    }
+#else
+    /* test the actual access, not just any access to the page due to LAP */
+    while (len) {
+        const uint64_t pagelen = -(addr | -TARGET_PAGE_MASK);
+        const uint64_t curlen = MIN(pagelen, len);
+
+        probe_write(env, addr, curlen, cpu_mmu_index(env, false), ra);
+        addr = wrap_address(env, addr + curlen);
+        len -= curlen;
+    }
+#endif
+}

Conny, I can resend if you don't feel like fixing up (or there is more to do).
Cornelia Huck March 7, 2019, 2:40 p.m. UTC | #3
On Thu, 7 Mar 2019 15:34:27 +0100
David Hildenbrand <david@redhat.com> wrote:

> On 07.03.19 15:10, Richard Henderson wrote:
> > On 3/7/19 4:15 AM, David Hildenbrand wrote:  
> >> +void probe_write_access(CPUS390XState *env, uint64_t addr, uint64_t len,
> >> +                        uintptr_t ra)
> >> +{
> >> +#ifdef CONFIG_USER_ONLY
> >> +    if (!h2g_valid(addr) || !h2g_valid(addr + len - 1)) {
> >> +        s390_program_interrupt(env, PGM_ADDRESSING, ILEN_AUTO, ra);
> >> +    }  
> > 
> > You need
> > 
> >   || page_check_range(addr, len, PAGE_WRITE) < 0
> > 
> > as well.  
> 
> Indeed, thanks.
> 
> So it should be
> 
> 
> +void probe_write_access(CPUS390XState *env, uint64_t addr, uint64_t len,
> +                        uintptr_t ra)
> +{
> +#ifdef CONFIG_USER_ONLY
> +    if (!h2g_valid(addr) || !h2g_valid(addr + len - 1) ||
> +        page_check_range(addr, len, PAGE_WRITE) < 0) {
> +        s390_program_interrupt(env, PGM_ADDRESSING, ILEN_AUTO, ra);
> +    }
> +#else
> +    /* test the actual access, not just any access to the page due to LAP */
> +    while (len) {
> +        const uint64_t pagelen = -(addr | -TARGET_PAGE_MASK);
> +        const uint64_t curlen = MIN(pagelen, len);
> +
> +        probe_write(env, addr, curlen, cpu_mmu_index(env, false), ra);
> +        addr = wrap_address(env, addr + curlen);
> +        len -= curlen;
> +    }
> +#endif
> +}
> 
> Conny, I can resend if you don't feel like fixing up (or there is more to do).
> 

If that's the only thing, I can easily fold it in.
Richard Henderson March 7, 2019, 3:15 p.m. UTC | #4
On 3/7/19 6:34 AM, David Hildenbrand wrote:
> So it should be
> 
> 
> +void probe_write_access(CPUS390XState *env, uint64_t addr, uint64_t len,
> +                        uintptr_t ra)
> +{
> +#ifdef CONFIG_USER_ONLY
> +    if (!h2g_valid(addr) || !h2g_valid(addr + len - 1) ||
> +        page_check_range(addr, len, PAGE_WRITE) < 0) {
> +        s390_program_interrupt(env, PGM_ADDRESSING, ILEN_AUTO, ra);
> +    }

Correct.  With that,
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~
diff mbox series

Patch

diff --git a/target/s390x/helper.h b/target/s390x/helper.h
index 577edb384f..e2710f4fb3 100644
--- a/target/s390x/helper.h
+++ b/target/s390x/helper.h
@@ -123,6 +123,7 @@  DEF_HELPER_4(cu42, i32, env, i32, i32, i32)
 DEF_HELPER_5(msa, i32, env, i32, i32, i32, i32)
 DEF_HELPER_FLAGS_1(stpt, TCG_CALL_NO_RWG, i64, env)
 DEF_HELPER_FLAGS_1(stck, TCG_CALL_NO_RWG_SE, i64, env)
+DEF_HELPER_FLAGS_3(probe_write_access, TCG_CALL_NO_WG, void, env, i64, i64)
 
 /* === Vector Support Instructions === */
 DEF_HELPER_FLAGS_4(vll, TCG_CALL_NO_WG, void, env, ptr, i64, i64)
diff --git a/target/s390x/internal.h b/target/s390x/internal.h
index 07b69b8ea0..3b4855c175 100644
--- a/target/s390x/internal.h
+++ b/target/s390x/internal.h
@@ -349,6 +349,8 @@  void ioinst_handle_sal(S390CPU *cpu, uint64_t reg1, uintptr_t ra);
 
 /* mem_helper.c */
 target_ulong mmu_real2abs(CPUS390XState *env, target_ulong raddr);
+void probe_write_access(CPUS390XState *env, uint64_t addr, uint64_t len,
+                        uintptr_t ra);
 
 
 /* mmu_helper.c */
diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c
index a506d9ef99..b0fd5a2668 100644
--- a/target/s390x/mem_helper.c
+++ b/target/s390x/mem_helper.c
@@ -2623,3 +2623,28 @@  uint32_t HELPER(cu42)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
     return convert_unicode(env, r1, r2, m3, GETPC(),
                            decode_utf32, encode_utf16);
 }
+
+void probe_write_access(CPUS390XState *env, uint64_t addr, uint64_t len,
+                        uintptr_t ra)
+{
+#ifdef CONFIG_USER_ONLY
+    if (!h2g_valid(addr) || !h2g_valid(addr + len - 1)) {
+        s390_program_interrupt(env, PGM_ADDRESSING, ILEN_AUTO, ra);
+    }
+#else
+    /* test the actual access, not just any access to the page due to LAP */
+    while (len) {
+        const uint64_t pagelen = -(addr | -TARGET_PAGE_MASK);
+        const uint64_t curlen = MIN(pagelen, len);
+
+        probe_write(env, addr, curlen, cpu_mmu_index(env, false), ra);
+        addr = wrap_address(env, addr + curlen);
+        len -= curlen;
+    }
+#endif
+}
+
+void HELPER(probe_write_access)(CPUS390XState *env, uint64_t addr, uint64_t len)
+{
+    probe_write_access(env, addr, len, GETPC());
+}