Blame SOURCES/kvm-memory-Define-API-for-MemoryRegionOps-to-take-attrs-.patch

8be556
From f193533e350724bdb1818eb590608ec1bf7625b2 Mon Sep 17 00:00:00 2001
8be556
From: Xiao Wang <jasowang@redhat.com>
8be556
Date: Tue, 7 Jul 2015 09:18:10 +0200
8be556
Subject: [PATCH 122/217] memory: Define API for MemoryRegionOps to take attrs
8be556
 and return status
8be556
MIME-Version: 1.0
8be556
Content-Type: text/plain; charset=UTF-8
8be556
Content-Transfer-Encoding: 8bit
8be556
8be556
Message-id: <1436260751-25015-8-git-send-email-jasowang@redhat.com>
8be556
Patchwork-id: 66782
8be556
O-Subject: [RHEL7.2 qemu-kvm-rhev PATCH V2 07/68] memory: Define API for MemoryRegionOps to take attrs and return status
8be556
Bugzilla: 1227343
8be556
RH-Acked-by: Michael S. Tsirkin <mst@redhat.com>
8be556
RH-Acked-by: David Gibson <dgibson@redhat.com>
8be556
RH-Acked-by: Laurent Vivier <lvivier@redhat.com>
8be556
RH-Acked-by: Thomas Huth <thuth@redhat.com>
8be556
8be556
From: Peter Maydell <peter.maydell@linaro.org>
8be556
8be556
Define an API so that devices can register MemoryRegionOps whose read
8be556
and write callback functions are passed an arbitrary pointer to some
8be556
transaction attributes and can return a success-or-failure status code.
8be556
This will allow us to model devices which:
8be556
 * behave differently for ARM Secure/NonSecure memory accesses
8be556
 * behave differently for privileged/unprivileged accesses
8be556
 * may return a transaction failure (causing a guest exception)
8be556
   for erroneous accesses
8be556
8be556
This patch defines the new API and plumbs the attributes parameter through
8be556
to the memory.c public level functions io_mem_read() and io_mem_write(),
8be556
where it is currently dummied out.
8be556
8be556
The success/failure response indication is also propagated out to
8be556
io_mem_read() and io_mem_write(), which retain the old-style
8be556
boolean true-for-error return.
8be556
8be556
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8be556
Acked-by: Paolo Bonzini <pbonzini@redhat.com>
8be556
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
8be556
(cherry picked from commit cc05c43ad942165ecc6ffd39e41991bee43af044)
8be556
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
8be556
---
8be556
 include/exec/memattrs.h |  41 ++++++++++
8be556
 include/exec/memory.h   |  22 +++++
8be556
 memory.c                | 207 ++++++++++++++++++++++++++++++++----------------
8be556
 3 files changed, 203 insertions(+), 67 deletions(-)
8be556
 create mode 100644 include/exec/memattrs.h
8be556
8be556
diff --git a/include/exec/memattrs.h b/include/exec/memattrs.h
8be556
new file mode 100644
8be556
index 0000000..1cb3fc0
8be556
--- /dev/null
8be556
+++ b/include/exec/memattrs.h
8be556
@@ -0,0 +1,41 @@
8be556
+/*
8be556
+ * Memory transaction attributes
8be556
+ *
8be556
+ * Copyright (c) 2015 Linaro Limited.
8be556
+ *
8be556
+ * Authors:
8be556
+ *  Peter Maydell <peter.maydell@linaro.org>
8be556
+ *
8be556
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
8be556
+ * See the COPYING file in the top-level directory.
8be556
+ *
8be556
+ */
8be556
+
8be556
+#ifndef MEMATTRS_H
8be556
+#define MEMATTRS_H
8be556
+
8be556
+/* Every memory transaction has associated with it a set of
8be556
+ * attributes. Some of these are generic (such as the ID of
8be556
+ * the bus master); some are specific to a particular kind of
8be556
+ * bus (such as the ARM Secure/NonSecure bit). We define them
8be556
+ * all as non-overlapping bitfields in a single struct to avoid
8be556
+ * confusion if different parts of QEMU used the same bit for
8be556
+ * different semantics.
8be556
+ */
8be556
+typedef struct MemTxAttrs {
8be556
+    /* Bus masters which don't specify any attributes will get this
8be556
+     * (via the MEMTXATTRS_UNSPECIFIED constant), so that we can
8be556
+     * distinguish "all attributes deliberately clear" from
8be556
+     * "didn't specify" if necessary.
8be556
+     */
8be556
+    unsigned int unspecified:1;
8be556
+} MemTxAttrs;
8be556
+
8be556
+/* Bus masters which don't specify any attributes will get this,
8be556
+ * which has all attribute bits clear except the topmost one
8be556
+ * (so that we can distinguish "all attributes deliberately clear"
8be556
+ * from "didn't specify" if necessary).
8be556
+ */
8be556
+#define MEMTXATTRS_UNSPECIFIED ((MemTxAttrs) { .unspecified = 1 })
8be556
+
8be556
+#endif
8be556
diff --git a/include/exec/memory.h b/include/exec/memory.h
8be556
index a2ea587..88de117 100644
8be556
--- a/include/exec/memory.h
8be556
+++ b/include/exec/memory.h
8be556
@@ -28,6 +28,7 @@
8be556
 #ifndef CONFIG_USER_ONLY
