Return not just the tag memory, but the data memory, flags,
and attributes.  Make sure probe of NoTagAccess looks like
any other page permission failure.

Signed-off-by: Richard Henderson <[email protected]>
---
 target/arm/tcg/mte_helper.c | 102 +++++++++++++++++++++---------------
 1 file changed, 60 insertions(+), 42 deletions(-)

diff --git a/target/arm/tcg/mte_helper.c b/target/arm/tcg/mte_helper.c
index 8f7a222b9c..e6e78634b6 100644
--- a/target/arm/tcg/mte_helper.c
+++ b/target/arm/tcg/mte_helper.c
@@ -27,6 +27,7 @@
 #ifdef CONFIG_USER_ONLY
 #include "user/cpu_loop.h"
 #include "user/page-protection.h"
+#include "user/guest-host.h"
 #else
 #include "system/physmem.h"
 #endif
@@ -80,46 +81,53 @@ static void mte_perm_check_fail(CPUARMState *env, uint64_t 
dirty_ptr,
 }
 #endif
 
-static uint8_t *
+typedef struct AllocationTagMem {
+    uint8_t *tag_mem;
+    void *ptr_mem;
+    int flags;
+    MemTxAttrs attrs;
+} AllocationTagMem;
+
+static AllocationTagMem
 allocation_tag_mem_internal(CPUARMState *env, int ptr_mmu_idx,
-                            uint64_t ptr, MMUAccessType ptr_access,
+                            vaddr ptr, MMUAccessType ptr_access,
                             int ptr_size, MMUAccessType tag_access,
                             bool probe, uintptr_t ra)
 {
-#ifdef CONFIG_USER_ONLY
-    const size_t page_data_size = TARGET_PAGE_SIZE >> (LOG2_TAG_GRANULE + 1);
-    uint64_t clean_ptr = useronly_clean_ptr(ptr);
-    int flags = page_get_flags(clean_ptr);
-    uint8_t *tags;
-    uintptr_t index;
+    AllocationTagMem ret = { };
 
-    if (!(flags & (ptr_access == MMU_DATA_STORE ? PAGE_WRITE_ORG : 
PAGE_READ))) {
+#ifdef CONFIG_USER_ONLY
+    vaddr clean_ptr = useronly_clean_ptr(ptr);
+    int flags = page_get_flags(clean_ptr);
+    int req_flags = ptr_access == MMU_DATA_STORE ? PAGE_WRITE_ORG : PAGE_READ;
+
+    if (unlikely(!(flags & req_flags))) {
         if (probe) {
-            return NULL;
+            ret.flags = TLB_INVALID_MASK;
+            goto fini;
         }
         cpu_loop_exit_sigsegv(env_cpu(env), ptr, ptr_access,
                               !(flags & PAGE_VALID), ra);
     }
 
     /* Require both MAP_ANON and PROT_MTE for the page. */
-    if (!(flags & PAGE_ANON) || !(flags & PAGE_MTE)) {
-        return NULL;
+    if ((flags & PAGE_ANON) && (flags & PAGE_MTE)) {
+        size_t page_data_size = TARGET_PAGE_SIZE >> (LOG2_TAG_GRANULE + 1);
+        uint8_t *tags = page_get_target_data(clean_ptr, page_data_size);
+        uintptr_t index = extract64(ptr, LOG2_TAG_GRANULE + 1,
+                                    TARGET_PAGE_BITS - LOG2_TAG_GRANULE - 1);
+        ret.tag_mem = tags + index;
     }
 
-    tags = page_get_target_data(clean_ptr, page_data_size);
-
-    index = extract32(ptr, LOG2_TAG_GRANULE + 1,
-                      TARGET_PAGE_BITS - LOG2_TAG_GRANULE - 1);
-    return tags + index;
+    ret.ptr_mem = g2h_untagged_vaddr(clean_ptr);
+    ret.attrs = MEMTXATTRS_UNSPECIFIED;
 #else
     CPUTLBEntryFull *full;
-    MemTxAttrs attrs;
-    int in_page, flags;
+    int in_page;
     hwaddr ptr_paddr, tag_paddr, xlat;
     MemoryRegion *mr;
     ARMASIdx tag_asi;
     AddressSpace *tag_as;
-    void *host;
 
     /*
      * Probe the first byte of the virtual address.  This raises an
@@ -131,12 +139,13 @@ allocation_tag_mem_internal(CPUARMState *env, int 
ptr_mmu_idx,
      * for the pure probe, or assert that we received a valid page for the
      * no-fault-expected probe.
      */
-    flags = probe_access_full(env, ptr, 0, ptr_access, ptr_mmu_idx,
-                              ra == 0, &host, &full, ra);
-    if (unlikely(flags & TLB_INVALID_MASK)) {
+    ret.flags = probe_access_full(env, ptr, 0, ptr_access, ptr_mmu_idx,
+                                  ra == 0, &ret.ptr_mem, &full, ra);
+    if (unlikely(ret.flags & TLB_INVALID_MASK)) {
         assert(probe);
-        return NULL;
+        goto fini;
     }
+    ret.attrs = full->attrs;
 
     switch (full->extra.arm.pte_attrs) {
     case 0xf0: /* Tagged */
@@ -145,7 +154,9 @@ allocation_tag_mem_internal(CPUARMState *env, int 
ptr_mmu_idx,
     case 0xe0: /* NoTagAccess */
         if (cpu_isar_feature(aa64_mteperm, env_archcpu(env))) {
             if (probe) {
-                return NULL;
+                ret.ptr_mem = NULL;
+                ret.flags = TLB_INVALID_MASK;
+                goto fini;
             }
             assert(ra);
             mte_perm_check_fail(env, ptr, ra, tag_access == MMU_DATA_STORE);
@@ -153,27 +164,25 @@ allocation_tag_mem_internal(CPUARMState *env, int 
ptr_mmu_idx,
         /* fall through */
 
     default: /* Not Tagged */
-        return NULL;
+        goto fini;
     }
 
     /*
      * If not backed by host ram, there is no tag storage: access unchecked.
      * This is probably a guest os bug though, so log it.
      */
-    if (unlikely(flags & TLB_MMIO)) {
+    if (unlikely(ret.flags & TLB_MMIO)) {
         qemu_log_mask(LOG_GUEST_ERROR,
                       "Page @ 0x%" PRIx64 " indicates Tagged Normal memory "
                       "but is not backed by host ram\n", ptr);
-        return NULL;
+        goto fini;
     }
 
     /*
-     * Remember these values across the second lookup below,
+     * Remember this across the second lookup below,
      * which may invalidate this pointer via tlb resize.
      */
     ptr_paddr = full->phys_addr | (ptr & ~TARGET_PAGE_MASK);
-    attrs = full->attrs;
-    full = NULL;
 
     /*
      * The Normal memory access can extend to the next page.  E.g. a single
@@ -183,26 +192,30 @@ allocation_tag_mem_internal(CPUARMState *env, int 
ptr_mmu_idx,
      */
     in_page = -(ptr | TARGET_PAGE_MASK);
     if (unlikely(ptr_size > in_page)) {
-        flags |= probe_access_full(env, ptr + in_page, 0, ptr_access,
-                                   ptr_mmu_idx, ra == 0, &host, &full, ra);
-        assert(!(flags & TLB_INVALID_MASK));
+        void *discard_mem;
+        int flags2 = probe_access_full(env, ptr + in_page, 0, ptr_access,
+                                       ptr_mmu_idx, ra == 0,
+                                       &discard_mem, &full, ra);
+
+        assert(!(flags2 & TLB_INVALID_MASK));
+        ret.flags |= flags2;
     }
 
     /* Any debug exception has priority over a tag check exception. */
-    if (!probe && unlikely(flags & TLB_WATCHPOINT)) {
+    if (!probe && unlikely(ret.flags & TLB_WATCHPOINT)) {
         int wp = ptr_access == MMU_DATA_LOAD ? BP_MEM_READ : BP_MEM_WRITE;
         assert(ra != 0);
-        cpu_check_watchpoint(env_cpu(env), ptr, ptr_size, attrs, wp, ra);
+        cpu_check_watchpoint(env_cpu(env), ptr, ptr_size, ret.attrs, wp, ra);
     }
 
     /* Convert to the physical address in tag space.  */
     tag_paddr = ptr_paddr >> (LOG2_TAG_GRANULE + 1);
 
     /* Look up the address in tag space. */
-    tag_asi = attrs.secure ? ARMASIdx_TagS : ARMASIdx_TagNS;
+    tag_asi = ret.attrs.secure ? ARMASIdx_TagS : ARMASIdx_TagNS;
     tag_as = cpu_get_address_space(env_cpu(env), tag_asi);
     mr = address_space_translate(tag_as, tag_paddr, &xlat, NULL,
-                                 tag_access == MMU_DATA_STORE, attrs);
+                                 tag_access == MMU_DATA_STORE, ret.attrs);
 
     /*
      * Note that @mr will never be NULL.  If there is nothing in the address
@@ -215,7 +228,7 @@ allocation_tag_mem_internal(CPUARMState *env, int 
ptr_mmu_idx,
                       "Tag Memory @ 0x%" HWADDR_PRIx " not found for "
                       "Normal Memory @ 0x%" HWADDR_PRIx "\n",
                       tag_paddr, ptr_paddr);
-        return NULL;
+        goto fini;
     }
 
     /*
@@ -227,8 +240,11 @@ allocation_tag_mem_internal(CPUARMState *env, int 
ptr_mmu_idx,
         physical_memory_set_dirty_flag(tag_ra, DIRTY_MEMORY_MIGRATION);
     }
 
-    return memory_region_get_ram_ptr(mr) + xlat;
+    ret.tag_mem = memory_region_get_ram_ptr(mr) + xlat;
 #endif
+
+ fini:
+    return ret;
 }
 
 static G_NORETURN void canonical_tag_write_fail(CPUARMState *env,
@@ -250,7 +266,8 @@ static uint8_t *allocation_tag_mem(CPUARMState *env, int 
ptr_mmu_idx,
                                    uintptr_t ra)
 {
     return allocation_tag_mem_internal(env, ptr_mmu_idx, ptr, ptr_access,
-                                       ptr_size, tag_access, false, ra);
+                                       ptr_size, tag_access, false, ra)
+           .tag_mem;
 }
 
 uint8_t *allocation_tag_mem_probe(CPUARMState *env, int ptr_mmu_idx,
@@ -258,7 +275,8 @@ uint8_t *allocation_tag_mem_probe(CPUARMState *env, int 
ptr_mmu_idx,
                                   int ptr_size, MMUAccessType tag_access)
 {
     return allocation_tag_mem_internal(env, ptr_mmu_idx, ptr, ptr_access,
-                                       ptr_size, tag_access, true, 0);
+                                       ptr_size, tag_access, true, 0)
+           .tag_mem;
 }
 
 uint64_t HELPER(irg)(CPUARMState *env, uint64_t rn, uint64_t rm)
-- 
2.43.0


Reply via email to