8be556
 #include "exec/hwaddr.h"
8be556
 #endif
8be556
+#include "exec/memattrs.h"
8be556
 #include "qemu/queue.h"
8be556
 #include "qemu/int128.h"
8be556
 #include "qemu/notify.h"
8be556
@@ -68,6 +69,16 @@ struct IOMMUTLBEntry {
8be556
     IOMMUAccessFlags perm;
8be556
 };
8be556
 
8be556
+/* New-style MMIO accessors can indicate that the transaction failed.
8be556
+ * A zero (MEMTX_OK) response means success; anything else is a failure
8be556
+ * of some kind. The memory subsystem will bitwise-OR together results
8be556
+ * if it is synthesizing an operation from multiple smaller accesses.
8be556
+ */
8be556
+#define MEMTX_OK 0
8be556
+#define MEMTX_ERROR             (1U << 0) /* device returned an error */
8be556
+#define MEMTX_DECODE_ERROR      (1U << 1) /* nothing at that address */
8be556
+typedef uint32_t MemTxResult;
8be556
+
8be556
 /*
8be556
  * Memory region callbacks
8be556
  */
8be556
@@ -84,6 +95,17 @@ struct MemoryRegionOps {
8be556
                   uint64_t data,
8be556
                   unsigned size);
8be556
 
8be556
+    MemTxResult (*read_with_attrs)(void *opaque,
8be556
+                                   hwaddr addr,
8be556
+                                   uint64_t *data,
8be556
+                                   unsigned size,
8be556
+                                   MemTxAttrs attrs);
8be556
+    MemTxResult (*write_with_attrs)(void *opaque,
8be556
+                                    hwaddr addr,
8be556
+                                    uint64_t data,
8be556
+                                    unsigned size,
8be556
+                                    MemTxAttrs attrs);
8be556
+
8be556
     enum device_endian endianness;
8be556
     /* Guest-visible constraints: */
8be556
     struct {
8be556
diff --git a/memory.c b/memory.c
8be556
index a11e9bf..23d6345 100644
8be556
--- a/memory.c
8be556
+++ b/memory.c
8be556
@@ -368,57 +368,84 @@ static void adjust_endianness(MemoryRegion *mr, uint64_t *data, unsigned size)
8be556
     }
8be556
 }
8be556
 
8be556
-static void memory_region_oldmmio_read_accessor(MemoryRegion *mr,
8be556
+static MemTxResult memory_region_oldmmio_read_accessor(MemoryRegion *mr,
8be556
+                                                       hwaddr addr,
8be556
+                                                       uint64_t *value,
8be556
+                                                       unsigned size,
8be556
+                                                       unsigned shift,
8be556
+                                                       uint64_t mask,
8be556
+                                                       MemTxAttrs attrs)
8be556
+{
8be556
+    uint64_t tmp;
8be556
+
8be556
+    tmp = mr->ops->old_mmio.read[ctz32(size)](mr->opaque, addr);
8be556
+    trace_memory_region_ops_read(mr, addr, tmp, size);
8be556
+    *value |= (tmp & mask) << shift;
8be556
+    return MEMTX_OK;
8be556
+}
8be556
+
8be556
+static MemTxResult  memory_region_read_accessor(MemoryRegion *mr,
8be556
                                                 hwaddr addr,
8be556
                                                 uint64_t *value,
8be556
                                                 unsigned size,
8be556
                                                 unsigned shift,
8be556
-                                                uint64_t mask)
8be556
+                                                uint64_t mask,
8be556
+                                                MemTxAttrs attrs)
8be556
 {
8be556
     uint64_t tmp;
8be556
 
8be556
-    tmp = mr->ops->old_mmio.read[ctz32(size)](mr->opaque, addr);
8be556
+    if (mr->flush_coalesced_mmio) {
8be556
+        qemu_flush_coalesced_mmio_buffer();
8be556
+    }
8be556
+    tmp = mr->ops->read(mr->opaque, addr, size);
8be556
     trace_memory_region_ops_read(mr, addr, tmp, size);
8be556
     *value |= (tmp & mask) << shift;
8be556
+    return MEMTX_OK;
8be556
 }
8be556
 
8be556
-static void memory_region_read_accessor(MemoryRegion *mr,
8be556
-                                        hwaddr addr,
8be556
-                                        uint64_t *value,
8be556
-                                        unsigned size,
8be556
-                                        unsigned shift,
8be556
-                                        uint64_t mask)
8be556
+static MemTxResult memory_region_read_with_attrs_accessor(MemoryRegion *mr,
8be556
+                                                          hwaddr addr,
8be556
+                                                          uint64_t *value,
8be556
+                                                          unsigned size,
8be556
+                                                          unsigned shift,
8be556
+                                                          uint64_t mask,
8be556
+                                                          MemTxAttrs attrs)
8be556
 {
8be556
-    uint64_t tmp;
8be556
+    uint64_t tmp = 0;
8be556
+    MemTxResult r;
8be556
 
8be556
     if (mr->flush_coalesced_mmio) {
8be556
         qemu_flush_coalesced_mmio_buffer();
8be556
     }
8be556
-    tmp = mr->ops->read(mr->opaque, addr, size);
8be556
+    r = mr->ops->read_with_attrs(mr->opaque, addr, &tmp, size, attrs);
8be556
     trace_memory_region_ops_read(mr, addr, tmp, size);
8be556
     *value |= (tmp & mask) << shift;
8be556
+    return r;
8be556
 }
8be556
 
8be556
-static void memory_region_oldmmio_write_accessor(MemoryRegion *mr,
8be556
-                                                 hwaddr addr,
8be556
-                                                 uint64_t *value,
8be556
-                                                 unsigned size,
8be556
-                                                 unsigned shift,
8be556
-                                                 uint64_t mask)
8be556
+static MemTxResult memory_region_oldmmio_write_accessor(MemoryRegion *mr,
8be556
+                                                        hwaddr addr,
8be556
+                                                        uint64_t *value,
8be556
+                                                        unsigned size,
8be556
+                                                        unsigned shift,
8be556
+                                                        uint64_t mask,
8be556
+                                                        MemTxAttrs attrs)
8be556
 {
8be556
     uint64_t tmp;
8be556
 
8be556
     tmp = (*value >> shift) & mask;
8be556
     trace_memory_region_ops_write(mr, addr, tmp, size);
8be556
     mr->ops->old_mmio.write[ctz32(size)](mr->opaque, addr, tmp);
8be556
+    return MEMTX_OK;
8be556
 }
8be556
 
8be556
-static void memory_region_write_accessor(MemoryRegion *mr,
8be556
-                                         hwaddr addr,
8be556
-                                         uint64_t *value,
8be556
-                                         unsigned size,
8be556
-                                         unsigned shift,
8be556
-                                         uint64_t mask)
8be556
+static MemTxResult memory_region_write_accessor(MemoryRegion *mr,
8be556
+                                                hwaddr addr,
8be556
+                                                uint64_t *value,
8be556
+                                                unsigned size,
8be556
+                                                unsigned shift,
8be556
+                                                uint64_t mask,
8be556
+                                                MemTxAttrs attrs)
8be556
 {
8be556
     uint64_t tmp;
8be556
 
8be556
@@ -428,24 +455,46 @@ static void memory_region_write_accessor(MemoryRegion *mr,
8be556
     tmp = (*value >> shift) & mask;
8be556
     trace_memory_region_ops_write(mr, addr, tmp, size);
8be556
     mr->ops->write(mr->opaque, addr, tmp, size);
8be556
+    return MEMTX_OK;
8be556
 }
8be556
 
8be556
-static void access_with_adjusted_size(hwaddr addr,
8be556
+static MemTxResult memory_region_write_with_attrs_accessor(MemoryRegion *mr,
8be556
+                                                           hwaddr addr,
8be556
+                                                           uint64_t *value,
8be556
+                                                           unsigned size,
8be556
+                                                           unsigned shift,
8be556
+                                                           uint64_t mask,
8be556
+                                                           MemTxAttrs attrs)
8be556
+{
8be556
+    uint64_t tmp;
8be556
+
8be556
+    if (mr->flush_coalesced_mmio) {
8be556
+        qemu_flush_coalesced_mmio_buffer();
8be556
+    }
8be556
+    tmp = (*value >> shift) & mask;
8be556
+    trace_memory_region_ops_write(mr, addr, tmp, size);
8be556
+    return mr->ops->write_with_attrs(mr->opaque, addr, tmp, size, attrs);
8be556
+}
8be556
+
8be556
+static MemTxResult access_with_adjusted_size(hwaddr addr,
8be556
                                       uint64_t *value,
8be556
                                       unsigned size,
8be556
                                       unsigned access_size_min,
8be556
                                       unsigned access_size_max,
8be556
-                                      void (*access)(MemoryRegion *mr,
8be556
-                                                     hwaddr addr,
8be556
-                                                     uint64_t *value,
8be556
-                                                     unsigned size,
8be556
-                                                     unsigned shift,
8be556
-                                                     uint64_t mask),
8be556
-                                      MemoryRegion *mr)
8be556
+                                      MemTxResult (*access)(MemoryRegion *mr,
8be556
+                                                            hwaddr addr,
8be556
+                                                            uint64_t *value,
8be556
+                                                            unsigned size,
8be556
+                                                            unsigned shift,
8be556
+                                                            uint64_t mask,
8be556
+                                                            MemTxAttrs attrs),
8be556
+                                      MemoryRegion *mr,
8be556
+                                      MemTxAttrs attrs)
8be556
 {
8be556
     uint64_t access_mask;
8be556
     unsigned access_size;
8be556
     unsigned i;
8be556
+    MemTxResult r = MEMTX_OK;
8be556
 
8be556
     if (!access_size_min) {
8be556
         access_size_min = 1;
8be556
@@ -459,14 +508,16 @@ static void access_with_adjusted_size(hwaddr addr,
8be556
     access_mask = -1ULL >> (64 - access_size * 8);
8be556
     if (memory_region_big_endian(mr)) {
8be556
         for (i = 0; i < size; i += access_size) {
8be556
-            access(mr, addr + i, value, access_size,
8be556
-                   (size - access_size - i) * 8, access_mask);
8be556
+            r |= access(mr, addr + i, value, access_size,
8be556
+                        (size - access_size - i) * 8, access_mask, attrs);
8be556
         }
8be556
     } else {
8be556
         for (i = 0; i < size; i += access_size) {
8be556
-            access(mr, addr + i, value, access_size, i * 8, access_mask);
8be556
+            r |= access(mr, addr + i, value, access_size, i * 8,
8be556
+                        access_mask, attrs);
8be556
         }
8be556
     }
8be556
+    return r;
8be556
 }
8be556
 
8be556
 static AddressSpace *memory_region_to_address_space(MemoryRegion *mr)
8be556
@@ -1053,62 +1104,82 @@ bool memory_region_access_valid(MemoryRegion *mr,
8be556
     return true;
8be556
 }
8be556
 
8be556
-static uint64_t memory_region_dispatch_read1(MemoryRegion *mr,
8be556
-                                             hwaddr addr,
8be556
-                                             unsigned size)
8be556
+static MemTxResult memory_region_dispatch_read1(MemoryRegion *mr,
8be556
+                                                hwaddr addr,
8be556
+                                                uint64_t *pval,
8be556
+                                                unsigned size,
8be556
+                                                MemTxAttrs attrs)
8be556
 {
8be556
-    uint64_t data = 0;
8be556
+    *pval = 0;
8be556
 
8be556
     if (mr->ops->read) {
8be556
-        access_with_adjusted_size(addr, &data, size,
8be556
-                                  mr->ops->impl.min_access_size,
8be556
-                                  mr->ops->impl.max_access_size,
8be556
-                                  memory_region_read_accessor, mr);
8be556
+        return access_with_adjusted_size(addr, pval, size,
8be556
+                                         mr->ops->impl.min_access_size,
8be556
+                                         mr->ops->impl.max_access_size,
8be556
+                                         memory_region_read_accessor,
8be556
+                                         mr, attrs);
8be556
+    } else if (mr->ops->read_with_attrs) {
8be556
+        return access_with_adjusted_size(addr, pval, size,
8be556
+                                         mr->ops->impl.min_access_size,
8be556
+                                         mr->ops->impl.max_access_size,
8be556
+                                         memory_region_read_with_attrs_accessor,
8be556
+                                         mr, attrs);
8be556
     } else {
8be556
-        access_with_adjusted_size(addr, &data, size, 1, 4,
8be556
-                                  memory_region_oldmmio_read_accessor, mr);
8be556
+        return access_with_adjusted_size(addr, pval, size, 1, 4,
8be556
+                                         memory_region_oldmmio_read_accessor,
8be556
+                                         mr, attrs);
8be556
     }
8be556
-
8be556
-    return data;
8be556
 }
8be556
 
8be556
-static bool memory_region_dispatch_read(MemoryRegion *mr,
8be556
-                                        hwaddr addr,
8be556
-                                        uint64_t *pval,
8be556
-                                        unsigned size)
8be556
+static MemTxResult memory_region_dispatch_read(MemoryRegion *mr,
8be556
+                                               hwaddr addr,
8be556
+                                               uint64_t *pval,
8be556
+                                               unsigned size,
8be556
+                                               MemTxAttrs attrs)
8be556
 {
8be556
+    MemTxResult r;
8be556
+
8be556
     if (!memory_region_access_valid(mr, addr, size, false)) {
8be556
         *pval = unassigned_mem_read(mr, addr, size);
8be556
-        return true;
8be556
+        return MEMTX_DECODE_ERROR;
8be556
     }
8be556
 
8be556
-    *pval = memory_region_dispatch_read1(mr, addr, size);
8be556
+    r = memory_region_dispatch_read1(mr, addr, pval, size, attrs);
8be556
     adjust_endianness(mr, pval, size);
8be556
-    return false;
8be556
+    return r;
8be556
 }
8be556
 
8be556
-static bool memory_region_dispatch_write(MemoryRegion *mr,
8be556
-                                         hwaddr addr,
8be556
-                                         uint64_t data,
8be556
-                                         unsigned size)
8be556
+static MemTxResult memory_region_dispatch_write(MemoryRegion *mr,
8be556
+                                                hwaddr addr,
8be556
+                                                uint64_t data,
8be556
+                                                unsigned size,
8be556
+                                                MemTxAttrs attrs)
8be556
 {
8be556
     if (!memory_region_access_valid(mr, addr, size, true)) {
8be556
         unassigned_mem_write(mr, addr, data, size);
8be556
-        return true;
8be556
+        return MEMTX_DECODE_ERROR;
8be556
     }
8be556
 
8be556
     adjust_endianness(mr, &data, size);
8be556
 
8be556
     if (mr->ops->write) {
8be556
-        access_with_adjusted_size(addr, &data, size,
8be556
-                                  mr->ops->impl.min_access_size,
8be556
-                                  mr->ops->impl.max_access_size,
8be556
-                                  memory_region_write_accessor, mr);
8be556
+        return access_with_adjusted_size(addr, &data, size,
8be556
+                                         mr->ops->impl.min_access_size,
8be556
+                                         mr->ops->impl.max_access_size,
8be556
+                                         memory_region_write_accessor, mr,
8be556
+                                         attrs);
8be556
+    } else if (mr->ops->write_with_attrs) {
8be556
+        return
8be556
+            access_with_adjusted_size(addr, &data, size,
8be556
+                                      mr->ops->impl.min_access_size,
8be556
+                                      mr->ops->impl.max_access_size,
8be556
+                                      memory_region_write_with_attrs_accessor,
8be556
+                                      mr, attrs);
8be556
     } else {
8be556
-        access_with_adjusted_size(addr, &data, size, 1, 4,
8be556
-                                  memory_region_oldmmio_write_accessor, mr);
8be556
+        return access_with_adjusted_size(addr, &data, size, 1, 4,
8be556
+                                         memory_region_oldmmio_write_accessor,
8be556
+                                         mr, attrs);
8be556
     }
8be556
-    return false;
8be556
 }
8be556
 
8be556
 void memory_region_init_io(MemoryRegion *mr,
8be556
@@ -2001,13 +2072,15 @@ void address_space_destroy(AddressSpace *as)
8be556
 
8be556
 bool io_mem_read(MemoryRegion *mr, hwaddr addr, uint64_t *pval, unsigned size)
8be556
 {
8be556
-    return memory_region_dispatch_read(mr, addr, pval, size);
8be556
+    return memory_region_dispatch_read(mr, addr, pval, size,
8be556
+                                       MEMTXATTRS_UNSPECIFIED);
8be556
 }
8be556
 
8be556
 bool io_mem_write(MemoryRegion *mr, hwaddr addr,
8be556
                   uint64_t val, unsigned size)
8be556
 {
8be556
-    return memory_region_dispatch_write(mr, addr, val, size);
8be556
+    return memory_region_dispatch_write(mr, addr, val, size,
8be556
+                                        MEMTXATTRS_UNSPECIFIED);
8be556
 }
8be556
 
8be556
 typedef struct MemoryRegionList MemoryRegionList;
8be556
-- 
8be556
1.8.3.1
8be556